distinct bullet trail entities

This commit is contained in:
jacob 2026-03-19 20:38:58 -05:00
parent 18ad1fb69e
commit 926cfb5cce
4 changed files with 81 additions and 67 deletions

View File

@ -3151,6 +3151,8 @@ void P_StepFrame(P_Frame *frame)
// TDOO: More specific key with seed that only increments on player control (for less misprediction) // TDOO: More specific key with seed that only increments on player control (for less misprediction)
bullet->key = P_EntKeyFromU64(P_RandU64FromEnt(firer)); bullet->key = P_EntKeyFromU64(P_RandU64FromEnt(firer));
if (weapon->is_launcher) if (weapon->is_launcher)
{ {
bullet->is_bomb = 1; bullet->is_bomb = 1;
@ -3182,10 +3184,8 @@ void P_StepFrame(P_Frame *frame)
// TODO: Separate 'hits' from bullets, so that bullets can have multiple hits
{ {
P_EntList hits_to_spawn = Zi; P_EntList ents_to_spawn = Zi;
for (P_Ent *bullet = P_FirstEnt(frame); !P_IsEntNil(bullet); bullet = P_NextEnt(bullet)) for (P_Ent *bullet = P_FirstEnt(frame); !P_IsEntNil(bullet); bullet = P_NextEnt(bullet))
{ {
if (bullet->is_bullet) if (bullet->is_bullet)
@ -3315,7 +3315,7 @@ void P_StepFrame(P_Frame *frame)
bullet->xf.r = NormVec2(bullet_dir); bullet->xf.r = NormVec2(bullet_dir);
bullet->v = MulVec2(NormVec2(bullet_dir), initial_speed); bullet->v = MulVec2(NormVec2(bullet_dir), initial_speed);
bullet->v = AddVec2(bullet->v, firer->v); // bullet->v = AddVec2(bullet->v, firer->v);
} }
@ -3425,7 +3425,7 @@ void P_StepFrame(P_Frame *frame)
Vec2 normal = victim_raycast.normal; Vec2 normal = victim_raycast.normal;
bullet->bullet_hits_count += 1; bullet->bullet_hits_count += 1;
P_Ent *hit = P_PushTempEnt(scratch.arena, &hits_to_spawn); P_Ent *hit = P_PushTempEnt(scratch.arena, &ents_to_spawn);
{ {
hit->key = P_EntKeyFromU64(MixU64s(bullet->key.v, P_BulletHitBasis + bullet->bullet_hits_count)); hit->key = P_EntKeyFromU64(MixU64s(bullet->key.v, P_BulletHitBasis + bullet->bullet_hits_count));
hit->is_hit = 1; hit->is_hit = 1;
@ -3466,6 +3466,17 @@ void P_StepFrame(P_Frame *frame)
} }
bullet->v = MulVec2(bullet->v, 1.0 - SaturateF32(speed_falloff * sim_dt)); bullet->v = MulVec2(bullet->v, 1.0 - SaturateF32(speed_falloff * sim_dt));
// Create trail
{
P_Ent *trail = P_PushTempEnt(scratch.arena, &ents_to_spawn);
trail->key = P_EntKeyFromU64(MixU64s(bullet->key.v, P_BulletTrailBasis + frame->tick));
trail->is_trail = 1;
trail->trail_p0 = p0;
trail->trail_p1 = bullet->xf.t;
trail->lifetime_seconds = 0;
}
// TODO: Remove this // TODO: Remove this
if (!is_client && !P_IsEntNil(victim)) if (!is_client && !P_IsEntNil(victim))
{ {
@ -3473,7 +3484,7 @@ void P_StepFrame(P_Frame *frame)
{ {
victim->damage_attribution = damager->key; victim->damage_attribution = damager->key;
} }
victim->health -= 0.25; // victim->health -= 0.25;
} }
// Prune out of bounds bullet // Prune out of bounds bullet
@ -3489,7 +3500,7 @@ void P_StepFrame(P_Frame *frame)
} }
} }
} }
P_SpawnEntsFromList(frame, hits_to_spawn); P_SpawnEntsFromList(frame, ents_to_spawn);
} }

View File

