Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions lib/include/chomper/animations/deathAnimation.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "chomper/animator.hpp"

namespace chomper::animation {
class DeathAnimation : public chomper::IAnimation {
public:
DeathAnimation(std::span<le::RenderInstance const> instances);
void tick(kvf::Seconds dt) final;
void draw(le::IRenderer& renderer) const final;

private:
struct Segment {
float remaining{};
float lifetime{};
float rotSpeed{};
glm::vec2 velocity{};
le::drawable::Quad quad{};
Comment thread
stanplayzz marked this conversation as resolved.
Outdated
};

std::vector<Segment> m_segments{};

le::Random m_random{};
};
} // namespace chomper::animation
25 changes: 25 additions & 0 deletions lib/include/chomper/animator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once
#include <kvf/time.hpp>
#include <le2d/drawable/shape.hpp>
#include <le2d/random.hpp>
#include <le2d/render_instance.hpp>

namespace chomper {
class IAnimation : public klib::Polymorphic {
public:
virtual void tick(kvf::Seconds dt) = 0;
virtual void draw(le::IRenderer& renderer) const = 0;
};

class Animator {
public:
void play(std::unique_ptr<IAnimation> animation);

void tick(kvf::Seconds dt);

void draw(le::IRenderer& renderer) const;

private:
std::vector<std::unique_ptr<IAnimation>> m_playing{};
};
} // namespace chomper
3 changes: 3 additions & 0 deletions lib/include/chomper/player.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include "chomper/animator.hpp"
#include "chomper/controller.hpp"
#include "chomper/debug_inspector.hpp"
#include "chomper/snake.hpp"
Expand Down Expand Up @@ -66,5 +67,7 @@ class Player : public IController::IListener, public IDebugInspector, public kli
// bool to decide wether to remove the tail, turn false if the snake has eaten
bool m_shouldPop = true;
bool m_graceMove{};

Animator m_animator{};
};
} // namespace chomper
75 changes: 75 additions & 0 deletions lib/src/animations/deathAnimation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include "chomper/animations/deathAnimation.hpp"
#include "chomper/world_space.hpp"
#include <numbers>

namespace chomper::animation {
namespace {
constexpr auto easeOut(float t) {
return 1.f - ((1.f - t) * (1.f - t));
}
} // namespace

DeathAnimation::DeathAnimation(std::span<le::RenderInstance const> instances) {
m_segments.clear();
m_segments.reserve(instances.size());

for (auto const& instance : instances) {
auto dir = m_random.next_float(0, 360);
auto lifetime = m_random.next_float(2, 5);
auto speed = m_random.next_float(300, 600);
auto rotSpeed = m_random.next_float(5.f, 20.f);

auto rad = dir * std::numbers::pi_v<float> / 180.f;

Segment seg;
seg.rotSpeed = rotSpeed;
seg.velocity = {std::cos(rad) * speed, std::sin(rad) * speed};
seg.remaining = lifetime;
seg.lifetime = lifetime;
seg.quad.create(tileSize_v);
seg.quad.tint = instance.tint;
seg.quad.transform = instance.transform;
m_segments.push_back(seg);
}
}
void DeathAnimation::tick(kvf::Seconds dt) {
for (auto& seg : m_segments) {
if (seg.remaining <= 0.f) {
continue;
}

seg.remaining -= dt.count();

auto t = std::clamp(1.f - (seg.remaining / seg.lifetime), 0.f, 1.f);

auto eased = 1.f - easeOut(t);

seg.quad.transform.position += seg.velocity * eased * dt.count();
if (worldSpace::isOutOfBounds(worldSpace::worldToGrid(seg.quad.transform.position))) {
seg.velocity = -seg.velocity;
}

float angle = dt.count() * eased * seg.rotSpeed;
auto o = seg.quad.transform.orientation;
auto cos = std::cos(angle);
auto sin = std::sin(angle);
seg.quad.transform.orientation = {(o.x * cos) - (o.y * sin), (o.x * sin) + (o.y * cos)};
Comment thread
stanplayzz marked this conversation as resolved.
Outdated

float scale = 1.f;
if (t > 0.8f) {
float u = (t - 0.8f) / 0.2f; // 0 → 1
scale = 1.f - u; // 1 → 0
}
seg.quad.transform.scale = {scale, scale};
}
}

void DeathAnimation::draw(le::IRenderer& renderer) const {
for (auto const& segment : m_segments) {
if (segment.remaining > 0.f) {
segment.quad.draw(renderer);
}
}
}

} // namespace chomper::animation
19 changes: 19 additions & 0 deletions lib/src/animator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "chomper/animator.hpp"

namespace chomper {
void Animator::play(std::unique_ptr<IAnimation> animation) {
m_playing.emplace_back(std::move(animation));
}

void Animator::tick(kvf::Seconds dt) {
for (auto const& animation : m_playing) {
animation->tick(dt);
}
Comment thread
stanplayzz marked this conversation as resolved.
}

void Animator::draw(le::IRenderer& renderer) const {
for (auto const& animation : m_playing) {
animation->draw(renderer);
}
}
} // namespace chomper
10 changes: 8 additions & 2 deletions lib/src/player.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "chomper/player.hpp"
#include "chomper/animations/deathAnimation.hpp"
#include "chomper/controllers/player_controller.hpp"
#include "chomper/engine.hpp"
#include "chomper/world_size.hpp"
Expand All @@ -18,12 +19,13 @@ Player::Player(le::input::ScopedActionMapping& mapping, gsl::not_null<Engine con
}

void Player::tick(kvf::Seconds dt) {
m_animator.tick(dt);

if (!m_info.alive) {
return;
}

m_controller->tick(dt);

m_moveTimer += dt;

if (m_moveTimer >= moveSpeed_v) {
Expand Down Expand Up @@ -69,6 +71,7 @@ void Player::move() {
if (isCollidingWithSelf(targetGrid) || isCollidingWithWall(targetGrid)) {
if (m_graceMove) {
m_info.alive = false;
m_animator.play(std::make_unique<animation::DeathAnimation>(m_snake.getSegments()));
} else {
m_graceMove = true;
}
Expand Down Expand Up @@ -96,7 +99,10 @@ void Player::updateScoreText() {
}

void Player::draw(le::IRenderer& renderer) const {
m_snake.draw(renderer);
if (m_info.alive) {
m_snake.draw(renderer);
}
m_animator.draw(renderer);
m_scoreText.draw(renderer);
}

Expand Down
3 changes: 1 addition & 2 deletions lib/src/runtimes/game.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "chomper/runtimes/game.hpp"
#include "chomper/im_util.hpp"
#include "chomper/runtimes/entrypoint.hpp"
#include "chomper/world_space.hpp"
#include <le2d/random.hpp>
#include <algorithm>
Expand Down Expand Up @@ -40,7 +39,7 @@ void Game::tick(kvf::Seconds const dt) {

// On death
if (!m_player->getInfo().alive) {
m_engine->setNextRuntime<runtime::Entrypoint>();
// m_engine->setNextRuntime<runtime::Entrypoint>();
Comment thread
stanplayzz marked this conversation as resolved.
Outdated
}
}

Expand Down