#include "systems.h" #include "../game_state.h" #include #include void updateParticleEmitter(ecs_iter_t *it) { ParticleEmitter *emitter = ecs_field(it, ParticleEmitter, 1); f32 dt = GetFrameTime(); for (i32 i = 0; i < it->count; i++) { ecs_entity_t entity = it->entities[i]; if (ecs_has(ECS, entity, EmitterAttachment)) { EmitterAttachment attachment = *ecs_get(ECS, entity, EmitterAttachment); if (!ecs_is_alive(ECS, attachment.baseEntity)) { ecs_delete(ECS, entity); continue; } Vector2 pos = *ecs_get(ECS, entity, Position); pos = Vector2Add(pos, attachment.offset); emitter->pos = pos; } emitter[i].emitterElapsed += dt; if (emitter[i].emitterElapsed >= emitter[i].emitterLifetime) ecs_delete(ECS, entity); } } 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; Vector2 vel = Vector2Lerp(particle->startVel, particle->endVel, alpha); f32 size = Lerp(particle->startSize, particle->endSize, alpha); 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) }; //BeginBlendMode(particle->blend); f32 hSize = size * 0.5f; Vector2 center = particle->pos; Rectangle src = getTextureRect(particle->tileID); src.x += 0.1f; src.y += 0.1f; src.width -= 0.2f; src.height -= 0.2f; DrawTexturePro(tex, src, (Rectangle) { center.x, center.y, size, size }, (Vector2) {hSize, hSize}, rot, color); //EndBlendMode(); particle->pos = Vector2Add(particle->pos, Vector2Scale(vel, dt)); particle->elapsed += dt; 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) { return (Vector2) { randFloatRange(from.x, to.x), randFloatRange(from.y, to.y) }; } static inline Color randColorRange(Color from, Color to) { return (Color) { .r = GetRandomValue(from.r, to.r), .g = GetRandomValue(from.g, to.g), .b = GetRandomValue(from.b, to.b), .a = GetRandomValue(from.a, to.a), }; } Particle spawnParticle(const ParticleEmitter *emitter) { const struct ParticleEmitterData *data = &emitter->data; return (Particle) { .pos = Vector2Add(emitter->pos, randVector2Range(data->minOffset, data->maxOffset)), .rotation = 0.0f, .startVel = randVector2Range(data->minStartVel, data->maxStartVel), .endVel = randVector2Range(data->minEndVel, data->maxEndVel), .startSize = randFloatRange(data->minStartSize, data->maxStartSize), .endSize = randFloatRange(data->minEndSize, data->maxEndSize), .startRotSpeed = randFloatRange(data->minStartRotSpeed, data->maxStartRotSpeed), .endRotSpeed = randFloatRange(data->minEndRotSpeed, data->maxEndRotSpeed), .startColor = randColorRange(data->minStartColor, data->maxStartColor), .endColor = randColorRange(data->minEndColor, data->maxEndColor), .blend = data->blend, .tileID = data->tileID, .elapsed = 0.0f, .lifetime = randFloatRange(data->minLifetime, data->maxLifetime), }; } void updateAnimationState(ecs_iter_t *it) { Animation *anim = ecs_field(it, Animation, 1); TextureRegion *text = ecs_field(it, TextureRegion, 2); for (i32 i = 0; i < it->count; i++) { ecs_entity_t entity = it->entities[i]; AnimType type = ANIM_IDLE; if (ecs_has(ECS, entity, Velocity)) { Velocity vel = *ecs_get(ECS, entity, Velocity); f32 len = Vector2Length(vel); if (len > 1.0f) { type = ANIM_WALK; text[i].flipX = vel.x < 0; } } if (type != anim[i].animType) { anim[i].animType = type; anim[i].sequence = entityGetAnimationSequence(anim[i].entityType, type); anim[i].curFrame = 0; anim[i].elapsed = 0; } } } void updateAnimation(ecs_iter_t *it) { Animation *anim = ecs_field(it, Animation, 1); TextureRegion *texture = ecs_field(it, TextureRegion, 2); float dt = GetFrameTime(); for (i32 i = 0; i < it->count; i++) { ecs_entity_t entity = it->entities[i]; AnimationFrame frame = anim[i].frame; AnimationSequence seq = anim[i].sequence; anim[i].elapsed += dt; if (anim[i].elapsed < frame.duration) continue; i32 nextFrame = (anim[i].curFrame + 1) % seq.frameCount; anim[i].curFrame = nextFrame; anim[i].frame = entityGetAnimationFrame(anim[i].entityType, anim[i].animType, nextFrame); anim[i].elapsed = 0.0f; texture[i].rec = getTextureRect(anim[i].frame.frame); if (ecs_has(ECS, entity, Owner)) { Owner owner = *ecs_get(ECS, entity, Owner); BzTileID base = anim[i].frame.frame; Vector2 offset = getTileOffset(base, owner.player); texture[i].rec.x += offset.x; texture[i].rec.y += offset.y; } } } void updateEasingSystem(ecs_iter_t *it) { Easing *easing = ecs_field(it, Easing, 1); f32 dt = GetFrameTime(); for (i32 i = 0; i < it->count; i++) { ecs_entity_t entity = it->entities[i]; if (easing[i].elapsed > easing[i].duration) { ecs_remove(ECS, entity, Easing); continue; } if (!ecs_has_id(ECS, entity, easing[i].compID)) continue; easing[i].elapsed += dt; f32 alpha = easing[i].elapsed / easing[i].duration; alpha = BZ_MIN(1.0f, alpha); f32 prevX = easing[i].x; easing[i].x = bzEase(easing[i].easingFunc, alpha); const Easing *e = &easing[i]; f32 x = e->x; // Inner x = e->easeStart + e->easeTarget * x + e->easeOffset; // Outer x = e->start + e->target * x + e->offset; easing[i].x = x; u8 *compData = ecs_get_mut_id(ECS, entity, easing[i].compID); compData += easing[i].memberOffset; f32 *out = (f32 *) compData; *out -= prevX; *out += x; } }