Skip to content

Commit 7c7f974

Browse files
committed
animator
animator
1 parent b096144 commit 7c7f974

7 files changed

Lines changed: 154 additions & 4 deletions

File tree

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include "chomper/animator.hpp"
2+
3+
namespace chomper::animation {
4+
class DeathAnimation : public chomper::IAnimation {
5+
public:
6+
DeathAnimation(std::span<le::RenderInstance const> instances);
7+
void tick(kvf::Seconds dt) final;
8+
void draw(le::IRenderer& renderer) const final;
9+
10+
private:
11+
struct Segment {
12+
float remaining{};
13+
float lifetime{};
14+
float rotSpeed{};
15+
glm::vec2 velocity{};
16+
le::drawable::Quad quad{};
17+
};
18+
19+
std::vector<Segment> m_segments{};
20+
21+
le::Random m_random{};
22+
};
23+
} // namespace chomper::animation

lib/include/chomper/animator.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#pragma once
2+
#include <kvf/time.hpp>
3+
#include <le2d/drawable/shape.hpp>
4+
#include <le2d/random.hpp>
5+
#include <le2d/render_instance.hpp>
6+
7+
namespace chomper {
8+
class IAnimation : public klib::Polymorphic {
9+
public:
10+
virtual void tick(kvf::Seconds dt) = 0;
11+
virtual void draw(le::IRenderer& renderer) const = 0;
12+
};
13+
14+
class Animator {
15+
public:
16+
void play(std::unique_ptr<IAnimation> animation);
17+
18+
void tick(kvf::Seconds dt);
19+
20+
void draw(le::IRenderer& renderer) const;
21+
22+
private:
23+
std::vector<std::unique_ptr<IAnimation>> m_playing{};
24+
};
25+
} // namespace chomper

lib/include/chomper/player.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#pragma once
2+
#include "chomper/animator.hpp"
23
#include "chomper/controller.hpp"
34
#include "chomper/debug_inspector.hpp"
45
#include "chomper/snake.hpp"
@@ -66,5 +67,7 @@ class Player : public IController::IListener, public IDebugInspector, public kli
6667
// bool to decide wether to remove the tail, turn false if the snake has eaten
6768
bool m_shouldPop = true;
6869
bool m_graceMove{};
70+
71+
Animator m_animator{};
6972
};
7073
} // namespace chomper
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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

lib/src/animator.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include "chomper/animator.hpp"
2+
3+
namespace chomper {
4+
void Animator::play(std::unique_ptr<IAnimation> animation) {
5+
m_playing.emplace_back(std::move(animation));
6+
}
7+
8+
void Animator::tick(kvf::Seconds dt) {
9+
for (auto const& animation : m_playing) {
10+
animation->tick(dt);
11+
}
12+
}
13+
14+
void Animator::draw(le::IRenderer& renderer) const {
15+
for (auto const& animation : m_playing) {
16+
animation->draw(renderer);
17+
}
18+
}
19+
} // namespace chomper

lib/src/player.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "chomper/player.hpp"
2+
#include "chomper/animations/deathAnimation.hpp"
23
#include "chomper/controllers/player_controller.hpp"
34
#include "chomper/engine.hpp"
45
#include "chomper/world_size.hpp"
@@ -18,12 +19,13 @@ Player::Player(le::input::ScopedActionMapping& mapping, gsl::not_null<Engine con
1819
}
1920

2021
void Player::tick(kvf::Seconds dt) {
22+
m_animator.tick(dt);
23+
2124
if (!m_info.alive) {
2225
return;
2326
}
2427

2528
m_controller->tick(dt);
26-
2729
m_moveTimer += dt;
2830

2931
if (m_moveTimer >= moveSpeed_v) {
@@ -69,6 +71,7 @@ void Player::move() {
6971
if (isCollidingWithSelf(targetGrid) || isCollidingWithWall(targetGrid)) {
7072
if (m_graceMove) {
7173
m_info.alive = false;
74+
m_animator.play(std::make_unique<animation::DeathAnimation>(m_snake.getSegments()));
7275
} else {
7376
m_graceMove = true;
7477
}
@@ -96,7 +99,10 @@ void Player::updateScoreText() {
9699
}
97100

98101
void Player::draw(le::IRenderer& renderer) const {
99-
m_snake.draw(renderer);
102+
if (m_info.alive) {
103+
m_snake.draw(renderer);
104+
}
105+
m_animator.draw(renderer);
100106
m_scoreText.draw(renderer);
101107
}
102108

lib/src/runtimes/game.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include "chomper/runtimes/game.hpp"
22
#include "chomper/im_util.hpp"
3-
#include "chomper/runtimes/entrypoint.hpp"
43
#include "chomper/world_space.hpp"
54
#include <le2d/random.hpp>
65
#include <algorithm>
@@ -40,7 +39,7 @@ void Game::tick(kvf::Seconds const dt) {
4039

4140
// On death
4241
if (!m_player->getInfo().alive) {
43-
m_engine->setNextRuntime<runtime::Entrypoint>();
42+
// m_engine->setNextRuntime<runtime::Entrypoint>();
4443
}
4544
}
4645

0 commit comments

Comments
 (0)