collisions: some fixes

This commit is contained in:
2026-08-26 19:20:43 +02:00
parent c94c2dc757
commit f1205e3851
+17 -13
View File
@@ -6,7 +6,9 @@ interface Ball {
vel: Vec2d;
}
const gravity = new Vec2d(0, 1000); // px/s^2
const GRAVITY = new Vec2d(0, 1000);
const BALL_RADIUS = 25;
let lastTime: number | undefined = undefined;
const box = [
@@ -27,26 +29,26 @@ function update(ctx: CanvasRenderingContext2D, timestamp: number) {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
// update
for (let i = balls.length - 1; i >= 0; i--) {
outer: for (let i = balls.length - 1; i >= 0; i--) {
let ball = balls[i];
const steps = 10;
const stepDt = dt / steps;
for (let step = 0; step < steps; step++) { // subdive the time step to improve accuracy
for (let step = 0; step < steps; step++) { // subdivide the time step to improve accuracy
balls[i].pos = ball.pos.add(ball.vel.scale(stepDt)); // update pos
if (balls[i].pos.y > ctx.canvas.height) {
balls.splice(i, 1); // remove if out of bounds
continue;
continue outer;
}
ball.vel = ball.vel.add(gravity.scale(stepDt)); // apply gravity
ball.vel = ball.vel.add(GRAVITY.scale(stepDt)); // apply gravity
// check collisions with each segment of the box
const friction = 0.5;
const restitution = 0.8;
ball = resolve_collision(ball, a, b, { friction, restitution});
ball = resolve_collision(ball, b, c, { friction, restitution});
ball = resolve_collision(ball, c, d, { friction, restitution});
ball = resolve_collision(ball, d, a, { friction, restitution});
ball = resolveBallSegmentCollision(ball, [a, b], { friction, restitution});
ball = resolveBallSegmentCollision(ball, [b, c], { friction, restitution});
ball = resolveBallSegmentCollision(ball, [c, d], { friction, restitution});
ball = resolveBallSegmentCollision(ball, [d, a], { friction, restitution});
}
balls[i] = ball;
@@ -54,7 +56,7 @@ function update(ctx: CanvasRenderingContext2D, timestamp: number) {
// drawing
for (const p of balls) {
fillCircle(ctx, p.pos, 5, 0xff00ff);
fillCircle(ctx, p.pos, BALL_RADIUS, 0xff00ff);
}
// draw box
@@ -70,7 +72,9 @@ function update(ctx: CanvasRenderingContext2D, timestamp: number) {
window.requestAnimationFrame((t) => update(ctx, t));
}
function resolve_collision(ball: Ball, a: Vec2d, b: Vec2d, { restitution = 1, friction = 0 }: { restitution?: number, friction?: number } = {}) {
function resolveBallSegmentCollision(ball: Ball, segment: [Vec2d, Vec2d], { restitution = 1, friction = 0 }: { restitution?: number, friction?: number } = {}) {
const [a, b] = segment;
const ab = b.sub(a);
const ab_sqlen = ab.dot(ab);
const point = ball.pos.sub(a); // pos of the ball relative to a
@@ -80,8 +84,7 @@ function resolve_collision(ball: Ball, a: Vec2d, b: Vec2d, { restitution = 1, fr
const closest_point = a.add(ab.scale(t));
const offset = ball.pos.sub(closest_point); // vector from the point to the segment
if (offset.length() < 5) {
console.log("collide")
if (offset.length() < BALL_RADIUS) {
const normal = offset.normalize();
// Decompose velocity into normal and tangent components
const norm_speed = ball.vel.dot(normal);
@@ -122,6 +125,7 @@ window.onload = () => {
const y = evt.clientY - rect.top;
addBall(x, y);
};
canvas.ontouchstart = (evt: TouchEvent) => {
const rect = canvas.getBoundingClientRect();
console.assert(evt.touches.length == 1, "mutiple touches are not supported");