eco2d/code/modules/source/system_vehicle.c

192 lines
6.9 KiB
C
Raw Normal View History

2021-08-29 10:48:29 +00:00
#include "debug_draw.h"
2021-08-10 11:19:45 +00:00
#define VEH_ENTER_RADIUS 45.0f
void LeaveVehicle(ecs_iter_t *it) {
2021-08-10 11:19:45 +00:00
Input *in = ecs_column(it, Input, 1);
IsInVehicle *vehp = ecs_column(it, IsInVehicle, 2);
2021-08-29 12:59:00 +00:00
Velocity *v = ecs_column(it, Velocity, 3);
2021-08-10 11:19:45 +00:00
for (int i = 0; i < it->count; i++) {
if (!in[i].use) continue;
Vehicle *veh = 0;
if ((veh = ecs_get_mut_if(it->world, vehp->veh, Vehicle))) {
for (int k = 0; k < 4; k++) {
if (veh->seats[k] == it->entities[i]) {
veh->seats[k] = 0;
break;
2021-08-10 11:19:45 +00:00
}
}
2021-08-11 09:24:44 +00:00
in[i].use = false;
ecs_remove(it->world, it->entities[i], IsInVehicle);
2021-08-29 12:59:00 +00:00
// NOTE(zaklaus): push passenger out
{
2021-08-30 09:59:36 +00:00
float px = zpl_cos(veh->heading)*400.0f;
float py = zpl_sin(veh->heading)*400.0f;
v->x += py;
v->y -= px;
2021-08-29 12:59:00 +00:00
}
2021-08-10 11:19:45 +00:00
} else {
ZPL_PANIC("unreachable code");
}
}
}
void EnterVehicle(ecs_iter_t *it) {
Input *in = ecs_column(it, Input, 1);
Position *p = ecs_column(it, Position, 2);
for (int i = 0; i < it->count; i++) {
if (!in[i].use) continue;
size_t ents_count;
int64_t *ents = world_chunk_query_entities(it->entities[i], &ents_count, 2);
2021-09-08 22:10:11 +00:00
bool has_entered_veh = false;
for (size_t j = 0; j < ents_count; j++) {
2021-08-10 22:02:11 +00:00
Vehicle *veh = 0;
2021-09-08 22:10:11 +00:00
if (has_entered_veh) break;
if ((veh = ecs_get_mut_if(it->world, ents[j], Vehicle))) {
Position const* p2 = ecs_get(it->world, ents[j], Position);
float dx = p2->x - p[i].x;
float dy = p2->y - p[i].y;
float range = zpl_sqrt(dx*dx + dy*dy);
if (range <= VEH_ENTER_RADIUS) {
for (int k = 0; k < 4; k++) {
if (veh->seats[k] != 0) continue;
// NOTE(zaklaus): We can enter the vehicle, yay!
veh->seats[k] = it->entities[i];
ecs_set(it->world, it->entities[i], IsInVehicle, {
.veh = ents[j]
});
p[i] = *p2;
2021-08-11 09:24:44 +00:00
in[i].use = false;
2021-09-08 22:10:11 +00:00
has_entered_veh = true;
2021-08-10 11:19:45 +00:00
break;
}
}
}
}
}
}
2021-08-10 23:06:12 +00:00
#define VEHICLE_FORCE 34.8f
2021-08-30 09:59:36 +00:00
#define VEHICLE_ACCEL 0.42f
2021-08-10 11:19:45 +00:00
#define VEHICLE_DECEL 0.28f
2021-08-30 09:59:36 +00:00
#define VEHICLE_STEER 3.89f
#define VEHICLE_BRAKE_FORCE 0.84f
2021-08-10 11:19:45 +00:00
void VehicleHandling(ecs_iter_t *it) {
Vehicle *veh = ecs_column(it, Vehicle, 1);
Position *p = ecs_column(it, Position, 2);
Velocity *v = ecs_column(it, Velocity, 3);
for (int i = 0; i < it->count; i++) {
Vehicle *car = &veh[i];
for (int j = 0; j < 4; j++) {
// NOTE(zaklaus): Perform seat cleanup
2021-08-10 15:42:23 +00:00
if (!world_entity_valid(veh[i].seats[j])) {
2021-08-10 11:19:45 +00:00
veh[i].seats[j] = 0;
continue;
}
ecs_entity_t pe = veh[i].seats[j];
// NOTE(zaklaus): Handle driver input
if (j == 0) {
Input const* in = ecs_get(it->world, pe, Input);
2021-08-10 11:19:45 +00:00
2021-08-30 09:59:36 +00:00
car->force += zpl_lerp(0.0f, in->y * VEHICLE_FORCE, VEHICLE_ACCEL*it->delta_time);
2021-08-29 12:59:00 +00:00
if (in->sprint) {
2021-08-30 09:59:36 +00:00
car->force = zpl_lerp(car->force, 0.0f, VEHICLE_BRAKE_FORCE*it->delta_time);
2021-08-29 12:59:00 +00:00
if (zpl_abs(car->force) < 5.5f)
car->force = 0.0f;
}
2021-08-30 18:05:43 +00:00
car->steer *= 0.97f;
2021-08-30 09:59:36 +00:00
car->steer += (in->x * VEHICLE_STEER)*it->delta_time;
2021-08-10 11:19:45 +00:00
car->steer = zpl_clamp(car->steer, -40.0f, 40.0f);
}
}
2021-08-29 12:59:00 +00:00
car->force = zpl_clamp(car->force, car->reverse_speed, car->speed);
2021-08-10 11:19:45 +00:00
// NOTE(zaklaus): Vehicle physics
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);
2021-08-29 12:59:00 +00:00
world_block_lookup lookup = world_block_from_realpos(p[i].x, p[i].y);
float drag = zpl_clamp(blocks_get_drag(lookup.block_id), 0.0f, 1.0f);
bk_x += car->force * drag * zpl_cos(car->heading);
bk_y += car->force * drag * zpl_sin(car->heading);
fr_x += car->force * drag * zpl_cos(car->heading + zpl_to_radians(car->steer));
fr_y += car->force * drag * zpl_sin(car->heading + zpl_to_radians(car->steer));
2021-08-10 11:19:45 +00:00
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);
2021-08-29 10:48:29 +00:00
2021-08-29 15:56:58 +00:00
world_block_lookup lookahead = world_block_from_realpos(p[i].x+PHY_LOOKAHEAD(v[i].x), p[i].y+PHY_LOOKAHEAD(v[i].y));
uint32_t flags = blocks_get_flags(lookahead.block_id);
if (flags & BLOCK_FLAG_COLLISION) {
car->force = 0.0f;
}
2021-08-29 12:59:00 +00:00
for (int j = 0; j < 4; j++) {
if (!world_entity_valid(veh[i].seats[j])) continue;
ecs_entity_t pe = veh[i].seats[j];
// NOTE(zaklaus): Update passenger position
{
Position *p2 = ecs_get_mut(it->world, pe, Position, NULL);
Velocity *v2 = ecs_get_mut(it->world, pe, Velocity, NULL);
*p2 = p[i];
*v2 = v[i];
}
}
2021-08-29 10:48:29 +00:00
{
debug_v2 b2 = {p[i].x + zpl_cos(car->heading)*(car->wheel_base), p[i].y + zpl_sin(car->heading)*(car->wheel_base)};
debug_push_line((debug_v2){p[i].x, p[i].y}, b2, 0x0000FFFF);
2021-09-08 09:52:11 +00:00
// NOTE(zaklaus): force
2021-08-29 10:48:29 +00:00
{
float dx = zpl_cos(car->heading);
float dy = zpl_sin(car->heading);
debug_push_circle((debug_v2){p[i].x+dx*car->force, p[i].y+dy*car->force}, 5.0f, 0x00FF00FF);
}
2021-09-08 09:52:11 +00:00
// NOTE(zaklaus): steer
{
float dx = zpl_sin(car->heading);
float dy = -zpl_cos(car->heading);
debug_push_circle((debug_v2){p[i].x+dx*car->steer*-20, p[i].y+dy*car->steer*-20}, 5.0f, 0x00FFAAFF);
}
2021-08-29 10:48:29 +00:00
}
2021-08-10 11:19:45 +00:00
}
}
2021-08-11 08:54:52 +00:00
void ClearVehicle(ecs_iter_t *it) {
Vehicle *veh = ecs_column(it, Vehicle, 1);
for (int i = 0; i < it->count; i++) {
for (int k = 0; k < 4; k++) {
2021-08-11 10:22:46 +00:00
if (world_entity_valid(veh[i].seats[k])) {
2021-08-11 08:54:52 +00:00
ecs_remove(it->world, veh[i].seats[k], IsInVehicle);
}
}
}
}