Add actions
This commit is contained in:
@@ -24,9 +24,14 @@ add_executable(PixelDefense
|
|||||||
game/pathfinding.c
|
game/pathfinding.c
|
||||||
game/pathfinding.h
|
game/pathfinding.h
|
||||||
game/systems.h
|
game/systems.h
|
||||||
|
game/systems_ai.c
|
||||||
game/systems_entity.c
|
game/systems_entity.c
|
||||||
game/systems_input.c
|
game/systems_input.c
|
||||||
game/systems_ui.c
|
game/systems_ui.c
|
||||||
|
game/unit_actions.c
|
||||||
|
game/unit_actions.h
|
||||||
|
game/unit_ai.c
|
||||||
|
game/unit_ai.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ ECS_COMPONENT_DECLARE(TextureRegion);
|
|||||||
|
|
||||||
ECS_COMPONENT_DECLARE(Animation);
|
ECS_COMPONENT_DECLARE(Animation);
|
||||||
|
|
||||||
|
ECS_COMPONENT_DECLARE(UnitAction);
|
||||||
ECS_TAG_DECLARE(Selectable);
|
ECS_TAG_DECLARE(Selectable);
|
||||||
ECS_TAG_DECLARE(Selected);
|
ECS_TAG_DECLARE(Selected);
|
||||||
|
|
||||||
@@ -35,8 +36,6 @@ ECS_TAG_DECLARE(Attackable);
|
|||||||
|
|
||||||
ECS_COMPONENT_DECLARE(Storage);
|
ECS_COMPONENT_DECLARE(Storage);
|
||||||
|
|
||||||
ECS_COMPONENT_DECLARE(HarvestTask);
|
|
||||||
|
|
||||||
void initComponentIDs(ecs_world_t *ecs) {
|
void initComponentIDs(ecs_world_t *ecs) {
|
||||||
ECS_TAG_DEFINE(ecs, TextureTerrain);
|
ECS_TAG_DEFINE(ecs, TextureTerrain);
|
||||||
ECS_TAG_DEFINE(ecs, TextureBuildings);
|
ECS_TAG_DEFINE(ecs, TextureBuildings);
|
||||||
@@ -61,6 +60,7 @@ void initComponentIDs(ecs_world_t *ecs) {
|
|||||||
|
|
||||||
ECS_COMPONENT_DEFINE(ecs, Animation);
|
ECS_COMPONENT_DEFINE(ecs, Animation);
|
||||||
|
|
||||||
|
ECS_COMPONENT_DEFINE(ecs, UnitAction);
|
||||||
ECS_TAG_DEFINE(ecs, Selectable);
|
ECS_TAG_DEFINE(ecs, Selectable);
|
||||||
ECS_TAG_DEFINE(ecs, Selected);
|
ECS_TAG_DEFINE(ecs, Selected);
|
||||||
|
|
||||||
@@ -72,6 +72,4 @@ void initComponentIDs(ecs_world_t *ecs) {
|
|||||||
ECS_TAG_DEFINE(ecs, Attackable);
|
ECS_TAG_DEFINE(ecs, Attackable);
|
||||||
|
|
||||||
ECS_COMPONENT_DEFINE(ecs, Storage);
|
ECS_COMPONENT_DEFINE(ecs, Storage);
|
||||||
|
|
||||||
ECS_COMPONENT_DEFINE(ecs, HarvestTask);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <flecs.h>
|
#include <flecs.h>
|
||||||
|
|
||||||
#include "game_tileset.h"
|
#include "game_tileset.h"
|
||||||
|
#include "unit_actions.h"
|
||||||
|
|
||||||
extern ECS_TAG_DECLARE(TextureTerrain);
|
extern ECS_TAG_DECLARE(TextureTerrain);
|
||||||
extern ECS_TAG_DECLARE(TextureBuildings);
|
extern ECS_TAG_DECLARE(TextureBuildings);
|
||||||
@@ -124,6 +125,12 @@ typedef struct EntityArms {
|
|||||||
* Gameplay components
|
* Gameplay components
|
||||||
*********************************************************/
|
*********************************************************/
|
||||||
|
|
||||||
|
extern ECS_COMPONENT_DECLARE(UnitAction);
|
||||||
|
|
||||||
|
typedef struct ActionOverseer {
|
||||||
|
|
||||||
|
} ActionOverseer;
|
||||||
|
|
||||||
extern ECS_TAG_DECLARE(Selectable);
|
extern ECS_TAG_DECLARE(Selectable);
|
||||||
extern ECS_TAG_DECLARE(Selected);
|
extern ECS_TAG_DECLARE(Selected);
|
||||||
|
|
||||||
@@ -144,27 +151,13 @@ extern ECS_TAG_DECLARE(Workable);
|
|||||||
extern ECS_TAG_DECLARE(Attackable);
|
extern ECS_TAG_DECLARE(Attackable);
|
||||||
|
|
||||||
typedef struct Storage {
|
typedef struct Storage {
|
||||||
int capacity[RES_COUNT];
|
int capacity[RES_COUNT];
|
||||||
int amount[RES_COUNT];
|
int amount[RES_COUNT];
|
||||||
int reserved[RES_COUNT];
|
int reserved[RES_COUNT];
|
||||||
int pending[RES_COUNT];
|
int pending[RES_COUNT];
|
||||||
} Storage;
|
} Storage;
|
||||||
extern ECS_COMPONENT_DECLARE(Storage);
|
extern ECS_COMPONENT_DECLARE(Storage);
|
||||||
|
|
||||||
typedef struct HarvestTask {
|
|
||||||
ecs_entity_t entity;
|
|
||||||
} HarvestTask;
|
|
||||||
extern ECS_COMPONENT_DECLARE(HarvestTask);
|
|
||||||
|
|
||||||
typedef struct WorkerTask {
|
|
||||||
enum {
|
|
||||||
HARVEST,
|
|
||||||
BUILD,
|
|
||||||
} type;
|
|
||||||
ecs_entity_t target;
|
|
||||||
//struct WorkerTask *next;
|
|
||||||
} WorkerTask;
|
|
||||||
|
|
||||||
void initComponentIDs(ecs_world_t *ecs);
|
void initComponentIDs(ecs_world_t *ecs);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ typedef struct Game {
|
|||||||
BzStackAlloc stackAlloc;
|
BzStackAlloc stackAlloc;
|
||||||
struct {
|
struct {
|
||||||
BzObjectPool *pathData;
|
BzObjectPool *pathData;
|
||||||
|
BzObjectPool *actions;
|
||||||
} pools;
|
} pools;
|
||||||
struct {
|
struct {
|
||||||
bool path;
|
bool path;
|
||||||
|
|||||||
15
game/main.c
15
game/main.c
@@ -108,8 +108,12 @@ bool init(void *userData) {
|
|||||||
game->stackAlloc = bzStackAllocCreate(10 * 1000 * 1000); // 10 MB
|
game->stackAlloc = bzStackAllocCreate(10 * 1000 * 1000); // 10 MB
|
||||||
// init pools
|
// init pools
|
||||||
game->pools.pathData = bzObjectPoolCreate(&(BzObjectPoolDesc) {
|
game->pools.pathData = bzObjectPoolCreate(&(BzObjectPoolDesc) {
|
||||||
.objectSize=sizeof(PathData),
|
.objectSize = sizeof(PathData),
|
||||||
.objectsPerPage=512
|
.objectsPerPage = 512
|
||||||
|
});
|
||||||
|
game->pools.actions = bzObjectPoolCreate(&(BzObjectPoolDesc) {
|
||||||
|
.objectSize = sizeof(UnitAction),
|
||||||
|
.objectsPerPage = 1024,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -171,7 +175,8 @@ bool init(void *userData) {
|
|||||||
ECS_SYSTEM(ECS, entityMoveToTarget, EcsOnUpdate, Position, Rotation, Velocity, TargetPosition, Steering);
|
ECS_SYSTEM(ECS, entityMoveToTarget, EcsOnUpdate, Position, Rotation, Velocity, TargetPosition, Steering);
|
||||||
ECS_SYSTEM(ECS, entityFollowPath, EcsOnUpdate, Path);
|
ECS_SYSTEM(ECS, entityFollowPath, EcsOnUpdate, Path);
|
||||||
|
|
||||||
ECS_SYSTEM(ECS, entityHarvestTaskSystem, EcsOnUpdate, Position, Rotation, HarvestTask);
|
//ECS_SYSTEM(ECS, entityHarvestTaskSystem, EcsOnUpdate, Position, Rotation, HarvestTask);
|
||||||
|
ECS_SYSTEM(ECS, updateUnitActions, EcsOnUpdate, UnitAction);
|
||||||
|
|
||||||
//ECS_SYSTEM(ECS, entityUpdateAnimationState, EcsOnUpdate, Velocity, AnimationType);
|
//ECS_SYSTEM(ECS, entityUpdateAnimationState, EcsOnUpdate, Velocity, AnimationType);
|
||||||
ECS_SYSTEM(ECS, entityUpdateAnimation, EcsOnUpdate, Animation, TextureRegion);
|
ECS_SYSTEM(ECS, entityUpdateAnimation, EcsOnUpdate, Animation, TextureRegion);
|
||||||
@@ -213,6 +218,7 @@ void deinit(void *userData) {
|
|||||||
|
|
||||||
bzStackAllocDestroy(&gameCopy.stackAlloc);
|
bzStackAllocDestroy(&gameCopy.stackAlloc);
|
||||||
bzObjectPoolDestroy(gameCopy.pools.pathData);
|
bzObjectPoolDestroy(gameCopy.pools.pathData);
|
||||||
|
bzObjectPoolDestroy(gameCopy.pools.actions);
|
||||||
bzSpatialGridDestroy(gameCopy.entityGrid);
|
bzSpatialGridDestroy(gameCopy.entityGrid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +277,8 @@ void imguiRender(float dt, void *userData) {
|
|||||||
createWorker((Position) {1100, 400}, (Size) {10, 10}, game->entityGrid,
|
createWorker((Position) {1100, 400}, (Size) {10, 10}, game->entityGrid,
|
||||||
&game->map.tilesets[2], 1322);
|
&game->map.tilesets[2], 1322);
|
||||||
}
|
}
|
||||||
igText("Num paths from pool available: %llu", bzObjectPoolGetNumFree(game->pools.pathData));
|
igText("PathData pool available: %llu", bzObjectPoolGetNumFree(game->pools.pathData));
|
||||||
|
igText("Action pool available: %llu", bzObjectPoolGetNumFree(game->pools.actions));
|
||||||
const char *inputState = "NONE";
|
const char *inputState = "NONE";
|
||||||
switch (input->state) {
|
switch (input->state) {
|
||||||
case INPUT_NONE:
|
case INPUT_NONE:
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ ecs_entity_t createWorker(Position position, Size size, BzSpatialGrid *grid, BzT
|
|||||||
.curFrame = 0,
|
.curFrame = 0,
|
||||||
.elapsed = 0.0f,
|
.elapsed = 0.0f,
|
||||||
});
|
});
|
||||||
|
ecs_set(ECS, e, UnitAction, {NULL, NULL});
|
||||||
ecs_add_id(ECS, e, Selectable);
|
ecs_add_id(ECS, e, Selectable);
|
||||||
ecs_add_id(ECS, e, Unit);
|
ecs_add_id(ECS, e, Unit);
|
||||||
ecs_add_id(ECS, e, Worker);
|
ecs_add_id(ECS, e, Worker);
|
||||||
|
|||||||
@@ -7,9 +7,18 @@
|
|||||||
|
|
||||||
typedef struct Game Game;
|
typedef struct Game Game;
|
||||||
|
|
||||||
void entityClearTasks(const ecs_entity_t entity);
|
|
||||||
bool entitySetPath(const ecs_entity_t entity, const Vector2 target, Game *game);
|
bool entitySetPath(const ecs_entity_t entity, const Vector2 target, Game *game);
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
* AI systems
|
||||||
|
**********************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 0: Game (singleton)
|
||||||
|
* 1: UnitAction
|
||||||
|
*/
|
||||||
|
void updateUnitActions(ecs_iter_t *it);
|
||||||
|
|
||||||
|
|
||||||
/**********************************
|
/**********************************
|
||||||
* Entity Systems
|
* Entity Systems
|
||||||
|
|||||||
13
game/systems_ai.c
Normal file
13
game/systems_ai.c
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#include "systems.h"
|
||||||
|
|
||||||
|
#include "game_state.h"
|
||||||
|
|
||||||
|
void updateUnitActions(ecs_iter_t *it) {
|
||||||
|
Game *game = ecs_singleton_get_mut(ECS, Game);
|
||||||
|
UnitAction *action = ecs_field(it, UnitAction, 1);
|
||||||
|
|
||||||
|
for (i32 i = 0; i < it->count; i++) {
|
||||||
|
ecs_entity_t entity = it->entities[i];
|
||||||
|
handleAction(entity, &action[i], game);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,9 +8,6 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <raymath.h>
|
#include <raymath.h>
|
||||||
|
|
||||||
void entityClearTasks(const ecs_entity_t entity) {
|
|
||||||
ecs_remove(ECS, entity, HarvestTask);
|
|
||||||
}
|
|
||||||
bool entitySetPath(const ecs_entity_t entity, const Vector2 target, Game *game) {
|
bool entitySetPath(const ecs_entity_t entity, const Vector2 target, Game *game) {
|
||||||
const Vector2 *pPath = ecs_get(ECS, entity, Position);
|
const Vector2 *pPath = ecs_get(ECS, entity, Position);
|
||||||
BZ_ASSERT(pPath);
|
BZ_ASSERT(pPath);
|
||||||
@@ -217,6 +214,7 @@ static ecs_entity_t findNearestStorage(ResourceType type) {
|
|||||||
return closest;
|
return closest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
void entityHarvestTaskSystem(ecs_iter_t *it) {
|
void entityHarvestTaskSystem(ecs_iter_t *it) {
|
||||||
Game *game = ecs_singleton_get_mut(ECS, Game);
|
Game *game = ecs_singleton_get_mut(ECS, Game);
|
||||||
|
|
||||||
@@ -270,6 +268,7 @@ void entityHarvestTaskSystem(ecs_iter_t *it) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
void entityUpdateAnimationState(ecs_iter_t *it) {
|
void entityUpdateAnimationState(ecs_iter_t *it) {
|
||||||
Velocity *velocity = ecs_field(it, Velocity, 1);
|
Velocity *velocity = ecs_field(it, Velocity, 1);
|
||||||
|
|||||||
@@ -83,7 +83,13 @@ void inputUnitAction(Game *game, InputState *input) {
|
|||||||
while (ecs_query_next(&it)) {
|
while (ecs_query_next(&it)) {
|
||||||
for (i32 i = 0; i < it.count; i++) {
|
for (i32 i = 0; i < it.count; i++) {
|
||||||
const ecs_entity_t entity = it.entities[i];
|
const ecs_entity_t entity = it.entities[i];
|
||||||
ecs_set(ECS, entity, HarvestTask, {taskEntity});
|
const Position target = *ecs_get(ECS, taskEntity, Position);
|
||||||
|
addAction(entity, game, &(const Action) {
|
||||||
|
.type = ACTION_MOVE_TO,
|
||||||
|
.as.moveTo.target = target,
|
||||||
|
.as.moveTo.proximityThreshold = 10.0f,
|
||||||
|
});
|
||||||
|
//ecs_set(ECS, entity, HarvestTask, {taskEntity});
|
||||||
goto while_break;
|
goto while_break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
93
game/unit_actions.c
Normal file
93
game/unit_actions.c
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#include "unit_actions.h"
|
||||||
|
#include "game_state.h"
|
||||||
|
#include "components.h"
|
||||||
|
#include "systems.h"
|
||||||
|
|
||||||
|
#include <raymath.h>
|
||||||
|
|
||||||
|
void actionMoveTo(ecs_entity_t entity, Action *action, Game *game) {
|
||||||
|
const Vector2 target = action->as.moveTo.target;
|
||||||
|
if (!ecs_has(ECS, entity, Path)) {
|
||||||
|
entitySetPath(entity, target, game);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Vector2 pos = *ecs_get(ECS, entity, Position);
|
||||||
|
|
||||||
|
f32 dst = Vector2Distance(pos, target);
|
||||||
|
if (dst < action->as.moveTo.proximityThreshold) {
|
||||||
|
action->finished = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void actionCollectResource(ecs_entity_t entity, Action *action, Game *game) {
|
||||||
|
|
||||||
|
}
|
||||||
|
void actionDepositResource(ecs_entity_t entity, Action *action, Game *game) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleAction(ecs_entity_t entity, UnitAction *unitAction, Game *game) {
|
||||||
|
Action *action = unitAction->first;
|
||||||
|
if (action == NULL) return;
|
||||||
|
switch (action->type) {
|
||||||
|
case ACTION_NONE:
|
||||||
|
break;
|
||||||
|
case ACTION_MOVE_TO:
|
||||||
|
actionMoveTo(entity, action, game);
|
||||||
|
break;
|
||||||
|
case ACTION_COLLECT_RESOURCE:
|
||||||
|
actionCollectResource(entity, action, game);
|
||||||
|
break;
|
||||||
|
case ACTION_DEPOSIT_RESOURCE:
|
||||||
|
actionDepositResource(entity, action, game);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BZ_ASSERT(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
action->elapsed += GetFrameTime();
|
||||||
|
if (action->finished) {
|
||||||
|
unitAction->first = action->next;
|
||||||
|
if (unitAction->last == action) {
|
||||||
|
unitAction->last = NULL;
|
||||||
|
BZ_ASSERT(unitAction->first == unitAction->last);
|
||||||
|
}
|
||||||
|
BzObjectPool *pool = game->pools.actions;
|
||||||
|
bzObjectPoolRelease(pool, action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void clearActions(ecs_entity_t entity, Game *game) {
|
||||||
|
if (!ecs_has(ECS, entity, UnitAction)) return;
|
||||||
|
UnitAction *unitAction = ecs_get_mut(ECS, entity, UnitAction);
|
||||||
|
|
||||||
|
BzObjectPool *pool = game->pools.actions;
|
||||||
|
|
||||||
|
Action *pAction = unitAction->first;
|
||||||
|
while (pAction) {
|
||||||
|
bzObjectPoolRelease(pool, pAction);
|
||||||
|
pAction = pAction->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
unitAction->first = NULL;
|
||||||
|
unitAction->last = NULL;
|
||||||
|
}
|
||||||
|
void addAction(ecs_entity_t entity, Game *game, const Action *action) {
|
||||||
|
BZ_ASSERT(action);
|
||||||
|
BZ_ASSERT(ecs_has(ECS, entity, UnitAction));
|
||||||
|
|
||||||
|
UnitAction *unitAction = ecs_get_mut(ECS, entity, UnitAction);
|
||||||
|
BzObjectPool *pool = game->pools.actions;
|
||||||
|
|
||||||
|
Action *newAction = bzObjectPool(pool);
|
||||||
|
BZ_ASSERT(newAction);
|
||||||
|
*newAction = *action;
|
||||||
|
|
||||||
|
newAction->next = NULL;
|
||||||
|
if (unitAction->last) {
|
||||||
|
Action *last = unitAction->last;
|
||||||
|
last->next = newAction;
|
||||||
|
unitAction->last = newAction;
|
||||||
|
} else {
|
||||||
|
unitAction->first = newAction;
|
||||||
|
unitAction->last = newAction;
|
||||||
|
}
|
||||||
|
}
|
||||||
51
game/unit_actions.h
Normal file
51
game/unit_actions.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#ifndef PIXELDEFENSE_UNIT_ACTIONS_H
|
||||||
|
#define PIXELDEFENSE_UNIT_ACTIONS_H
|
||||||
|
|
||||||
|
#include <breeze.h>
|
||||||
|
#include <flecs.h>
|
||||||
|
|
||||||
|
typedef struct Game Game;
|
||||||
|
|
||||||
|
typedef enum ActionType {
|
||||||
|
ACTION_NONE,
|
||||||
|
ACTION_MOVE_TO,
|
||||||
|
ACTION_COLLECT_RESOURCE,
|
||||||
|
ACTION_DEPOSIT_RESOURCE,
|
||||||
|
ACTION_COUNT,
|
||||||
|
} ActionType;
|
||||||
|
|
||||||
|
typedef struct ActionMoveTo {
|
||||||
|
Vector2 target;
|
||||||
|
f32 proximityThreshold;
|
||||||
|
} ActionMoveTo;
|
||||||
|
typedef struct ActionCollectResource {
|
||||||
|
|
||||||
|
} ActionCollectResource;
|
||||||
|
typedef struct ActionDepositResource {
|
||||||
|
|
||||||
|
} ActionDepositResource;
|
||||||
|
|
||||||
|
typedef struct Action {
|
||||||
|
ActionType type;
|
||||||
|
union {
|
||||||
|
ActionMoveTo moveTo;
|
||||||
|
ActionCollectResource collectResource;
|
||||||
|
ActionDepositResource depositResource;
|
||||||
|
} as;
|
||||||
|
|
||||||
|
f32 elapsed;
|
||||||
|
bool finished;
|
||||||
|
|
||||||
|
struct Action *next;
|
||||||
|
} Action;
|
||||||
|
|
||||||
|
typedef struct UnitAction {
|
||||||
|
Action *first;
|
||||||
|
Action *last;
|
||||||
|
} UnitAction;
|
||||||
|
|
||||||
|
void handleAction(ecs_entity_t entity, UnitAction *unitAction, Game *game);
|
||||||
|
void clearActions(ecs_entity_t entity, Game *game);
|
||||||
|
void addAction(ecs_entity_t entity, Game *game, const Action *action);
|
||||||
|
|
||||||
|
#endif //PIXELDEFENSE_UNIT_ACTIONS_H
|
||||||
1
game/unit_ai.c
Normal file
1
game/unit_ai.c
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#include "unit_ai.h"
|
||||||
5
game/unit_ai.h
Normal file
5
game/unit_ai.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#ifndef PIXELDEFENSE_UNIT_AI_H
|
||||||
|
#define PIXELDEFENSE_UNIT_AI_H
|
||||||
|
|
||||||
|
|
||||||
|
#endif //PIXELDEFENSE_UNIT_AI_H
|
||||||
Reference in New Issue
Block a user