diff --git a/collisions.ts b/collisions.ts index 42db8e2..2eca4c1 100644 --- a/collisions.ts +++ b/collisions.ts @@ -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");