Add actions

This commit is contained in:
2023-12-17 09:06:14 +01:00
parent 5c1859cf1b
commit 4f2ac9a0eb
14 changed files with 213 additions and 31 deletions

View File

@@ -24,9 +24,14 @@ add_executable(PixelDefense
game/pathfinding.c
game/pathfinding.h
game/systems.h
game/systems_ai.c
game/systems_entity.c
game/systems_input.c
game/systems_ui.c
game/unit_actions.c
game/unit_actions.h
game/unit_ai.c
game/unit_ai.h
)

View File

@@ -23,6 +23,7 @@ ECS_COMPONENT_DECLARE(TextureRegion);
ECS_COMPONENT_DECLARE(Animation);
ECS_COMPONENT_DECLARE(UnitAction);
ECS_TAG_DECLARE(Selectable);
ECS_TAG_DECLARE(Selected);
@@ -35,8 +36,6 @@ ECS_TAG_DECLARE(Attackable);
ECS_COMPONENT_DECLARE(Storage);
ECS_COMPONENT_DECLARE(HarvestTask);
void initComponentIDs(ecs_world_t *ecs) {
ECS_TAG_DEFINE(ecs, TextureTerrain);
ECS_TAG_DEFINE(ecs, TextureBuildings);
@@ -61,6 +60,7 @@ void initComponentIDs(ecs_world_t *ecs) {
ECS_COMPONENT_DEFINE(ecs, Animation);
ECS_COMPONENT_DEFINE(ecs, UnitAction);
ECS_TAG_DEFINE(ecs, Selectable);
ECS_TAG_DEFINE(ecs, Selected);
@@ -72,6 +72,4 @@ void initComponentIDs(ecs_world_t *ecs) {
ECS_TAG_DEFINE(ecs, Attackable);
ECS_COMPONENT_DEFINE(ecs, Storage);
ECS_COMPONENT_DEFINE(ecs, HarvestTask);
}

View File

@@ -5,6 +5,7 @@
#include <flecs.h>
#include "game_tileset.h"
#include "unit_actions.h"
extern ECS_TAG_DECLARE(TextureTerrain);
extern ECS_TAG_DECLARE(TextureBuildings);
@@ -124,6 +125,12 @@ typedef struct EntityArms {
* Gameplay components
*********************************************************/
extern ECS_COMPONENT_DECLARE(UnitAction);
typedef struct ActionOverseer {
} ActionOverseer;
extern ECS_TAG_DECLARE(Selectable);
extern ECS_TAG_DECLARE(Selected);
@@ -144,27 +151,13 @@ extern ECS_TAG_DECLARE(Workable);
extern ECS_TAG_DECLARE(Attackable);
typedef struct Storage {
int capacity[RES_COUNT];
int amount[RES_COUNT];
int reserved[RES_COUNT];
int pending[RES_COUNT];
int capacity[RES_COUNT];
int amount[RES_COUNT];
int reserved[RES_COUNT];
int pending[RES_COUNT];
} 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);

View File

@@ -20,6 +20,7 @@ typedef struct Game {
BzStackAlloc stackAlloc;
struct {
BzObjectPool *pathData;
BzObjectPool *actions;
} pools;
struct {
bool path;

View File

@@ -108,8 +108,12 @@ bool init(void *userData) {
game->stackAlloc = bzStackAllocCreate(10 * 1000 * 1000); // 10 MB
// init pools
game->pools.pathData = bzObjectPoolCreate(&(BzObjectPoolDesc) {
.objectSize=sizeof(PathData),
.objectsPerPage=512
.objectSize = sizeof(PathData),
.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, 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, entityUpdateAnimation, EcsOnUpdate, Animation, TextureRegion);
@@ -213,6 +218,7 @@ void deinit(void *userData) {
bzStackAllocDestroy(&gameCopy.stackAlloc);
bzObjectPoolDestroy(gameCopy.pools.pathData);
bzObjectPoolDestroy(gameCopy.pools.actions);
bzSpatialGridDestroy(gameCopy.entityGrid);
}
@@ -271,7 +277,8 @@ void imguiRender(float dt, void *userData) {
createWorker((Position) {1100, 400}, (Size) {10, 10}, game->entityGrid,
&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";
switch (input->state) {
case INPUT_NONE:

View File

@@ -148,6 +148,7 @@ ecs_entity_t createWorker(Position position, Size size, BzSpatialGrid *grid, BzT
.curFrame = 0,
.elapsed = 0.0f,
});
ecs_set(ECS, e, UnitAction, {NULL, NULL});
ecs_add_id(ECS, e, Selectable);
ecs_add_id(ECS, e, Unit);
ecs_add_id(ECS, e, Worker);

View File

@@ -7,9 +7,18 @@
typedef struct Game Game;
void entityClearTasks(const ecs_entity_t entity);
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

13
game/systems_ai.c Normal file
View 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);
}
}

View File

@@ -8,9 +8,6 @@
#include <math.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) {
const Vector2 *pPath = ecs_get(ECS, entity, Position);
BZ_ASSERT(pPath);
@@ -217,6 +214,7 @@ static ecs_entity_t findNearestStorage(ResourceType type) {
return closest;
}
/*
void entityHarvestTaskSystem(ecs_iter_t *it) {
Game *game = ecs_singleton_get_mut(ECS, Game);
@@ -270,6 +268,7 @@ void entityHarvestTaskSystem(ecs_iter_t *it) {
}
}
*/
void entityUpdateAnimationState(ecs_iter_t *it) {
Velocity *velocity = ecs_field(it, Velocity, 1);

View File

@@ -83,7 +83,13 @@ void inputUnitAction(Game *game, InputState *input) {
while (ecs_query_next(&it)) {
for (i32 i = 0; i < it.count; 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;
}
}

93
game/unit_actions.c Normal file
View 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
View 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
View File

@@ -0,0 +1 @@
#include "unit_ai.h"

5
game/unit_ai.h Normal file
View File

@@ -0,0 +1,5 @@
#ifndef PIXELDEFENSE_UNIT_AI_H
#define PIXELDEFENSE_UNIT_AI_H
#endif //PIXELDEFENSE_UNIT_AI_H