diff --git a/code/foundation/src/models/components.h b/code/foundation/src/models/components.h index 7c8fb21..e10f14a 100644 --- a/code/foundation/src/models/components.h +++ b/code/foundation/src/models/components.h @@ -107,6 +107,9 @@ typedef struct { typedef struct { float hp; float max_hp; + + // acumulated damage + float dmg; } Health; typedef struct { char _unused; } Dead; @@ -119,14 +122,6 @@ typedef struct { uint8_t delay; } HealDelay; -typedef struct { - uint8_t _unused; -} HealthDecreased; - -typedef struct { - uint8_t amount; -} Damage; - typedef struct { uint16_t id; } Classify; @@ -286,8 +281,6 @@ typedef struct { X(Dead)\ X(HealthRegen)\ X(HealDelay)\ - X(HealthDecreased)\ - X(Damage)\ X(Mob)\ X(MobHuntPlayer)\ X(MobMelee)\ diff --git a/code/foundation/src/models/prefabs/prefabs_list.c b/code/foundation/src/models/prefabs/prefabs_list.c index 0209121..da98a5c 100644 --- a/code/foundation/src/models/prefabs/prefabs_list.c +++ b/code/foundation/src/models/prefabs/prefabs_list.c @@ -125,6 +125,7 @@ uint64_t mob_spawn(void) { hp->max_hp = hp->hp = 100.0f; ecs_add(world_ecs(), e, Mob); + ecs_set(world_ecs(), e, Health, { 60, 60, 0 }); ecs_set(world_ecs(), e, PhysicsBody, { .kind = PHYS_AABB, .mass = 1.0f }); return (uint64_t)e; diff --git a/code/foundation/src/systems/modules/system_health.c b/code/foundation/src/systems/modules/system_health.c index 609da21..d48f9f7 100644 --- a/code/foundation/src/systems/modules/system_health.c +++ b/code/foundation/src/systems/modules/system_health.c @@ -7,9 +7,7 @@ void HurtOnHazardBlock(ecs_iter_t *it) { for (int i = 0; i < it->count; i++) { world_block_lookup l = world_block_from_realpos(p[i].x, p[i].y); if (blocks_get_flags(l.bid) & BLOCK_FLAG_HAZARD) { - h->hp -= HAZARD_BLOCK_DMG; - h->hp = zpl_max(0.0f, h->hp); - ecs_add(it->world, it->entities[i], HealthDecreased); + h[i].dmg += HAZARD_BLOCK_DMG; } } } @@ -30,19 +28,17 @@ void RegenerateHP(ecs_iter_t *it) { } } -void OnHealthChangePutDelay(ecs_iter_t *it) { +void ProcessHealthDamage(ecs_iter_t *it) { for (int i = 0; i < it->count; i++) { - ecs_set(it->world, it->entities[i], HealDelay, { .delay = 10 }); - ecs_remove(it->world, it->entities[i], HealthDecreased); - } -} + Health *hp = ecs_get_mut(it->world, it->entities[i], Health); + if (hp->dmg > 0.0f) { + hp->hp = zpl_max(hp->hp-hp->dmg, 0.0f); + hp->dmg = 0.0f; + ecs_set(it->world, it->entities[i], HealDelay, { .delay = 10 }); -void OnHealthChangeCheckDead(ecs_iter_t *it) { - for (int i = 0; i < it->count; i++) { - const Health *hp = ecs_get(it->world, it->entities[i], Health); - - if (hp && hp->hp <= 0.0f) { - ecs_add(it->world, it->entities[i], Dead); + if (hp->hp <= 0.0f) { + ecs_add(it->world, it->entities[i], Dead); + } } } } diff --git a/code/foundation/src/systems/systems.c b/code/foundation/src/systems/systems.c index e1addd7..3c953f8 100644 --- a/code/foundation/src/systems/systems.c +++ b/code/foundation/src/systems/systems.c @@ -356,8 +356,7 @@ void SystemsImport(ecs_world_t *ecs) { ECS_SYSTEM_TICKED_EX(ecs, HurtOnHazardBlock, EcsOnUpdate, 20.0f, components.Position, components.Health); ECS_SYSTEM_TICKED_EX(ecs, RegenerateHP, EcsOnUpdate, 40.0f, components.Health, components.HealthRegen, !components.HealDelay); ECS_SYSTEM_TICKED_EX(ecs, TickDownHealDelay, EcsOnUpdate, 20.0f, components.HealDelay); - ECS_OBSERVER(ecs, OnHealthChangePutDelay, EcsOnAdd, components.HealthDecreased); - ECS_OBSERVER(ecs, OnHealthChangeCheckDead, EcsOnAdd, components.HealthDecreased); + ECS_SYSTEM_TICKED(ecs, ProcessHealthDamage, EcsPostUpdate, components.Health); ECS_OBSERVER(ecs, OnDead, EcsOnAdd, components.Dead); // collisions and movement physics diff --git a/code/games/survival/src/game.c b/code/games/survival/src/game.c index 472c476..3a7a323 100644 --- a/code/games/survival/src/game.c +++ b/code/games/survival/src/game.c @@ -20,11 +20,11 @@ void mob_systems(ecs_world_t *ecs) { ECS_SYSTEM_TICKED(ecs, MobMeleeAtk, EcsPostUpdate, components.Position, components.Mob, components.MobHuntPlayer, components.MobMelee); //NOTE(DavoSK): weapons - ecs_mobpos_query = ecs_query_new(world_ecs(), "components.Mob, components.Position"); + ecs_mobpos_query = ecs_query_new(world_ecs(), "components.Mob, components.Position, components.Health, components.Velocity"); ECS_SYSTEM_TICKED(ecs, WeaponKnifeMechanic, EcsPostUpdate, components.WeaponKnife, components.Position, components.Input); ECS_SYSTEM_TICKED(ecs, WeaponProjectileHit, EcsPostUpdate, components.WeaponProjectile, components.Position, components.Rotation); ECS_SYSTEM_TICKED(ecs, WeaponProjectileExpire, EcsPostUpdate, components.WeaponProjectile, components.Position); - //ECS_OBSERVER(ecs, MobDetectPlayers1, EcsOnAdd, components.Mob); + ECS_OBSERVER(ecs, MobOnDead, EcsOnAdd, components.Mob, components.Dead); } void game_input() { diff --git a/code/games/survival/src/system_mob.c b/code/games/survival/src/system_mob.c index 84579d6..35434c6 100644 --- a/code/games/survival/src/system_mob.c +++ b/code/games/survival/src/system_mob.c @@ -74,10 +74,15 @@ void MobMeleeAtk(ecs_iter_t *it) { float range = (dx*dx + dy*dy); if (range < MOB_MELEE_DIST) { - Health *hp = ecs_get_mut_ex(it->world, m->plr, Health); - hp->hp = zpl_max(hp->hp-MOB_MELEE_DMG, 0.0f); - ecs_add(it->world, m->plr, HealthDecreased); + Health *health = ecs_get_mut_ex(it->world, m->plr, Health); + health->dmg += MOB_MELEE_DMG; } mob[i].atk_delay = MOB_ATK_DELAY; } +} + +void MobOnDead(ecs_iter_t *it) { + for (int i = 0; i < it->count; i++) { + entity_despawn(it->entities[i]); + } } \ No newline at end of file diff --git a/code/games/survival/src/system_weapon.c b/code/games/survival/src/system_weapon.c index d95634e..810a34a 100644 --- a/code/games/survival/src/system_weapon.c +++ b/code/games/survival/src/system_weapon.c @@ -6,41 +6,42 @@ ZPL_DIAGNOSTIC_POP #define WEAPON_PROJECTILE_POS_OFFSET 200.0f #define WEAPON_PROJECTILE_SPEED 500.0f #define WEAPON_PROJECTILE_RANGE_LIFETIME 800.0f +#define WEAPON_HIT_FORCE_PUSH 40.0f //TODO(DavoSK): move to helpers, add srand float get_rand_between(float min, float max) { return ((float)rand() / (float)RAND_MAX) * (max - min) + min; } -void WeaponKnifeMechanic(ecs_iter_t *it) { - WeaponKnife *weapon = ecs_field(it, WeaponKnife, 1); - const Position *pos = ecs_field(it, Position, 2); - const Input *input = ecs_field(it, Input, 3); +void WeaponKnifeMechanic(ecs_iter_t* it) { + WeaponKnife* weapon = ecs_field(it, WeaponKnife, 1); + const Position* pos = ecs_field(it, Position, 2); + const Input* input = ecs_field(it, Input, 3); - for (int i = 0; i < it->count; i++) { - if (weapon[i].spawn_delay > 0) { - TICK_VAR(weapon[i].spawn_delay); + for (int i = 0; i < it->count; i++) { + if (weapon[i].spawn_delay > 0) { + TICK_VAR(weapon[i].spawn_delay); continue; - } + } - for(int j = 0; j < weapon[i].projectile_count; j++) { + for (int j = 0; j < weapon[i].projectile_count; j++) { ecs_entity_t e = entity_spawn(EKIND_WEAPON); - ecs_set(it->world, e, Sprite, { .spritesheet=0, .frame=2347 }); + ecs_set(it->world, e, Sprite, { .spritesheet = 0, .frame = 2347 }); ecs_set(it->world, e, TriggerOnly, { 0 }); - ecs_set(it->world, e, WeaponProjectile, { - .damage=weapon[i].damage, - .origin_x=pos[i].x, - .origin_y=pos[i].y - }); - - ecs_set(it->world, e, Rotation, { - .angle=zpl_to_degrees(zpl_arctan2(input[i].hx, input[i].hy)) - }); + ecs_set(it->world, e, WeaponProjectile, { + .damage = weapon[i].damage, + .origin_x = pos[i].x, + .origin_y = pos[i].y + }); + + ecs_set(it->world, e, Rotation, { + .angle = zpl_to_degrees(zpl_arctan2(input[i].hx, input[i].hy)) + }); ecs_set(it->world, e, Velocity, { - .x=input[i].hx*WEAPON_PROJECTILE_SPEED, - .y=input[i].hy*WEAPON_PROJECTILE_SPEED*-1 - }); + .x = input[i].hx * WEAPON_PROJECTILE_SPEED, + .y = input[i].hy * WEAPON_PROJECTILE_SPEED * -1 + }); zpl_vec2 input_vec = { .x = input[i].hy, @@ -48,119 +49,101 @@ void WeaponKnifeMechanic(ecs_iter_t *it) { }; zpl_vec2 pos_offset; - zpl_vec2_mul(&pos_offset, input_vec, get_rand_between(-WEAPON_PROJECTILE_POS_OFFSET, WEAPON_PROJECTILE_POS_OFFSET)); - Position *dest = ecs_get_mut(world_ecs(), e, Position); + zpl_vec2_mul(&pos_offset, input_vec, get_rand_between(-WEAPON_PROJECTILE_POS_OFFSET, WEAPON_PROJECTILE_POS_OFFSET)); + Position* dest = ecs_get_mut(world_ecs(), e, Position); dest->x = pos[i].x + pos_offset.x; - dest->y = pos[i].y + pos_offset.y; + dest->y = pos[i].y + pos_offset.y; } - weapon[i].spawn_delay = WEAPON_KNIFE_SPAWN_DELAY; - } + weapon[i].spawn_delay = WEAPON_KNIFE_SPAWN_DELAY; + } } -void WeaponProjectileExpire(ecs_iter_t *it) { - const WeaponProjectile *weapon = ecs_field(it, WeaponProjectile, 1); - const Position *pos = ecs_field(it, Position, 2); +void WeaponProjectileExpire(ecs_iter_t* it) { + const WeaponProjectile* weapon = ecs_field(it, WeaponProjectile, 1); + const Position* pos = ecs_field(it, Position, 2); - for (int i = 0; i < it->count; i++) { + for (int i = 0; i < it->count; i++) { zpl_vec2 v_origin = { .x = weapon[i].origin_x, .y = weapon[i].origin_y }; zpl_vec2 v_pos = { .x = pos[i].x, .y = pos[i].y }; zpl_vec2 v_dist; zpl_vec2_sub(&v_dist, v_origin, v_pos); const float d = zpl_vec2_mag(v_dist); - if(d > WEAPON_PROJECTILE_RANGE_LIFETIME) { + if (d > WEAPON_PROJECTILE_RANGE_LIFETIME) { entity_despawn(it->entities[i]); } } } -zpl_vec2 rotate_point(float cx, float cy, float angle, zpl_vec2 p){ +zpl_vec2 rotate_point(float cx, float cy, float angle, zpl_vec2 p) { return (zpl_vec2) { .x = zpl_cos(angle) * (p.x - cx) - zpl_sin(angle) * (p.y - cy) + cx, - .y = zpl_sin(angle) * (p.x - cx) + zpl_cos(angle) * (p.y - cy) + cy + .y = zpl_sin(angle) * (p.x - cx) + zpl_cos(angle) * (p.y - cy) + cy }; } -void WeaponProjectileHit(ecs_iter_t *it) { - const WeaponProjectile *weapon = ecs_field(it, WeaponProjectile, 1); - const Position *pos = ecs_field(it, Position, 2); - const Rotation *rot = ecs_field(it, Rotation, 3); +void WeaponProjectileHit(ecs_iter_t* it) { + const WeaponProjectile* weapon = ecs_field(it, WeaponProjectile, 1); + const Position* pos = ecs_field(it, Position, 2); + const Rotation* rot = ecs_field(it, Rotation, 3); for (int i = 0; i < it->count; i++) { - ecs_iter_t it2 = ecs_query_iter(world_ecs(), ecs_mobpos_query); + ecs_iter_t it2 = ecs_query_iter(it->world, ecs_mobpos_query); while (ecs_query_next(&it2)) { - Mob *mob = ecs_field(&it2, Mob, 1); - Position *mob_pos = ecs_field(&it2, Position, 2); - + Mob* mob = ecs_field(&it2, Mob, 1); + Position* mob_pos = ecs_field(&it2, Position, 2); + Health *mob_health = ecs_field(&it2, Health, 3); + Velocity *mob_velocity = ecs_field(&it2, Velocity, 4); + for (int j = 0; j < it2.count; j++) { float p_x = pos[i].x; float p_y = pos[i].y; float p2_x = mob_pos[j].x /*+ v2[j].x*/; float p2_y = mob_pos[j].y /*+ v2[j].y*/; - //NOTE(DavoSK): since our weapon has also rotation - //we need to rotate its bbox by rot - float rot_radians = zpl_to_radians(rot[i].angle); - zpl_vec2 bbox_min = rotate_point(p_x, p_y, rot_radians, (zpl_vec2){ - .x = p_x - WORLD_BLOCK_SIZE / 2, - .y = p_y - WORLD_BLOCK_SIZE / 4 - }); - - zpl_vec2 bbox_max = rotate_point(p_x, p_y, rot_radians, (zpl_vec2){ - .x = p_x + WORLD_BLOCK_SIZE / 2, - .y = p_y + WORLD_BLOCK_SIZE / 4 - }); - c2AABB box_a = { - .min = { .x = bbox_min.x, .y = bbox_min.y }, - .max = { .x = bbox_max.x, .y = bbox_max.y } + .min = { p_x - WORLD_BLOCK_SIZE / 4 , p_y - WORLD_BLOCK_SIZE / 4 }, + .max = { p_x + WORLD_BLOCK_SIZE / 4 , p_y + WORLD_BLOCK_SIZE / 4 }, }; c2AABB box_b = { - .min = { p2_x - WORLD_BLOCK_SIZE / 2, p2_y - WORLD_BLOCK_SIZE / 4 }, - .max = { p2_x + WORLD_BLOCK_SIZE / 2, p2_y + WORLD_BLOCK_SIZE / 4 }, + .min = { p2_x - WORLD_BLOCK_SIZE / 4, p2_y - WORLD_BLOCK_SIZE / 4 }, + .max = { p2_x + WORLD_BLOCK_SIZE / 4, p2_y + WORLD_BLOCK_SIZE / 4 }, }; - float r1x = (box_a.max.x-box_a.min.x); - float r1y = (box_a.max.y-box_a.min.y); - float r1 = (r1x*r1x + r1y*r1y)*.5f; + float r1x = (box_a.max.x - box_a.min.x); + float r1y = (box_a.max.y - box_a.min.y); + float r1 = (r1x * r1x + r1y * r1y) * .5f; - float r2x = (box_b.max.x-box_b.min.x); - float r2y = (box_b.max.y-box_b.min.y); - float r2 = (r2x*r2x + r2y*r2y)*.5f; + float r2x = (box_b.max.x - box_b.min.x); + float r2y = (box_b.max.y - box_b.min.y); + float r2 = (r2x * r2x + r2y * r2y) * .5f; - { - float dx = (p2_x-p_x); - float dy = (p2_y-p_y); - float d = (dx*dx + dy*dy); + float dx = (p2_x - p_x); + float dy = (p2_y - p_y); + float d2 = (dx * dx + dy * dy); + { - if (d > r1 && d > r2) - continue; - } + if (d2 > r1 && d2 > r2) + continue; + } - // c2Circle circle_a = { - // .p = { p_x, p_y }, - // .r = r1/2.f, - // }; + c2Manifold m = { 0 }; + c2AABBtoAABBManifold(box_a, box_b, &m); + float dd = zpl_sqrt(d2); - // c2Circle circle_b = { - // .p = { p2_x, p2_y }, - // .r = r2/2.f, - // }; + if (m.count > 0) { + mob_health[j].dmg += weapon[i].damage; + for (int k = 0; k < m.count; k++) { + float d = m.depths[k]; - // const void *shapes_a[] = { &circle_a, &box_a }; - // const void *shapes_b[] = { &circle_b, &box_b }; - - c2Manifold m = { 0 }; - c2Collide(&box_a, 0, C2_TYPE_AABB, &box_b, 0, C2_TYPE_AABB, &m); - - if(m.count) { - ecs_set(it->world, it2.entities[j], Damage, { .amount = weapon[i].damage }); - entity_despawn(it->entities[i]); + mob_velocity[j].x += (dx/dd)*d*WEAPON_HIT_FORCE_PUSH; + mob_velocity[j].y += (dy/dd)*d*WEAPON_HIT_FORCE_PUSH; + } } } } } -} \ No newline at end of file +}