Enemy swarm movement
This commit is contained in:
@@ -447,8 +447,8 @@
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":1126.83666666667,
|
||||
"y":592.916666666667
|
||||
"x":1126.84,
|
||||
"y":592.917
|
||||
},
|
||||
{
|
||||
"gid":28,
|
||||
@@ -459,8 +459,8 @@
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":1140.66666666667,
|
||||
"y":594.666666666667
|
||||
"x":1140.67,
|
||||
"y":594.667
|
||||
},
|
||||
{
|
||||
"gid":28,
|
||||
@@ -471,8 +471,8 @@
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":1125.66666666667,
|
||||
"y":609.666666666667
|
||||
"x":1125.67,
|
||||
"y":609.667
|
||||
},
|
||||
{
|
||||
"gid":28,
|
||||
@@ -484,7 +484,7 @@
|
||||
"visible":true,
|
||||
"width":10,
|
||||
"x":1139,
|
||||
"y":608.666666666667
|
||||
"y":608.667
|
||||
},
|
||||
{
|
||||
"gid":28,
|
||||
@@ -520,6 +520,162 @@
|
||||
"width":0,
|
||||
"x":1119,
|
||||
"y":571.5
|
||||
},
|
||||
{
|
||||
"height":0,
|
||||
"id":8,
|
||||
"name":"spawn",
|
||||
"point":true,
|
||||
"rotation":0,
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":32.0605727272727,
|
||||
"y":768.242090909091
|
||||
},
|
||||
{
|
||||
"height":0,
|
||||
"id":9,
|
||||
"name":"p1",
|
||||
"point":true,
|
||||
"rotation":0,
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":150,
|
||||
"y":510
|
||||
},
|
||||
{
|
||||
"height":0,
|
||||
"id":20,
|
||||
"name":"p0",
|
||||
"point":true,
|
||||
"rotation":0,
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":97.5,
|
||||
"y":644.5
|
||||
},
|
||||
{
|
||||
"height":0,
|
||||
"id":10,
|
||||
"name":"p2",
|
||||
"point":true,
|
||||
"rotation":0,
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":226,
|
||||
"y":353.333
|
||||
},
|
||||
{
|
||||
"height":0,
|
||||
"id":11,
|
||||
"name":"p3",
|
||||
"point":true,
|
||||
"rotation":0,
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":331.333,
|
||||
"y":254
|
||||
},
|
||||
{
|
||||
"height":0,
|
||||
"id":12,
|
||||
"name":"p4",
|
||||
"point":true,
|
||||
"rotation":0,
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":458,
|
||||
"y":214.667
|
||||
},
|
||||
{
|
||||
"height":0,
|
||||
"id":13,
|
||||
"name":"p5",
|
||||
"point":true,
|
||||
"rotation":0,
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":613.333,
|
||||
"y":198.667
|
||||
},
|
||||
{
|
||||
"height":0,
|
||||
"id":14,
|
||||
"name":"p6",
|
||||
"point":true,
|
||||
"rotation":0,
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":744,
|
||||
"y":226.667
|
||||
},
|
||||
{
|
||||
"height":0,
|
||||
"id":15,
|
||||
"name":"p7",
|
||||
"point":true,
|
||||
"rotation":0,
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":830.667,
|
||||
"y":266.667
|
||||
},
|
||||
{
|
||||
"height":0,
|
||||
"id":16,
|
||||
"name":"p8",
|
||||
"point":true,
|
||||
"rotation":0,
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":912,
|
||||
"y":325.333
|
||||
},
|
||||
{
|
||||
"height":0,
|
||||
"id":17,
|
||||
"name":"p9",
|
||||
"point":true,
|
||||
"rotation":0,
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":982,
|
||||
"y":389.333
|
||||
},
|
||||
{
|
||||
"height":0,
|
||||
"id":18,
|
||||
"name":"p10",
|
||||
"point":true,
|
||||
"rotation":0,
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":1038.67,
|
||||
"y":465.333
|
||||
},
|
||||
{
|
||||
"height":0,
|
||||
"id":19,
|
||||
"name":"p11",
|
||||
"point":true,
|
||||
"rotation":0,
|
||||
"type":"",
|
||||
"visible":true,
|
||||
"width":0,
|
||||
"x":1098.67,
|
||||
"y":530
|
||||
}],
|
||||
"opacity":1,
|
||||
"type":"objectgroup",
|
||||
@@ -528,7 +684,7 @@
|
||||
"y":0
|
||||
}],
|
||||
"nextlayerid":10,
|
||||
"nextobjectid":8,
|
||||
"nextobjectid":21,
|
||||
"orientation":"orthogonal",
|
||||
"renderorder":"right-down",
|
||||
"tiledversion":"1.10.2",
|
||||
|
||||
@@ -293,8 +293,7 @@ typedef struct Health {
|
||||
extern ECS_COMPONENT_DECLARE(Health);
|
||||
|
||||
typedef struct Swarm {
|
||||
|
||||
int _;
|
||||
i32 currWaypoint;
|
||||
} Swarm;
|
||||
extern ECS_COMPONENT_DECLARE(Swarm);
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ enum {
|
||||
COLL_LAYER_TRANSPARENCY = 7,
|
||||
};
|
||||
|
||||
#define PLAYER_ENEMY PLAYER_BLUE
|
||||
|
||||
typedef enum Player {
|
||||
PLAYER_RED = 0,
|
||||
PLAYER_BLUE = 1,
|
||||
|
||||
@@ -115,10 +115,57 @@ ecs_entity_t entityCreateWorker(const Position position, Player player, Game *ga
|
||||
return e;
|
||||
}
|
||||
|
||||
ecs_entity_t entityRecruit(EntityType type, Position position, Player player, Game *game) {
|
||||
ecs_entity_t entityCreateSwarmGoblin(const Position position, Player player, Game *game) {
|
||||
ecs_entity_t e = entityCreateBaseUnit(position, 10.0f, player, ENTITY_GOBLIN, ANIM_IDLE, game);
|
||||
ecs_set(ECS, e, Swarm, {
|
||||
.currWaypoint = 0,
|
||||
});
|
||||
ecs_set(ECS, e, Health, {
|
||||
.startHP = 40.0f,
|
||||
.hp = 40.0f,
|
||||
.lastChanged = -1.0f
|
||||
});
|
||||
|
||||
Unit *unit = ecs_get_mut(ECS, e, Unit);
|
||||
unit->minDamage = 5.0f;
|
||||
unit->maxDamage = 10.0f;
|
||||
unit->attackCooldown = 1.0f;
|
||||
unit->maxSpeed = 20.0f;
|
||||
|
||||
return e;
|
||||
}
|
||||
ecs_entity_t entityCreateSwarmOrc(const Position position, Player player, Game *game) {
|
||||
ecs_entity_t e = entityCreateBaseUnit(position, 10.0f, player, ENTITY_ORC, ANIM_IDLE, game);
|
||||
ecs_set(ECS, e, Swarm, {
|
||||
.currWaypoint = 0,
|
||||
});
|
||||
ecs_set(ECS, e, Health, {
|
||||
.startHP = 80.0f,
|
||||
.hp = 80.0f,
|
||||
.lastChanged = -1.0f
|
||||
});
|
||||
|
||||
Unit *unit = ecs_get_mut(ECS, e, Unit);
|
||||
unit->minDamage = 8.0f;
|
||||
unit->maxDamage = 22.0f;
|
||||
unit->attackCooldown = 1.8f;
|
||||
unit->maxSpeed = 12.0f;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
ecs_entity_t entityCreate(EntityType type, Position position, Player player, Game *game) {
|
||||
switch (type) {
|
||||
case ENTITY_WORKER:
|
||||
entityCreateWorker(position, player, game);
|
||||
return entityCreateWorker(position, player, game);
|
||||
case ENTITY_SOLDIER:
|
||||
return entityCreateSoldier(position, player, game);
|
||||
case ENTITY_WARRIOR:
|
||||
return entityCreateWarrior(position, player, game);
|
||||
case ENTITY_GOBLIN:
|
||||
return entityCreateSwarmGoblin(position, player, game);
|
||||
case ENTITY_ORC:
|
||||
return entityCreateSwarmOrc(position, player, game);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,10 @@ ecs_entity_t entityCreateBaseUnit(const Position position, f32 size, Player play
|
||||
ecs_entity_t entityCreateSoldier(const Position position, Player player, Game *game);
|
||||
ecs_entity_t entityCreateWarrior(const Position position, Player player, Game *game);
|
||||
ecs_entity_t entityCreateWorker(const Position position, Player player, Game *game);
|
||||
ecs_entity_t entityCreateSwarmGoblin(const Position position, Player player, Game *game);
|
||||
ecs_entity_t entityCreateSwarmOrc(const Position position, Player player, Game *game);
|
||||
|
||||
ecs_entity_t entityRecruit(EntityType type, Position position, Player player, Game *game);
|
||||
ecs_entity_t entityCreate(EntityType type, Position position, Player player, Game *game);
|
||||
|
||||
void getEntityCost(EntityType type, i32 cost[RES_COUNT]);
|
||||
bool canAffordEntity(EntityType type, PlayerResources res);
|
||||
|
||||
@@ -60,6 +60,8 @@ typedef struct PlayerResources {
|
||||
i64 popCapacity;
|
||||
} PlayerResources;
|
||||
|
||||
#define MAX_SWARM_WAYPOINTS 16
|
||||
|
||||
typedef struct Game {
|
||||
GameScreen screen;
|
||||
GameScreen nextScreen;
|
||||
@@ -80,6 +82,10 @@ typedef struct Game {
|
||||
WaveInfo waveInfo;
|
||||
ecs_entity_t keepEntity;
|
||||
|
||||
Vector2 swarmWaypoints[MAX_SWARM_WAYPOINTS];
|
||||
i32 swamNumWaypoints;
|
||||
Vector2 swarmSpawn;
|
||||
|
||||
BzStackAlloc stackAlloc;
|
||||
struct {
|
||||
BzBTNode *workerHarvest;
|
||||
|
||||
@@ -480,7 +480,7 @@ void update(float dt, void *userData) {
|
||||
break;
|
||||
}
|
||||
|
||||
updateWave(&game->waveInfo, dt);
|
||||
updateWave(&game->waveInfo, game, dt);
|
||||
|
||||
SoundState *soundState = ecs_singleton_get_mut(ECS, SoundState);
|
||||
soundsUpdate(soundState, getCameraBounds(game->camera));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "map_init.h"
|
||||
|
||||
#include <flecs.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "building_factory.h"
|
||||
#include "components.h"
|
||||
@@ -10,14 +11,37 @@
|
||||
#include "utils.h"
|
||||
#include "systems/systems.h"
|
||||
|
||||
i32 getSwarmWaypointIdx(u32 id) {
|
||||
char buf[4];
|
||||
for (i32 i = 0; i < MAX_SWARM_WAYPOINTS; i++) {
|
||||
snprintf(buf, sizeof(buf), "p%d", i);
|
||||
if (id == bzStringDefaultHash(buf))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool initGameObjectsLayer(BzTileMap *map, BzTileObjectGroup *objectGroup) {
|
||||
Game *game = ecs_singleton_get_mut(ECS, Game);
|
||||
game->swamNumWaypoints = 0;
|
||||
for (i32 i = 0; i < objectGroup->objectCount; i++) {
|
||||
BzTileObject object = objectGroup->objects[i];
|
||||
if (bzStringDefaultHash("camera") == object.id) {
|
||||
game->camera.target.x = object.shape.x;
|
||||
game->camera.target.y = object.shape.y;
|
||||
}
|
||||
i32 swarmIdx = getSwarmWaypointIdx(object.id);
|
||||
if (swarmIdx != -1) {
|
||||
game->swarmWaypoints[swarmIdx] = (Vector2) {
|
||||
object.shape.x,
|
||||
object.shape.y,
|
||||
};
|
||||
game->swamNumWaypoints = BZ_MAX(game->swamNumWaypoints, swarmIdx + 1);
|
||||
}
|
||||
if (bzStringDefaultHash("spawn") == object.id) {
|
||||
game->swarmSpawn.x = object.shape.x;
|
||||
game->swarmSpawn.y = object.shape.y;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -256,6 +256,110 @@ void entityMoveToTarget(ecs_iter_t *it) {
|
||||
}
|
||||
}
|
||||
|
||||
void entityMoveSwarm(ecs_iter_t *it) {
|
||||
Game *game = ecs_singleton_get_mut(ECS, Game);
|
||||
Position *pos = ecs_field(it, Position, 1);
|
||||
Velocity *vel = ecs_field(it, Velocity, 2);
|
||||
HitBox *hb = ecs_field(it, HitBox, 3);
|
||||
Swarm *swarm = ecs_field(it, Swarm, 4);
|
||||
Owner *owner = ecs_field(it, Owner, 5);
|
||||
Steering *steer = ecs_field(it, Steering, 6);
|
||||
|
||||
for (i32 i = 0; i < it->count; i++) {
|
||||
|
||||
// Vector2 align = Vector2Zero(); // Alignment (match velocity)
|
||||
Vector2 avoid = Vector2Zero(); // Separation
|
||||
Vector2 target = Vector2Zero();
|
||||
Vector2 cohesion = Vector2Zero(); // Cohesion (move towards center)
|
||||
|
||||
const f32 FRIEND_RADIUS = 22.0f;
|
||||
const f32 ENEMY_RADIUS = 52.0f;
|
||||
|
||||
const Vector2 center = entityGetCenter(pos[i], hb[i]);
|
||||
|
||||
const f32 RANGE = BZ_MAX(FRIEND_RADIUS, ENEMY_RADIUS);
|
||||
BzSpatialGridIter spatialIt = bzSpatialGridIter(game->entityGrid,
|
||||
center.x - RANGE, center.y - RANGE,
|
||||
RANGE * 2.0f, RANGE * 2.0f);
|
||||
|
||||
i32 numFriends = 0;
|
||||
while (bzSpatialGridQueryNext(&spatialIt)) {
|
||||
ecs_entity_t other = *(ecs_entity_t *) spatialIt.data;
|
||||
if (!ecs_has(ECS, other, Owner))
|
||||
continue;
|
||||
Owner otherOwner = *ecs_get(ECS, other, Owner);
|
||||
bool isFriend = owner[i].player == otherOwner.player;
|
||||
|
||||
if (!ecs_has(ECS, other, Position) || !ecs_has(ECS, other, HitBox))
|
||||
continue;
|
||||
Position otherPos = *ecs_get(ECS, other, Position);
|
||||
Rectangle otherHB = *ecs_get(ECS, other, HitBox);;
|
||||
Vector2 otherCenter = entityGetCenter(otherPos, otherHB);
|
||||
f32 dst = Vector2Distance(center, otherCenter);
|
||||
const f32 MIN_AVOID_DST = 18.0f;
|
||||
const f32 MIN_ENEMY_DST = ENEMY_RADIUS;
|
||||
if (isFriend) {
|
||||
if (dst < MIN_AVOID_DST) {
|
||||
Vector2 dif = Vector2Subtract(center, otherCenter);
|
||||
dif = Vector2Scale(Vector2Normalize(dif), MIN_AVOID_DST - dst);
|
||||
avoid = Vector2Add(avoid, dif);
|
||||
}
|
||||
Vector2Add(cohesion, otherCenter);
|
||||
numFriends++;
|
||||
} else {
|
||||
if (dst < MIN_ENEMY_DST) {
|
||||
//DrawCircleV(otherCenter, 2.0f, RED);
|
||||
Vector2 dif = Vector2Subtract(otherCenter, center);
|
||||
dif = Vector2Scale(Vector2Normalize(dif), MIN_ENEMY_DST - dst);
|
||||
target = Vector2Add(target, dif);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numFriends > 0) {
|
||||
cohesion = Vector2Divide(cohesion, (Vector2) { numFriends, numFriends });
|
||||
cohesion = Vector2Subtract(cohesion, center);
|
||||
}
|
||||
|
||||
|
||||
//bzLogInfo("%d %d", numFriends, numEnemies);
|
||||
|
||||
const f32 noiseRange = 10.0f;
|
||||
Vector2 noise = {
|
||||
randFloatRange(-noiseRange, noiseRange),
|
||||
randFloatRange(-noiseRange, noiseRange)
|
||||
};
|
||||
Vector2 followWaypoint = Vector2Zero();
|
||||
if (swarm[i].currWaypoint < game->swamNumWaypoints) {
|
||||
Vector2 waypoint = game->swarmWaypoints[swarm[i].currWaypoint];
|
||||
Vector2 waypointDir = Vector2Subtract(waypoint, center);
|
||||
followWaypoint = waypointDir;
|
||||
|
||||
f32 dst = Vector2Distance(center, waypoint);
|
||||
const f32 WAYPOINT_THRESHOLD = 54.0f;
|
||||
if (dst < WAYPOINT_THRESHOLD) {
|
||||
swarm[i].currWaypoint++;
|
||||
}
|
||||
}
|
||||
const f32 AVOID_FACTOR = 1.0f;
|
||||
const f32 TARGET_FACTOR = 2.2f;
|
||||
const f32 COHESION_FACTOR = 0.10f;
|
||||
const f32 WAYPOINT_FACTOR = 0.45f;
|
||||
const f32 NOISE_FACTOR = 0.2f;
|
||||
Vector2 move = Vector2Zero();
|
||||
move = Vector2Add(move, Vector2Scale(avoid, AVOID_FACTOR));
|
||||
move = Vector2Add(move, Vector2Scale(target, TARGET_FACTOR));
|
||||
//move = Vector2Add(move, Vector2Scale(cohesion, COHESION_FACTOR));
|
||||
move = Vector2Add(move, Vector2Scale(followWaypoint, WAYPOINT_FACTOR));
|
||||
move = Vector2Add(move, Vector2Scale(noise, NOISE_FACTOR));
|
||||
|
||||
//bzLogInfo("%.2f %.2f", move.x, move.y);
|
||||
//DrawLineV(center, Vector2Add(center, Vector2Scale(Vector2Normalize(avoid), 100)), ORANGE);
|
||||
|
||||
steer[i] = move;
|
||||
}
|
||||
}
|
||||
|
||||
void entityFollowPath(ecs_iter_t *it) {
|
||||
const Game *game = ecs_singleton_get(ECS, Game);
|
||||
|
||||
@@ -307,7 +411,7 @@ void updateBuildingRecruitment(ecs_iter_t *it) {
|
||||
slot->elapsed = 0;
|
||||
PlayerResources *playerRes = &game->playerResources[player];
|
||||
playerRes->pop--;
|
||||
entityRecruit(slot->entityType, placePos, player, game);
|
||||
entityCreate(slot->entityType, placePos, player, game);
|
||||
slot->numRecruiting--;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,8 +391,8 @@ void drawMainMenuUI(Game *game, f32 dt) {
|
||||
//loadMap(game, "assets/maps/tree_test.tmj");
|
||||
//loadMap(game, "assets/maps/entity_test.tmj");
|
||||
//loadMap(game, "assets/maps/worker_test.tmj");
|
||||
loadMap(game, "assets/maps/battle_test.tmj");
|
||||
//loadMap(game, "assets/maps/map_01.tmj");
|
||||
//loadMap(game, "assets/maps/battle_test.tmj");
|
||||
loadMap(game, "assets/maps/map_01.tmj");
|
||||
}
|
||||
if (uiMainMenuButton("Settings", true)) {
|
||||
setScreen(game, SCREEN_SETTINGS);
|
||||
|
||||
@@ -181,6 +181,7 @@ void setupSystems() {
|
||||
ECS_SYSTEM(ECS, entityUpdate, EcsOnUpdate, Position, HitBox, Velocity, Unit, Owner, SpatialGridID);
|
||||
|
||||
ECS_SYSTEM(ECS, entityMoveToTarget, EcsOnUpdate, Position, Velocity, TargetPosition, Steering);
|
||||
ECS_SYSTEM(ECS, entityMoveSwarm, EcsOnUpdate, Position, Velocity, HitBox, Swarm, Owner, Steering);
|
||||
ECS_SYSTEM(ECS, entityFollowPath, EcsOnUpdate, Path);
|
||||
|
||||
ECS_SYSTEM(ECS, updateBuildingRecruitment, EcsOnUpdate, Owner, Building, BuildingRecruitInfo);
|
||||
|
||||
@@ -143,6 +143,17 @@ void entityUpdate(ecs_iter_t *it);
|
||||
*/
|
||||
void entityMoveToTarget(ecs_iter_t *it);
|
||||
|
||||
/*
|
||||
* 0: Game (singleton for waypoints)
|
||||
* 1: Position
|
||||
* 2: Velocity
|
||||
* 3: HitBox
|
||||
* 4: Swarm
|
||||
* 5: Owner
|
||||
* 6: Steering
|
||||
*/
|
||||
void entityMoveSwarm(ecs_iter_t *it);
|
||||
|
||||
/*
|
||||
* 0: Game (singleton) for object pool
|
||||
* 1: Path
|
||||
|
||||
27
game/wave.c
27
game/wave.c
@@ -1,6 +1,8 @@
|
||||
#include "wave.h"
|
||||
#include "game_state.h"
|
||||
#include "components.h"
|
||||
#include "entity_factory.h"
|
||||
#include "utils.h"
|
||||
|
||||
WaveInfo getWaveInfo(i32 idx) {
|
||||
BZ_ASSERT(idx >= 0);
|
||||
@@ -24,14 +26,33 @@ WaveInfo getWaveInfo(i32 idx) {
|
||||
return info;
|
||||
}
|
||||
|
||||
void updateWave(WaveInfo *wave, f32 dt) {
|
||||
wave->orcsElapsed += dt;
|
||||
wave->goblinsElapsed += dt;
|
||||
static Vector2 randomizeSpawnPos(Vector2 spawnPoint, i32 range) {
|
||||
spawnPoint.x += randFloatRange(-range, range);
|
||||
spawnPoint.y += randFloatRange(-range, range);
|
||||
return spawnPoint;
|
||||
}
|
||||
|
||||
void updateWave(WaveInfo *wave, Game *game, f32 dt) {
|
||||
wave->elapsed += dt;
|
||||
if (wave->elapsed < wave->data.timeBeforeStart)
|
||||
return;
|
||||
wave->started = true;
|
||||
wave->orcsElapsed += dt;
|
||||
wave->goblinsElapsed += dt;
|
||||
|
||||
f32 timeForGoblin = 1.0f / wave->data.goblinSendRate;
|
||||
if (wave->goblinsElapsed >= timeForGoblin) {
|
||||
Vector2 spawnPos = randomizeSpawnPos(game->swarmSpawn, 20);
|
||||
entityCreate(ENTITY_GOBLIN, spawnPos, PLAYER_ENEMY, game);
|
||||
wave->goblinsElapsed -= timeForGoblin;
|
||||
}
|
||||
|
||||
f32 timeForOrc = 1.0f / wave->data.orcSendRate;
|
||||
if (wave->orcsElapsed >= timeForOrc) {
|
||||
Vector2 spawnPos = randomizeSpawnPos(game->swarmSpawn, 20);
|
||||
entityCreate(ENTITY_ORC, spawnPos, PLAYER_ENEMY, game);
|
||||
wave->orcsElapsed -= timeForOrc;
|
||||
}
|
||||
}
|
||||
|
||||
bool isWaveSendingOver(const WaveInfo *wave) {
|
||||
|
||||
@@ -25,6 +25,8 @@ typedef struct WaveInfo {
|
||||
|
||||
#define NUM_WAVES 5
|
||||
|
||||
typedef struct Game Game;
|
||||
|
||||
static WaveData predefWaves[NUM_WAVES] = {
|
||||
{ 10, 1.0f, 20, 2.0f, 0, 5 * 60 },
|
||||
{ 20, 1.0f, 40, 2.0f, 0, 2 * 60 },
|
||||
@@ -35,7 +37,7 @@ static WaveData predefWaves[NUM_WAVES] = {
|
||||
|
||||
WaveInfo getWaveInfo(i32 idx);
|
||||
|
||||
void updateWave(WaveInfo *wave, f32 dt);
|
||||
void updateWave(WaveInfo *wave, Game *game, f32 dt);
|
||||
|
||||
bool isWaveSendingOver(const WaveInfo *wave);
|
||||
bool isWaveOver(const WaveInfo *wave);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map version="1.10" tiledversion="1.10.2" orientation="orthogonal" renderorder="right-down" width="80" height="50" tilewidth="16" tileheight="16" infinite="0" nextlayerid="10" nextobjectid="20">
|
||||
<map version="1.10" tiledversion="1.10.2" orientation="orthogonal" renderorder="right-down" width="80" height="50" tilewidth="16" tileheight="16" infinite="0" nextlayerid="10" nextobjectid="21">
|
||||
<editorsettings>
|
||||
<export target="maps/map_01.tmj" format="json"/>
|
||||
<export target="../assets/maps/map_01.tmj" format="json"/>
|
||||
</editorsettings>
|
||||
<tileset firstgid="1" source="game.tsx"/>
|
||||
<layer id="1" name="terrain" width="80" height="50">
|
||||
@@ -393,12 +393,15 @@
|
||||
<object id="1" name="camera" x="1119" y="571.5">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="8" name="spawn" x="91.3333" y="665.333">
|
||||
<object id="8" name="spawn" x="32.0606" y="768.242">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="9" name="p1" x="150" y="510">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="20" name="p0" x="97.5" y="644.5">
|
||||
<point/>
|
||||
</object>
|
||||
<object id="10" name="p2" x="226" y="353.333">
|
||||
<point/>
|
||||
</object>
|
||||
|
||||
Reference in New Issue
Block a user