working wall collisions

This commit is contained in:
jacob 2026-02-09 17:16:09 -06:00
parent bf56bd7155
commit 09490d8c47
2 changed files with 191 additions and 622 deletions

View File

@ -1364,25 +1364,59 @@ P_Space P_SpaceFromFrame(Arena *arena, P_Frame *frame)
}
}
//- Debug draw walls
{
i64 wall_idx = 0;
//- Push walls to space
for (GenWall *wall = first_wall; wall; wall = wall->next)
{
Vec2 p0 = VEC2(wall->start.x / P_TilesPerMeter - P_WorldPitch / 2, wall->start.y / P_TilesPerMeter - P_WorldPitch / 2);
Vec2 p1 = VEC2(wall->end.x / P_TilesPerMeter - P_WorldPitch / 2, wall->end.y / P_TilesPerMeter - P_WorldPitch / 2);
u64 color_seed0 = MixU64(wall_idx + 1);
u64 color_seed1 = MixU64(color_seed0);
u64 color_seed2 = MixU64(color_seed1);
Vec4 color = Color_White;
color.r = Norm24(color_seed0) * 0.75 + 0.25;
color.g = Norm24(color_seed1) * 0.75 + 0.25;
color.b = Norm24(color_seed2) * 0.75 + 0.25;
P_DebugDrawLine(p0, p1, color);
++wall_idx;
// P_Shape shape = P_ShapeFromDesc(.count = 2, .points = { p0, p1 });
P_Shape shape = P_ShapeFromDesc(.count = 2, .points = { p0, p1 }, .radius = 0.01 );
Rng2 aabb = P_BoundingBoxFromShape(shape);
aabb = AddRng2Vec2(aabb, VEC2(P_WorldPitch / 2.0, P_WorldPitch / 2.0));
aabb.p0 = FloorVec2(aabb.p0);
aabb.p1 = CeilVec2(aabb.p1);
aabb.p1.x = MaxF32(aabb.p1.x, aabb.p0.x + 1);
aabb.p1.y = MaxF32(aabb.p1.y, aabb.p0.y + 1);
aabb = IntersectRng2(aabb, space_aabb);
u64 id = P_WallShapeIDBasis ^ MixU64s(
((u64)wall->start.x << 0) | ((u64)wall->start.y << 32),
((u64)wall->end.x << 0) | ((u64)wall->end.y << 32)
);
for (i32 y = aabb.p0.y; y < aabb.p1.y; ++y)
{
for (i32 x = aabb.p0.x; x < aabb.p1.x; ++x)
{
i64 cell_idx = y * P_WorldPitch + x;
P_SpaceCell *cell = &space.cells[cell_idx];
P_SpaceEntry *entry = PushStruct(arena, P_SpaceEntry);
SllStackPush(cell->first, entry);
entry->shape = shape;
entry->shape_id = id;
}
++wall_idx;
}
// P_DebugDrawShape(shape, Color_Cyan);
}
//- Debug draw walls
// {
// i64 wall_idx = 0;
// for (GenWall *wall = first_wall; wall; wall = wall->next)
// {
// Vec2 p0 = VEC2(wall->start.x / P_TilesPerMeter - P_WorldPitch / 2, wall->start.y / P_TilesPerMeter - P_WorldPitch / 2);
// Vec2 p1 = VEC2(wall->end.x / P_TilesPerMeter - P_WorldPitch / 2, wall->end.y / P_TilesPerMeter - P_WorldPitch / 2);
// u64 color_seed0 = MixU64(wall_idx + 1);
// u64 color_seed1 = MixU64(color_seed0);
// u64 color_seed2 = MixU64(color_seed1);
// Vec4 color = Color_White;
// color.r = Norm24(color_seed0) * 0.75 + 0.25;
// color.g = Norm24(color_seed1) * 0.75 + 0.25;
// color.b = Norm24(color_seed2) * 0.75 + 0.25;
// P_DebugDrawLine(p0, p1, color);
// ++wall_idx;
// }
// ++wall_idx;
// }
}
@ -2047,8 +2081,6 @@ void P_StepFrame(P_Frame *frame)
// TODO: Not like this
if (!is_predicting)
{
for (P_Ent *ent0 = P_FirstEnt(frame); !P_IsEntNil(ent0); ent0 = P_NextEnt(ent0))
{
if (ent0->is_guy)
@ -2223,468 +2255,8 @@ void P_StepFrame(P_Frame *frame)
}
}
}
// for (P_Ent *ent1 = P_FirstEnt(frame); !P_IsEntNil(ent1); ent1 = P_NextEnt(ent1))
// {
// if (ent1->is_guy && ent1->key.v > ent0->key.v)
// {
// P_Shape shape1 = P_WorldShapeFromEnt(ent1);
// // TODO: World query
// P_CollisionResult collision = P_CollisionResultFromShapes(shape0, shape1);
// if (collision.collision_points_count > 0)
// {
// P_ConstraintKey constraint_key = P_ConstraintKeyFromU64s(ent0->key.v, ent1->key.v);
// P_Constraint *constraint = P_ConstraintFromKey(frame, constraint_key);
// if (constraint->last_touched_tick < frame->tick)
// {
// if (P_IsConstraintNil(constraint))
// {
// constraint = P_PushConstraint(frame, constraint_key);
// }
// constraint->flags = P_ConstraintFlag_Gentle | P_ConstraintFlag_NoWarmStart;
// constraint->last_touched_tick = frame->tick;
// constraint->normal = collision.collision_normal;
// // constraint->friction = SqrtF32(ent0->friction * ent1->friction);
// constraint->friction = 0;
// // TODO: Real masses
// f32 inv_m0 = 10;
// f32 inv_m1 = 10;
// f32 inv_i0 = 0;
// f32 inv_i1 = 0;
// // Treat non-predicted guys as infinite-mass
// if (is_predicting && ent0 != local_guy)
// {
// inv_m0 = 0;
// }
// if (is_predicting && ent1 != local_guy)
// {
// inv_m1 = 0;
// }
// constraint->ent0 = ent0->key;
// constraint->ent1 = ent1->key;
// // constraint->static_center1 = shape1.center_of_mass;
// constraint->inv_m0 = inv_m0;
// constraint->inv_m1 = inv_m1;
// constraint->inv_i0 = inv_i0;
// constraint->inv_i1 = inv_i1;
// // Delete old contacts that are no longer present
// for (i32 contact_point_idx = 0; contact_point_idx < constraint->points_count; ++contact_point_idx)
// {
// P_ContactPoint *contact = &constraint->points[contact_point_idx];
// u32 id = contact->id;
// b32 match = 0;
// for (i32 collision_point_idx = 0; collision_point_idx < collision.collision_points_count; ++collision_point_idx)
// {
// if (collision.collision_points[collision_point_idx].id == id)
// {
// match = 1;
// break;
// }
// }
// if (!match)
// {
// // Delete contact by replacing with last in array
// *contact = constraint->points[constraint->points_count - 1];
// constraint->points_count -= 1;
// contact_point_idx -= 1;
// }
// }
// // Create / update contacts from collision
// for (i32 collision_point_idx = 0; collision_point_idx < collision.collision_points_count; ++collision_point_idx)
// {
// P_CollisionPoint collision_point = collision.collision_points[collision_point_idx];
// u32 id = collision_point.id;
// P_ContactPoint *contact = 0;
// {
// for (i32 contact_point_idx = 0; contact_point_idx < constraint->points_count; ++contact_point_idx)
// {
// P_ContactPoint *tmp = &constraint->points[contact_point_idx];
// if (tmp->id == id)
// {
// contact = tmp;
// break;
// }
// }
// if (!contact)
// {
// contact = &constraint->points[constraint->points_count];
// constraint->points_count += 1;
// ZeroStruct(contact);
// }
// }
// contact->id = id;
// Vec2 vcp0 = SubVec2(collision_point.p, shape0.center_of_mass);
// Vec2 vcp1 = SubVec2(collision_point.p, shape1.center_of_mass);
// contact->vcp0 = vcp0;
// contact->vcp1 = vcp1;
// contact->starting_separation = collision_point.separation;
// // Debug draw
// // {
// // // P_Ent *ent0 = P_EntFromKey(frame, constraint->ent0);
// // // P_Ent *ent1 = P_EntFromKey(frame, constraint->ent1);
// // Vec2 normal = constraint->normal;
// // Vec2 center0 = Zi;
// // Vec2 center1 = Zi;
// // if (!P_IsEntNil(ent0)) center0 = P_WorldShapeFromEnt(ent0).center_of_mass;
// // if (!P_IsEntNil(ent1)) center1 = P_WorldShapeFromEnt(ent1).center_of_mass;
// // Vec2 p0 = AddVec2(center0, vcp0);
// // Vec2 p1 = AddVec2(center1, vcp1);
// // P_DebugDrawPoint(p0, Color_Cyan);
// // P_DebugDrawLine(p0, AddVec2(p0, normal), Color_White);
// // }
// }
// }
// }
// }
// }
}
}
}
//////////////////////////////
//- Generate solid constraints
// TODO: Not like this
// for (P_Ent *ent0 = P_FirstEnt(frame); !P_IsEntNil(ent0); ent0 = P_NextEnt(ent0))
// {
// if (ent0->is_guy)
// {
// P_Shape shape0 = P_WorldShapeFromEnt(ent0);
// Rng2 aabb = P_BoundingBoxFromShape(shape0);
// P_Query query = P_QueryFromRect(scratch.arena, aabb, P_QueryFlag_IncludeWalls);
// for (P_QueryItem *item = query.first; item; item = item->next)
// {
// P_Shape shape1 = item->shape;
// // TODO: World query
// P_CollisionResult collision = P_CollisionResultFromShapes(shape0, shape1);
// if (collision.collision_points_count > 0)
// {
// P_Constraint *constraint = P_ConstraintFromKey(world_frame, constraint_key);
// if (P_IsConstraintNil(constraint))
// {
// constraint = P_PushConstraint(world_frame, constraint_key);
// }
// if (constraint->last_touched_tick < frame->tick)
// {
// constraint->last_touched_Tick = frame->tick;
// constraint->flags = P_ConstraintFlag_Solid;
// constraint->last_touched_tick = frame->tick;
// constraint->normal = collision.collision_normal;
// // constraint->friction = SqrtF32(ent0->friction * ent1->friction);
// constraint->friction = 0;
// // TODO: Real masses
// f32 inv_m0 = 10;
// f32 inv_m1 = 10;
// f32 inv_i0 = 0;
// f32 inv_i1 = 0;
// // Treat non-predicted guys as infinite-mass
// if (is_predicting && ent0 != local_guy)
// {
// inv_m0 = 0;
// }
// if (is_predicting && ent1 != local_guy)
// {
// inv_m1 = 0;
// }
// constraint->ent0 = ent0->key;
// constraint->ent1 = ent1->key;
// // constraint->static_center1 = shape1.center_of_mass;
// constraint->inv_m0 = inv_m0;
// constraint->inv_m1 = inv_m1;
// constraint->inv_i0 = inv_i0;
// constraint->inv_i1 = inv_i1;
// // Delete old contacts that are no longer present
// for (i32 contact_point_idx = 0; contact_point_idx < constraint->points_count; ++contact_point_idx)
// {
// P_ContactPoint *contact = &constraint->points[contact_point_idx];
// u32 id = contact->id;
// b32 match = 0;
// for (i32 collision_point_idx = 0; collision_point_idx < collision.collision_points_count; ++collision_point_idx)
// {
// if (collision.collision_points[collision_point_idx].id == id)
// {
// match = 1;
// break;
// }
// }
// if (!match)
// {
// // Delete contact by replacing with last in array
// *contact = constraint->points[constraint->points_count - 1];
// constraint->points_count -= 1;
// contact_point_idx -= 1;
// }
// }
// // Create / update contacts from collision
// for (i32 collision_point_idx = 0; collision_point_idx < collision.collision_points_count; ++collision_point_idx)
// {
// P_CollisionPoint collision_point = collision.collision_points[collision_point_idx];
// u32 id = collision_point.id;
// P_ContactPoint *contact = 0;
// {
// for (i32 contact_point_idx = 0; contact_point_idx < constraint->points_count; ++contact_point_idx)
// {
// P_ContactPoint *tmp = &constraint->points[contact_point_idx];
// if (tmp->id == id)
// {
// contact = tmp;
// break;
// }
// }
// if (!contact)
// {
// contact = &constraint->points[constraint->points_count];
// constraint->points_count += 1;
// ZeroStruct(contact);
// }
// }
// contact->id = id;
// Vec2 vcp0 = SubVec2(collision_point.p, shape0.center_of_mass);
// Vec2 vcp1 = SubVec2(collision_point.p, shape1.center_of_mass);
// contact->vcp0 = vcp0;
// contact->vcp1 = vcp1;
// contact->starting_separation = collision_point.separation;
// // Debug draw
// // {
// // // P_Ent *ent0 = P_EntFromKey(frame, constraint->ent0);
// // // P_Ent *ent1 = P_EntFromKey(frame, constraint->ent1);
// // Vec2 normal = constraint->normal;
// // Vec2 center0 = Zi;
// // Vec2 center1 = Zi;
// // if (!P_IsEntNil(ent0)) center0 = P_WorldShapeFromEnt(ent0).center_of_mass;
// // if (!P_IsEntNil(ent1)) center1 = P_WorldShapeFromEnt(ent1).center_of_mass;
// // Vec2 p0 = AddVec2(center0, vcp0);
// // Vec2 p1 = AddVec2(center1, vcp1);
// // P_DebugDrawPoint(p0, Color_Cyan);
// // P_DebugDrawLine(p0, AddVec2(p0, normal), Color_White);
// // }
// }
// }
// }
// }
// }
// }
// //////////////////////////////
// //- Generate solid constraints
// // TODO: Not like this
// for (P_Ent *ent0 = P_FirstEnt(frame); !P_IsEntNil(ent0); ent0 = P_NextEnt(ent0))
// {
// if (ent0->is_guy)
// {
// P_Shape shape0 = P_WorldShapeFromEnt(ent0);
// for (P_Ent *ent1 = P_FirstEnt(frame); !P_IsEntNil(ent1); ent1 = P_NextEnt(ent1))
// {
// if (ent1->is_guy && ent1->key.v > ent0->key.v)
// {
// P_Shape shape1 = P_WorldShapeFromEnt(ent1);
// // TODO: World query
// P_CollisionResult collision = P_CollisionResultFromShapes(shape0, shape1);
// if (collision.collision_points_count > 0)
// {
// // FIXME: Key lookup
// P_Constraint *constraint = 0;
// {
// b32 match = 0;
// for (i64 constraint_idx = 0; constraint_idx < frame->constraints_count; ++constraint_idx)
// {
// constraint = &frame->constraints[constraint_idx];
// if (P_MatchEntKey(constraint->ent0, ent0->key) && P_MatchEntKey(constraint->ent1, ent1->key))
// {
// match = 1;
// break;
// }
// }
// if (!match)
// {
// if (frame->constraints_count < frame->constraints_cap)
// {
// constraint = &frame->constraints[frame->constraints_count];
// frame->constraints_count += 1;
// ZeroStruct(constraint);
// }
// }
// }
// if (constraint)
// {
// constraint->flags = P_ConstraintFlag_Solid;
// constraint->last_touched_tick = frame->tick;
// constraint->normal = collision.collision_normal;
// // constraint->friction = SqrtF32(ent0->friction * ent1->friction);
// constraint->friction = 0;
// // TODO: Real masses
// f32 inv_m0 = 10;
// f32 inv_m1 = 10;
// f32 inv_i0 = 0;
// f32 inv_i1 = 0;
// // Treat non-predicted guys as infinite-mass
// if (is_predicting && ent0 != local_guy)
// {
// inv_m0 = 0;
// }
// if (is_predicting && ent1 != local_guy)
// {
// inv_m1 = 0;
// }
// constraint->ent0 = ent0->key;
// constraint->ent1 = ent1->key;
// // constraint->static_center1 = shape1.center_of_mass;
// constraint->inv_m0 = inv_m0;
// constraint->inv_m1 = inv_m1;
// constraint->inv_i0 = inv_i0;
// constraint->inv_i1 = inv_i1;
// // Delete old contacts that are no longer present
// for (i32 contact_point_idx = 0; contact_point_idx < constraint->points_count; ++contact_point_idx)
// {
// P_ContactPoint *contact = &constraint->points[contact_point_idx];
// u32 id = contact->id;
// b32 match = 0;
// for (i32 collision_point_idx = 0; collision_point_idx < collision.collision_points_count; ++collision_point_idx)
// {
// if (collision.collision_points[collision_point_idx].id == id)
// {
// match = 1;
// break;
// }
// }
// if (!match)
// {
// // Delete contact by replacing with last in array
// *contact = constraint->points[constraint->points_count - 1];
// constraint->points_count -= 1;
// contact_point_idx -= 1;
// }
// }
// // Create / update contacts from collision
// for (i32 collision_point_idx = 0; collision_point_idx < collision.collision_points_count; ++collision_point_idx)
// {
// P_CollisionPoint collision_point = collision.collision_points[collision_point_idx];
// u32 id = collision_point.id;
// P_ContactPoint *contact = 0;
// {
// for (i32 contact_point_idx = 0; contact_point_idx < constraint->points_count; ++contact_point_idx)
// {
// P_ContactPoint *tmp = &constraint->points[contact_point_idx];
// if (tmp->id == id)
// {
// contact = tmp;
// break;
// }
// }
// if (!contact)
// {
// contact = &constraint->points[constraint->points_count];
// constraint->points_count += 1;
// ZeroStruct(contact);
// }
// }
// contact->id = id;
// Vec2 vcp0 = SubVec2(collision_point.p, shape0.center_of_mass);
// Vec2 vcp1 = SubVec2(collision_point.p, shape1.center_of_mass);
// contact->vcp0 = vcp0;
// contact->vcp1 = vcp1;
// contact->starting_separation = collision_point.separation;
// // Debug draw
// // {
// // // P_Ent *ent0 = P_EntFromKey(frame, constraint->ent0);
// // // P_Ent *ent1 = P_EntFromKey(frame, constraint->ent1);
// // Vec2 normal = constraint->normal;
// // Vec2 center0 = Zi;
// // Vec2 center1 = Zi;
// // if (!P_IsEntNil(ent0)) center0 = P_WorldShapeFromEnt(ent0).center_of_mass;
// // if (!P_IsEntNil(ent1)) center1 = P_WorldShapeFromEnt(ent1).center_of_mass;
// // Vec2 p0 = AddVec2(center0, vcp0);
// // Vec2 p1 = AddVec2(center1, vcp1);
// // P_DebugDrawPoint(p0, Color_Cyan);
// // P_DebugDrawLine(p0, AddVec2(p0, normal), Color_White);
// // }
// }
// }
// }
// }
// }
// }
// }
//////////////////////////////
//- Prune constraints
@ -2696,14 +2268,9 @@ void P_StepFrame(P_Frame *frame)
{
b32 prune = 1;
if (constraint->last_touched_tick == frame->tick)
{
P_Ent *ent0 = P_EntFromKey(frame, constraint->ent0);
P_Ent *ent1 = P_EntFromKey(frame, constraint->ent1);
if (!P_IsEntNil(ent0) && !P_IsEntNil(ent1))
{
prune = 0;
}
}
if (prune)
{
prune_constraints[prune_constraints_count] = constraint;

View File

@ -6,6 +6,8 @@
#define P_NilEntKey ((P_EntKey) { 0 })
#define P_NilConstraintKey ((P_EntKey) { 0 })
#define P_WallShapeIDBasis 0x40d501b4cf6d4f0cull
Struct(P_EntKey)
{
u64 v;