This commit is contained in:
Schluffe
2026-04-08 22:53:39 +02:00
parent c349dcec29
commit 20a1de7647
3 changed files with 143 additions and 81 deletions
+98 -36
View File
@@ -2,7 +2,12 @@ import type { Circle } from "#/engine/Circle.ts";
import type { Polygon } from "#/engine/Polygon.ts";
import type { Rect } from "#/engine/Rect.ts";
import $ from "#/engine/Scene.ts";
import { createVector, getDotProduct, type Vector } from "#/engine/Vector.ts";
import {
createVector,
getDotProduct,
invScale,
type Vector,
} from "#/engine/Vector.ts";
export enum Shape {
Circle,
@@ -95,6 +100,31 @@ export function createCollider(
};
}
function castOnCircle(
dx: number,
dy: number,
vx: number,
vy: number,
radius: number,
): number | null {
const a = vx * vx + vy * vy;
const b = 2 * (dx * vx + dy * vy);
const c = dx * dx + dy * dy - radius * radius;
let dis = b * b - 4 * a * c;
if (dis < 0) {
return null;
}
dis = Math.sqrt(dis);
const time = (-b - dis) / (2 * a);
if (time >= 0 && time <= 1) {
return time;
}
return null;
}
const inflAABB = {
x: 0,
y: 0,
@@ -179,52 +209,84 @@ function circleOnCircle(
const bx = positionB.x + colliderB.offset.x;
const by = positionB.y + colliderB.offset.y;
const inflRadius =
(colliderA.body as Circle).radius + (colliderB.body as Circle).radius;
const dx = ax - bx;
const dy = ay - by;
const vx = velocityA.x * delta;
const vy = velocityA.y * delta;
const radius =
(colliderA.body as Circle).radius + (colliderB.body as Circle).radius;
const disX = velocityA.x * delta;
const disY = velocityA.y * delta;
const time = castOnCircle(dx, dy, vx, vy, radius);
if (time === null) {
collision.cid = "";
collision.time = 0;
collision.normal.x = 0;
collision.normal.y = 0;
const a = disX * disX + disY * disY;
const b = 2 * (dx * disX + dy * disY);
const c = dx * dx + dy * dy - inflRadius * inflRadius;
let disc = b * b - 4 * a * c;
if (disc >= 0) {
disc = Math.sqrt(disc);
const time = (-b - disc) / (2 * a);
if (time >= 0 && time <= 1) {
const nx = dx + disX * time;
const ny = dy + disY * time;
const inv = 1.0 / Math.sqrt(nx * nx + ny * ny);
collision.normal.x = nx * inv;
collision.normal.y = ny * inv;
collision.time = time;
return;
}
return;
}
collision.cid = "";
collision.time = 0;
collision.normal.x = 0;
collision.normal.y = 0;
collision.time = time;
invScale(collision.normal, dx + vx * time, dy + vy * time);
}
const inflCircleAABB = {
x: 0,
y: 0,
width: 0,
height: 0,
};
function circleOnRect(
collision: Collision,
colliderA: Collider,
positionA: Vector,
velocityA: Vector,
colliderB: Collider,
positionB: Vector,
circleColl: Collider,
circlePos: Vector,
circleVel: Vector,
rectColl: Collider,
rectPos: Vector,
delta: number,
) {}
) {
const cx = circlePos.x + circleColl.offset.x;
const cy = circlePos.y + circleColl.offset.y;
const rx = rectPos.x + rectColl.offset.x;
const ry = rectPos.y + rectColl.offset.y;
const radius = (circleColl.body as Circle).radius;
inflCircleAABB.x = rx - radius;
inflCircleAABB.y = ry - radius;
inflCircleAABB.width = rectColl.width + radius;
inflCircleAABB.height = rectColl.height + radius;
const disX = circleVel.x * delta;
const disY = circleVel.y * delta;
let txNear = (inflCircleAABB.x - cx) / disX;
let txFar = (inflCircleAABB.x + inflCircleAABB.width - cx) / disX;
let tyNear = (inflCircleAABB.y - cy) / disY;
let tyFar = (inflCircleAABB.y + inflCircleAABB.width - cy) / disY;
if (txNear > txFar) {
[txNear, txFar] = [txFar, txNear];
}
if (tyNear > tyFar) {
[tyNear, tyFar] = [tyFar, tyNear];
}
// no collision at all
if (txNear > tyFar || tyNear > txFar) {
return;
}
const thNear = Math.max(txNear, tyNear);
const thFar = Math.min(txFar, tyFar);
// thFar < 0, collision is behind a frame
// thNear > 1, collision is ahead a frame
if (thFar < 0 || thNear > 1) {
return;
}
// WIP
}
function circleOnPolygon(
collision: Collision,