|
| 1 | +#include "chomper/animations/deathAnimation.hpp" |
| 2 | +#include "chomper/world_space.hpp" |
| 3 | +#include <numbers> |
| 4 | + |
| 5 | +namespace chomper::animation { |
| 6 | +namespace { |
| 7 | +constexpr auto easeOut(float t) { |
| 8 | + return 1.f - ((1.f - t) * (1.f - t)); |
| 9 | +} |
| 10 | +} // namespace |
| 11 | + |
| 12 | +DeathAnimation::DeathAnimation(std::span<le::RenderInstance const> instances) { |
| 13 | + m_segments.clear(); |
| 14 | + m_segments.reserve(instances.size()); |
| 15 | + |
| 16 | + for (auto const& instance : instances) { |
| 17 | + auto dir = m_random.next_float(0, 360); |
| 18 | + auto lifetime = m_random.next_float(2, 5); |
| 19 | + auto speed = m_random.next_float(300, 600); |
| 20 | + auto rotSpeed = m_random.next_float(5.f, 20.f); |
| 21 | + |
| 22 | + auto rad = dir * std::numbers::pi_v<float> / 180.f; |
| 23 | + |
| 24 | + Segment seg; |
| 25 | + seg.rotSpeed = rotSpeed; |
| 26 | + seg.velocity = {std::cos(rad) * speed, std::sin(rad) * speed}; |
| 27 | + seg.remaining = lifetime; |
| 28 | + seg.lifetime = lifetime; |
| 29 | + seg.quad.create(tileSize_v); |
| 30 | + seg.quad.tint = instance.tint; |
| 31 | + seg.quad.transform = instance.transform; |
| 32 | + m_segments.push_back(seg); |
| 33 | + } |
| 34 | +} |
| 35 | +void DeathAnimation::tick(kvf::Seconds dt) { |
| 36 | + for (auto& seg : m_segments) { |
| 37 | + if (seg.remaining <= 0.f) { |
| 38 | + continue; |
| 39 | + } |
| 40 | + |
| 41 | + seg.remaining -= dt.count(); |
| 42 | + |
| 43 | + auto t = std::clamp(1.f - (seg.remaining / seg.lifetime), 0.f, 1.f); |
| 44 | + |
| 45 | + auto eased = 1.f - easeOut(t); |
| 46 | + |
| 47 | + seg.quad.transform.position += seg.velocity * eased * dt.count(); |
| 48 | + if (worldSpace::isOutOfBounds(worldSpace::worldToGrid(seg.quad.transform.position))) { |
| 49 | + seg.velocity = -seg.velocity; |
| 50 | + } |
| 51 | + |
| 52 | + float angle = dt.count() * eased * seg.rotSpeed; |
| 53 | + auto o = seg.quad.transform.orientation; |
| 54 | + auto cos = std::cos(angle); |
| 55 | + auto sin = std::sin(angle); |
| 56 | + seg.quad.transform.orientation = {(o.x * cos) - (o.y * sin), (o.x * sin) + (o.y * cos)}; |
| 57 | + |
| 58 | + float scale = 1.f; |
| 59 | + if (t > 0.8f) { |
| 60 | + float u = (t - 0.8f) / 0.2f; // 0 → 1 |
| 61 | + scale = 1.f - u; // 1 → 0 |
| 62 | + } |
| 63 | + seg.quad.transform.scale = {scale, scale}; |
| 64 | + } |
| 65 | +} |
| 66 | + |
| 67 | +void DeathAnimation::draw(le::IRenderer& renderer) const { |
| 68 | + for (auto const& segment : m_segments) { |
| 69 | + if (segment.remaining > 0.f) { |
| 70 | + segment.quad.draw(renderer); |
| 71 | + } |
| 72 | + } |
| 73 | +} |
| 74 | + |
| 75 | +} // namespace chomper::animation |
0 commit comments