diff --git a/mario/blocks.cpp b/mario/blocks.cpp index 76fed2b..d3dd4ff 100644 --- a/mario/blocks.cpp +++ b/mario/blocks.cpp @@ -42,42 +42,43 @@ void MarioBlock::visit(SDLPP::Visitor &visitor) { destroy(); } #else - if (visitor.getFromId() == MARIO_TOP_DETECT && - dynamic_cast(visitor).canDestroy()) { - // TODO if big mario and _can_be_destroyed - if (_destructible && !hasCoin()) { - destroy(); - } else if (_bouncable) { - BounceVisitor bv; - bv.setVisitorType(VisitorType::Terrain); + if (visitor.getFromId() == MARIO_TOP_DETECT) { + auto &mario_visitor = dynamic_cast(visitor); + if (mario_visitor.canDestroy()) { + if ((_destructible && !hasCoin()) || (_can_be_destroyed && mario_visitor.isBig() && !hasCoin())) { + destroy(); + } else if (_bouncable) { + BounceVisitor bv; + bv.setVisitorType(VisitorType::Terrain); - setPos(getPos() - SDLPP::Vec2D(0, BLOCK_SIZE)); - if (getCollisions().size() < 2) - addCollision( - SDLPP::RectColider(0.1, 0.1, 0.8, 0.8, BOUNCE_COLLISION)); - updateSizeAndPosition(); - g_playground->visitCollisions(*this, bv); - setPos(getPos() + SDLPP::Vec2D(0, BLOCK_SIZE)); - updateSizeAndPosition(); - if (bv.canBounce()) - bounce(); - } - if (hasCoin()) { - removeCoin(); - auto coin = - createTerrainBlock(COIN_ID, LandType::OVERWORLD, renderer); - coin->setPos(getPos()); - std::dynamic_pointer_cast(coin)->setParent(this); - dynamic_cast(visitor).setCoin(); - dynamic_cast(visitor).setCoinBlock(coin); - } - if (hasMushroom()) { - removeMushroom(); - auto mushroom = - createTerrainBlock(MUSHROOM_ID, LandType::OVERWORLD, renderer); - mushroom->setPos(getPos()); - std::dynamic_pointer_cast(mushroom)->setParent(this); - dynamic_cast(visitor).setMushroomBlock(mushroom); + setPos(getPos() - SDLPP::Vec2D(0, BLOCK_SIZE)); + if (getCollisions().size() < 2) + addCollision( + SDLPP::RectColider(0.1, 0.1, 0.8, 0.8, BOUNCE_COLLISION)); + updateSizeAndPosition(); + g_playground->visitCollisions(*this, bv); + setPos(getPos() + SDLPP::Vec2D(0, BLOCK_SIZE)); + updateSizeAndPosition(); + if (bv.canBounce()) + bounce(); + } + if (hasCoin()) { + removeCoin(); + auto coin = + createTerrainBlock(COIN_ID, LandType::OVERWORLD, renderer); + coin->setPos(getPos()); + std::dynamic_pointer_cast(coin)->setParent(this); + dynamic_cast(visitor).setCoin(); + dynamic_cast(visitor).setCoinBlock(coin); + } + if (hasMushroom()) { + removeMushroom(); + auto mushroom = + createTerrainBlock(MUSHROOM_ID, LandType::OVERWORLD, renderer); + mushroom->setPos(getPos()); + std::dynamic_pointer_cast(mushroom)->setParent(this); + dynamic_cast(visitor).setMushroomBlock(mushroom); + } } } #endif diff --git a/mario/blocks/goombablock.cpp b/mario/blocks/goombablock.cpp index 3d443f7..6e6bd5b 100644 --- a/mario/blocks/goombablock.cpp +++ b/mario/blocks/goombablock.cpp @@ -7,7 +7,7 @@ GoombaBlock::GoombaBlock(int x, int y, std::shared_ptr &renderer) : MarioBlock(x, y, renderer, g_enemies_texture, GOOMBA_WALK_ANIM[0], - true, true) { + false, false) { #ifndef EDITOR setAnimationFrames(GOOMBA_WALK_ANIM); setAnimationSpeed(12.5); @@ -22,6 +22,7 @@ GoombaBlock::GoombaBlock(int x, int y, SDLPP::RectColider(0.9, 0.25, 0.1, 0.6, NPC_RIGHT_SIDE_DETECT)); addCollision(std::make_shared(0.35, 0, 0.3, 0.15, NPC_TOP_DETECT)); + setBouncable(false); #ifndef EDITOR setMovement(-0.19, 0); #endif @@ -58,7 +59,7 @@ void GoombaBlock::handleVisitor(SDLPP::Visitor &visitor) { if (isOnGround()) { setPos(getPos().getX(), g_visitor.getGroundY() - BLOCK_SIZE); } - if((!g_visitor.canGoLeft() && getMovement().getX() < 0) || + if ((!g_visitor.canGoLeft() && getMovement().getX() < 0) || (!g_visitor.canGoRight() && getMovement().getX() > 0)) { setPos(g_visitor.getValidXPos(), getPos().getY()); setMovement(-getMovement().getX(), getMovement().getY()); diff --git a/mario/blocks/mushroomblock.cpp b/mario/blocks/mushroomblock.cpp index 25014d3..585688b 100644 --- a/mario/blocks/mushroomblock.cpp +++ b/mario/blocks/mushroomblock.cpp @@ -28,7 +28,7 @@ void MushroomBlock::custom_move(int ticks) { _parent = nullptr; } else if (_parent == nullptr && !isTraveling() && !_started_movement) { _started_movement = true; - setMovement(movementSpeed / 2, 0); + setMovement(movementSpeed / 4, 0); } gravity(ticks); MarioBlock::custom_move(ticks); diff --git a/mario/main.cpp b/mario/main.cpp index 02f02a5..9e2ce81 100644 --- a/mario/main.cpp +++ b/mario/main.cpp @@ -191,7 +191,7 @@ void doInputMainGame(std::shared_ptr scene) { if (!moving_objects[i]->wasVisible()) { continue; } - auto visitor = getVisitor(*moving_objects[i], *scene, g_death, + auto visitor = getVisitor(*moving_objects[i], *scene, coin_count, moving_objects); scene->visitCollisions(*moving_objects[i], *visitor); moving_objects[i]->handleVisitor(*visitor); diff --git a/mario/mario.cpp b/mario/mario.cpp index dd8f781..1cf1b32 100644 --- a/mario/mario.cpp +++ b/mario/mario.cpp @@ -99,7 +99,7 @@ void Mario::handleVisitor(SDLPP::Visitor &visitor) { resetMovementY(); stop_jump = true; } - if (m_visitor.shouldBounce()) { + if (m_visitor.shouldBounce() && getMovement().getY() > 0) { addMovement(0, -bounce_speed); } // make sure Mario isn't stuck inside a wall @@ -128,7 +128,7 @@ void Mario::handleVisitor(SDLPP::Visitor &visitor) { } } if (m_visitor.hasMushroom()) { - setType(LandType::UNDERWORLD); + setBig(); } if (m_visitor.levelEnd() && controllable) { if (std::abs(getPos().getX() - m_visitor.getEndPos().getX()) < @@ -137,8 +137,19 @@ void Mario::handleVisitor(SDLPP::Visitor &visitor) { stopMovement(); } } + if (m_visitor.isDead()) { + handleDeath(); + } #endif } +void Mario::handleDeath() { + if (isBig() && ticks_till_vulnurable <= 0) { + unsetBig(); + ticks_till_vulnurable = base_vulnurable_ticks; + } else if (ticks_till_vulnurable <= 0) { + setDeath(); + } +} void Mario::jump() { if (!controllable) { @@ -162,6 +173,9 @@ void Mario::stopJump() { } void Mario::custom_move(int ticks) { + if (ticks_till_vulnurable > 0) { + ticks_till_vulnurable -= ticks; + } MarioBlock::custom_move(ticks); if (!jumping && on_ground) return; diff --git a/mario/mario.hpp b/mario/mario.hpp index 3bbbc14..58e62e4 100644 --- a/mario/mario.hpp +++ b/mario/mario.hpp @@ -4,6 +4,11 @@ #include "../sdlpp/sdlpp_rectrenderer.hpp" #include "sprites.hpp" #include "blocks.hpp" +#include <_types/_uint8_t.h> + +#define BIG_FLAG 0x0001 +#define FIRE_FLAG 0x0002 +#define STAR_FLAG 0x0004 class Mario : public MarioBlock { public: @@ -20,6 +25,40 @@ public: bool isDead() { return _death; } + void handleDeath(); + void setBig() { + if (isBig()) { + setFireFlag(); + } else { + setBigFlag(); + } + } + void unsetBig() { + if (hasFire()) { + unsetFireFlag(); + } else { + unsetBigFlag(); + } + } + void setStar() { + setStarFlag(); + } + void unsetStar() { + unsetStarFlag(); + } + + bool isBig() const { + return special_flags & BIG_FLAG; + } + bool hasFire() const { + return special_flags & FIRE_FLAG; + } + bool hasStar() const { + return special_flags & STAR_FLAG; + } + bool isJumping() const { + return jumping; + } private: void setDeath(bool dead = true) { @@ -37,13 +76,35 @@ private: double slow_jump = 0; bool on_ground = true; int ticks_till_gravity = 0; + int ticks_till_vulnurable = 0; // gravity should be added every frame in 60fps game const int base_gravity_ticks = 1000 / 60; + const int base_vulnurable_ticks = 1000; const double gravity_add_jumping = jump_movement / 32.0; const double gravity_add_falling = jump_movement / (64.0 / 7.0); std::shared_ptr top_collision = nullptr; void setWorldTypeSrc(LandType::Value world) override; void stopMovement(); + uint8_t special_flags = 0; + + void setBigFlag() { + special_flags = special_flags | BIG_FLAG; + } + void setFireFlag() { + special_flags = special_flags | FIRE_FLAG; + } + void setStarFlag() { + special_flags = special_flags | STAR_FLAG; + } + void unsetBigFlag() { + special_flags = special_flags & ~BIG_FLAG; + } + void unsetFireFlag() { + special_flags = special_flags & ~FIRE_FLAG; + } + void unsetStarFlag() { + special_flags = special_flags & ~STAR_FLAG; + } }; #endif diff --git a/mario/visitors/goomba_visitor.cpp b/mario/visitors/goomba_visitor.cpp index 48b6c01..59e5fb8 100644 --- a/mario/visitors/goomba_visitor.cpp +++ b/mario/visitors/goomba_visitor.cpp @@ -2,6 +2,7 @@ #include "../../sdlpp/sdlpp_renderobject.hpp" #include "../objectids.hpp" #include "../sprites.hpp" +#include "../mario.hpp" void GoombaVisitor::visit(const SDLPP::RenderObject &obj) { auto id = obj.getId(); @@ -49,8 +50,11 @@ void GoombaVisitor::visit(const SDLPP::RenderObject &obj) { death = true; break; case MARIO_ID: - if (from == NPC_TOP_DETECT) { - death = true; + { + auto &mario = dynamic_cast(obj); + if (from == NPC_TOP_DETECT && obj.getPos().getY() <= goomba_pos.getY() - BLOCK_SIZE && !mario.isJumping()) { + death = true; + } } break; default: diff --git a/mario/visitors/goomba_visitor.hpp b/mario/visitors/goomba_visitor.hpp index 01a6ae0..34518a6 100644 --- a/mario/visitors/goomba_visitor.hpp +++ b/mario/visitors/goomba_visitor.hpp @@ -8,7 +8,8 @@ class GoombaVisitor : public SDLPP::Visitor { public: - GoombaVisitor() = default; + GoombaVisitor() = delete; + GoombaVisitor(const SDLPP::Vec2D &pos) : goomba_pos(pos) {} void visit(const SDLPP::RenderObject &obj) override; bool isOnGround() const { return onGround; @@ -59,6 +60,7 @@ private: bool top_hit = false; SDLPP::Vec2D movement_blockage; double validXPos = 0; + const SDLPP::Vec2D goomba_pos; }; #endif diff --git a/mario/visitors/mario_visitor.cpp b/mario/visitors/mario_visitor.cpp index 85c9be8..5dde814 100644 --- a/mario/visitors/mario_visitor.cpp +++ b/mario/visitors/mario_visitor.cpp @@ -55,7 +55,7 @@ void MarioVisitor::visit(const SDLPP::RenderObject &obj) { case GOOMBA_ID: if (from != MARIO_FLOOR_DETECT && from != MARIO_ENEMY_DETECT) { _death = true; - } else { + } else if (from == MARIO_FLOOR_DETECT || from == MARIO_ENEMY_DETECT) { _bounce = true; } break; diff --git a/mario/visitors/mario_visitor.hpp b/mario/visitors/mario_visitor.hpp index eeab795..3883ec3 100644 --- a/mario/visitors/mario_visitor.hpp +++ b/mario/visitors/mario_visitor.hpp @@ -8,11 +8,13 @@ class MarioVisitor : public SDLPP::Visitor { public: - MarioVisitor(bool is_jumping, SDLPP::Scene &scene, bool &death, + MarioVisitor(bool is_jumping, SDLPP::Scene &scene, int &coin_count, - std::vector> &moving_objects) - : jumping(is_jumping), _scene(scene), _death(death), - _coin_count(coin_count), _moving_objects(moving_objects) {} + std::vector> &moving_objects, + bool is_big, bool has_star) + : jumping(is_jumping), _scene(scene), + _coin_count(coin_count), _moving_objects(moving_objects), + _is_big(is_big), _has_star(has_star) {} void visit(const SDLPP::RenderObject &obj) override; bool isOnGround() const { return onGround; @@ -116,6 +118,14 @@ public: return endPos; } + bool isBig() const { + return _is_big; + } + + bool hasStar() const { + return _has_star; + } + private: bool onGround = false; double groundY = 0; @@ -133,13 +143,15 @@ private: SDLPP::Vec2D movement_blockage; std::shared_ptr coin_block = nullptr; SDLPP::Scene &_scene; - bool &_death; int &_coin_count; bool mushroom = false; std::vector> &_moving_objects; bool _bounce = false; bool _end = false; SDLPP::Vec2D endPos; + bool _is_big = false; + bool _has_star = false; + bool _death = false; }; #endif diff --git a/mario/visitors/visitor_generator.cpp b/mario/visitors/visitor_generator.cpp index 158ee71..a5c06a5 100644 --- a/mario/visitors/visitor_generator.cpp +++ b/mario/visitors/visitor_generator.cpp @@ -3,18 +3,22 @@ #include "mario_visitor.hpp" #include "mushroom_visitor.hpp" #include "goomba_visitor.hpp" +#include "../mario.hpp" std::shared_ptr -getVisitor(const MarioBlock &block, SDLPP::Scene &scene, bool &death, +getVisitor(const MarioBlock &block, SDLPP::Scene &scene, int &coin_count, std::vector> &moving_objects) { std::shared_ptr result{}; switch (block.getId()) { case MARIO_ID: - result = std::static_pointer_cast( - std::make_shared(block.getMovement().getY() < 0, - scene, death, coin_count, - moving_objects)); + { + auto &mario = dynamic_cast(block); + result = std::static_pointer_cast( + std::make_shared(block.getMovement().getY() < 0, + scene, coin_count, + moving_objects, mario.isBig(), mario.hasStar())); + } break; case MUSHROOM_ID: result = std::static_pointer_cast( @@ -22,7 +26,7 @@ getVisitor(const MarioBlock &block, SDLPP::Scene &scene, bool &death, break; case GOOMBA_ID: result = std::static_pointer_cast( - std::make_shared()); + std::make_shared(block.getPos())); break; default: break; diff --git a/mario/visitors/visitor_generator.hpp b/mario/visitors/visitor_generator.hpp index 8b10843..30bb902 100644 --- a/mario/visitors/visitor_generator.hpp +++ b/mario/visitors/visitor_generator.hpp @@ -4,7 +4,7 @@ #include "../blocks.hpp" std::shared_ptr -getVisitor(const MarioBlock &block, SDLPP::Scene &scene, bool &quit, +getVisitor(const MarioBlock &block, SDLPP::Scene &scene, int &coin_count, std::vector> &moving_objects);