From 033358749fad7d23989d979b54fd021fc4bd3e95 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Sat, 1 Mar 2025 00:24:19 -0500 Subject: [PATCH] Animations now have an easing/ease_rate setting that will do a dynamic scaling effect on them during the animation sequence. --- assets/config.json | 2 +- assets/enemies.json | 12 ++++++------ components.cpp | 26 ++++++++++++++++++++++---- components.hpp | 4 ++++ dbc.hpp | 2 +- easings.hpp | 4 ++++ main.cpp | 2 +- raycaster.cpp | 4 +++- 8 files changed, 42 insertions(+), 14 deletions(-) diff --git a/assets/config.json b/assets/config.json index 1774494..7198d07 100644 --- a/assets/config.json +++ b/assets/config.json @@ -53,7 +53,7 @@ "player": { }, "worldgen": { - "enemy_probability": 50, + "enemy_probability": 80, "empty_room_probability": 10, "device_probability": 10 } diff --git a/assets/enemies.json b/assets/enemies.json index 02ff373..6a4167f 100644 --- a/assets/enemies.json +++ b/assets/enemies.json @@ -20,7 +20,7 @@ {"_type": "Combat", "hp": 20, "max_hp": 20, "damage": 1, "dead": false}, {"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "EnemyConfig", "hearing_distance": 5}, - {"_type": "Animation", "scale": 0.1, "simple": true, "frames": 10, "speed": 0.3}, + {"_type": "Animation", "easing": 1, "ease_rate": 0.2, "scale": 0.1, "simple": true, "frames": 10, "speed": 0.3}, {"_type": "Sprite", "name": "armored_knight"}, {"_type": "Sound", "attack": "Sword_Hit_2", "death": "Humanoid_Death_1"} ] @@ -35,7 +35,7 @@ {"_type": "Motion", "dx": 0, "dy": 0, "random": true}, {"_type": "EnemyConfig", "hearing_distance": 5}, {"_type": "Sprite", "name": "axe_ranger"}, - {"_type": "Animation", "scale": 0.1, "simple": false, "frames": 10, "speed": 0.6}, + {"_type": "Animation", "easing": 3, "ease_rate": 0.5, "scale": 0.1, "simple": false, "frames": 10, "speed": 0.6}, {"_type": "Sound", "attack": "Sword_Hit_2", "death": "Ranger_1"} ] }, @@ -49,7 +49,7 @@ {"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "EnemyConfig", "hearing_distance": 5}, {"_type": "Sprite", "name": "evil_eye"}, - {"_type": "Animation", "scale": 0.1, "simple": false, "frames": 10, "speed": 0.3}, + {"_type": "Animation", "easing": 3, "ease_rate": 0.1, "scale": 0.1, "simple": false, "frames": 10, "speed": 0.3}, {"_type": "Sound", "attack": "Evil_Eye_Sound_2", "death": "Evil_Eye_Sound_1"} ] }, @@ -62,7 +62,7 @@ {"_type": "Combat", "hp": 20, "max_hp": 20, "damage": 20, "dead": false}, {"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "EnemyConfig", "hearing_distance": 10}, - {"_type": "Animation", "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0}, + {"_type": "Animation", "easing": 3, "ease_rate": 0.5, "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0}, {"_type": "Sprite", "name": "rat_with_sword"}, {"_type": "Sound", "attack": "Small_Rat", "death": "Creature_Death_1"} ] @@ -76,7 +76,7 @@ {"_type": "Combat", "hp": 50, "max_hp": 50, "damage": 50, "dead": false}, {"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "EnemyConfig", "hearing_distance": 3}, - {"_type": "Animation", "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0}, + {"_type": "Animation", "easing": 2, "ease_rate": 0.2, "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0}, {"_type": "Sprite", "name": "rat_king"}, {"_type": "Sound", "attack": "Medium_Rat", "death": "Creature_Death_1"} ] @@ -90,7 +90,7 @@ {"_type": "Combat", "hp": 20, "max_hp": 20, "damage": 20, "dead": false}, {"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "EnemyConfig", "hearing_distance": 10}, - {"_type": "Animation", "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0}, + {"_type": "Animation", "easing": 2, "ease_rate": 0.5, "scale": 0.1, "simple": true, "frames": 10, "speed": 1.0}, {"_type": "Sprite", "name": "hairy_spider"}, {"_type": "Sound", "attack": "Spider_1", "death": "Spider_2"} ] diff --git a/components.cpp b/components.cpp index e293823..6e8fab1 100644 --- a/components.cpp +++ b/components.cpp @@ -1,5 +1,6 @@ #include "components.hpp" #include "point.hpp" +#include "easings.hpp" namespace components { ENROLL_COMPONENT(Position, location.x, location.y); @@ -7,7 +8,7 @@ namespace components { ENROLL_COMPONENT(Motion, dx, dy, random); ENROLL_COMPONENT(Combat, hp, max_hp, damage, dead); ENROLL_COMPONENT(Device, config, events); - ENROLL_COMPONENT(Animation, scale, simple, frames, speed); + ENROLL_COMPONENT(Animation, scale, simple, frames, speed, easing, ease_rate); ENROLL_COMPONENT(Sound, attack, death); void configure_entity(const ComponentMap& component_map, DinkyECS::World& world, DinkyECS::Entity ent, json& data) { @@ -41,11 +42,28 @@ namespace components { } } + float Animation::twitching() { + switch(easing) { + case ease::SINE: + return ease::sine(float(frames) / subframe * ease_rate); + case ease::OUT_CIRC: + return ease::sine(ease::out_circ(float(frames) / subframe * ease_rate)); + case ease::OUT_BOUNCE: + return ease::sine(ease::out_bounce(float(frames) / subframe * ease_rate)); + case ease::IN_OUT_BACK: + return ease::sine(ease::in_out_back(float(frames) / subframe * ease_rate)); + default: + dbc::sentinel( + fmt::format("Invalid easing {} given to animation", + int(easing))); + } + } + void Animation::step(sf::Vector2f& scale_out, sf::IntRect& rect_out) { if(playing && current < frames) { - scale_out.x += scale; - scale_out.y += scale; - + float tick = twitching(); + scale_out.x = std::lerp(scale_out.x, scale_out.x + scale, tick); + scale_out.y = std::lerp(scale_out.y, scale_out.y + scale, tick); if(!simple) { rect_out.position.x += current * TEXTURE_WIDTH; } diff --git a/components.hpp b/components.hpp index 2775315..4a21460 100644 --- a/components.hpp +++ b/components.hpp @@ -9,6 +9,7 @@ #include #include #include +#include "easings.hpp" #define ENROLL_COMPONENT(COMPONENT, ...) \ NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(COMPONENT, __VA_ARGS__); \ @@ -105,8 +106,11 @@ namespace components { int current = 0; bool playing = false; float subframe = 0; + ease::Style easing = ease::IN_OUT_BACK; + float ease_rate = 0.5f; void play(); + float twitching(); void step(sf::Vector2f& scale_out, sf::IntRect& rect_out); }; diff --git a/dbc.hpp b/dbc.hpp index 919d729..bb55122 100644 --- a/dbc.hpp +++ b/dbc.hpp @@ -20,7 +20,7 @@ namespace dbc { class PostCondError : public Error {}; void log(const string &message); - void sentinel(const string &message); + [[noreturn]] void sentinel(const string &message); void pre(const string &message, bool test); void pre(const string &message, std::function tester); void post(const string &message, bool test); diff --git a/easings.hpp b/easings.hpp index b17577c..6770b5d 100644 --- a/easings.hpp +++ b/easings.hpp @@ -3,6 +3,10 @@ namespace ease { + enum Style { + SINE, OUT_CIRC, OUT_BOUNCE, IN_OUT_BACK, NONE + }; + inline double sine(double x) { return (std::sin(x) + 1.0) / 2.0; } diff --git a/main.cpp b/main.cpp index d5aa686..89c047a 100644 --- a/main.cpp +++ b/main.cpp @@ -6,7 +6,7 @@ int main(int argc, char* argv[]) { textures::init(); sound::init(); - sound::mute(false); + sound::mute(true); gui::FSM main; main.event(gui::Event::STARTED); Autowalker walker(main); diff --git a/raycaster.cpp b/raycaster.cpp index 6b72f4d..bd59935 100644 --- a/raycaster.cpp +++ b/raycaster.cpp @@ -151,8 +151,9 @@ void Raycaster::sprite_casting(sf::RenderTarget &target) { int d = y * texture_height - $height * half_height + sprite_height * half_height; int tex_y = ((d * texture_height) / sprite_height) / texture_height; + sf::Vector2f origin{texture_width / 2, texture_height / 2}; sf::Vector2f scale{sprite_scale_w, sprite_scale_h}; - sf::Vector2f position{x, y}; + sf::Vector2f position{x + origin.x * scale.x, y + origin.y * scale.y}; sf::IntRect in_texture{ {tex_x, tex_y}, {tex_render_width, texture_height}}; if($level.world->has(rec.second)) { @@ -160,6 +161,7 @@ void Raycaster::sprite_casting(sf::RenderTarget &target) { if(animation.playing) animation.step(scale, in_texture); } + sf_sprite->setOrigin(origin); sf_sprite->setScale(scale); sf_sprite->setTextureRect(in_texture); sf_sprite->setPosition(position);