From fa949e1298d7dead882e46e6df2e9ac40f868469 Mon Sep 17 00:00:00 2001 From: Noel Berry Date: Sun, 3 Jan 2021 15:11:49 -0800 Subject: [PATCH] attack / hurt / bramble!! --- CMakeLists.txt | 2 +- content/map/0x0.png | Bin 168 -> 187 bytes content/sprites/bramble.ase | Bin 0 -> 743 bytes content/sprites/player.ase | Bin 1735 -> 1888 bytes content/sprites/pop.ase | Bin 0 -> 1242 bytes src/components/animator.cpp | 7 +++ src/components/animator.h | 2 + src/components/hurtable.cpp | 17 ++++++++ src/components/hurtable.h | 24 +++++++++++ src/components/player.cpp | 83 +++++++++++++++++++++++++++++++++--- src/components/player.h | 7 +++ src/components/timer.cpp | 26 +++++++++++ src/components/timer.h | 24 +++++++++++ src/factory.cpp | 44 +++++++++++++++++++ src/factory.h | 2 + src/game.cpp | 17 +++++++- src/masks.h | 2 + src/world.cpp | 5 +++ src/world.h | 2 + 19 files changed, 256 insertions(+), 8 deletions(-) create mode 100644 content/sprites/bramble.ase create mode 100644 content/sprites/pop.ase create mode 100644 src/components/hurtable.cpp create mode 100644 src/components/hurtable.h create mode 100644 src/components/timer.cpp create mode 100644 src/components/timer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0305e4b..18d94bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ add_executable(game src/masks.h src/factory.h src/factory.cpp - "src/assets/tileset.h" "src/assets/tileset.cpp" "src/components/tilemap.h" "src/components/tilemap.cpp") + "src/assets/tileset.h" "src/assets/tileset.cpp" "src/components/tilemap.h" "src/components/tilemap.cpp" "src/components/hurtable.h" "src/components/hurtable.cpp" "src/components/timer.h" "src/components/timer.cpp") # Reference blah target_link_libraries(game blah) diff --git a/content/map/0x0.png b/content/map/0x0.png index bfdb1adcbc5be7255a96e30d718c9e91eea59618..1642027036fd645b30078c160a615e6d38f57991 100644 GIT binary patch delta 146 zcmV;D0B!%M0lNW^F@JSQL_t(YiDP77VEE540Dx&AEFHCY)Z$T#hn~gPt9LP6uik|s z#>ha2lI#C}Oe>?4RyM(8mQC zTQS5Y%gbe@y9pNJUK|C}@01E&B07*qoM6N<$f))2a AD*ylh delta 126 zcmV-^0D=Fz0jL3xF?V7~L_t(YiDP77VEE540Dx&AEFHCY)Z$T#hlj;1^swarf6T%W zZn1Z!K8nQF=@&5+XYDg!nC5f=t`=DhHZg4G!T@9cbT5KsbwS2f46z9_ya{Q;3kG)_ gQ|dcxVB}>d04y*U=;#(+)&Kwi07*qoM6N<$g64QN2LJ#7 diff --git a/content/sprites/bramble.ase b/content/sprites/bramble.ase new file mode 100644 index 0000000000000000000000000000000000000000..d2a5dbce964f829c4227047a8155d88b1d1d68e5 GIT binary patch literal 743 zcmb`EPe>F|9LImUDi?_y$j@(-JE`TowvuirCvsm%mbzN0-4*}7J5H%ZYSbBc zp*{=~O+h%>br${@u7jDm1k9yg!hf3$aQb%#v_1!5Ef~1* z0A3&X1!FTB_AIZ$FW(DL(?n+8eS{D1k3-Y4;I*z!c>DYWd>abE%+(l7kA8xaQ>}1f zFrY0C;I_ZJqTmpm0DasM#~NjPk;N2E91+A0HN23*2p!u+Yb;P8pKy|iC6hqXi1OP> z$_0xJ1u^7e^j>^K1y3-kI`H9(TN&MA_V&jcscM{U{5Yo>a;4vl#Z_>3?hF;s?)ERW zM=xEeokz4DVOFMqxI`D~2 zKPyAiK3DURu~dGlyYGqNd3tiF@O~+h%q1exIk3qwX}QOV{q zra+eZCZPDQkBkf{K$;PVi-4F_fq{XCftTSw6OaQ2d<^^y6?2vbo#tau;P~{v{+6Gm zs$o=4Tmetb3|1MgoqT-`eHq2;UwHIAnp)a(+IWw{Mc#j@)9vfd%4OW$r1{f){gawA dRd?cMrvI9)7W`d4#QPV|Nt??;EOK%wU5t!!t^N^v`@RPw>tD~i=kr|N_nhzN_rA}lEFoVib`dpP6p>@k~U53ZePr=FwiB$81!_}1I=tKK|8x^po#xY z@Iu&EkXJ;5e!UZ5&xaL|MkA!CrV&g@x&wv?1fZ|CCm7?923DJyfg?UVa410pX5~49 zY2hZc00qc0@14Q~MW6!c!yV$VhBAC13sY#q5rVLT8oVF{Bj_+LGz|+VARpmKMl3QB zh%`j$FiDgQxY3|MgAih2I8Wa&t9$ocMjmwW0dzsAjP zoo^X_L!C3OQ=gd8Vhu{=cIt2kl(+-N+$ANB`HLzR=~PhAW=`kwBEB3(rZJ~@c~MHT zW=_*iWZvGE5rZ{Tmkh4Wx|E4Bi7T$@w^t+_wxh>$sn!}KY>^`vRl<=^#f`A^4M z8*=S!>*kA#i>u{jw|a@`z@5=R?hnO1YP$gf2l3PrJ zP0hJq>gzSE6}=4=1~eW^@OTtG`RRU>=y<2nnW^5H#Ba@4`)q}^J%i%u)Y;zav57)2 z)@r#E{km(oJ9S1cW1Gs2|Ej1G6{vLNxa@|?iDtUuiWiklKM3|JwT*t(5cs&xd(lXnUzV~!cYHTF$V=-QQdFAe6dE+eW(ED!D5=j0j~q`*TJ= 0 && m_animation_index < m_sprite->animations.size()) + return &m_sprite->animations[m_animation_index]; + return nullptr; +} + void Animator::play(const String& animation, bool restart) { BLAH_ASSERT(m_sprite, "No Sprite Assigned!"); diff --git a/src/components/animator.h b/src/components/animator.h index 007a34d..3e9aab8 100644 --- a/src/components/animator.h +++ b/src/components/animator.h @@ -22,6 +22,8 @@ namespace TL Animator(const String& sprite); const Sprite* sprite() const; + const Sprite::Animation* animation() const; + void play(const String& animation, bool restart = false); void update() override; void render(Batch& batch) override; diff --git a/src/components/hurtable.cpp b/src/components/hurtable.cpp new file mode 100644 index 0000000..21b219e --- /dev/null +++ b/src/components/hurtable.cpp @@ -0,0 +1,17 @@ +#include "hurtable.h" + +using namespace TL; + +void Hurtable::update() +{ + if (collider && on_hurt && m_cooldown_timer <= 0) + { + if (collider->check(hurt_by)) + { + m_cooldown_timer = cooldown; + on_hurt(this); + } + } + + m_cooldown_timer -= Time::delta; +} diff --git a/src/components/hurtable.h b/src/components/hurtable.h new file mode 100644 index 0000000..f4d477b --- /dev/null +++ b/src/components/hurtable.h @@ -0,0 +1,24 @@ +#pragma once +#include "../world.h" +#include "collider.h" +#include +#include + +using namespace Blah; + +namespace TL +{ + class Hurtable : public Component + { + private: + float m_cooldown_timer = 0; + + public: + Collider* collider = nullptr; + uint32_t hurt_by = 0; + float cooldown = 1.0f; + std::function on_hurt; + + void update() override; + }; +} \ No newline at end of file diff --git a/src/components/player.cpp b/src/components/player.cpp index 2bfe552..9ded4a1 100644 --- a/src/components/player.cpp +++ b/src/components/player.cpp @@ -1,6 +1,8 @@ #include "player.h" #include "mover.h" #include "animator.h" +#include "collider.h" +#include "../masks.h" using namespace TL; @@ -11,9 +13,12 @@ namespace constexpr float ground_accel = 500; constexpr float air_accel = 20; constexpr float friction = 800; + constexpr float hurt_friction = 200; constexpr float gravity = 450; constexpr float jump_force = -105; constexpr float jump_time = 0.18f; + constexpr float hurt_duration = 0.5f; + constexpr float invincible_duration = 1.5f; } Player::Player() @@ -42,6 +47,7 @@ void Player::update() auto mover = get(); auto anim = get(); + auto hitbox = get(); auto was_on_ground = m_on_ground; m_on_ground = mover->on_ground(); int input = input_move.value_i().x; @@ -57,7 +63,6 @@ void Player::update() // set m_facing anim->scale.x = Calc::abs(anim->scale.x) * m_facing; - } // NORMAL STATE @@ -117,7 +122,11 @@ void Player::update() input_attack.clear_press_buffer(); m_state = st_attack; - m_attack_timer = anim->sprite()->get_animation("attack")->duration(); + m_attack_timer = 0; + + if (!m_attack_collider) + m_attack_collider = entity()->add(Collider::make_rect(RectI())); + m_attack_collider->mask = Mask::player_attack; if (m_on_ground) mover->speed.x = 0; @@ -127,14 +136,47 @@ void Player::update() else if (m_state == st_attack) { anim->play("attack"); - m_attack_timer -= Time::delta; + m_attack_timer += Time::delta; - if (m_attack_timer <= 0) + // setup hitbox + if (m_attack_timer < 0.2f) + { + m_attack_collider->set_rect(RectI(-16, -12, 16, 8)); + } + else if (m_attack_timer < 0.5f) + { + m_attack_collider->set_rect(RectI(8, -8, 16, 8)); + } + else if (m_attack_collider) + { + m_attack_collider->destroy(); + m_attack_collider = nullptr; + } + + // flip hitbox if you're facing left + if (m_facing < 0 && m_attack_collider) + { + auto rect = m_attack_collider->get_rect(); + rect.x = -(rect.x + rect.w); + m_attack_collider->set_rect(rect); + } + + // end the attack + if (m_attack_timer >= anim->animation()->duration()) { anim->play("idle"); m_state = st_normal; } } + // HURT STATE + else if (m_state == st_hurt) + { + m_hurt_timer -= Time::delta; + if (m_hurt_timer <= 0) + m_state = st_normal; + + mover->speed.x = Calc::approach(mover->speed.x, 0, hurt_friction * Time::delta); + } // Variable Jumping if (m_jump_timer > 0) @@ -145,13 +187,44 @@ void Player::update() m_jump_timer = 0; } + // Invincible timer + if (m_state != st_hurt && m_invincible_timer > 0) + { + if (Time::on_interval(0.05f)) + anim->visible = !anim->visible; + + m_invincible_timer -= Time::delta; + if (m_invincible_timer <= 0) + anim->visible = true; + } + // Gravity if (!m_on_ground) { float grav = gravity; - if (Calc::abs(mover->speed.y) < 20 && input_jump.down()) + if (m_state == st_normal && Calc::abs(mover->speed.y) < 20 && input_jump.down()) grav *= 0.4f; mover->speed.y += grav * Time::delta; } + + // Hurt Check! + if (m_invincible_timer <= 0 && hitbox->check(Mask::enemy)) + { + Time::pause_for(0.1f); + anim->play("hurt"); + + if (m_attack_collider) + { + m_attack_collider->destroy(); + m_attack_collider = nullptr; + } + + mover->speed = Vec2(-m_facing * 100, -80); + + health--; + m_hurt_timer = hurt_duration; + m_invincible_timer = invincible_duration; + m_state = st_hurt; + } } diff --git a/src/components/player.h b/src/components/player.h index bcc3cc7..9a072da 100644 --- a/src/components/player.h +++ b/src/components/player.h @@ -6,11 +6,15 @@ using namespace Blah; namespace TL { + class Collider; class Player : public Component { public: static constexpr int st_normal = 0; static constexpr int st_attack = 1; + static constexpr int st_hurt = 2; + + int health = 3; VirtualStick input_move; VirtualButton input_jump; @@ -24,6 +28,9 @@ namespace TL int m_facing = 1; float m_jump_timer = 0; float m_attack_timer = 0; + float m_hurt_timer = 0; + float m_invincible_timer = 0; + Collider* m_attack_collider = nullptr; bool m_on_ground; }; } \ No newline at end of file diff --git a/src/components/timer.cpp b/src/components/timer.cpp new file mode 100644 index 0000000..b8e7748 --- /dev/null +++ b/src/components/timer.cpp @@ -0,0 +1,26 @@ +#include "timer.h" + +using namespace TL; + +Timer::Timer(float duration, const std::function& on_end) + : m_duration(duration), on_end(on_end) +{ + +} + +void Timer::start(float duration) +{ + m_duration = duration; +} + +void Timer::update() +{ + if (m_duration > 0) + { + m_duration -= Time::delta; + if (m_duration <= 0 && on_end) + { + on_end(this); + } + } +} diff --git a/src/components/timer.h b/src/components/timer.h new file mode 100644 index 0000000..09de587 --- /dev/null +++ b/src/components/timer.h @@ -0,0 +1,24 @@ +#pragma once +#include "../world.h" +#include +#include + +using namespace Blah; + +namespace TL +{ + class Timer : public Component + { + private: + float m_duration = 0; + + public: + Timer() = default; + Timer(float duration, const std::function& on_end = nullptr); + + void start(float duration); + std::function on_end; + + void update() override; + }; +} \ No newline at end of file diff --git a/src/factory.cpp b/src/factory.cpp index 3b609b3..edfa36d 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -1,8 +1,11 @@ #include "factory.h" +#include "masks.h" #include "components/animator.h" #include "components/collider.h" #include "components/mover.h" #include "components/player.h" +#include "components/hurtable.h" +#include "components/timer.h" using namespace TL; @@ -22,3 +25,44 @@ Entity* Factory::player(World* world, Point position) en->add(Player()); return en; } + +Entity* Factory::bramble(World* world, Point position) +{ + auto en = world->add_entity(position); + + auto anim = en->add(Animator("bramble")); + anim->play("idle"); + anim->depth = -5; + + auto hitbox = en->add(Collider::make_rect(RectI(-4, -8, 8, 8))); + hitbox->mask = Mask::enemy; + + auto hurtable = en->add(Hurtable()); + hurtable->hurt_by = Mask::player_attack; + hurtable->collider = hitbox; + hurtable->on_hurt = [](Hurtable* self) + { + Time::pause_for(0.1f); + pop(self->world(), self->entity()->position + Point(0, -4)); + self->entity()->destroy(); + }; + + return en; +} + +Entity* Factory::pop(World* world, Point position) +{ + auto en = world->add_entity(position); + + auto anim = en->add(Animator("pop")); + anim->play("pop"); + anim->depth = -20; + + auto timer = en->add(Timer(anim->animation()->duration(), [](Timer* self) + { + self->entity()->destroy(); + })); + + return en; +} + diff --git a/src/factory.h b/src/factory.h index 3236eb1..72334aa 100644 --- a/src/factory.h +++ b/src/factory.h @@ -9,5 +9,7 @@ namespace TL namespace Factory { Entity* player(World* world, Point position); + Entity* bramble(World* world, Point position); + Entity* pop(World* world, Point position); } } \ No newline at end of file diff --git a/src/game.cpp b/src/game.cpp index 71d35cb..9094d32 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -11,7 +11,7 @@ using namespace TL; namespace { - constexpr float transition_duration = 0.75f; + constexpr float transition_duration = 0.4f; } void Game::startup() @@ -91,6 +91,11 @@ void Game::load_room(Point cell) if (!world.first()) Factory::player(&world, world_position + Point(tile_width / 2, tile_height)); break; + + // brambles + case 0xd77bba: + Factory::bramble(&world, world_position + Point(tile_width / 2, tile_height)); + break; } } } @@ -134,6 +139,8 @@ void Game::update() // see if room exists if (Content::find_room(next_room)) { + Time::pause_for(0.1f); + // transiton to it! m_transition = true; m_next_ease = 0; @@ -165,12 +172,17 @@ void Game::update() // Room Transition routine else { + // increment ease + m_next_ease = Calc::approach(m_next_ease, 1.0f, Time::delta / transition_duration); + + // get last & next camera position auto last_cam = Vec2(m_last_room.x * width, m_last_room.y * height); auto next_cam = Vec2(m_next_room.x * width, m_next_room.y * height); - m_next_ease = Calc::approach(m_next_ease, 1.0f, Time::delta / transition_duration); + // LERP camera position camera = last_cam + (next_cam - last_cam) * Ease::cube_in_out(m_next_ease); + // Finish Transition if (m_next_ease >= 1.0f) { // delete old objects (except player!) @@ -180,6 +192,7 @@ void Game::update() world.destroy_entity(it); } + Time::pause_for(0.1f); m_transition = false; } } diff --git a/src/masks.h b/src/masks.h index 47d43af..c59480b 100644 --- a/src/masks.h +++ b/src/masks.h @@ -6,5 +6,7 @@ namespace TL struct Mask { static constexpr uint32_t solid = 1 << 0; + static constexpr uint32_t player_attack = 1 << 1; + static constexpr uint32_t enemy = 1 << 2; }; } \ No newline at end of file diff --git a/src/world.cpp b/src/world.cpp index f6b4854..43076a5 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -97,6 +97,11 @@ Blah::Vector& Entity::components() return m_components; } +void Entity::destroy() +{ + m_world->destroy_entity(this); +} + const Blah::Vector& Entity::components() const { return m_components; diff --git a/src/world.h b/src/world.h index 2252a1e..f80fa6e 100644 --- a/src/world.h +++ b/src/world.h @@ -95,6 +95,8 @@ namespace TL Blah::Vector& components(); const Blah::Vector& components() const; + + void destroy(); private: Blah::Vector m_components;