Plane collision
This commit is contained in:
parent
99a306c10b
commit
ee9c4b0290
|
|
@ -33,9 +33,11 @@ export function gameLoop<T extends Record<string, unknown> | void>(setupOrFrame:
|
|||
const now = performance.now();
|
||||
const dt = (now - prevFrame) / 1000;
|
||||
|
||||
const newState = await frame(dt, state);
|
||||
if (newState) {
|
||||
state = newState;
|
||||
if (dt < 1) {
|
||||
const newState = await frame(dt, state);
|
||||
if (newState) {
|
||||
state = newState;
|
||||
}
|
||||
}
|
||||
|
||||
prevFrame = performance.now();
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ typedef struct rigid_body_t {
|
|||
////////// Prototypes
|
||||
|
||||
void rigid_body_resolve_collision(rigid_body* rb);
|
||||
int rigid_body_collide(rigid_body* a, rigid_body* b);
|
||||
void rigid_body_handle_collision(rigid_body* a, rigid_body* b);
|
||||
float point_to_line_dist(vec2 point, vec2 line_point, vec2 line_norm);
|
||||
|
||||
////////// Globals
|
||||
|
||||
|
|
@ -84,6 +84,15 @@ EXPORT(rigid_body_new_circle) rigid_body* rigid_body_new_circle(float x, float y
|
|||
return rb;
|
||||
}
|
||||
|
||||
EXPORT(rigid_body_new_plane) rigid_body* rigid_body_new_plane(float x, float y, float nx, float ny) {
|
||||
rigid_body* rb = rigid_body_new(x, y, 0, 0, INFINITY);
|
||||
|
||||
rb->type = TYPE_PLANE;
|
||||
rb->plane.normal = vec2_normalize((vec2){nx, ny});
|
||||
|
||||
return rb;
|
||||
}
|
||||
|
||||
EXPORT(rigid_body_free) void rigid_body_free(rigid_body* rb) {
|
||||
if (rb == rigid_body_head) {
|
||||
rigid_body_head = rb->next;
|
||||
|
|
@ -102,9 +111,9 @@ EXPORT(rigid_body_free) void rigid_body_free(rigid_body* rb) {
|
|||
}
|
||||
|
||||
EXPORT(rigid_body_update) void rigid_body_update(rigid_body* rb, float dt) {
|
||||
if (!isinf(rb->mass)) {
|
||||
rigid_body_resolve_collision(rb);
|
||||
rigid_body_resolve_collision(rb);
|
||||
|
||||
if (!isinf(rb->mass)) {
|
||||
rb->vel.x += rb->force.x * dt / rb->mass;
|
||||
rb->vel.y += rb->force.y * dt / rb->mass;
|
||||
|
||||
|
|
@ -131,35 +140,30 @@ EXPORT(rigid_body_add_force) void rigid_body_add_force(rigid_body* rb, float fx,
|
|||
}
|
||||
|
||||
void rigid_body_resolve_collision(rigid_body* rb) {
|
||||
rigid_body* current = rigid_body_head;
|
||||
rigid_body* current = rb->next;
|
||||
int is_static = isinf(rb->mass);
|
||||
|
||||
while (current) {
|
||||
if (current != rb && rigid_body_collide(rb, current)) {
|
||||
if (!is_static || !isinf(current->mass)) {
|
||||
rigid_body_handle_collision(rb, current);
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
|
||||
int rigid_body_collide(rigid_body* rb1, rigid_body* rb2) {
|
||||
if (rb1->type == TYPE_CIRCLE && rb2->type == TYPE_CIRCLE) {
|
||||
float dx = rb2->pos.x - rb1->pos.x;
|
||||
float dy = rb2->pos.y - rb1->pos.y;
|
||||
float distance = sqrtf(dx * dx + dy * dy);
|
||||
return distance < rb1->circle.radius + rb2->circle.radius;
|
||||
}
|
||||
|
||||
return 0; // Handle other types later
|
||||
}
|
||||
|
||||
void rigid_body_handle_collision(rigid_body* rb1, rigid_body* rb2) {
|
||||
if (rb1->type == TYPE_CIRCLE && rb2->type == TYPE_CIRCLE) {
|
||||
vec2 d = vec2_sub(rb2->pos, rb1->pos);
|
||||
vec2 n = vec2_normalize(d);
|
||||
float distance = vec2_mag(d);
|
||||
|
||||
float overlap = rb1->circle.radius + rb2->circle.radius - distance;
|
||||
vec2 n_overlap = vec2_mul(n, overlap / 2);
|
||||
if (overlap < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
vec2 n = vec2_normalize(d);
|
||||
float factor = (isinf(rb1->mass) || isinf(rb2->mass)) ? 1 : 0.5;
|
||||
vec2 n_overlap = vec2_mul(n, overlap * factor);
|
||||
|
||||
if (!isinf(rb1->mass)) {
|
||||
rb1->pos = vec2_sub(rb1->pos, n_overlap);
|
||||
|
|
@ -194,5 +198,28 @@ void rigid_body_handle_collision(rigid_body* rb1, rigid_body* rb2) {
|
|||
if (!isinf(rb2->mass)) {
|
||||
rb2->vel = vec2_add(v2t, vec2_mul(n, v2n_new));
|
||||
}
|
||||
} else if (rb1->type == TYPE_PLANE && rb2->type == TYPE_CIRCLE) {
|
||||
float distance = point_to_line_dist(rb2->pos, rb1->pos, rb1->plane.normal) - rb2->circle.radius;
|
||||
|
||||
float overlap = -distance;
|
||||
if (overlap < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
vec2 n = rb1->plane.normal;
|
||||
vec2 n_overlap = vec2_mul(n, overlap);
|
||||
|
||||
rb2->pos = vec2_add(rb2->pos, n_overlap);
|
||||
|
||||
float vn = vec2_dot(rb2->vel, n);
|
||||
vec2 vt = vec2_sub(rb2->vel, vec2_mul(n, vn));
|
||||
rb2->vel = vec2_add(vt, vec2_mul(n, -vn));
|
||||
} else if (rb1->type == TYPE_CIRCLE && rb2->type == TYPE_PLANE) {
|
||||
rigid_body_handle_collision(rb2, rb1);
|
||||
}
|
||||
}
|
||||
|
||||
float point_to_line_dist(vec2 p, vec2 line_point, vec2 normal) {
|
||||
vec2 diff = vec2_sub(p, line_point);
|
||||
return vec2_dot(diff, normal);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,14 @@ namespace Physics {
|
|||
const bodies = new Set<number>();
|
||||
|
||||
export function newCircle(x: number, y: number, radius: number, mass: number = 1.0): number {
|
||||
const circlePtr = E.rigid_body_new_circle(x, y, 0, 0, mass, radius);
|
||||
bodies.add(circlePtr);
|
||||
return circlePtr;
|
||||
const body = E.rigid_body_new_circle(x, y, 0, 0, mass, radius);
|
||||
bodies.add(body);
|
||||
return body;
|
||||
}
|
||||
export function newPlane(x: number, y: number, nx: number, ny: number): number {
|
||||
const body = E.rigid_body_new_plane(x, y, nx, ny);
|
||||
bodies.add(body);
|
||||
return body;
|
||||
}
|
||||
|
||||
export function deleteBody(body: number) {
|
||||
|
|
|
|||
|
|
@ -24,25 +24,27 @@ const setup = () => {
|
|||
event.preventDefault();
|
||||
const { x, y } = getRealPoint(canvas, event);
|
||||
console.log(event.button);
|
||||
const mass = event.button === 0 ? 1 : Number.POSITIVE_INFINITY;
|
||||
const mass = event.button === 0 ? Math.random() : Number.POSITIVE_INFINITY;
|
||||
const r = event.button === 0 ? 16 : 4;
|
||||
Physics.newCircle(x, y, r, mass);
|
||||
return false;
|
||||
});
|
||||
|
||||
Physics.newPlane(0, 0, 1, 0);
|
||||
Physics.newPlane(0, 0, 0, 1);
|
||||
Physics.newPlane(0, canvas.height, 0, -1);
|
||||
Physics.newPlane(canvas.width, 0, -1, 0);
|
||||
|
||||
return { canvas, ctx };
|
||||
}
|
||||
|
||||
const frame = (dt: number, state: ReturnType<typeof setup>) => {
|
||||
Physics.addGlobalForce(0, 98);
|
||||
Physics.addGlobalForce(0, 100);
|
||||
Physics.update(dt);
|
||||
|
||||
const { ctx, canvas } = state;
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
for (const { id, x, y, radius } of Physics.getBodies()) {
|
||||
if (y >= canvas.height) {
|
||||
Physics.deleteBody(id);
|
||||
}
|
||||
ctx.fillStyle = `hsl(${id % 360}, 100%, 50%)`;
|
||||
if (radius) {
|
||||
ctx.beginPath();
|
||||
|
|
|
|||
Loading…
Reference in New Issue