diff --git a/mario/blocks/turtleblock.cpp b/mario/blocks/turtleblock.cpp new file mode 100644 index 0000000..bd5da67 --- /dev/null +++ b/mario/blocks/turtleblock.cpp @@ -0,0 +1,116 @@ +#include "turtleblock.hpp" +#include "../sprites.hpp" +#include "../global_vars.hpp" +#include "../objectids.hpp" +#include "../visitors/turtle_visitor.hpp" + +TurtleBlock::TurtleBlock(int x, int y, + std::shared_ptr &renderer) + : MarioBlock(x, y-1, renderer, g_enemies_texture, TURTLE_WALK_ANIM[0], + false, false) { + setSize({BLOCK_SIZE, 2*BLOCK_SIZE}); +#ifndef EDITOR + setAnimationFrames(TURTLE_WALK_ANIM); + setAnimationSpeed(12.5); + resumeAnimation(); +#endif + setId(TURTLE_ID); + auto bottom_detect = SDLPP::RectColider(0.2, 1, 0.6, 0, NPC_FLOOR_DETECT); + bottom_detect.setMinHeight(1); + addCollision(bottom_detect); + addCollision(SDLPP::RectColider(0, 0.5, 0.1, 0.35, NPC_LEFT_SIDE_DETECT)); + addCollision( + SDLPP::RectColider(0.9, 0.5, 0.1, 0.35, NPC_RIGHT_SIDE_DETECT)); + addCollision(std::make_shared(0, 0.25, 1, 0.15, + NPC_TOP_DETECT)); + setBouncable(false); +#ifndef EDITOR + setMovement(-0.19, 0); +#endif +} + +void TurtleBlock::move(int ticks) { +#ifndef EDITOR + if (wasVisible()) { + MarioBlock::move(ticks); + } +#else + MarioBlock::move(ticks); +#endif +} + +void TurtleBlock::custom_move(int ticks) { +#ifndef EDITOR + if (death_started) { + death_countdown -= ticks; + if (death_countdown <= 0) { + destroy(); + } + } else { + gravity(ticks); + } +#endif + MarioBlock::custom_move(ticks); +} + +void TurtleBlock::handleVisitor(SDLPP::Visitor &visitor) { +#ifndef EDITOR + switched_after_turtle = false; + auto &t_visitor = dynamic_cast(visitor); + setOnGround(t_visitor.isOnGround()); + if (isOnGround()) { + setPos(getPos().getX(), t_visitor.getGroundY() - BLOCK_SIZE*(isShell() ? 1 : 2)); + } + if ((!t_visitor.canGoLeft() && getMovement().getX() < 0) || + (!t_visitor.canGoRight() && getMovement().getX() > 0)) { + setPos(t_visitor.getValidXPos(), getPos().getY()); + setMovement(-getMovement().getX(), getMovement().getY()); + flipHorizontally(); + } + if (t_visitor.shouldBounce()) { + setMovement(getMovement().getX(), -0.5); + } + if (t_visitor.isDead()) { + if(!isShell()) { + setShell(); +// pauseAnimation(); + setAnimationFrames(TURTLE_SHELL_ANIM); + setAnimationSpeed(4); + next_movement = -2 * getMovement().getX(); + setMovement(0, 0); + setSize({BLOCK_SIZE, BLOCK_SIZE}); + setPos(getPos().getX(), getPos().getY() + BLOCK_SIZE); + } else { + if(getMovement().getX() == 0) { + resumeAnimation(); + setMovement(next_movement, 0); + } else { + pauseAnimation(); + next_movement = -next_movement; + setMovement(0, 0); + setTextureSourceRect(TURTLE_SHELL_ANIM[2]); + } + } + } + if (t_visitor.instantDeath()) { + destroy(); + } + if (t_visitor.switchMovement()) { + if (isShell()) { + switched_after_turtle = true; + if(getMovement().getX() == 0) { + setMovement(t_visitor.getNextMovement(), getMovement().getY()); + } else { + setMovement(-getMovement().getX(), getMovement().getY()); + } + setPos(t_visitor.getTurtleHitValidPos(), getPos().getY()); + } else { + destroy(); + } + } +#endif +} + +void TurtleBlock::startDeath() { + death_started = true; +} \ No newline at end of file diff --git a/mario/blocks/turtleblock.hpp b/mario/blocks/turtleblock.hpp new file mode 100644 index 0000000..f63c61c --- /dev/null +++ b/mario/blocks/turtleblock.hpp @@ -0,0 +1,35 @@ +#ifndef TURTLE_BLOCK_HPP +#define TURTLE_BLOCK_HPP + +#include "../blocks.hpp" + +class TurtleBlock : public MarioBlock { +public: + TurtleBlock(int x, int y, std::shared_ptr &renderer); + void custom_move(int ticks) override; + void move(int ticks) override; + void handleVisitor(SDLPP::Visitor &visitor) override; + bool isShell() const { + return is_shell; + } + void setShell(bool shell = true) { + is_shell = shell; + } + double getMovementAfterSwitch() const { + if(switched_after_turtle) { + return -getMovement().getX(); + } else { + return getMovement().getX(); + } + } + +private: + void startDeath(); + int death_countdown = 100; + bool death_started = false; + bool is_shell = false; + double next_movement = 0; + bool switched_after_turtle = false; +}; + +#endif diff --git a/mario/visitors/turtle_visitor.cpp b/mario/visitors/turtle_visitor.cpp new file mode 100644 index 0000000..ef4e848 --- /dev/null +++ b/mario/visitors/turtle_visitor.cpp @@ -0,0 +1,87 @@ +#include "turtle_visitor.hpp" +#include "../../sdlpp/sdlpp_renderobject.hpp" +#include "../objectids.hpp" +#include "../sprites.hpp" +#include "../mario.hpp" +#include "../blocks/turtleblock.hpp" + +void TurtleVisitor::visit(const SDLPP::RenderObject &obj) { + auto id = obj.getId(); + auto marioBlock = reinterpret_cast(obj); + switch (id) { + case FLOOR_ID: + case BRICK_ID: + case BRICK_TOP_ID: + if(marioBlock.isBouncing()) { + bounce = true; + instant_death = true; + return; + } + case PIPE_LEFT_BOTTOM_ID: + case PIPE_RIGHT_BOTTOM_ID: + case PIPE_LEFT_TOP_ID: + case PIPE_RIGHT_TOP_ID: + case STEP_ID: + case SIDEWAY_PIPE_END_TOP_ID: + case SIDEWAY_PIPE_END_BOTTOM_ID: + case SIDEWAY_PIPE_MIDDLE_BOTTOM_ID: + case SIDEWAY_PIPE_MIDDLE_TOP_ID: + case SIDEWAY_PIPE_CONNECTOR_BOTTOM_ID: + case SIDEWAY_PIPE_CONNECTOR_TOP_ID: + case TREE_PLATFORM_TOP_LEFT_ID: + case TREE_PLATFORM_TOP_RIGHT_ID: + case MUSHROOM_PLATFORM_TOP_MIDDLE_ID: + case MUSHROOM_PLATFORM_TOP_LEFT_ID: + case MUSHROOM_PLATFORM_TOP_RIGHT_ID: + case CANNON_TOWER_ID: + case CANNON_PEDESTAL_ID: + case CANNON_ID: + if (from == NPC_FLOOR_DETECT) { + onGround = true; + groundY = obj.getPos().getY(); + } else if (from == NPC_LEFT_SIDE_DETECT) { + if (!left && !right) { + movement_blockage = obj.getPos(); + validXPos = movement_blockage.getX() + BLOCK_SIZE; + } + left = true; + } else if (from == NPC_RIGHT_SIDE_DETECT) { + if (!left && !right) { + movement_blockage = obj.getPos(); + validXPos = movement_blockage.getX() - BLOCK_SIZE; + } + right = true; + } + break; + case DEATH_ID: + instant_death = true; + break; + case TURTLE_ID: + { + auto &turtle = dynamic_cast(obj); + if ((from == NPC_LEFT_SIDE_DETECT || from == NPC_RIGHT_SIDE_DETECT) && turtle.isShell()) { + switch_movement = true; + next_movement = turtle.getMovementAfterSwitch(); + if(from == NPC_LEFT_SIDE_DETECT) { + valid_turtle_hit_pos = obj.getPos().getX() + BLOCK_SIZE; + } else { + valid_turtle_hit_pos = obj.getPos().getX() - BLOCK_SIZE; + } + } + } + break; + case MARIO_ID: + { + auto &mario = dynamic_cast(obj); + if (from == NPC_TOP_DETECT && obj.getPos().getY() <= turtle_pos.getY() - 0.5*BLOCK_SIZE && !mario.isJumping()) { + death = true; + } + } + break; + case FIREBALL_ID: + instant_death = true; + break; + default: + break; + } +} diff --git a/mario/visitors/turtle_visitor.hpp b/mario/visitors/turtle_visitor.hpp new file mode 100644 index 0000000..a693d8d --- /dev/null +++ b/mario/visitors/turtle_visitor.hpp @@ -0,0 +1,86 @@ +#ifndef TURTLE_VISITOR_H +#define TURTLE_VISITOR_H + +#include "../../sdlpp/sdlpp_visitor.hpp" +#include "../../sdlpp/sdlpp_geometry.hpp" +#include "../../sdlpp/sdlpp_scene.hpp" +#include "../blocks.hpp" + +class TurtleVisitor : public SDLPP::Visitor { +public: + TurtleVisitor() = delete; + TurtleVisitor(const SDLPP::Vec2D &pos) : turtle_pos(pos) {} + void visit(const SDLPP::RenderObject &obj) override; + bool isOnGround() const { + return onGround; + } + bool isDead() const { + return death; + } + bool instantDeath() const { + return instant_death; + } + void setFromId(uint64_t id) override { + from = id; + } + void setVisitorType(uint64_t type) override { + _type = type; + } + uint64_t getVisitorType() const override { + return _type; + } + uint64_t getFromId() const override { + return from; + } + bool canGoLeft() const { + return !left; + } + bool canGoRight() const { + return !right; + } + double getGroundY() const { + return groundY; + } + bool topBlock() const { + return top_hit; + } + + const SDLPP::Vec2D &getMovementBlockage() { + return movement_blockage; + } + double getValidXPos() const { + return validXPos; + } + bool switchMovement() const { + return switch_movement; + } + double getNextMovement() const { + return next_movement; + } + double getTurtleHitValidPos() const { + return valid_turtle_hit_pos; + } + bool shouldBounce() const { + return bounce; + } + +private: + bool onGround = false; + double groundY = 0; + uint64_t _type{}; + bool death = false; + bool instant_death = false; + uint64_t from = -1; + bool left = false; + bool right = false; + bool top_hit = false; + bool bounce = false; + SDLPP::Vec2D movement_blockage; + double validXPos = 0; + const SDLPP::Vec2D turtle_pos; + bool switch_movement = false; + double next_movement = 0; + double valid_turtle_hit_pos = 0; +}; + +#endif