slerp legs

This commit is contained in:
jacob 2026-04-04 18:06:34 -05:00
parent 92ed9a4c2d
commit be610d4055
7 changed files with 128 additions and 116 deletions

View File

@ -1992,20 +1992,7 @@ void P_SpawnEntsFromList(P_Frame *frame, P_EntList ents)
DllQueuePushNPZ(&P_NilEnt, frame->first_ent, frame->last_ent, dst, next, prev);
DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin);
}
{
P_Ent *old_next = dst->next;
P_Ent *old_prev = dst->prev;
P_Ent *old_next_in_bin = dst->next_in_bin;
P_Ent *old_prev_in_bin = dst->prev_in_bin;
{
*dst = *src;
dst->xf = NormXform(dst->xf);
}
dst->next = old_next;
dst->prev = old_prev;
dst->next_in_bin = old_next_in_bin;
dst->prev_in_bin = old_prev_in_bin;
}
dst->net_state = src->net_state;
dst->created_at_ns = frame->time_ns;
dst->created_at_tick = frame->tick;
dst->sim = !P_tl.is_client;
@ -3189,11 +3176,11 @@ void P_StepFrame(P_Frame *frame)
b32 is_bomb = 0;
if (button == P_Button_PrimaryFire && (firer->control.held[button] || firer->control.downs[button]))
{
// fire_rate = 100;
bullets_per_fire = 4;
fire_rate = 25;
bullets_per_fire = 5;
// fire_rate = 50;
fire_rate = 50;
bullets_per_fire = 1;
// fire_rate = 50;
// bullets_per_fire = 1;
firing = (weapon->last_fire_ns + NsFromSeconds(1.0 / fire_rate)) <= frame->time_ns;
if (firing)
{
@ -3267,9 +3254,10 @@ void P_StepFrame(P_Frame *frame)
//////////////////////////////
//- Bullet properties
// f32 spread = Tau * 0.05;
// f32 spread = Tau * 0.5;
f32 spread = Tau * 0.05;
// f32 spread = Tau * 0.2;
f32 spread = Tau * 0.01;
// f32 spread = Tau * 0.01;
// f32 spread = 0;
b32 should_ricochet = 0;
@ -3754,54 +3742,58 @@ void P_StepFrame(P_Frame *frame)
// }
// }
//////////////////////////////
//- Kill guys
{
P_EntList ents_to_spawn = Zi;
for (P_Ent *guy = P_FirstEnt(frame); !P_IsEntNil(guy); guy = P_NextEnt(guy))
{
if (guy->is_guy && guy->health <= 0)
P_EntList ents_to_spawn = Zi;
for (P_Ent *guy = P_FirstEnt(frame); !P_IsEntNil(guy); guy = P_NextEnt(guy))
{
P_Ent *old_guy = P_EntFromKey(prev_frame, guy->key);
if (old_guy->health > 0)
if (guy->is_guy && guy->health <= 0)
{
P_Ent *player = P_EntFromKey(frame, guy->source);
P_Ent *killer = P_EntFromKey(frame, guy->damage_attribution);
// Update kill info
P_Ent *old_guy = P_EntFromKey(prev_frame, guy->key);
if (old_guy->health > 0)
{
if (player->is_player)
P_Ent *player = P_EntFromKey(frame, guy->source);
P_Ent *killer = P_EntFromKey(frame, guy->damage_attribution);
// Update kill info
{
player->deaths += 1;
if (player->is_player)
{
player->deaths += 1;
}
if (killer->is_player && !P_MatchEntKey(player->key, killer->key))
{
killer->kills += 1;
}
guy->exists = 0;
guy->continuity_gen += 1;
guy->health = 1;
}
if (killer->is_player && !P_MatchEntKey(player->key, killer->key))
// Push kill event
{
killer->kills += 1;
P_Ent *death = P_PushTempEnt(scratch.arena, &ents_to_spawn);
death->key = P_EntKeyFromU64(MixU64s(guy->key.v, P_DeathBasis + (u64)player->deaths));
death->death_pos = guy->xf.t;
death->is_death = 1;
death->death_victim = player->key;
death->death_killer = killer->key;
death->lifetime_seconds = P_ObservationDurationSeconds;
}
guy->exists = 0;
guy->continuity_gen += 1;
guy->health = 1;
}
// Push kill event
{
P_Ent *death = P_PushTempEnt(scratch.arena, &ents_to_spawn);
death->key = P_EntKeyFromU64(MixU64s(guy->key.v, P_DeathBasis + (u64)player->deaths));
death->death_pos = guy->xf.t;
death->is_death = 1;
death->death_victim = player->key;
death->death_killer = killer->key;
death->lifetime_seconds = P_ObservationDurationSeconds;
}
}
}
P_SpawnEntsFromList(frame, ents_to_spawn);
}
//////////////////////////////
//- Smooth values
for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
{
f32 lerp_rate = SaturateF32(25 * sim_dt);
ent->smoothed_move_dir = SlerpVec2(ent->smoothed_move_dir, NormVec2(ent->control.move), lerp_rate);
}
P_SpawnEntsFromList(frame, ents_to_spawn);
}
//////////////////////////////
//- Debug draw

View File

@ -113,29 +113,13 @@ Struct(P_Control)
f32 downs[P_Button_COUNT];
};
Struct(P_Ent)
Struct(P_NetworkedEntState)
{
//- Internal world state
P_Ent *next;
P_Ent *prev;
P_Ent *next_in_bin;
P_Ent *prev_in_bin;
//- Persistent data
P_EntKey key;
u64 rand_seq;
i64 created_at_ns;
i64 created_at_tick;
f64 lifetime_seconds;
//- Client data
i64 initial_observation_time_ns;
i64 last_observation_time_ns;
b32 is_first_observation;
//- Build data
@ -150,12 +134,15 @@ Struct(P_Ent)
Xform xf;
f64 lifetime_seconds;
u64 rand_seq;
//- Bullet
b32 is_bullet;
u32 bullet_hits_count;
//- Events
b32 is_trail;
@ -242,6 +229,35 @@ Struct(P_Ent)
Vec2 v; // Linear velocity
f32 w; // Angular velocity
//- Smoothed values
Vec2 smoothed_move_dir;
};
Struct(P_LocalEntState)
{
//- Observation info
i64 initial_observation_time_ns;
i64 last_observation_time_ns;
b32 is_first_observation;
// Vec2 smoothed_v;
// Vec2 smoothed_v_dir;
// Vec2 smoothed_move_dir;
// f32 smoothed_w;
};
Struct(P_Ent)
{
P_Ent *next;
P_Ent *prev;
P_Ent *next_in_bin;
P_Ent *prev_in_bin;
Embed(P_NetworkedEntState, net_state);
Embed(P_LocalEntState, local_state);
};
Struct(P_EntListNode)

View File

@ -794,7 +794,7 @@ void S_TickForever(WaveLaneCtx *lane)
{
// TODO: Delta compress
should_transmit = 1;
BB_WriteBytes(&packer_bbw, StringFromStruct(ent));
BB_WriteBytes(&packer_bbw, StringFromStruct(&ent->net_state));
}
u64 delta_end = BB_GetNumBytesWritten(&packer_bbw);
if (should_transmit)

View File

@ -52,30 +52,30 @@ PERSIST Readonly String P_PresetHumanNames[] = {
// Taken from a random GMOD server
PERSIST Readonly String P_PresetPlayerNames[] = {
CompLit("lionberg"),
CompLit("charlie main"),
CompLit("frezh"),
CompLit("KARMA"),
CompLit("Kirep"),
CompLit("Cyan Crayon"),
CompLit("THE WIFE"),
CompLit("Panda"),
CompLit("adoti"),
CompLit("yoyota"),
CompLit("Mr. Bones"),
CompLit("TaurusJ3"),
CompLit("dub"),
CompLit("Tidunbly"),
CompLit("Siepter"),
CompLit("frezh"),
CompLit("lowayo"),
CompLit("Zunix"),
CompLit("_Runne_"),
CompLit("Fr0stie"),
CompLit("Mr. Bones"),
CompLit("Lumby"),
CompLit("Legs"),
CompLit("Talids"),
CompLit("yoyota"),
CompLit("Train"),
CompLit("lionberg"),
CompLit("Cyan Crayon"),
CompLit("Poy"),
CompLit("Kaitsedd"),
CompLit("Panda"),
CompLit("THE WIFE"),
CompLit("KARMA"),
CompLit("jiyu"),
CompLit("charlie main"),
};

View File

@ -1822,11 +1822,11 @@ void V_TickForever(WaveLaneCtx *lane)
while (!done && BB_NumBitsRemaining(&bbr) > 0)
{
// TODO: Delta compress
P_Ent *raw_ent = (P_Ent *)BB_ReadBytesRaw(&bbr, sizeof(P_Ent));
if (raw_ent)
P_NetworkedEntState *raw_net_state = (P_NetworkedEntState *)BB_ReadBytesRaw(&bbr, sizeof(P_NetworkedEntState));
if (raw_net_state)
{
P_EntListNode tmp_ent_node = Zi;
CopyStruct(&tmp_ent_node.ent, raw_ent);
CopyStruct(&tmp_ent_node.ent.net_state, raw_net_state);
P_EntList ent_list = Zi;
ent_list.first = &tmp_ent_node;
ent_list.last = &tmp_ent_node;
@ -2429,8 +2429,10 @@ void V_TickForever(WaveLaneCtx *lane)
ent->xf.t = LerpVec2(left->xf.t, right->xf.t, blend_t);
ent->xf.r = SlerpVec2(left->xf.r, right->xf.r, blend_t);
ent->walk_time_accum_ns = LerpI64(left->walk_time_accum_ns, right->walk_time_accum_ns, blend_t);
ent->fire_time_accum_ns = LerpI64(left->fire_time_accum_ns, right->fire_time_accum_ns, blend_t);
ent->v = LerpVec2(left->v, right->v, blend_t);
ent->w = LerpF32(left->w, right->w, blend_t);
ent->smoothed_move_dir = SlerpVec2(left->smoothed_move_dir, right->smoothed_move_dir, blend_t);
}
}
}
@ -2456,6 +2458,8 @@ void V_TickForever(WaveLaneCtx *lane)
{
P_EntKey key = ent->key;
i64 expiration_ns = NsFromSeconds(P_ObservationDurationSeconds);
//- Fetch observation
V_Observation *obs = 0;
{
V_ObservationBin *bin = &V.observation_bins[key.v % countof(V.observation_bins)];
@ -2499,6 +2503,8 @@ void V_TickForever(WaveLaneCtx *lane)
}
obs->last_observation_time_ns = frame->time_ns;
}
//- Observe
ent->last_observation_time_ns = frame->time_ns;
ent->is_first_observation = obs->initial_observation_time_ns == frame->time_ns;
}
@ -2897,7 +2903,8 @@ void V_TickForever(WaveLaneCtx *lane)
SPR_Sprite legs = Zi;
Affine legs_pix_to_world_af = AffineIdentity;
{
Vec2 legs_dir = NormVec2(ent->control.move);
// Vec2 legs_dir = NormVec2(ent->control.move);
Vec2 legs_dir = ent->smoothed_move_dir;
if (P_IsEntRolling(local_frame, ent))
{
legs_dir = ent->xf.r;
@ -3441,10 +3448,10 @@ void V_TickForever(WaveLaneCtx *lane)
//- Wall impact particles
if (material != P_MaterialKind_Flesh)
{
// Hot debris
//- Debris
{
V_Emitter emitter = Zi;
emitter.kind = V_ParticleKind_HotDebris;
emitter.kind = V_ParticleKind_Debris;
emitter.count = 32;
f32 angle = AngleFromVec2(impact_dir);
@ -3466,13 +3473,13 @@ void V_TickForever(WaveLaneCtx *lane)
//- Wall spark
//- Hot debris
{
V_Emitter emitter = Zi;
emitter.kind = V_ParticleKind_Spark;
emitter.kind = V_ParticleKind_HotDebris;
// emitter.count = MaxF32(1000 * frame->dt, 1);
// emitter.count = 128;
emitter.count = 1;
emitter.count = 32;
f32 angle = AngleFromVec2(impact_dir);
@ -3668,12 +3675,16 @@ void V_TickForever(WaveLaneCtx *lane)
// f32 speed = 100;
f32 speed_spread = speed * 2;
emitter.pos.p0 = emitter.pos.p1 = frame->world_cursor;
f32 particles_per_meter_per_second = Kibi(128);
emitter.pos.p0 = prev_frame->world_cursor;
emitter.pos.p1 = frame->world_cursor;
f32 len_meters = MaxF32(Vec2Len(SubVec2(emitter.pos.p1, emitter.pos.p0)), 1);
emitter.count = particles_per_meter_per_second * len_meters * frame->dt;
emitter.speed.min = speed - speed_spread * 0.5;
emitter.speed.max = speed + speed_spread * 0.5;
emitter.angle.min = angle - angle_spread * 0.5;
emitter.angle.max = angle + angle_spread * 0.5;
emitter.count = Kibi(32) * frame->dt;
V_PushParticles(emitter);
}
@ -3733,26 +3744,18 @@ void V_TickForever(WaveLaneCtx *lane)
f32 speed = 100;
f32 speed_spread = speed * 2;
emitter.pos.p0 = emitter.pos.p1 = frame->world_cursor;
f32 particles_per_meter_per_second = Kibi(128);
emitter.pos.p0 = prev_frame->world_cursor;
emitter.pos.p1 = frame->world_cursor;
f32 len_meters = MaxF32(Vec2Len(SubVec2(emitter.pos.p1, emitter.pos.p0)), 1);
emitter.count = particles_per_meter_per_second * len_meters * frame->dt;
emitter.speed.min = speed - speed_spread * 0.5;
emitter.speed.max = speed + speed_spread * 0.5;
emitter.angle.min = angle - angle_spread * 0.5;
emitter.angle.max = angle + angle_spread * 0.5;
// emitter.falloff.min = emitter.falloff.max = 0;
// emitter.count = CeilF32(Kibi(64) * frame->dt);
// emitter.count = CeilF32(Mebi(32) * frame->dt);
// emitter.count = CeilF32(Mebi(8) * frame->dt);
// emitter.count = Mebi(16);
// emitter.count = Mebi(2);
// emitter.count = Kibi(32);
emitter.count = Kibi(8);
// emitter.count = 128;
// emitter.count = 128;
// emitter.count = 32;
// emitter.count = 1;
V_PushParticles(emitter);
}
@ -5619,10 +5622,10 @@ void V_TickForever(WaveLaneCtx *lane)
// TODO: Remove this
if (frame->tick == 1)
{
frame->show_consoles = 1;
}
// if (frame->tick == 1)
// {
// frame->show_consoles = 1;
// }

View File

@ -378,6 +378,7 @@ Struct(V_Observation)
V_Observation *prev;
V_Observation *next_in_bin;
V_Observation *prev_in_bin;
u64 key;
i64 initial_observation_time_ns;
i64 last_observation_time_ns;

View File

@ -79,10 +79,10 @@ Enum(V_ParticleLayer)
/* Layer */ V_ParticleLayer_Mid, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ Inf, Inf, \
/* Falloff */ 10, 20, \
/* Prune speed threshold */ 0.01, \
/* Falloff */ 20, 30, \
/* Prune speed threshold */ 0.1, \
/* Base color */ VEC4(0.4, 0.3, 0.2, 1), \
/* Dry color factor */ VEC4(1, 1, 1, 1) \
/* Dry color factor */ VEC4(0.2, 0.1, 0.1, 1) \
) \
X( \
/* Name */ Fire, \
@ -103,12 +103,12 @@ Enum(V_ParticleLayer)
/* Lifetime */ Inf, Inf, \
/* Falloff */ 20, 30, \
/* Prune speed threshold */ 0.1, \
/* Base color */ VEC4(0.4, 0.3, 0.2, 1), \
/* Base color */ VEC4(2, 0.5, 0, 1), \
/* Dry color factor */ VEC4(0.2, 0.1, 0.1, 1) \
) \
X( \
/* Name */ Spark, \
/* Flags */ V_ParticleFlag_StainWhenPruned, \
/* Flags */ V_ParticleFlag_None, \
/* Layer */ V_ParticleLayer_Mid, \
/* Stain rate, pen chance */ 0, 0, \
/* Lifetime */ 0.2, 0.3, \