diff --git a/game/components.c b/game/components.c index cc0d30b..beea1d8 100644 --- a/game/components.c +++ b/game/components.c @@ -8,6 +8,7 @@ ECS_COMPONENT_DECLARE(Resource); ECS_COMPONENT_DECLARE(Owner); +ECS_COMPONENT_DECLARE(FloatyTextParticle); ECS_COMPONENT_DECLARE(EmitterAttachment); ECS_COMPONENT_DECLARE(ParticleEmitter); ECS_COMPONENT_DECLARE(ParticleLayer0); @@ -57,6 +58,7 @@ void initComponentIDs(ecs_world_t *ecs) { 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); diff --git a/game/components.h b/game/components.h index d2ee4d8..8a4ed7a 100644 --- a/game/components.h +++ b/game/components.h @@ -41,6 +41,18 @@ extern ECS_COMPONENT_DECLARE(Owner); * Particle components *********************************************************/ +typedef struct FloatyTextParticle { + Vector2 pos; + Vector2 speed; + Color color; + Color targetColor; + char text[12]; + f32 txtSize; + f32 duration; + f32 elapsed; +} FloatyTextParticle; +extern ECS_COMPONENT_DECLARE(FloatyTextParticle); + typedef struct EmitterAttachment { ecs_entity_t baseEntity; Vector2 offset; @@ -185,7 +197,10 @@ extern ECS_COMPONENT_DECLARE(Easing); /********************************************************** * Event components *********************************************************/ +typedef Rectangle HitBox; + typedef struct DamageEvent { + HitBox hitbox; f32 amount; } DamageEvent; @@ -202,7 +217,6 @@ typedef struct DamageEvent { * Gameplay components *********************************************************/ -typedef Rectangle HitBox; extern ECS_COMPONENT_DECLARE(HitBox); extern ECS_COMPONENT_DECLARE(BzBTState); diff --git a/game/systems/s_animation.c b/game/systems/s_animation.c index 8dec256..b925695 100644 --- a/game/systems/s_animation.c +++ b/game/systems/s_animation.c @@ -6,6 +6,49 @@ #include #include +static inline int lerpInt(int start, int end, f32 alpha) +{ + float result = start + alpha * (end - start); + return result; +} +static inline Color lerpColor(Color start, Color end, f32 alpha) { + return (Color) { + .r = lerpInt(start.r, end.r, alpha), + .g = lerpInt(start.g, end.g, alpha), + .b = lerpInt(start.b, end.b, alpha), + .a = lerpInt(start.a, end.a, alpha), + }; +} + +void renderFloatyTextParticle(ecs_iter_t *it) { + Game *game = ecs_singleton_get_mut(ECS, Game); + FloatyTextParticle *floaty = ecs_field(it, FloatyTextParticle, 1); + f32 dt = GetFrameTime(); + + for (i32 i = 0; i < it->count; i++) { + ecs_entity_t entity = it->entities[i]; + + f32 alpha = floaty[i].elapsed / floaty[i].duration; + Color color = lerpColor(floaty[i].color, floaty[i].targetColor, alpha); + Font font = game->font; + // Shadow + Vector2 shadowPos = floaty[i].pos; + shadowPos.x += 0.4f; + shadowPos.y += 0.4f; + Color shadowColor = DARKGRAY; + shadowColor.a = color.a; + DrawTextEx(font, floaty[i].text, shadowPos, floaty[i].txtSize, 1.0f, shadowColor); + DrawTextEx(font, floaty[i].text, floaty[i].pos, floaty[i].txtSize, 1.0f, color); + + // pos += speed * dt + floaty[i].pos = Vector2Add(floaty[i].pos, Vector2Scale(floaty[i].speed, dt)); + + floaty[i].elapsed += dt; + if (floaty[i].elapsed >= floaty[i].duration) + ecs_delete(ECS, entity); + } +} + void updateParticleEmitter(ecs_iter_t *it) { ParticleEmitter *emitter = ecs_field(it, ParticleEmitter, 1); f32 dt = GetFrameTime(); @@ -29,12 +72,6 @@ void updateParticleEmitter(ecs_iter_t *it) { } } -static inline int lerpInt(int start, int end, int amount) -{ - float result = start + amount*(end - start); - - return result; -} bool updateParticle(const Texture2D tex, Particle *particle, f32 dt) { f32 alpha = particle->elapsed / particle->lifetime; @@ -43,12 +80,7 @@ bool updateParticle(const Texture2D tex, Particle *particle, f32 dt) { f32 rot = Lerp(particle->startRotSpeed, particle->endRotSpeed, alpha); Color startC = particle->startColor; Color endC = particle->endColor; - Color color = { - .r = lerpInt(startC.r, endC.r, alpha), - .g = lerpInt(startC.g, endC.g, alpha), - .b = lerpInt(startC.b, endC.b, alpha), - .a = lerpInt(startC.a, endC.a, alpha) - }; + Color color = lerpColor(startC, endC, alpha); BeginBlendMode(particle->blend); f32 hSize = size * 0.5f; diff --git a/game/systems/s_entity.c b/game/systems/s_entity.c index 32bcb8e..c848a0b 100644 --- a/game/systems/s_entity.c +++ b/game/systems/s_entity.c @@ -197,6 +197,7 @@ void entityUpdate(ecs_iter_t *it) { dealDmg *= multiplier; damageEvent(other, (DamageEvent) { + .hitbox = otherBounds, .amount = dealDmg }); diff --git a/game/systems/s_event.c b/game/systems/s_event.c index 04ba4bf..ba3e5fc 100644 --- a/game/systems/s_event.c +++ b/game/systems/s_event.c @@ -1,7 +1,10 @@ +#include #include "systems.h" #include "../game_state.h" #include "../sounds.h" +#include "../utils.h" +#include "../entity_factory.h" void damageEvent(ecs_entity_t entity, DamageEvent event) { BZ_ASSERT(ecs_has(ECS, entity, Health)); @@ -9,6 +12,24 @@ void damageEvent(ecs_entity_t entity, DamageEvent event) { Health *health = ecs_get_mut(ECS, entity, Health); health->hp -= event.amount; + Vector2 pos = { + event.hitbox.x + event.hitbox.width * 0.5f + randFloatRange(-2, 2), + event.hitbox.y + randFloatRange(2, 4) + }; + + FloatyTextParticle floatyText = { + .pos = pos, + .speed = { randFloatRange(-12, 12), -randFloatRange(26, 32) }, + .color = {255, 0, 0, 255}, + .targetColor = {255, 0, 0, GetRandomValue(60, 120)}, + .txtSize = 6.5f, + .duration = randFloatRange(0.3, 0.68f), + .elapsed = 0 + }; + snprintf(floatyText.text, sizeof(floatyText.text), "-%.1f", event.amount); + ecs_entity_t floaty = entityCreateEmpty(); + ecs_set_ptr(ECS, floaty, FloatyTextParticle, &floatyText); + bool hasAnimation = ecs_has(ECS, entity, Animation); if (hasAnimation && health->hp > 0) { // Still alive, just play hurt anim diff --git a/game/systems/systems.c b/game/systems/systems.c index f634c9e..526ae80 100644 --- a/game/systems/systems.c +++ b/game/systems/systems.c @@ -127,6 +127,8 @@ void setupSystems() { ECS_SYSTEM(ECS, updateEasingSystem, EcsOnUpdate, Easing, Position, HitBox, Rotation); ECS_SYSTEM(ECS, renderHealthBar, EcsOnUpdate, Position, HitBox, Health); + ECS_SYSTEM(ECS, renderFloatyTextParticle, EcsOnUpdate, FloatyTextParticle); + ECS_SYSTEM(ECS, renderDebugPath, EcsOnUpdate, Path); ECS_SYSTEM(ECS, renderColliders, EcsOnUpdate, Position, HitBox); diff --git a/game/systems/systems.h b/game/systems/systems.h index 89cdc3c..2bbb2e9 100644 --- a/game/systems/systems.h +++ b/game/systems/systems.h @@ -37,6 +37,12 @@ void setAIBehaviour(ecs_entity_t entity, const BzBTNode *root, * Animation Systems **********************************/ +/* + * 0: Game (singleton for Font) + * 1: FloatyTextParticle + */ +void renderFloatyTextParticle(ecs_iter_t *it); + /* * 1: ParticleEmitter */