collisions: some fixes
This commit is contained in:
+17
-13
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user