From fb9cebd8ffee8979b2c81c9b26aab657bee78679 Mon Sep 17 00:00:00 2001 From: Noel Berry Date: Sun, 3 Jan 2021 14:08:22 -0800 Subject: [PATCH] room transition + attack anim --- content/map/0x0.png | Bin 129 -> 168 bytes content/map/1x0.png | Bin 0 -> 130 bytes content/sprites/player.ase | Bin 980 -> 1735 bytes content/tilesets/castle.ase | Bin 634 -> 635 bytes content/tilesets/grass.ase | Bin 0 -> 697 bytes content/tilesets/plants.ase | Bin 0 -> 609 bytes src/assets/sprite.cpp | 11 ++++ src/assets/sprite.h | 10 +++ src/components/animator.cpp | 16 ++++- src/components/animator.h | 4 +- src/components/player.cpp | 128 +++++++++++++++++++++++++----------- src/components/player.h | 8 ++- src/components/tilemap.cpp | 2 + src/game.cpp | 118 ++++++++++++++++++++++++++++++--- src/game.h | 6 ++ 15 files changed, 249 insertions(+), 54 deletions(-) create mode 100644 content/map/1x0.png create mode 100644 content/tilesets/grass.ase create mode 100644 content/tilesets/plants.ase diff --git a/content/map/0x0.png b/content/map/0x0.png index fa32c71b7e20fe7e09bffd0985e0763ad7a62ab1..bfdb1adcbc5be7255a96e30d718c9e91eea59618 100644 GIT binary patch delta 126 zcmV-^0D=F30jL3xF?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<$g30VO%>V!Z delta 87 zcmZ3%*vL4+Fu>Z=#WBRAGx^W||NraT7#Vz+6JMU#GGk(6W1>l)yRKZE*ye!K3PIcs rlWOK{J>Q^m_#@-7i<_#hBt-s3Hb2nXAt5Q5nPuo{ckWiYgK4*<`{`GK c-I=Tm4RO4MdnTUg1)9U)>FVdQ&MBb@01redQ~&?~ literal 0 HcmV?d00001 diff --git a/content/sprites/player.ase b/content/sprites/player.ase index 2ebbb89df08f8e0749822585909b6a7680b9ad8a..15baa48dc6c5a1c93b1962f9fc32390294dce3c5 100644 GIT binary patch delta 784 zcmcb@ew>&4I2!}QgQXk{8Vni}xl0-MZEWmdWY1+_V31H?nJmDh;LFUw0^}h9W`?5D zJZ1)FBq1P^g(0gnw}6#_9aWf(A+e++F*!RJD6FKwG})Xi$Q_M>HB~Cy$hVD*k(H((wlZ!(r|*&DZ!wHb1t6C z?>_g$VZHD(>AIH+v(H9-RgEp&Fnzl0673Y%eFgKs?zvO`*0n5m?*Y5(w;%ZSHQ3AY z%8SQLtt#To;xfy#Jeb_8sGUKbNTe*N(2?i!YkFLHcXg z?YX)C;-zkLKa?|@!pUC<*Qfv$Ry^3hp67izsNba{{N4#2~?nnXBAa|4iF{V32 zVSxg2hZ8VR)~%i-vPE>ZxLJIFtB#bxi=9#$U-WiVt~c!tO^VaYz$nJudu{SwqurH2C*ZVD}glUM3P+-!q*6 delta 107 zcmV-x0F?jx1o{L4dXWKt0s66lhyej{lL`VGRr~)R6EH9^U=hU>N9N_1A1v`dn8IWv N$q#h=0|3Oi!-LhpEdBrh diff --git a/content/tilesets/grass.ase b/content/tilesets/grass.ase new file mode 100644 index 0000000000000000000000000000000000000000..9c5c998d2ed51d2af2a10d41faf9d3984f6ed5a7 GIT binary patch literal 697 zcmcJN-Aj{E9DtA3*a$DWFtIdts3mm#sVKhSfu*A6!S_*B@Zm)-0c?&G_ zEx?LS1>F-L;P~7cRE!Xv14HnV{|c<~df~~^64+1_fcGpG7;{y?ndUGI-YkZJ3!3tB zfvx)YF4=GiZa_Zmgi}p2y~I*VCXEDAM;cv3QACd3q7)S*;75)bElz~kP?>d;+yeg& z3Bo9jooPB-Cvyh*V2~TH6hF$w=zojG+XE*KZ+oJdR$Qx7rynYxmX#X4Ras!_J=YpN z@@#im=FE>5-&~GJe@%ET9*L)P-=ALmb-;YN|8?{G6~o@@>DpHz+tD{ecgG&tbDf8l zCa*s4Sl)55eyr6PJ^#|*{`Rx~lnU?aiDe%A9%=g&=u3A$=qeia{LY_9P3gNf;&^QB V2`#yA1ZOjv+T!B@qjk_yybkC**>(T` literal 0 HcmV?d00001 diff --git a/content/tilesets/plants.ase b/content/tilesets/plants.ase new file mode 100644 index 0000000000000000000000000000000000000000..53ac4649e84e58fae00b6dab6480607dff9b42e0 GIT binary patch literal 609 zcmb`F&nv@W9LGPijh!WOu_q+A{YbPZHMy9Bs3FSqwPj005~&rDT4@(0Cb@{h!AUuY zIFQ_waIhaZDvo}Ay*6ZjfKNTIKF{Z==ly!VeS336;_C)cVqqCXq>uGi%+f=NAm`fSdmnz^@-m8UY1St&R4#Y+85tXU_SRu?H%Rj{$L4hCEf81>e|yWt9Wy%vB^ z$II~Tr5Y|hw7}4T9o8%iLQl{JTRr8_S?7ZF^`p@4n}%J338=+%*mH3Y&u`zMPKm^J z_TWr-4hBOZ*y(MBW9|stb~@p8y9Tc&_hEFg2}XwOdWZ*@(%)Ut@CaUjKJJKPjWWK- zVu~h?2x5mCUPxhtPTED+u|R=*!bv8UOae(G%9>76M)+GONS-wJPWVTZql1lE2`V|F z^HY3RiR8-oism~sJ+{4krc#>mWbHKco}9KN1MbIsXRQ0f=(jbm77Pyr%C=^A S&*mEjk~5c6{jwJC34Q^16Q`2^ literal 0 HcmV?d00001 diff --git a/src/assets/sprite.cpp b/src/assets/sprite.cpp index e69de29..6f76a13 100644 --- a/src/assets/sprite.cpp +++ b/src/assets/sprite.cpp @@ -0,0 +1,11 @@ +#include "sprite.h" + +using namespace TL; + +const Sprite::Animation* TL::Sprite::get_animation(const String& name) const +{ + for (auto& it : animations) + if (it.name == name) + return ⁢ + return nullptr; +} diff --git a/src/assets/sprite.h b/src/assets/sprite.h index e9c4e75..6ebd967 100644 --- a/src/assets/sprite.h +++ b/src/assets/sprite.h @@ -17,10 +17,20 @@ namespace TL { String name; Vector frames; + + float duration() const + { + float d = 0; + for (auto& it : frames) + d += it.duration; + return d; + } }; String name; Vec2 origin; Vector animations; + + const Animation* get_animation(const String& name) const; }; } \ No newline at end of file diff --git a/src/components/animator.cpp b/src/components/animator.cpp index 92f198a..ba2386b 100644 --- a/src/components/animator.cpp +++ b/src/components/animator.cpp @@ -9,7 +9,12 @@ Animator::Animator(const String& sprite) m_animation_index = 0; } -void Animator::play(const String& animation) +const Sprite* Animator::sprite() const +{ + return m_sprite; +} + +void Animator::play(const String& animation, bool restart) { BLAH_ASSERT(m_sprite, "No Sprite Assigned!"); @@ -17,8 +22,13 @@ void Animator::play(const String& animation) { if (m_sprite->animations[i].name == animation) { - m_animation_index = i; - m_frame_index = 0; + if (m_animation_index != i || restart) + { + m_animation_index = i; + m_frame_index = 0; + m_frame_counter = 0; + } + break; } } diff --git a/src/components/animator.h b/src/components/animator.h index c0515d3..007a34d 100644 --- a/src/components/animator.h +++ b/src/components/animator.h @@ -21,8 +21,8 @@ namespace TL Animator() = default; Animator(const String& sprite); - void play(const String& animation); - + const Sprite* sprite() const; + void play(const String& animation, bool restart = false); void update() override; void render(Batch& batch) override; diff --git a/src/components/player.cpp b/src/components/player.cpp index b460e12..2bfe552 100644 --- a/src/components/player.cpp +++ b/src/components/player.cpp @@ -27,12 +27,18 @@ Player::Player() .press_buffer(0.15f) .add_key(Key::X) .add_button(0, Button::A); + + input_attack = VirtualButton() + .press_buffer(0.15f) + .add_key(Key::C) + .add_button(0, Button::X); } void Player::update() { input_move.update(); input_jump.update(); + input_attack.update(); auto mover = get(); auto anim = get(); @@ -44,37 +50,99 @@ void Player::update() { // land squish if (!was_on_ground && m_on_ground) - anim->scale = Vec2(facing * 1.5f, 0.7f); + anim->scale = Vec2(m_facing * 1.5f, 0.7f); // lerp scale back to one - anim->scale = Calc::approach(anim->scale, Vec2(facing, 1.0f), Time::delta * 4); + anim->scale = Calc::approach(anim->scale, Vec2(m_facing, 1.0f), Time::delta * 4); + + // set m_facing + anim->scale.x = Calc::abs(anim->scale.x) * m_facing; - // set facing - anim->scale.x = Calc::abs(anim->scale.x) * facing; } - // Horizontal Movement + // NORMAL STATE + if (m_state == st_normal) { - // Acceleration - mover->speed.x += input * (m_on_ground ? ground_accel : air_accel) * Time::delta; - - // Maxspeed - auto maxspd = (m_on_ground ? max_ground_speed : max_air_speed); - if (Calc::abs(mover->speed.x) > maxspd) + // Current Animation + if (m_on_ground) { - mover->speed.x = Calc::approach( - mover->speed.x, - Calc::sign(mover->speed.x) * maxspd, - 2000 * Time::delta); + if (input != 0) + anim->play("run"); + else + anim->play("idle"); + } + else + { + anim->play("jump"); } - // Friction - if (input == 0 && m_on_ground) - mover->speed.x = Calc::approach(mover->speed.x, 0, friction * Time::delta); + // Horizontal Movement + { + // Acceleration + mover->speed.x += input * (m_on_ground ? ground_accel : air_accel) * Time::delta; - // Facing Direction - if (input != 0 && m_on_ground) - facing = input; + // Maxspeed + auto maxspd = (m_on_ground ? max_ground_speed : max_air_speed); + if (Calc::abs(mover->speed.x) > maxspd) + { + mover->speed.x = Calc::approach( + mover->speed.x, + Calc::sign(mover->speed.x) * maxspd, + 2000 * Time::delta); + } + + // Friction + if (input == 0 && m_on_ground) + mover->speed.x = Calc::approach(mover->speed.x, 0, friction * Time::delta); + + // Facing Direction + if (input != 0 && m_on_ground) + m_facing = input; + } + + // Invoke Jumping + { + if (input_jump.pressed() && mover->on_ground()) + { + input_jump.clear_press_buffer(); + anim->scale = Vec2(m_facing * 0.65f, 1.4f); + mover->speed.x = input * max_air_speed; + m_jump_timer = jump_time; + } + } + + // Begin Attack + if (input_attack.pressed()) + { + input_attack.clear_press_buffer(); + + m_state = st_attack; + m_attack_timer = anim->sprite()->get_animation("attack")->duration(); + + if (m_on_ground) + mover->speed.x = 0; + } + } + // ATTACK STATE + else if (m_state == st_attack) + { + anim->play("attack"); + m_attack_timer -= Time::delta; + + if (m_attack_timer <= 0) + { + anim->play("idle"); + m_state = st_normal; + } + } + + // Variable Jumping + if (m_jump_timer > 0) + { + mover->speed.y = -100; + m_jump_timer -= Time::delta; + if (!input_jump.down()) + m_jump_timer = 0; } // Gravity @@ -86,22 +154,4 @@ void Player::update() mover->speed.y += grav * Time::delta; } - - // Jumping - { - if (input_jump.pressed() && mover->on_ground()) - { - anim->scale = Vec2(facing * 0.65f, 1.4f); - mover->speed.x = input * max_air_speed; - m_jump_timer = jump_time; - } - - if (m_jump_timer > 0) - { - mover->speed.y = -100; - m_jump_timer -= Time::delta; - if (!input_jump.down()) - m_jump_timer = 0; - } - } } diff --git a/src/components/player.h b/src/components/player.h index c66bbd6..bcc3cc7 100644 --- a/src/components/player.h +++ b/src/components/player.h @@ -9,15 +9,21 @@ namespace TL class Player : public Component { public: + static constexpr int st_normal = 0; + static constexpr int st_attack = 1; + VirtualStick input_move; VirtualButton input_jump; + VirtualButton input_attack; Player(); void update() override; private: - int facing = 1; + int m_state = st_normal; + int m_facing = 1; float m_jump_timer = 0; + float m_attack_timer = 0; bool m_on_ground; }; } \ No newline at end of file diff --git a/src/components/tilemap.cpp b/src/components/tilemap.cpp index 276ab62..289410c 100644 --- a/src/components/tilemap.cpp +++ b/src/components/tilemap.cpp @@ -52,10 +52,12 @@ void Tilemap::set_cells(int x, int y, int w, int h, const Subtexture* tex) void Tilemap::render(Batch& batch) { + batch.push_matrix(Mat3x2::create_translation(entity()->position)); for (int x = 0; x < m_columns; x ++) for (int y = 0; y < m_rows; y ++) if (m_grid[x + y * m_columns].texture) { batch.tex(m_grid[x + y * m_columns], Vec2(x * m_tile_width, y * m_tile_height)); } + batch.pop_matrix(); } diff --git a/src/game.cpp b/src/game.cpp index 83a676c..71d35cb 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -4,10 +4,16 @@ #include "assets/tileset.h" #include "components/collider.h" #include "components/tilemap.h" +#include "components/player.h" #include "factory.h" using namespace TL; +namespace +{ + constexpr float transition_duration = 0.75f; +} + void Game::startup() { // load our content @@ -21,6 +27,8 @@ void Game::startup() m_draw_colliders = false; + // camera setup + camera = Vec2::zero; load_room(Point(0, 0)); } @@ -30,14 +38,16 @@ void Game::load_room(Point cell) BLAH_ASSERT(grid, "Room doesn't exist!"); room = cell; - // destroy all the entities - world.clear(); + // get room offset + auto offset = Point(cell.x * width, cell.y * height); // get the castle tileset for now auto castle = Content::find_tileset("castle"); + auto grass = Content::find_tileset("grass"); + auto plants = Content::find_tileset("plants"); // make the floor - auto floor = world.add_entity(); + auto floor = world.add_entity(offset); auto tilemap = floor->add(Tilemap(8, 8, columns, rows)); auto solids = floor->add(Collider::make_grid(8, 40, 23)); solids->mask = Mask::solid; @@ -46,6 +56,7 @@ void Game::load_room(Point cell) for (int x = 0; x < columns; x ++) for (int y = 0; y < rows; y++) { + Point world_position = offset + Point(x * tile_width, y * tile_height); Color col = grid->pixels[x + y * columns]; uint32_t rgb = ((uint32_t)col.r << 16) | @@ -58,15 +69,27 @@ void Game::load_room(Point cell) case 0x000000: break; - // solids + // castle tiles case 0xffffff: tilemap->set_cell(x, y, &castle->random_tile()); solids->set_cell(x, y, true); break; - // player + // grass tiles + case 0x8f974a: + tilemap->set_cell(x, y, &grass->random_tile()); + solids->set_cell(x, y, true); + break; + + // plants tiles + case 0x4b692f: + tilemap->set_cell(x, y, &plants->random_tile()); + break; + + // player (only if it doesn't already exist) case 0x6abe30: - Factory::player(&world, Point(x * tile_width + tile_width / 2, (y + 1) * tile_height)); + if (!world.first()) + Factory::player(&world, world_position + Point(tile_width / 2, tile_height)); break; } } @@ -79,12 +102,87 @@ void Game::shutdown() void Game::update() { + // Toggle Collider Render if (Input::pressed(Key::F1)) m_draw_colliders = !m_draw_colliders; - if (Input::pressed(Key::F2)) - load_room(room); - world.update(); + // Reload Current Room + if (Input::pressed(Key::F2)) + { + m_transition = false; + world.clear(); + load_room(room); + } + + // Normal Update + if (!m_transition) + { + world.update(); + + auto player = world.first(); + if (player) + { + auto pos = player->entity()->position; + auto bounds = RectI(room.x * width, room.y * height, width, height); + if (!bounds.contains(pos)) + { + // target room + Point next_room = Point(pos.x / width, pos.y / height); + if (pos.x < 0) next_room.x--; + if (pos.y < 0) next_room.y--; + + // see if room exists + if (Content::find_room(next_room)) + { + // transiton to it! + m_transition = true; + m_next_ease = 0; + m_next_room = next_room; + m_last_room = room; + + // store entities from the previous room + m_last_entities.clear(); + Entity* e = world.first_entity(); + while (e) + { + m_last_entities.push_back(e); + e = e->next(); + } + + // load contents of the next room + load_room(next_room); + } + // doesn't exist, clamp player + else + { + player->entity()->position = Point( + Calc::clamp_int(pos.x, bounds.x, bounds.x + bounds.w), + Calc::clamp_int(pos.y, bounds.y, bounds.y + bounds.h)); + } + } + } + } + // Room Transition routine + else + { + 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); + camera = last_cam + (next_cam - last_cam) * Ease::cube_in_out(m_next_ease); + + if (m_next_ease >= 1.0f) + { + // delete old objects (except player!) + for (auto& it : m_last_entities) + { + if (!it->get()) + world.destroy_entity(it); + } + + m_transition = false; + } + } } void Game::render() @@ -93,6 +191,7 @@ void Game::render() { buffer->clear(0x150e22); + batch.push_matrix(Mat3x2::create_translation(-camera)); world.render(batch); if (m_draw_colliders) @@ -105,6 +204,7 @@ void Game::render() } } + batch.pop_matrix(); batch.render(buffer); batch.clear(); } diff --git a/src/game.h b/src/game.h index af06765..6df38a2 100644 --- a/src/game.h +++ b/src/game.h @@ -20,6 +20,7 @@ namespace TL FrameBufferRef buffer; Batch batch; Point room; + Vec2 camera; void load_room(Point cell); void startup(); @@ -29,5 +30,10 @@ namespace TL private: bool m_draw_colliders; + bool m_transition = false; + float m_next_ease; + Point m_next_room; + Point m_last_room; + Vector m_last_entities; }; } \ No newline at end of file