@ -9,6 +9,7 @@
#define P_WallShapeIDBasis 0x40d501b4cf6d4f0cull #define P_WallShapeIDBasis 0x40d501b4cf6d4f0cull
#define P_BulletSpreadBasis 0xc3b72fe38ca5a1d6ull #define P_BulletSpreadBasis 0xc3b72fe38ca5a1d6ull
#define P_BulletHitBasis 0xbc70fc783c1c507full #define P_BulletHitBasis 0xbc70fc783c1c507full
#define P_BulletTrailBasis 0x27c011f891c571feull
Struct(P_EntKey) Struct(P_EntKey)
{ {
@ -152,6 +153,12 @@ Struct(P_Ent)
Vec2 hit_entry_velocity; Vec2 hit_entry_velocity;
P_MaterialKind hit_material; P_MaterialKind hit_material;
//- Trail
b32 is_trail;
Vec2 trail_p0;
Vec2 trail_p1;
//- Bomb //- Bomb
b32 is_bomb; b32 is_bomb;

View File

@ -23,7 +23,7 @@ String P_PackWorld(Arena *arena, P_World *src_world)
{ {
// TODO: Pack ignored ents // TODO: Pack ignored ents
b32 ignore = 0; b32 ignore = 0;
if (ent->is_weapon || ent->is_bullet || ent->is_bomb || ent->is_hit) if (ent->is_weapon || ent->is_bullet || ent->is_bomb || ent->is_hit || ent->is_trail)
{ {
ignore = 1; ignore = 1;
} }

View File

@ -1905,7 +1905,7 @@ void V_TickForever(WaveLaneCtx *lane)
{ {
V_ObservationBin *bin = &V.observation_bins[key.v % countof(V.observation_bins)]; V_ObservationBin *bin = &V.observation_bins[key.v % countof(V.observation_bins)];
obs = bin->first; obs = bin->first;
for (; obs; obs = obs->next) for (; obs; obs = obs->next_in_bin)
{ {
if (obs->key == key.v) if (obs->key == key.v)
{ {
@ -2465,76 +2465,72 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// ////////////////////////////
//- Push bullet trail particles //- Push bullet trail particles
// TODO: Not like this
// for (P_Ent *trail = P_FirstEnt(local_frame); !P_IsEntNil(trail); trail = P_NextEnt(trail)) // for (P_Ent *trail = P_FirstEnt(local_frame); !P_IsEntNil(trail); trail = P_NextEnt(trail))
// { // {
// if (trail->is_trail) // if (trail->is_trail && trail->is_first_observation)
// { // {
// // FIXME: Use 'last visible' pos // Vec2 p0 = trail->trail_p0;
// P_Ent *old_bullet = P_EntFromKey(prev_local_frame, bullet->key); // Vec2 p1 = trail->trail_p1;
// Vec2 start = old_bullet->xf.t;
// Vec2 end = bullet->xf.t;
// if (P_IsEntNil(old_bullet))
// {
// start = end;
// }
// b32 skip = 0; // P_DebugDrawLine(p0, p1, Color_Cyan);
// if (bullet->has_hit)
// {
// Vec2 hit_pos = bullet->hit_entry;
// if (DotVec2(SubVec2(hit_pos, start), SubVec2(end, start)) < 0)
// {
// skip = 1;
// }
// // V_DrawPoint(MulAffineVec2(frame->af.world_to_screen, start), Color_Red);
// // V_DrawPoint(MulAffineVec2(frame->af.world_to_screen, end), Color_Purple);
// end = hit_pos;
// }
// if (!skip)
// {
// {
// f32 trail_len = Vec2Len(SubVec2(end, start));
// f32 particles_count = trail_len * frame->dt * Kibi(8); // Particles per meter per second
// particles_count = MaxF32(particles_count, 1);
// f32 angle = AngleFromVec2(PerpVec2(SubVec2(end, start)));
// // f32 angle = AngleFromVec2(NegVec2(SubVec2(end, start)));
// V_Emitter emitter = Zi;
// {
// emitter.kind = V_ParticleKind_BulletTrail;
// emitter.count = particles_count;
// f32 angle_spread = Tau / 4.0;
// emitter.angle.min = angle - angle_spread / 2;
// emitter.angle.max = angle + angle_spread / 2;
// emitter.pos.p0 = start;
// emitter.pos.p1 = end;
// // emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1));
// // emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1));
// emitter.speed.min = -1;
// emitter.speed.max = 1;
// }
// V_PushParticles(emitter);
// }
// }
// } // }
// } // }
// TODO: Not like this
for (P_Ent *trail = P_FirstEnt(local_frame); !P_IsEntNil(trail); trail = P_NextEnt(trail))
{
if (trail->is_trail && trail->is_first_observation)
{
Vec2 p0 = trail->trail_p0;
Vec2 p1 = trail->trail_p1;
f32 trail_len = Vec2Len(SubVec2(p1, p0));
f32 particles_count = trail_len * frame->dt * Kibi(8); // Particles per meter per second
particles_count = MaxF32(particles_count, 1);
f32 angle = AngleFromVec2(PerpVec2(SubVec2(p1, p0)));
// f32 angle = AngleFromVec2(NegVec2(SubVec2(p1, p0)));
V_Emitter emitter = Zi;
{
emitter.kind = V_ParticleKind_BulletTrail;
emitter.count = particles_count;
f32 angle_spread = Tau / 4.0;
emitter.angle.min = angle - angle_spread / 2;
emitter.angle.max = angle + angle_spread / 2;
emitter.pos.p0 = p0;
emitter.pos.p1 = p1;
// emitter.color_lin = LinearFromSrgb(VEC4(0, 1, 0, 1));
// emitter.color_lin = LinearFromSrgb(VEC4(0.8, 0.6, 0.2, 1));
emitter.speed.min = -1;
emitter.speed.max = 1;
}
V_PushParticles(emitter);
}
}
@ -2660,7 +2656,7 @@ void V_TickForever(WaveLaneCtx *lane)
emitter.speed.max = speed + speed_spread * 0.5; emitter.speed.max = speed + speed_spread * 0.5;
emitter.angle.min = angle - angle_spread * 0.5; emitter.angle.min = angle - angle_spread * 0.5;
emitter.angle.max = angle + angle_spread * 0.5; emitter.angle.max = angle + angle_spread * 0.5;
emitter.count = TweakFloat("Emitter count", 1, 0, 100) * (Kibi(1) * frame->dt); emitter.count = TweakFloat("Emitter count", 8, 0, Kibi(64));
V_PushParticles(emitter); V_PushParticles(emitter);
} }
} }