mob spawner + friendly fire

master
Dominik Madarász 2023-07-26 14:53:50 +02:00
parent d864661e65
commit 213710e922
4 changed files with 104 additions and 21 deletions

View File

@ -260,6 +260,7 @@ typedef struct {
typedef struct { typedef struct {
uint8_t damage; uint8_t damage;
float origin_x, origin_y; float origin_x, origin_y;
ecs_entity_t owner;
} WeaponProjectile; } WeaponProjectile;
#define _COMPS\ #define _COMPS\

View File

@ -8,7 +8,12 @@
#include "gui/notifications.h" #include "gui/notifications.h"
float get_rand_between(float min, float max) {
return ((float)rand() / (float)RAND_MAX) * (max - min) + min;
}
static ecs_query_t *ecs_mobpos_query = NULL; static ecs_query_t *ecs_mobpos_query = NULL;
static ecs_query_t *ecs_pawn_query = NULL;
// custom systems // custom systems
#include "system_mob.c" #include "system_mob.c"
@ -19,9 +24,11 @@ void mob_systems(ecs_world_t *ecs) {
ECS_SYSTEM(ecs, MobMovement, EcsPostUpdate, components.Velocity, components.Position, components.MobHuntPlayer, !components.Dead); ECS_SYSTEM(ecs, MobMovement, EcsPostUpdate, components.Velocity, components.Position, components.MobHuntPlayer, !components.Dead);
ECS_SYSTEM_TICKED(ecs, MobMeleeAtk, EcsPostUpdate, components.Position, components.Mob, components.MobHuntPlayer, components.MobMelee, !components.Dead); ECS_SYSTEM_TICKED(ecs, MobMeleeAtk, EcsPostUpdate, components.Position, components.Mob, components.MobHuntPlayer, components.MobMelee, !components.Dead);
ECS_SYSTEM_TICKED(ecs, MobDespawnDead, EcsPostUpdate, components.Mob, components.Dead); ECS_SYSTEM_TICKED(ecs, MobDespawnDead, EcsPostUpdate, components.Mob, components.Dead);
ECS_SYSTEM_TICKED(ecs, MobSpawner, EcsPostUpdate, components.Input, components.Position);
//NOTE(DavoSK): weapons //NOTE(DavoSK): weapons
ecs_mobpos_query = ecs_query_new(world_ecs(), "components.Mob, components.Position, components.Health, components.Velocity, !components.Dead"); ecs_mobpos_query = ecs_query_new(world_ecs(), "components.Mob, components.Position, components.Health, components.Velocity, !components.Dead");
ecs_pawn_query = ecs_query_new(world_ecs(), "components.Position, components.Health, components.Velocity, !components.Dead");
ECS_SYSTEM_TICKED(ecs, WeaponKnifeMechanic, EcsPostUpdate, components.WeaponKnife, components.Position, components.Input, !components.Dead); ECS_SYSTEM_TICKED(ecs, WeaponKnifeMechanic, EcsPostUpdate, components.WeaponKnife, components.Position, components.Input, !components.Dead);
ECS_SYSTEM_TICKED(ecs, WeaponProjectileHit, EcsPostUpdate, components.WeaponProjectile, components.Position, components.Rotation); ECS_SYSTEM_TICKED(ecs, WeaponProjectileHit, EcsPostUpdate, components.WeaponProjectile, components.Position, components.Rotation);
ECS_SYSTEM_TICKED(ecs, WeaponProjectileExpire, EcsPostUpdate, components.WeaponProjectile, components.Position); ECS_SYSTEM_TICKED(ecs, WeaponProjectileExpire, EcsPostUpdate, components.WeaponProjectile, components.Position);

View File

@ -1,3 +1,21 @@
#define MOB_SPAWN_DELAY (uint16_t)(20*1.5f)
#define MOB_SPAWN_PERCENTAGE_FROM_MAX 0.05f
#define MOB_INITIAL_MAX 50
#define MOB_GROWTH_FACTOR 5.0f
#define MOB_GROWTH_CONTROL 50.0f
#define MOB_SPAWN_DIST 12*WORLD_BLOCK_SIZE;
#define MOB_MAX_SPAWN_TRIES 5
static uint64_t max_mobs = MOB_INITIAL_MAX;
static uint64_t mob_kills = 0;
static uint16_t mob_spawn_timer = MOB_SPAWN_DELAY;
static int16_t player_spawn_counter = -1;
void recalc_max_mobs() {
max_mobs = (uint64_t)zpl_round(MOB_INITIAL_MAX + MOB_GROWTH_FACTOR * zpl_exp((float)mob_kills / MOB_GROWTH_CONTROL));
zpl_printf("Max mobs: %d\n", max_mobs);
}
void MobDetectPlayers(ecs_iter_t *it) { void MobDetectPlayers(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 1); Position *p = ecs_field(it, Position, 1);
@ -27,10 +45,6 @@ void MobDetectPlayers(ecs_iter_t *it) {
} }
} }
void MobDetectPlayers1(ecs_iter_t *it) {
}
#define MOB_MOVEMENT_SPEED 300.0f #define MOB_MOVEMENT_SPEED 300.0f
void MobMovement(ecs_iter_t *it) { void MobMovement(ecs_iter_t *it) {
@ -93,6 +107,9 @@ void MobOnDead(ecs_iter_t *it) {
v[i] = (Velocity){0.0f, 0.0f}; v[i] = (Velocity){0.0f, 0.0f};
ecs_remove(it->world, it->entities[i], PhysicsBody); ecs_remove(it->world, it->entities[i], PhysicsBody);
++mob_kills;
recalc_max_mobs();
pkt_code_send(0, 0, (pkt_send_code){ pkt_code_send(0, 0, (pkt_send_code){
.code = SURV_CODE_SHOW_NOTIF, .code = SURV_CODE_SHOW_NOTIF,
.data = "mob died" .data = "mob died"
@ -114,5 +131,65 @@ void MobDespawnDead(ecs_iter_t *it) {
} }
void MobSpawner(ecs_iter_t *it) { void MobSpawner(ecs_iter_t *it) {
Position *pos = ecs_field(it, Position, 2);
if (mob_spawn_timer > 0) {
TICK_VAR(mob_spawn_timer);
return;
}
ecs_iter_t mob_it = ecs_query_iter(it->world, ecs_mobpos_query);
uint64_t curr_mobs = 0;
while (ecs_query_next(&mob_it)) {
curr_mobs += mob_it.count;
}
if (curr_mobs >= max_mobs) {
return;
}
uint16_t mobs_to_spawn = zpl_max(1, (uint16_t)zpl_floor(MOB_SPAWN_PERCENTAGE_FROM_MAX*max_mobs));
player_spawn_counter = (player_spawn_counter+1)%it->count;
for (int i = player_spawn_counter; i < it->count; i++) {
const uint32_t radius = MOB_SPAWN_DIST;
uint32_t ox = (uint32_t)pos[i].x;
uint32_t oy = (uint32_t)pos[i].y;
uint8_t tries_done = 0;
for (;;) {
if (mobs_to_spawn == 0) {
mob_spawn_timer = MOB_SPAWN_DELAY;
return;
}
if (tries_done == MOB_MAX_SPAWN_TRIES) {
break;
}
float angle = get_rand_between(0, 2*ZPL_PI);
float dist = get_rand_between((float)radius, radius*1.5f);
uint32_t cx = (uint32_t)(ox + dist * zpl_cos(angle));
uint32_t cy = (uint32_t)(oy + dist * zpl_sin(angle));
if (cx >= world_dim() || cy >= world_dim() || cx <= 0 || cy <= 0) {
tries_done++;
continue;
}
world_block_lookup l = world_block_from_realpos((float)cx, (float)cy);
uint32_t flags = blocks_get_flags(l.bid);
if (flags & BLOCK_FLAG_COLLISION) {
tries_done++;
continue;
}
ecs_entity_t e = entity_spawn_id(ASSET_MOB);
entity_set_position(e, (float)cx, (float)cy);
ecs_add(world_ecs(), e, MobMelee);
mobs_to_spawn--;
}
}
} }

View File

@ -8,11 +8,6 @@ ZPL_DIAGNOSTIC_POP
#define WEAPON_PROJECTILE_RANGE_LIFETIME 800.0f #define WEAPON_PROJECTILE_RANGE_LIFETIME 800.0f
#define WEAPON_HIT_FORCE_PUSH 400.0f #define WEAPON_HIT_FORCE_PUSH 400.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) { void WeaponKnifeMechanic(ecs_iter_t* it) {
WeaponKnife* weapon = ecs_field(it, WeaponKnife, 1); WeaponKnife* weapon = ecs_field(it, WeaponKnife, 1);
const Position* pos = ecs_field(it, Position, 2); const Position* pos = ecs_field(it, Position, 2);
@ -31,7 +26,8 @@ void WeaponKnifeMechanic(ecs_iter_t* it) {
ecs_set(it->world, e, WeaponProjectile, { ecs_set(it->world, e, WeaponProjectile, {
.damage = weapon[i].damage, .damage = weapon[i].damage,
.origin_x = pos[i].x, .origin_x = pos[i].x,
.origin_y = pos[i].y .origin_y = pos[i].y,
.owner = it->entities[i]
}); });
ecs_set(it->world, e, StreamLayerOverride, { .layer = 0 }); ecs_set(it->world, e, StreamLayerOverride, { .layer = 0 });
@ -90,18 +86,20 @@ void WeaponProjectileHit(ecs_iter_t* it) {
const Rotation* rot = ecs_field(it, Rotation, 3); const Rotation* rot = ecs_field(it, Rotation, 3);
for (int i = 0; i < it->count; i++) { for (int i = 0; i < it->count; i++) {
ecs_iter_t it2 = ecs_query_iter(it->world, ecs_mobpos_query); ecs_iter_t it2 = ecs_query_iter(it->world, ecs_pawn_query);
while (ecs_query_next(&it2)) { while (ecs_query_next(&it2)) {
Mob* mob = ecs_field(&it2, Mob, 1); Position* pawn_pos = ecs_field(&it2, Position, 1);
Position* mob_pos = ecs_field(&it2, Position, 2); Health *pawn_health = ecs_field(&it2, Health, 2);
Health *mob_health = ecs_field(&it2, Health, 3); Velocity *pawn_velocity = ecs_field(&it2, Velocity, 3);
Velocity *mob_velocity = ecs_field(&it2, Velocity, 4);
for (int j = 0; j < it2.count; j++) { for (int j = 0; j < it2.count; j++) {
if (weapon[i].owner == it2.entities[j])
continue;
float p_x = pos[i].x; float p_x = pos[i].x;
float p_y = pos[i].y; float p_y = pos[i].y;
float p2_x = mob_pos[j].x /*+ v2[j].x*/; float p2_x = pawn_pos[j].x /*+ v2[j].x*/;
float p2_y = mob_pos[j].y /*+ v2[j].y*/; float p2_y = pawn_pos[j].y /*+ v2[j].y*/;
c2AABB box_a = { c2AABB box_a = {
.min = { p_x - WORLD_BLOCK_SIZE / 4 , p_y - WORLD_BLOCK_SIZE / 4 }, .min = { p_x - WORLD_BLOCK_SIZE / 4 , p_y - WORLD_BLOCK_SIZE / 4 },
@ -133,10 +131,10 @@ void WeaponProjectileHit(ecs_iter_t* it) {
if (c2AABBtoAABB(box_a, box_b)) { if (c2AABBtoAABB(box_a, box_b)) {
float dd = zpl_sqrt(d2); float dd = zpl_sqrt(d2);
mob_health[j].dmg += weapon[i].damage; pawn_health[j].dmg += weapon[i].damage;
mob_velocity[j].x += (dx/dd)*WEAPON_HIT_FORCE_PUSH; pawn_velocity[j].x += (dx/dd)*WEAPON_HIT_FORCE_PUSH;
mob_velocity[j].y += (dy/dd)*WEAPON_HIT_FORCE_PUSH; pawn_velocity[j].y += (dy/dd)*WEAPON_HIT_FORCE_PUSH;
} }
} }
} }