Files
PixelDefense/game/components.c
2024-02-11 19:23:40 +01:00

358 lines
12 KiB
C

#include "components.h"
#include "ai_actions.h"
ECS_TAG_DECLARE(GameEntity);
ECS_COMPONENT_DECLARE(Resource);
ECS_COMPONENT_DECLARE(Owner);
ECS_COMPONENT_DECLARE(FloatyTextParticle);
ECS_COMPONENT_DECLARE(EmitterAttachment);
ECS_COMPONENT_DECLARE(ParticleEmitter);
ECS_COMPONENT_DECLARE(ParticleLayer0);
ECS_COMPONENT_DECLARE(ParticleLayer1);
ECS_COMPONENT_DECLARE(SpatialGridID);
ECS_COMPONENT_DECLARE(Position);
ECS_COMPONENT_DECLARE(Size);
ECS_COMPONENT_DECLARE(Velocity);
ECS_COMPONENT_DECLARE(Rotation);
ECS_COMPONENT_DECLARE(Orientation);
ECS_COMPONENT_DECLARE(Steering);
ECS_COMPONENT_DECLARE(TargetPosition);
ECS_COMPONENT_DECLARE(Path);
ECS_COMPONENT_DECLARE(TextureRegion);
ECS_COMPONENT_DECLARE(Animation);
ECS_COMPONENT_DECLARE(Easing);
ECS_COMPONENT_DECLARE(HitBox);
ECS_COMPONENT_DECLARE(BzBTState);
ECS_COMPONENT_DECLARE(AIBlackboard);
ECS_TAG_DECLARE(Selectable);
ECS_TAG_DECLARE(Selected);
ECS_COMPONENT_DECLARE(AddPopCapacity);
ECS_COMPONENT_DECLARE(ConsumePopCapacity);
ECS_COMPONENT_DECLARE(Health);
ECS_COMPONENT_DECLARE(Worker);
ECS_COMPONENT_DECLARE(Building);
ECS_COMPONENT_DECLARE(Swarm);
ECS_COMPONENT_DECLARE(Unit);
ECS_COMPONENT_DECLARE(Tower);
ECS_COMPONENT_DECLARE(Projectile);
ECS_COMPONENT_DECLARE(BuildingRecruitInfo);
ECS_COMPONENT_DECLARE(Storage);
ECS_COMPONENT_DECLARE(Harvestable);
ECS_TAG_DECLARE(Buildable);
ECS_TAG_DECLARE(Workable);
ECS_TAG_DECLARE(Attackable);
ECS_COMPONENT_DECLARE(DrawLayer);
ECS_COMPONENT_DECLARE(AttachedEntity);
ECS_COMPONENT_DECLARE(DelayDelete);
void initComponentIDs(ecs_world_t *ecs) {
ECS_TAG_DEFINE(ecs, GameEntity);
ECS_COMPONENT_DEFINE(ecs, Resource);
ECS_COMPONENT_DEFINE(ecs, Owner);
ECS_COMPONENT_DEFINE(ecs, FloatyTextParticle);
ECS_COMPONENT_DEFINE(ecs, EmitterAttachment);
ECS_COMPONENT_DEFINE(ecs, ParticleEmitter);
ECS_COMPONENT_DEFINE(ecs, ParticleLayer0);
ECS_COMPONENT_DEFINE(ecs, ParticleLayer1);
ECS_COMPONENT_DEFINE(ecs, SpatialGridID);
ECS_COMPONENT_DEFINE(ecs, Position);
ECS_COMPONENT_DEFINE(ecs, Size);
ECS_COMPONENT_DEFINE(ecs, Velocity);
ECS_COMPONENT_DEFINE(ecs, Rotation);
ECS_COMPONENT_DEFINE(ecs, Orientation);
ECS_COMPONENT_DEFINE(ecs, Steering);
ECS_COMPONENT_DEFINE(ecs, TargetPosition);
ECS_COMPONENT_DEFINE(ecs, Path);
ECS_COMPONENT_DEFINE(ecs, TextureRegion);
ECS_COMPONENT_DEFINE(ecs, Animation);
ECS_COMPONENT_DEFINE(ecs, Easing);
ECS_COMPONENT_DEFINE(ecs, HitBox);
ECS_COMPONENT_DEFINE(ecs, BzBTState);
ECS_COMPONENT_DEFINE(ecs, AIBlackboard);
ECS_TAG_DEFINE(ecs, Selectable);
ECS_TAG_DEFINE(ecs, Selected);
ECS_COMPONENT_DEFINE(ecs, AddPopCapacity);
ECS_COMPONENT_DEFINE(ecs, ConsumePopCapacity);
ECS_COMPONENT_DEFINE(ecs, Health);
ECS_COMPONENT_DEFINE(ecs, Worker);
ECS_COMPONENT_DEFINE(ecs, Building);
ECS_COMPONENT_DEFINE(ecs, Swarm);
ECS_COMPONENT_DEFINE(ecs, Unit);
ECS_COMPONENT_DEFINE(ecs, Tower);
ECS_COMPONENT_DEFINE(ecs, Projectile);
ECS_COMPONENT_DEFINE(ecs, BuildingRecruitInfo);
ECS_COMPONENT_DEFINE(ecs, Storage);
ECS_COMPONENT_DEFINE(ecs, Harvestable);
ECS_TAG_DEFINE(ecs, Buildable);
ECS_TAG_DEFINE(ecs, Workable);
ECS_TAG_DEFINE(ecs, Attackable);
ECS_COMPONENT_DEFINE(ecs, DrawLayer);
ECS_COMPONENT_DEFINE(ecs, AttachedEntity);
ECS_COMPONENT_DEFINE(ecs, DelayDelete);
}
#include <rlImGui.h>
void igTagCheckbox(const char *label, ecs_world_t *ecs,
ecs_entity_t entity, ecs_entity_t tag) {
bool hasTag = ecs_has_id(ecs, entity, tag);
igCheckbox(label, &hasTag);
if (hasTag)
ecs_add_id(ecs, entity, tag);
else
ecs_remove_id(ecs, entity, tag);
}
void igResource(ecs_world_t *ecs,
ecs_entity_t entity, ecs_entity_t comp) {
Resource *res = ecs_get_mut_id(ecs, entity, comp);
const char *resStrings[RES_COUNT];
for (i32 i = 0; i < RES_COUNT; i++) {
resStrings[i] = getResourceTypePrettyName(i);
}
int curType = res->type;
igCombo_Str_arr("Type", &curType, resStrings, RES_COUNT, -1);
res->type = curType;
igInputInt("Amount", &res->amount, 1, 10, 0);
}
void igOwner(ecs_world_t *ecs,
ecs_entity_t entity, ecs_entity_t comp) {
Owner *owner = ecs_get_mut_id(ecs, entity, comp);
igText("PlayerID: %d", owner->player);
}
void igSpatialGridID(ecs_world_t *ecs,
ecs_entity_t entity, ecs_entity_t comp) {
SpatialGridID *id = ecs_get_mut_id(ecs, entity, comp);
igText("SpatialID", *id);
}
void igVec2(Vector2 *vec) {
igInputFloat("X", &vec->x, 1.0f, 10.0f, "%.2f", 0);
igInputFloat("Y", &vec->y, 1.0f, 10.0f, "%.2f", 0);
}
void igVec2Comp(ecs_world_t *ecs,
ecs_entity_t entity, ecs_entity_t comp) {
Vector2 *vec = ecs_get_mut_id(ecs, entity, comp);
igVec2(vec);
}
void igFloat(ecs_world_t *ecs,
ecs_entity_t entity, ecs_entity_t comp) {
f32 *f = ecs_get_mut_id(ecs, entity, comp);
igInputFloat("", f, 0.1f, 1.0f, "%.2f", 0);
}
void igPath(ecs_world_t *ecs,
ecs_entity_t entity, ecs_entity_t comp) {
Path path = *(Path *) ecs_get_mut_id(ecs, entity, comp);
i32 idx = 0;
while (path.paths) {
for (int32_t i = path.curWaypoint; i < path.paths->numWaypoints; i++) {
igPushID_Int(idx);
igText("Waypoint %d:", idx);
igInputFloat("X", &path.paths->waypoints[i].x, 1, 16, "%.2f", 0);
igInputFloat("Y", &path.paths->waypoints[i].y, 1, 16, "%.2f", 0);
igPopID();
idx++;
}
path.paths = path.paths->next;
path.curWaypoint = 0;
}
}
void igRect(Rectangle *rect) {
igInputFloat("X", &rect->x, 1, 16, "%.2f", 0);
igInputFloat("Y", &rect->y, 1, 16, "%.2f", 0);
igInputFloat("Width", &rect->width, 1, 16, "%.2f", 0);
igInputFloat("Height", &rect->height, 1, 16, "%.2f", 0);
}
void igTextureRegion(ecs_world_t *ecs,
ecs_entity_t entity, ecs_entity_t comp) {
TextureRegion *tex = ecs_get_mut_id(ecs, entity, comp);
igText("Texture: %d", tex->texture.id);
igRect(&tex->rec);
bool flipX = tex->flipX;
bool flipY = tex->flipY;
igCheckbox("flipX", &flipX);
igCheckbox("flipY", &flipY);
tex->flipX = flipX;
tex->flipY = flipY;
}
static void igEntityType(EntityType *type) {
const char *prettyStrings[ENTITY_COUNT];
for (int i = 0; i < ENTITY_COUNT; i++) {
prettyStrings[i] = getEntityStr(i);
}
igCombo_Str_arr("EntityType", type, prettyStrings, ENTITY_COUNT, -1);
}
static void igAnimType(AnimType *type) {
const char *prettyStrings[ANIM_COUNT];
for (int i = 0; i < ANIM_COUNT; i++) {
prettyStrings[i] = getEntityAnimationStr(i);
}
igCombo_Str_arr("AnimType", type, prettyStrings, ANIM_COUNT, -1);
}
void igAnimation(ecs_world_t *ecs,
ecs_entity_t entity, ecs_entity_t comp) {
Animation *anim = ecs_get_mut_id(ecs, entity, comp);
EntityType curEntityType = anim->entityType;
igEntityType(&curEntityType);
anim->entityType = curEntityType;
AnimType curAnimType = anim->animType;
igAnimType(&curAnimType);
anim->animType = curAnimType;
igText("tileset: %p", anim->tileset);
igText("curFrame: %d", anim->curFrame);
igText("elapsed: %.2f < %.2F", anim->elapsed, anim->frame.duration);
}
void igEasing(ecs_world_t *ecs,
ecs_entity_t entity, ecs_entity_t comp) {
Easing *easing = ecs_get_mut_id(ecs, entity, comp);
igText("Component: %d, offset: %d", easing->compID, easing->offset);
igText("x = %.2f + %.2f * (%.2f + (%.2f * %.2f) + %.2f) + %.2f",
easing->start, easing->target, easing->easeStart, easing->easeTarget,
easing->x, easing->easeOffset, easing->offset);
}
void igArms(ecs_world_t *ecs,
ecs_entity_t entity, ecs_entity_t comp) {
}
void igArm(ecs_world_t *ecs,
ecs_entity_t entity, ecs_entity_t comp) {
}
static const BzBTNodeState *findNodeState(const BzBTNode *node, const BzBTNodeState *state) {
const BzBTNodeState *pState = state;
// Although it's painfully slow, it serves as a debug tool,
// so speed is not a critical concern.
while (pState) {
const BzBTNodeState *next = bzBTNodeStateNext(pState);
if (bzBTNodeMatchesState(node, pState))
return pState;
pState = next;
}
return NULL;
}
static void visualizeBTState(const BzBTNode *node, const BzBTNodeState *state, bool sameLine, bool isActive, i32 depth) {
const BzBTNode *child = bzBTNodeChild(node);
BzBTNodeType type = bzBTGetNodeType(node);
char extraInfo[128];
extraInfo[0] = '\0';
const BzBTNodeState *nodeState = findNodeState(node, state);
bool hasState = nodeState != NULL;
isActive |= nodeState != NULL;
switch (type) {
case BZ_BT_DECOR_REPEAT:
if (hasState) {
snprintf(extraInfo, sizeof(extraInfo), " (%d < %d)",
bzBTRepeatStateGetIter(nodeState),
bzBTDecorGetRepeat(node));
} else {
snprintf(extraInfo, sizeof(extraInfo), " (%d)", bzBTDecorGetRepeat(node));
}
break;
case BZ_BT_DECOR_DELAY:
if (isActive) {
snprintf(extraInfo, sizeof(extraInfo), " (%.2f < %.2fms)",
bzBTDelayStateGetElapsed(nodeState),
bzBTDecorGetDelay(node));
} else {
snprintf(extraInfo, sizeof(extraInfo), " (%.2fms)", bzBTDecorGetDelay(node));
}
break;
case BZ_BT_ACTION:
snprintf(extraInfo, sizeof(extraInfo), " (%s:%p)",
bzBTNodeGetName(node) ? bzBTNodeGetName(node) : "?",
bzBTActionGetFn(node));
break;
default:
break;
}
ImVec4 color = {1.0f, 1.0f, 1.0f, 1.0f};
if (isActive)
color = (ImVec4) {1.0f, 1.0f, 0.5f, 1.0f};
bool hasSingleChild = child && bzBTNodeNext(child) == NULL;
i32 offset = depth * 2;
if (sameLine) offset = 0;
const char *prefix = sameLine ? " > " : "";
const char *postfix = child != NULL && !hasSingleChild ? ":" : "";
igTextColored(color, "%s%*s%s%s%s", prefix, offset, "", bzBTNodeTypeToStr(type), extraInfo, postfix);
bool isComposite = type == BZ_BT_COMP_SELECTOR ||
type == BZ_BT_COMP_PSELECTOR ||
type == BZ_BT_COMP_SEQUENCE ||
type == BZ_BT_COMP_PSEQUENCE;
depth++;
while (child) {
if (hasSingleChild) igSameLine(0, 0);
bool childHasState = hasState && isComposite && bzBTCompStateGetRunningChild(nodeState) == child;
visualizeBTState(child, state, hasSingleChild, childHasState, depth);
child = bzBTNodeNext(child);
}
}
void igVisualizeBTState(const BzBTNode *node, const BzBTNodeState *state) {
igSeparatorText("Tree State");
visualizeBTState(node, state, false, true, 0);
igSeparatorText("State stack");
size_t stateSize = 0;
const BzBTNodeState *pState = state;
while (pState) {
const BzBTNode *pNode = bzBTNodeStateGetNode(pState);
stateSize += bzBTGetNodeStateSize();
BzBTNodeType type = bzBTGetNodeType(pNode);
igText("%s", bzBTNodeTypeToStr(type));
pState = bzBTNodeStateNext(pState);
}
igNewLine();
igText("Total stack state size: %ld bytes.", stateSize);
}
void igBzBTState(ecs_world_t *ecs,
ecs_entity_t entity, ecs_entity_t comp) {
}
void igAIBlackboard(ecs_world_t *ecs,
ecs_entity_t entity, ecs_entity_t comp) {
}
void igWorker(ecs_world_t *ecs,
ecs_entity_t entity, ecs_entity_t comp) {
}
void igUnit(ecs_world_t *ecs,
ecs_entity_t entity, ecs_entity_t comp) {
}