Add hurt, die animation when taking damage
This commit is contained in:
@@ -48,6 +48,8 @@ ECS_TAG_DECLARE(Buildable);
|
|||||||
ECS_TAG_DECLARE(Workable);
|
ECS_TAG_DECLARE(Workable);
|
||||||
ECS_TAG_DECLARE(Attackable);
|
ECS_TAG_DECLARE(Attackable);
|
||||||
|
|
||||||
|
ECS_COMPONENT_DECLARE(DelayDelete);
|
||||||
|
|
||||||
void initComponentIDs(ecs_world_t *ecs) {
|
void initComponentIDs(ecs_world_t *ecs) {
|
||||||
ECS_TAG_DEFINE(ecs, GameEntity);
|
ECS_TAG_DEFINE(ecs, GameEntity);
|
||||||
|
|
||||||
@@ -95,6 +97,7 @@ void initComponentIDs(ecs_world_t *ecs) {
|
|||||||
ECS_TAG_DEFINE(ecs, Workable);
|
ECS_TAG_DEFINE(ecs, Workable);
|
||||||
ECS_TAG_DEFINE(ecs, Attackable);
|
ECS_TAG_DEFINE(ecs, Attackable);
|
||||||
|
|
||||||
|
ECS_COMPONENT_DEFINE(ecs, DelayDelete);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <rlImGui.h>
|
#include <rlImGui.h>
|
||||||
|
|||||||
@@ -156,6 +156,8 @@ typedef struct Animation {
|
|||||||
|
|
||||||
i32 curFrame;
|
i32 curFrame;
|
||||||
f32 elapsed;
|
f32 elapsed;
|
||||||
|
|
||||||
|
bool playInFull;
|
||||||
} Animation;
|
} Animation;
|
||||||
extern ECS_COMPONENT_DECLARE(Animation);
|
extern ECS_COMPONENT_DECLARE(Animation);
|
||||||
|
|
||||||
@@ -183,6 +185,10 @@ extern ECS_COMPONENT_DECLARE(Easing);
|
|||||||
/**********************************************************
|
/**********************************************************
|
||||||
* Event components
|
* Event components
|
||||||
*********************************************************/
|
*********************************************************/
|
||||||
|
typedef struct DamageEvent {
|
||||||
|
f32 amount;
|
||||||
|
} DamageEvent;
|
||||||
|
|
||||||
typedef struct HarvestEvent {
|
typedef struct HarvestEvent {
|
||||||
ResourceType type;
|
ResourceType type;
|
||||||
i32 amount;
|
i32 amount;
|
||||||
@@ -240,6 +246,10 @@ extern ECS_COMPONENT_DECLARE(Worker);
|
|||||||
// Unit can:
|
// Unit can:
|
||||||
// - Attack
|
// - Attack
|
||||||
typedef struct Unit {
|
typedef struct Unit {
|
||||||
|
f32 attackCooldown;
|
||||||
|
f32 attackElapsed;
|
||||||
|
f32 minDamage;
|
||||||
|
f32 maxDamage;
|
||||||
f32 maxSpeed;
|
f32 maxSpeed;
|
||||||
f32 acceleration;
|
f32 acceleration;
|
||||||
f32 deceleration;
|
f32 deceleration;
|
||||||
@@ -273,6 +283,15 @@ extern ECS_COMPONENT_DECLARE(Harvestable);
|
|||||||
extern ECS_TAG_DECLARE(Buildable);
|
extern ECS_TAG_DECLARE(Buildable);
|
||||||
extern ECS_TAG_DECLARE(Attackable);
|
extern ECS_TAG_DECLARE(Attackable);
|
||||||
|
|
||||||
|
/**********************************************************
|
||||||
|
* DelayDelete components
|
||||||
|
*********************************************************/
|
||||||
|
typedef struct DelayDelete {
|
||||||
|
f32 time;
|
||||||
|
f32 elapsed;
|
||||||
|
} DelayDelete;
|
||||||
|
extern ECS_COMPONENT_DECLARE(DelayDelete);
|
||||||
|
|
||||||
void initComponentIDs(ecs_world_t *ecs);
|
void initComponentIDs(ecs_world_t *ecs);
|
||||||
|
|
||||||
void igTagCheckbox(const char *label, ecs_world_t *ecs,
|
void igTagCheckbox(const char *label, ecs_world_t *ecs,
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ ecs_entity_t entityCreateBaseUnit(const Position position, f32 size, Player play
|
|||||||
ecs_set(ECS, e, AIBlackboard, {.entity = e});
|
ecs_set(ECS, e, AIBlackboard, {.entity = e});
|
||||||
ecs_add_id(ECS, e, Selectable);
|
ecs_add_id(ECS, e, Selectable);
|
||||||
ecs_set(ECS, e, Unit, {
|
ecs_set(ECS, e, Unit, {
|
||||||
|
.attackElapsed = 0.0f,
|
||||||
|
.attackCooldown = 1.0f,
|
||||||
|
.minDamage = 1.0f,
|
||||||
|
.maxDamage = 2.0f,
|
||||||
.acceleration = 80.0f,
|
.acceleration = 80.0f,
|
||||||
.maxSpeed = 15.0f,
|
.maxSpeed = 15.0f,
|
||||||
.deceleration = 0.1f,
|
.deceleration = 0.1f,
|
||||||
@@ -67,6 +71,28 @@ 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 entityCreateSoldier(const Position position, Player player, Game *game) {
|
||||||
ecs_entity_t e = entityCreateBaseUnit(position, 10.0f, player, ENTITY_SOLDIER, ANIM_IDLE, game);
|
ecs_entity_t e = entityCreateBaseUnit(position, 10.0f, player, ENTITY_SOLDIER, ANIM_IDLE, game);
|
||||||
|
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;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
ecs_entity_t entityCreateWarrior(const Position position, Player player, Game *game) {
|
||||||
|
ecs_entity_t e = entityCreateBaseUnit(position, 10.0f, player, ENTITY_WARRIOR, ANIM_IDLE, game);
|
||||||
|
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;
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ ecs_entity_t entityCreateEmpty();
|
|||||||
ecs_entity_t entityCreateBaseUnit(const Position position, f32 size, Player player,
|
ecs_entity_t entityCreateBaseUnit(const Position position, f32 size, Player player,
|
||||||
EntityType type, AnimType startAnim, Game *game);
|
EntityType type, AnimType startAnim, Game *game);
|
||||||
ecs_entity_t entityCreateSoldier(const Position position, Player player, Game *game);
|
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 entityCreateWorker(const Position position, Player player, Game *game);
|
||||||
|
|
||||||
ecs_entity_t entityRecruit(EntityType type, Position position, Player player, Game *game);
|
ecs_entity_t entityRecruit(EntityType type, Position position, Player player, Game *game);
|
||||||
|
|||||||
@@ -744,6 +744,62 @@ static bool entityHasAnimation(EntityType entity, AnimType type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static f32 entityGetAnimationLength(EntityType entity, AnimType type) {
|
||||||
|
switch (entity) {
|
||||||
|
case ENTITY_WORKER:
|
||||||
|
switch (type) {
|
||||||
|
case ANIM_IDLE: return 0.4f;
|
||||||
|
case ANIM_WALK: return 0.72f;
|
||||||
|
case ANIM_HURT: return 0.42000000000000004f;
|
||||||
|
case ANIM_DIE: return 0.9000000000000001f;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
case ENTITY_SOLDIER:
|
||||||
|
switch (type) {
|
||||||
|
case ANIM_IDLE: return 0.4f;
|
||||||
|
case ANIM_WALK: return 0.72f;
|
||||||
|
case ANIM_HURT: return 0.42000000000000004f;
|
||||||
|
case ANIM_DIE: return 0.7000000000000001f;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
case ENTITY_WARRIOR:
|
||||||
|
switch (type) {
|
||||||
|
case ANIM_IDLE: return 0.4f;
|
||||||
|
case ANIM_WALK: return 0.72f;
|
||||||
|
case ANIM_HURT: return 0.42000000000000004f;
|
||||||
|
case ANIM_DIE: return 0.7000000000000001f;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
case ENTITY_MAGE:
|
||||||
|
switch (type) {
|
||||||
|
case ANIM_IDLE: return 0.4f;
|
||||||
|
case ANIM_WALK: return 0.72f;
|
||||||
|
case ANIM_HURT: return 0.42000000000000004f;
|
||||||
|
case ANIM_DIE: return 0.7000000000000001f;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
case ENTITY_ORC:
|
||||||
|
switch (type) {
|
||||||
|
case ANIM_IDLE: return 0.4f;
|
||||||
|
case ANIM_WALK: return 0.72f;
|
||||||
|
case ANIM_HURT: return 0.42000000000000004f;
|
||||||
|
case ANIM_DIE: return 0.7000000000000001f;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
case ENTITY_GOBLIN:
|
||||||
|
switch (type) {
|
||||||
|
case ANIM_IDLE: return 0.4f;
|
||||||
|
case ANIM_WALK: return 0.72f;
|
||||||
|
case ANIM_HURT: return 0.42000000000000004f;
|
||||||
|
case ANIM_DIE: return 0.7000000000000001f;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
BZ_ASSERT(0);
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
static AnimationSequence entityGetAnimationSequence(EntityType entity, AnimType type) {
|
static AnimationSequence entityGetAnimationSequence(EntityType entity, AnimType type) {
|
||||||
switch (entity) {
|
switch (entity) {
|
||||||
case ENTITY_WORKER:
|
case ENTITY_WORKER:
|
||||||
@@ -807,7 +863,7 @@ static AnimationFrame entityGetAnimationFrame(EntityType entity, AnimType type,
|
|||||||
case ANIM_IDLE: return ((AnimationFrame []) {{27, 0.2000f}, {28, 0.2000f}}) [frameIdx];
|
case ANIM_IDLE: return ((AnimationFrame []) {{27, 0.2000f}, {28, 0.2000f}}) [frameIdx];
|
||||||
case ANIM_WALK: return ((AnimationFrame []) {{29, 0.1800f}, {30, 0.1800f}, {31, 0.1800f}, {30, 0.1800f}}) [frameIdx];
|
case ANIM_WALK: return ((AnimationFrame []) {{29, 0.1800f}, {30, 0.1800f}, {31, 0.1800f}, {30, 0.1800f}}) [frameIdx];
|
||||||
case ANIM_HURT: return ((AnimationFrame []) {{32, 0.1400f}, {33, 0.1400f}, {34, 0.1400f}}) [frameIdx];
|
case ANIM_HURT: return ((AnimationFrame []) {{32, 0.1400f}, {33, 0.1400f}, {34, 0.1400f}}) [frameIdx];
|
||||||
case ANIM_DIE: return ((AnimationFrame []) {{32, 0.1400f}, {33, 0.1400f}, {34, 0.1400f}, {35, 0.1400f}, {36, 0.1400f}}) [frameIdx];
|
case ANIM_DIE: return ((AnimationFrame []) {{32, 0.1400f}, {33, 0.1400f}, {34, 0.1400f}, {35, 0.1400f}, {36, 0.3400f}}) [frameIdx];
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
case ENTITY_SOLDIER:
|
case ENTITY_SOLDIER:
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "systems.h"
|
#include "systems.h"
|
||||||
|
|
||||||
#include "../game_state.h"
|
#include "../game_state.h"
|
||||||
|
#include "../utils.h"
|
||||||
|
|
||||||
#include <raymath.h>
|
#include <raymath.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -68,11 +69,6 @@ bool updateParticle(const Texture2D tex, Particle *particle, f32 dt) {
|
|||||||
particle->elapsed += dt;
|
particle->elapsed += dt;
|
||||||
return alpha >= 1.0f;
|
return alpha >= 1.0f;
|
||||||
}
|
}
|
||||||
// https://stackoverflow.com/questions/13408990/how-to-generate-random-float-number-in-c
|
|
||||||
static inline f32 randFloatRange(f32 min, f32 max) {
|
|
||||||
float scale = rand() / (float) RAND_MAX; /* [0, 1.0] */
|
|
||||||
return min + scale * ( max - min ); /* [min, max] */
|
|
||||||
}
|
|
||||||
static inline Vector2 randVector2Range(Vector2 from, Vector2 to) {
|
static inline Vector2 randVector2Range(Vector2 from, Vector2 to) {
|
||||||
return (Vector2) {
|
return (Vector2) {
|
||||||
randFloatRange(from.x, to.x),
|
randFloatRange(from.x, to.x),
|
||||||
@@ -107,10 +103,18 @@ Particle spawnParticle(const ParticleEmitter *emitter) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void animationSetState(Animation *anim, AnimType type, bool playInFull) {
|
||||||
|
anim->animType = type;
|
||||||
|
anim->sequence = entityGetAnimationSequence(anim->entityType, type);
|
||||||
|
anim->curFrame = 0;
|
||||||
|
anim->elapsed = 0;
|
||||||
|
anim->playInFull = playInFull;
|
||||||
|
}
|
||||||
void updateAnimationState(ecs_iter_t *it) {
|
void updateAnimationState(ecs_iter_t *it) {
|
||||||
Animation *anim = ecs_field(it, Animation, 1);
|
Animation *anim = ecs_field(it, Animation, 1);
|
||||||
TextureRegion *text = ecs_field(it, TextureRegion, 2);
|
TextureRegion *text = ecs_field(it, TextureRegion, 2);
|
||||||
for (i32 i = 0; i < it->count; i++) {
|
for (i32 i = 0; i < it->count; i++) {
|
||||||
|
if (anim->playInFull) continue;
|
||||||
ecs_entity_t entity = it->entities[i];
|
ecs_entity_t entity = it->entities[i];
|
||||||
AnimType type = ANIM_IDLE;
|
AnimType type = ANIM_IDLE;
|
||||||
if (ecs_has(ECS, entity, Velocity)) {
|
if (ecs_has(ECS, entity, Velocity)) {
|
||||||
@@ -123,10 +127,7 @@ void updateAnimationState(ecs_iter_t *it) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type != anim[i].animType) {
|
if (type != anim[i].animType) {
|
||||||
anim[i].animType = type;
|
animationSetState(&anim[i], type, false);
|
||||||
anim[i].sequence = entityGetAnimationSequence(anim[i].entityType, type);
|
|
||||||
anim[i].curFrame = 0;
|
|
||||||
anim[i].elapsed = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,6 +146,7 @@ void updateAnimation(ecs_iter_t *it) {
|
|||||||
if (anim[i].elapsed < frame.duration) continue;
|
if (anim[i].elapsed < frame.duration) continue;
|
||||||
|
|
||||||
i32 nextFrame = (anim[i].curFrame + 1) % seq.frameCount;
|
i32 nextFrame = (anim[i].curFrame + 1) % seq.frameCount;
|
||||||
|
if (nextFrame == 0) anim[i].playInFull = false;
|
||||||
anim[i].curFrame = nextFrame;
|
anim[i].curFrame = nextFrame;
|
||||||
anim[i].frame = entityGetAnimationFrame(anim[i].entityType, anim[i].animType, nextFrame);
|
anim[i].frame = entityGetAnimationFrame(anim[i].entityType, anim[i].animType, nextFrame);
|
||||||
anim[i].elapsed = 0.0f;
|
anim[i].elapsed = 0.0f;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "../input.h"
|
#include "../input.h"
|
||||||
#include "../pathfinding.h"
|
#include "../pathfinding.h"
|
||||||
#include "../entity_factory.h"
|
#include "../entity_factory.h"
|
||||||
|
#include "../utils.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <raymath.h>
|
#include <raymath.h>
|
||||||
@@ -144,16 +145,22 @@ void entityUpdateKinematic(ecs_iter_t *it) {
|
|||||||
position[i] = Vector2Add(position[i], Vector2Scale(velocity[i], dt));
|
position[i] = Vector2Add(position[i], Vector2Scale(velocity[i], dt));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void entityUpdatePhysics(ecs_iter_t *it) {
|
void entityUpdate(ecs_iter_t *it) {
|
||||||
Game *game = ecs_singleton_get_mut(ECS, Game);
|
Game *game = ecs_singleton_get_mut(ECS, Game);
|
||||||
Position *position = ecs_field(it, Position, 1);
|
Position *position = ecs_field(it, Position, 1);
|
||||||
HitBox *hitbox = ecs_field(it, HitBox, 2);
|
HitBox *hitbox = ecs_field(it, HitBox, 2);
|
||||||
Velocity *velocity = ecs_field(it, Velocity, 3);
|
Velocity *velocity = ecs_field(it, Velocity, 3);
|
||||||
SpatialGridID *spatialID = ecs_field(it, SpatialGridID, 4);
|
Unit *unit = ecs_field(it, Unit, 4);
|
||||||
|
Owner *owner = ecs_field(it, Owner, 5);
|
||||||
|
SpatialGridID *spatialID = ecs_field(it, SpatialGridID, 6);
|
||||||
|
|
||||||
f32 dt = it->delta_time;
|
f32 dt = it->delta_time;
|
||||||
|
|
||||||
for (i32 i = 0; i < it->count; i++) {
|
for (i32 i = 0; i < it->count; i++) {
|
||||||
|
// Attack thingies
|
||||||
|
unit[i].attackElapsed += dt;
|
||||||
|
bool canAttack = unit[i].attackElapsed > unit[i].attackCooldown;
|
||||||
|
|
||||||
// Only update "stationary" entities
|
// Only update "stationary" entities
|
||||||
bool stationary = Vector2Length(velocity[i]) <= 0.2f;
|
bool stationary = Vector2Length(velocity[i]) <= 0.2f;
|
||||||
Rectangle bounds = entityTransformHitBox(position[i], hitbox[i]);
|
Rectangle bounds = entityTransformHitBox(position[i], hitbox[i]);
|
||||||
@@ -173,9 +180,35 @@ void entityUpdatePhysics(ecs_iter_t *it) {
|
|||||||
if (!CheckCollisionRecs(bounds, otherBounds)) {
|
if (!CheckCollisionRecs(bounds, otherBounds)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attack update
|
||||||
|
if (canAttack && ecs_has(ECS, other, Health) && ecs_has(ECS, other, Owner)) {
|
||||||
|
Health *otherHealth = ecs_get_mut(ECS, other, Health);
|
||||||
|
Player otherPlayer = ecs_get(ECS, other, Owner)->player;
|
||||||
|
|
||||||
|
if (otherPlayer != owner[i].player) {
|
||||||
|
Rectangle collisionRec = GetCollisionRec(bounds, otherBounds);
|
||||||
|
f32 percentageCovered = (collisionRec.width * collisionRec.height) / (bounds.width * bounds.height);
|
||||||
|
|
||||||
|
f32 dealDmg = randFloatRange(unit[i].minDamage, unit[i].maxDamage);
|
||||||
|
f32 multiplier = 1.0f + percentageCovered;
|
||||||
|
multiplier = Clamp(multiplier, 0.8f, 1.6f);
|
||||||
|
|
||||||
|
dealDmg *= multiplier;
|
||||||
|
|
||||||
|
damageEvent(other, (DamageEvent) {
|
||||||
|
.amount = dealDmg
|
||||||
|
});
|
||||||
|
|
||||||
|
canAttack = false;
|
||||||
|
unit[i].attackElapsed = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Physics update
|
||||||
slowDown += 0.1f;
|
slowDown += 0.1f;
|
||||||
Position dif = Vector2Subtract(otherPos, position[i]);
|
Position dif = Vector2Subtract(otherPos, position[i]);
|
||||||
//dif = Vector2Normalize(dif);
|
|
||||||
dir = Vector2Add(dir, dif);
|
dir = Vector2Add(dir, dif);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,7 +303,7 @@ void updateBuildingRecruitment(ecs_iter_t *it) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderHealth(ecs_iter_t *it) {
|
void renderHealthBar(ecs_iter_t *it) {
|
||||||
Position *pos = ecs_field(it, Position, 1);
|
Position *pos = ecs_field(it, Position, 1);
|
||||||
HitBox *hitbox = ecs_field(it, HitBox, 2);
|
HitBox *hitbox = ecs_field(it, HitBox, 2);
|
||||||
Health *health = ecs_field(it, Health, 3);
|
Health *health = ecs_field(it, Health, 3);
|
||||||
|
|||||||
@@ -3,6 +3,36 @@
|
|||||||
#include "../game_state.h"
|
#include "../game_state.h"
|
||||||
#include "../sounds.h"
|
#include "../sounds.h"
|
||||||
|
|
||||||
|
void damageEvent(ecs_entity_t entity, DamageEvent event) {
|
||||||
|
BZ_ASSERT(ecs_has(ECS, entity, Health));
|
||||||
|
|
||||||
|
Health *health = ecs_get_mut(ECS, entity, Health);
|
||||||
|
health->hp -= event.amount;
|
||||||
|
|
||||||
|
bool hasAnimation = ecs_has(ECS, entity, Animation);
|
||||||
|
if (hasAnimation && health->hp > 0) {
|
||||||
|
// Still alive, just play hurt anim
|
||||||
|
Animation *animation = ecs_get_mut(ECS, entity, Animation);
|
||||||
|
animationSetState(animation, ANIM_HURT, true);
|
||||||
|
} else if (hasAnimation) {
|
||||||
|
// Delay delete
|
||||||
|
Animation *animation = ecs_get_mut(ECS, entity, Animation);
|
||||||
|
animationSetState(animation, ANIM_DIE, true);
|
||||||
|
ecs_set(ECS, entity, DelayDelete, {
|
||||||
|
.time = entityGetAnimationLength(animation->entityType, ANIM_DIE)
|
||||||
|
});
|
||||||
|
// Remove, so it becomes inactive
|
||||||
|
ecs_remove_id(ECS, entity, Selectable);
|
||||||
|
ecs_remove(ECS, entity, Health);
|
||||||
|
ecs_remove(ECS, entity, Unit);
|
||||||
|
ecs_remove(ECS, entity, Building);
|
||||||
|
} else {
|
||||||
|
// No animation, delete right away
|
||||||
|
ecs_delete(ECS, entity);
|
||||||
|
}
|
||||||
|
health->lastChanged = GetTime();
|
||||||
|
}
|
||||||
|
|
||||||
i32 harvestEvent(ecs_entity_t entity, HarvestEvent event) {
|
i32 harvestEvent(ecs_entity_t entity, HarvestEvent event) {
|
||||||
BZ_ASSERT(ecs_has_id(ECS, entity, ecs_id(Harvestable)));
|
BZ_ASSERT(ecs_has_id(ECS, entity, ecs_id(Harvestable)));
|
||||||
BZ_ASSERT(ecs_has(ECS, entity, Resource));
|
BZ_ASSERT(ecs_has(ECS, entity, Resource));
|
||||||
|
|||||||
@@ -291,9 +291,9 @@ void drawMainMenuUI(Game *game, f32 dt) {
|
|||||||
if (uiMainMenuButton("Play", true)) {
|
if (uiMainMenuButton("Play", true)) {
|
||||||
setScreen(game, SCREEN_GAME);
|
setScreen(game, SCREEN_GAME);
|
||||||
unloadMap(game);
|
unloadMap(game);
|
||||||
//loadMap(game, "assets/maps/tree_test.tmj");
|
loadMap(game, "assets/maps/tree_test.tmj");
|
||||||
//loadMap(game, "assets/maps/entity_test.tmj");
|
//loadMap(game, "assets/maps/entity_test.tmj");
|
||||||
loadMap(game, "assets/maps/map_01.tmj");
|
//loadMap(game, "assets/maps/map_01.tmj");
|
||||||
}
|
}
|
||||||
if (uiMainMenuButton("Settings", true)) {
|
if (uiMainMenuButton("Settings", true)) {
|
||||||
setScreen(game, SCREEN_SETTINGS);
|
setScreen(game, SCREEN_SETTINGS);
|
||||||
|
|||||||
@@ -73,6 +73,19 @@ ECS_MOVE(Building, dst, src, {
|
|||||||
*dst = *src;
|
*dst = *src;
|
||||||
})
|
})
|
||||||
|
|
||||||
|
void delayDeleteUpdate(ecs_iter_t *it) {
|
||||||
|
DelayDelete *delay = ecs_field(it, DelayDelete, 1);
|
||||||
|
|
||||||
|
f32 dt = GetFrameTime();
|
||||||
|
|
||||||
|
for (i32 i = 0; i < it->count; i++) {
|
||||||
|
delay[i].elapsed += dt;
|
||||||
|
|
||||||
|
if (delay[i].elapsed >= delay[i].time)
|
||||||
|
ecs_delete(ECS, it->entities[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void setupSystems() {
|
void setupSystems() {
|
||||||
ecs_set_hooks(ECS, SpatialGridID, {
|
ecs_set_hooks(ECS, SpatialGridID, {
|
||||||
.dtor = ecs_dtor(SpatialGridID),
|
.dtor = ecs_dtor(SpatialGridID),
|
||||||
@@ -99,7 +112,7 @@ void setupSystems() {
|
|||||||
|
|
||||||
ECS_SYSTEM(ECS, entityUpdateSpatialID, EcsOnUpdate, Position, HitBox, Velocity, SpatialGridID);
|
ECS_SYSTEM(ECS, entityUpdateSpatialID, EcsOnUpdate, Position, HitBox, Velocity, SpatialGridID);
|
||||||
ECS_SYSTEM(ECS, entityUpdateKinematic, EcsOnUpdate, Position, Velocity, Steering, Unit);
|
ECS_SYSTEM(ECS, entityUpdateKinematic, EcsOnUpdate, Position, Velocity, Steering, Unit);
|
||||||
ECS_SYSTEM(ECS, entityUpdatePhysics, EcsOnUpdate, Position, HitBox, Velocity, SpatialGridID);
|
ECS_SYSTEM(ECS, entityUpdate, EcsOnUpdate, Position, HitBox, Velocity, Unit, Owner, SpatialGridID);
|
||||||
|
|
||||||
ECS_SYSTEM(ECS, entityMoveToTarget, EcsOnUpdate, Position, Velocity, TargetPosition, Steering);
|
ECS_SYSTEM(ECS, entityMoveToTarget, EcsOnUpdate, Position, Velocity, TargetPosition, Steering);
|
||||||
ECS_SYSTEM(ECS, entityFollowPath, EcsOnUpdate, Path);
|
ECS_SYSTEM(ECS, entityFollowPath, EcsOnUpdate, Path);
|
||||||
@@ -113,12 +126,14 @@ void setupSystems() {
|
|||||||
ECS_SYSTEM(ECS, updateAnimation, EcsOnUpdate, Animation, TextureRegion);
|
ECS_SYSTEM(ECS, updateAnimation, EcsOnUpdate, Animation, TextureRegion);
|
||||||
ECS_SYSTEM(ECS, updateEasingSystem, EcsOnUpdate, Easing, Position, HitBox, Rotation);
|
ECS_SYSTEM(ECS, updateEasingSystem, EcsOnUpdate, Easing, Position, HitBox, Rotation);
|
||||||
|
|
||||||
ECS_SYSTEM(ECS, renderHealth, EcsOnUpdate, Position, HitBox, Health);
|
ECS_SYSTEM(ECS, renderHealthBar, EcsOnUpdate, Position, HitBox, Health);
|
||||||
ECS_SYSTEM(ECS, renderDebugPath, EcsOnUpdate, Path);
|
ECS_SYSTEM(ECS, renderDebugPath, EcsOnUpdate, Path);
|
||||||
|
|
||||||
ECS_SYSTEM(ECS, renderColliders, EcsOnUpdate, Position, HitBox);
|
ECS_SYSTEM(ECS, renderColliders, EcsOnUpdate, Position, HitBox);
|
||||||
ECS_SYSTEM(ECS, renderOrientationDirection, EcsOnUpdate, Position, Orientation);
|
ECS_SYSTEM(ECS, renderOrientationDirection, EcsOnUpdate, Position, Orientation);
|
||||||
|
|
||||||
|
ECS_SYSTEM(ECS, delayDeleteUpdate, EcsOnUpdate, DelayDelete);
|
||||||
|
|
||||||
renderDebugPathSystem = renderDebugPath;
|
renderDebugPathSystem = renderDebugPath;
|
||||||
renderOrientDirSystem = renderOrientationDirection;
|
renderOrientDirSystem = renderOrientationDirection;
|
||||||
renderCollidersSystem = renderColliders;
|
renderCollidersSystem = renderColliders;
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ bool updateParticle(const Texture2D tex, Particle *particle, f32 dt);
|
|||||||
|
|
||||||
Particle spawnParticle(const ParticleEmitter *emitter);
|
Particle spawnParticle(const ParticleEmitter *emitter);
|
||||||
|
|
||||||
|
void animationSetState(Animation *anim, AnimType type, bool playInFull);
|
||||||
/*
|
/*
|
||||||
* 1: Animation
|
* 1: Animation
|
||||||
* 2: TextureRegion
|
* 2: TextureRegion
|
||||||
@@ -117,13 +118,16 @@ void entityUpdateSpatialID(ecs_iter_t *it);
|
|||||||
void entityUpdateKinematic(ecs_iter_t *it);
|
void entityUpdateKinematic(ecs_iter_t *it);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* Big system for updating physics and attacking
|
||||||
* 0: Game (singleton) for collisions
|
* 0: Game (singleton) for collisions
|
||||||
* 1: Position
|
* 1: Position
|
||||||
* 2: HitBox
|
* 2: HitBox
|
||||||
* 2: Velocity
|
* 3: Velocity
|
||||||
* 3: SpatialGridID
|
* 4: Unit
|
||||||
|
* 5: Owner
|
||||||
|
* 6: SpatialGridID
|
||||||
*/
|
*/
|
||||||
void entityUpdatePhysics(ecs_iter_t *it);
|
void entityUpdate(ecs_iter_t *it);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 1: Position
|
* 1: Position
|
||||||
@@ -152,7 +156,7 @@ void updateBuildingRecruitment(ecs_iter_t *it);
|
|||||||
* 2: HitBox
|
* 2: HitBox
|
||||||
* 3: Health
|
* 3: Health
|
||||||
*/
|
*/
|
||||||
void renderHealth(ecs_iter_t *it);
|
void renderHealthBar(ecs_iter_t *it);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 1: Position
|
* 1: Position
|
||||||
@@ -177,6 +181,8 @@ void renderDebugPath(ecs_iter_t *it);
|
|||||||
* Event Systems
|
* Event Systems
|
||||||
**********************************/
|
**********************************/
|
||||||
|
|
||||||
|
void damageEvent(ecs_entity_t entity, DamageEvent event);
|
||||||
|
|
||||||
i32 harvestEvent(ecs_entity_t entity, HarvestEvent event);
|
i32 harvestEvent(ecs_entity_t entity, HarvestEvent event);
|
||||||
void depositEvent(ecs_entity_t entity, DepositEvent event);
|
void depositEvent(ecs_entity_t entity, DepositEvent event);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <raylib.h>
|
#include <raylib.h>
|
||||||
#include <breeze.h>
|
#include <breeze.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
static Rectangle getCameraBounds(Camera2D camera) {
|
static Rectangle getCameraBounds(Camera2D camera) {
|
||||||
Rectangle bounds = {
|
Rectangle bounds = {
|
||||||
@@ -18,6 +19,12 @@ static Rectangle getCameraBounds(Camera2D camera) {
|
|||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/13408990/how-to-generate-random-float-number-in-c
|
||||||
|
static inline f32 randFloatRange(f32 min, f32 max) {
|
||||||
|
float scale = rand() / (float) RAND_MAX; /* [0, 1.0] */
|
||||||
|
return min + scale * ( max - min ); /* [min, max] */
|
||||||
|
}
|
||||||
|
|
||||||
// Implemented in main.c
|
// Implemented in main.c
|
||||||
bool serializeGameData(const char *path, const GameData *gameData);
|
bool serializeGameData(const char *path, const GameData *gameData);
|
||||||
bool deserializeGameData(const char *path, GameData *gameData);
|
bool deserializeGameData(const char *path, GameData *gameData);
|
||||||
|
|||||||
@@ -432,7 +432,7 @@
|
|||||||
"tileid":35
|
"tileid":35
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"duration":140,
|
"duration":340,
|
||||||
"tileid":36
|
"tileid":36
|
||||||
}],
|
}],
|
||||||
"id":35,
|
"id":35,
|
||||||
|
|||||||
@@ -199,7 +199,7 @@
|
|||||||
<frame tileid="33" duration="140"/>
|
<frame tileid="33" duration="140"/>
|
||||||
<frame tileid="34" duration="140"/>
|
<frame tileid="34" duration="140"/>
|
||||||
<frame tileid="35" duration="140"/>
|
<frame tileid="35" duration="140"/>
|
||||||
<frame tileid="36" duration="140"/>
|
<frame tileid="36" duration="340"/>
|
||||||
</animation>
|
</animation>
|
||||||
</tile>
|
</tile>
|
||||||
<tile id="36" type="worker">
|
<tile id="36" type="worker">
|
||||||
|
|||||||
@@ -381,6 +381,34 @@ class EnumWriter:
|
|||||||
writer.block_end()
|
writer.block_end()
|
||||||
writer.empty_line()
|
writer.empty_line()
|
||||||
|
|
||||||
|
|
||||||
|
def output_anim_length(self, func_name):
|
||||||
|
writer = self.writer
|
||||||
|
writer.output(f"static f32 {func_name}({self.enum_type} entity, {self.anim_type} type) ")
|
||||||
|
writer.block_start()
|
||||||
|
|
||||||
|
writer.output("switch (entity) ")
|
||||||
|
writer.block_start()
|
||||||
|
for entity, animation_types in self.anim_map.items():
|
||||||
|
writer.output(f"case {entity}:\n")
|
||||||
|
writer.indent()
|
||||||
|
writer.output("switch (type) ")
|
||||||
|
writer.block_start()
|
||||||
|
for anim_type in animation_types:
|
||||||
|
anim = self.anim_map[entity][anim_type]
|
||||||
|
duration = sum([x['duration'] * 0.001 for x in anim])
|
||||||
|
writer.output(f"case {anim_type}: return {duration}f;\n")
|
||||||
|
writer.output("default: break;\n")
|
||||||
|
writer.block_end()
|
||||||
|
writer.unindent()
|
||||||
|
writer.output("default: break;\n")
|
||||||
|
writer.block_end()
|
||||||
|
|
||||||
|
writer.output("BZ_ASSERT(0);\n")
|
||||||
|
writer.output("return 0.0f;\n")
|
||||||
|
writer.block_end()
|
||||||
|
writer.empty_line()
|
||||||
|
|
||||||
def output_anim_sequence(self, func_name):
|
def output_anim_sequence(self, func_name):
|
||||||
writer = self.writer
|
writer = self.writer
|
||||||
writer.output(f"static AnimationSequence {func_name}({self.enum_type} entity, {self.anim_type} type) ")
|
writer.output(f"static AnimationSequence {func_name}({self.enum_type} entity, {self.anim_type} type) ")
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ anim_writer.output_enum_to_tile("getEntityTile")
|
|||||||
anim_writer.output_enum_to_str("getEntityStr")
|
anim_writer.output_enum_to_str("getEntityStr")
|
||||||
anim_writer.output_anim_enum_to_str("getEntityAnimationStr")
|
anim_writer.output_anim_enum_to_str("getEntityAnimationStr")
|
||||||
anim_writer.output_has_anim("entityHasAnimation")
|
anim_writer.output_has_anim("entityHasAnimation")
|
||||||
|
anim_writer.output_anim_length("entityGetAnimationLength")
|
||||||
anim_writer.output_anim_sequence("entityGetAnimationSequence")
|
anim_writer.output_anim_sequence("entityGetAnimationSequence")
|
||||||
anim_writer.output_anim_frame("entityGetAnimationFrame")
|
anim_writer.output_anim_frame("entityGetAnimationFrame")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user