code: add vehicle handling
parent
d1016f68a0
commit
e00b8d7e5f
|
@ -22,6 +22,9 @@ pkt_desc pkt_entity_view_desc[] = {
|
||||||
{ PKT_HALF(entity_view, hp) },
|
{ PKT_HALF(entity_view, hp) },
|
||||||
{ PKT_HALF(entity_view, max_hp) },
|
{ PKT_HALF(entity_view, max_hp) },
|
||||||
|
|
||||||
|
{ PKT_KEEP_IF(entity_view, kind, EKIND_VEHICLE, 1) }, // NOTE(zaklaus): keep for vehicles
|
||||||
|
{ PKT_HALF(entity_view, heading) },
|
||||||
|
|
||||||
{ PKT_END },
|
{ PKT_END },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,9 @@ typedef struct entity_view {
|
||||||
uint8_t is_dirty;
|
uint8_t is_dirty;
|
||||||
int64_t tex;
|
int64_t tex;
|
||||||
|
|
||||||
|
// NOTE(zaklaus): vehicle
|
||||||
|
float heading, theading;
|
||||||
|
|
||||||
// NOTE(zaklaus): internals
|
// NOTE(zaklaus): internals
|
||||||
uint8_t layer_id;
|
uint8_t layer_id;
|
||||||
uint64_t last_update;
|
uint64_t last_update;
|
||||||
|
|
|
@ -115,6 +115,7 @@ void lerp_entity_positions(uint64_t key, entity_view * data);
|
||||||
void do_entity_fadeinout(uint64_t key, entity_view * data);
|
void do_entity_fadeinout(uint64_t key, entity_view * data);
|
||||||
|
|
||||||
float zpl_lerp(float,float,float);
|
float zpl_lerp(float,float,float);
|
||||||
|
float zpl_to_degrees(float);
|
||||||
|
|
||||||
void platform_render() {
|
void platform_render() {
|
||||||
profile(PROF_ENTITY_LERP) {
|
profile(PROF_ENTITY_LERP) {
|
||||||
|
@ -220,9 +221,9 @@ void DEBUG_draw_entities(uint64_t key, entity_view * data) {
|
||||||
case EKIND_VEHICLE: {
|
case EKIND_VEHICLE: {
|
||||||
float x = data->x;
|
float x = data->x;
|
||||||
float y = data->y;
|
float y = data->y;
|
||||||
float const w = 50;
|
float const w = 80;
|
||||||
float const h = 80;
|
float const h = 50;
|
||||||
DrawRectanglePro((Rectangle){x,y,w,h}, (Vector2){w/2.0f,h/2.0f}, 0.0f, ColorAlpha(RED, data->tran_time));
|
DrawRectanglePro((Rectangle){x,y,w,h}, (Vector2){w/2.0f,h/2.0f}, zpl_to_degrees(data->heading), ColorAlpha(RED, data->tran_time));
|
||||||
}break;
|
}break;
|
||||||
default:break;
|
default:break;
|
||||||
}
|
}
|
||||||
|
@ -237,9 +238,11 @@ void lerp_entity_positions(uint64_t key, entity_view *data) {
|
||||||
#if 1
|
#if 1
|
||||||
data->x = smooth_val(data->x, data->tx, view->delta_time[data->layer_id]);
|
data->x = smooth_val(data->x, data->tx, view->delta_time[data->layer_id]);
|
||||||
data->y = smooth_val(data->y, data->ty, view->delta_time[data->layer_id]);
|
data->y = smooth_val(data->y, data->ty, view->delta_time[data->layer_id]);
|
||||||
|
data->heading = smooth_val_spherical(data->heading, data->theading, view->delta_time[data->layer_id]);
|
||||||
#else
|
#else
|
||||||
data->x = data->tx;
|
data->x = data->tx;
|
||||||
data->y = data->ty;
|
data->y = data->ty;
|
||||||
|
data->heading = data->theading;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,26 @@ static inline float map_factor(float x) {
|
||||||
return 1.0f - x*x*x*x*x*x*x*x;
|
return 1.0f - x*x*x*x*x*x*x*x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline float base_angle(float x) {
|
||||||
|
while (x > ZPL_TAU) x -= ZPL_TAU;
|
||||||
|
while (x < 0.0f) x += ZPL_TAU;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float spherical_lerp(float a, float b, float t) {
|
||||||
|
a = base_angle(a);
|
||||||
|
b = base_angle(b);
|
||||||
|
float d = b - a;
|
||||||
|
|
||||||
|
if (d < -ZPL_PI) {
|
||||||
|
b += ZPL_TAU;
|
||||||
|
} else if (d > ZPL_PI) {
|
||||||
|
b -= ZPL_TAU;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base_angle(zpl_lerp(a, b, t));
|
||||||
|
}
|
||||||
|
|
||||||
float smooth_val(float cur, float tgt, uint64_t dt) {
|
float smooth_val(float cur, float tgt, uint64_t dt) {
|
||||||
float factor = zpl_clamp01(map_factor(zpl_unlerp(dt, WORLD_TRACKER_UPDATE_FAST_MS, WORLD_TRACKER_UPDATE_SLOW_MS)));
|
float factor = zpl_clamp01(map_factor(zpl_unlerp(dt, WORLD_TRACKER_UPDATE_FAST_MS, WORLD_TRACKER_UPDATE_SLOW_MS)));
|
||||||
|
|
||||||
|
@ -24,15 +44,24 @@ float smooth_val(float cur, float tgt, uint64_t dt) {
|
||||||
return zpl_lerp(cur, tgt, zpl_lerp(PREDICT_SMOOTH_FACTOR_LO, PREDICT_SMOOTH_FACTOR_HI, factor));
|
return zpl_lerp(cur, tgt, zpl_lerp(PREDICT_SMOOTH_FACTOR_LO, PREDICT_SMOOTH_FACTOR_HI, factor));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float smooth_val_spherical(float cur, float tgt, uint64_t dt) {
|
||||||
|
float factor = zpl_clamp01(map_factor(zpl_unlerp(dt, WORLD_TRACKER_UPDATE_FAST_MS, WORLD_TRACKER_UPDATE_SLOW_MS)));
|
||||||
|
|
||||||
|
return spherical_lerp(cur, tgt, zpl_lerp(PREDICT_SMOOTH_FACTOR_LO, PREDICT_SMOOTH_FACTOR_HI, factor));
|
||||||
|
}
|
||||||
|
|
||||||
void predict_receive_update(entity_view *d, entity_view *data) {
|
void predict_receive_update(entity_view *d, entity_view *data) {
|
||||||
if (d && data->flag & EFLAG_INTERP) {
|
if (d && data->flag & EFLAG_INTERP) {
|
||||||
// NOTE(zaklaus): store target pos but keep x,y unchanged
|
// NOTE(zaklaus): store target pos but keep x,y unchanged
|
||||||
float tx = data->x;
|
float tx = data->x;
|
||||||
float ty = data->y;
|
float ty = data->y;
|
||||||
|
float theading = data->heading;
|
||||||
data->x = d->x;
|
data->x = d->x;
|
||||||
data->y = d->y;
|
data->y = d->y;
|
||||||
|
data->heading = d->heading;
|
||||||
data->tx = tx;
|
data->tx = tx;
|
||||||
data->ty = ty;
|
data->ty = ty;
|
||||||
|
data->theading = theading;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->tran_effect = d->tran_effect;
|
data->tran_effect = d->tran_effect;
|
||||||
|
|
|
@ -3,3 +3,4 @@
|
||||||
|
|
||||||
float smooth_val(float cur, float tgt, uint64_t dt);
|
float smooth_val(float cur, float tgt, uint64_t dt);
|
||||||
void predict_receive_update(entity_view *d, entity_view *data);
|
void predict_receive_update(entity_view *d, entity_view *data);
|
||||||
|
float smooth_val_spherical(float cur, float tgt, uint64_t dt);
|
|
@ -8,7 +8,9 @@
|
||||||
uint64_t vehicle_spawn(void) {
|
uint64_t vehicle_spawn(void) {
|
||||||
ecs_entity_t e = entity_spawn(EKIND_VEHICLE);
|
ecs_entity_t e = entity_spawn(EKIND_VEHICLE);
|
||||||
|
|
||||||
ecs_set(world_ecs(), e, Vehicle, {0});
|
Vehicle *veh = ecs_get_mut(world_ecs(), e, Vehicle, NULL);
|
||||||
|
zpl_zero_item(veh);
|
||||||
|
veh->wheel_base = 60.0f;
|
||||||
return (uint64_t)e;
|
return (uint64_t)e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,11 @@ entity_view world_build_entity_view(int64_t e) {
|
||||||
view.max_hp = health->max_hp;
|
view.max_hp = health->max_hp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ecs_get(world_ecs(), e, Vehicle)) {
|
||||||
|
Vehicle const* veh = ecs_get(world_ecs(), e, Vehicle);
|
||||||
|
view.heading = veh->heading;
|
||||||
|
}
|
||||||
|
|
||||||
if (ecs_get(world_ecs(), e, Chunk)) {
|
if (ecs_get(world_ecs(), e, Chunk)) {
|
||||||
Chunk *chpos = ecs_get_mut(world_ecs(), e, Chunk, 0);
|
Chunk *chpos = ecs_get_mut(world_ecs(), e, Chunk, 0);
|
||||||
view.x = chpos->x;
|
view.x = chpos->x;
|
||||||
|
|
|
@ -59,6 +59,7 @@ int32_t tracker_read_create(librg_world *w, librg_event *e) {
|
||||||
if (data.flag & EFLAG_INTERP) {
|
if (data.flag & EFLAG_INTERP) {
|
||||||
data.tx = data.x;
|
data.tx = data.x;
|
||||||
data.ty = data.y;
|
data.ty = data.y;
|
||||||
|
data.theading = data.heading;
|
||||||
}
|
}
|
||||||
entity_view_update_or_create(&view->entities, entity_id, data);
|
entity_view_update_or_create(&view->entities, entity_id, data);
|
||||||
entity_view_mark_for_fadein(&view->entities, entity_id);
|
entity_view_mark_for_fadein(&view->entities, entity_id);
|
||||||
|
|
|
@ -51,6 +51,11 @@ ECS_STRUCT(Classify, {
|
||||||
|
|
||||||
ECS_STRUCT(Vehicle, {
|
ECS_STRUCT(Vehicle, {
|
||||||
uint64_t seats[4];
|
uint64_t seats[4];
|
||||||
|
|
||||||
|
float speed;
|
||||||
|
float heading;
|
||||||
|
float steer;
|
||||||
|
float wheel_base;
|
||||||
});
|
});
|
||||||
|
|
||||||
ECS_COMPONENT_EXTERN(Chunk);
|
ECS_COMPONENT_EXTERN(Chunk);
|
||||||
|
|
|
@ -201,12 +201,35 @@ void EnterOrLeaveVehicle(ecs_iter_t *it) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define VEHICLE_MAX_SPEED 500.0f
|
||||||
|
#define VEHICLE_ACCEL 2.1f
|
||||||
|
#define VEHICLE_STEER 0.01f
|
||||||
|
|
||||||
void VehicleHandling(ecs_iter_t *it) {
|
void VehicleHandling(ecs_iter_t *it) {
|
||||||
Vehicle *veh = ecs_column(it, Vehicle, 1);
|
Vehicle *veh = ecs_column(it, Vehicle, 1);
|
||||||
Position *p = ecs_column(it, Position, 2);
|
Position *p = ecs_column(it, Position, 2);
|
||||||
Velocity *v = ecs_column(it, Velocity, 3);
|
Velocity *v = ecs_column(it, Velocity, 3);
|
||||||
|
|
||||||
for (int i = 0; i < it->count; i++) {
|
for (int i = 0; i < it->count; i++) {
|
||||||
|
Vehicle *car = &veh[i];
|
||||||
|
car->speed *= 0.99f;
|
||||||
|
car->steer *= 0.97f;
|
||||||
|
|
||||||
|
float fr_x = p[i].x + (car->wheel_base/2.0f) * zpl_cos(car->heading);
|
||||||
|
float fr_y = p[i].y + (car->wheel_base/2.0f) * zpl_sin(car->heading);
|
||||||
|
|
||||||
|
float bk_x = p[i].x - (car->wheel_base/2.0f) * zpl_cos(car->heading);
|
||||||
|
float bk_y = p[i].y - (car->wheel_base/2.0f) * zpl_sin(car->heading);
|
||||||
|
|
||||||
|
bk_x += car->speed * zpl_cos(car->heading);
|
||||||
|
bk_y += car->speed * zpl_sin(car->heading);
|
||||||
|
fr_x += car->speed * zpl_cos(car->heading + zpl_to_radians(car->steer));
|
||||||
|
fr_y += car->speed * zpl_sin(car->heading + zpl_to_radians(car->steer));
|
||||||
|
|
||||||
|
v[i].x = (fr_x + bk_x) / 2.0f - p[i].x;
|
||||||
|
v[i].y = (fr_y + bk_y) / 2.0f - p[i].y;
|
||||||
|
car->heading = zpl_arctan2(fr_y - bk_y, fr_x - bk_x);
|
||||||
|
|
||||||
for (int j = 0; j < 4; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
// NOTE(zaklaus): Perform seat cleanup
|
// NOTE(zaklaus): Perform seat cleanup
|
||||||
if (!ecs_is_alive(world_ecs(), veh[i].seats[j])) {
|
if (!ecs_is_alive(world_ecs(), veh[i].seats[j])) {
|
||||||
|
@ -219,15 +242,19 @@ void VehicleHandling(ecs_iter_t *it) {
|
||||||
// NOTE(zaklaus): Update passenger position
|
// NOTE(zaklaus): Update passenger position
|
||||||
{
|
{
|
||||||
Position *p2 = ecs_get_mut(world_ecs(), pe, Position, NULL);
|
Position *p2 = ecs_get_mut(world_ecs(), pe, Position, NULL);
|
||||||
|
Velocity *v2 = ecs_get_mut(world_ecs(), pe, Velocity, NULL);
|
||||||
*p2 = p[i];
|
*p2 = p[i];
|
||||||
|
*v2 = v[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(zaklaus): Handle driver input
|
// NOTE(zaklaus): Handle driver input
|
||||||
if (j == 0) {
|
if (j == 0) {
|
||||||
// TODO(zaklaus): Be lazy about it for now, implement wheels later
|
|
||||||
Input const* in = ecs_get(world_ecs(), pe, Input);
|
Input const* in = ecs_get(world_ecs(), pe, Input);
|
||||||
v[i].x += in->x;
|
|
||||||
v[i].y += in->y;
|
car->speed += in->y * VEHICLE_ACCEL;
|
||||||
|
car->speed = zpl_clamp(car->speed, -VEHICLE_MAX_SPEED, VEHICLE_MAX_SPEED);
|
||||||
|
car->steer += in->x * -VEHICLE_STEER * (zpl_abs(car->speed*2.5f) / VEHICLE_MAX_SPEED);
|
||||||
|
car->steer = zpl_clamp(car->steer, -40.0f, 40.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -242,7 +269,7 @@ void SystemsImport(ecs_world_t *ecs) {
|
||||||
ECS_SYSTEM(ecs, DemoNPCMoveAround, EcsOnLoad, components.Velocity, components.EcsDemoNPC);
|
ECS_SYSTEM(ecs, DemoNPCMoveAround, EcsOnLoad, components.Velocity, components.EcsDemoNPC);
|
||||||
ECS_SYSTEM(ecs, EnterOrLeaveVehicle, EcsOnLoad, components.Input, components.Position);
|
ECS_SYSTEM(ecs, EnterOrLeaveVehicle, EcsOnLoad, components.Input, components.Position);
|
||||||
|
|
||||||
ECS_SYSTEM(ecs, MoveWalk, EcsOnUpdate, components.Position, components.Velocity);
|
ECS_SYSTEM(ecs, MoveWalk, EcsOnUpdate, components.Position, components.Velocity, !components.Vehicle);
|
||||||
ECS_SYSTEM(ecs, HurtOnHazardBlock, EcsOnUpdate, components.Position, components.Health);
|
ECS_SYSTEM(ecs, HurtOnHazardBlock, EcsOnUpdate, components.Position, components.Health);
|
||||||
ECS_SYSTEM(ecs, RegenerateHP, EcsOnUpdate, components.Health);
|
ECS_SYSTEM(ecs, RegenerateHP, EcsOnUpdate, components.Health);
|
||||||
ECS_SYSTEM(ecs, VehicleHandling, EcsOnUpdate, components.Vehicle, components.Position, components.Velocity);
|
ECS_SYSTEM(ecs, VehicleHandling, EcsOnUpdate, components.Vehicle, components.Position, components.Velocity);
|
||||||
|
|
Loading…
Reference in New Issue