diff --git a/mario/CMakeLists.txt b/mario/CMakeLists.txt index 15115a1..28a3742 100644 --- a/mario/CMakeLists.txt +++ b/mario/CMakeLists.txt @@ -75,9 +75,11 @@ target_sources(mario PRIVATE visitors/goomba_visitor.cpp PRIVATE visitors/bounce_visitor.cpp PRIVATE visitors/visitor_generator.cpp + PRIVATE visitors/projectile_visitor.cpp PRIVATE blocks/coinblock.cpp PRIVATE blocks/mushroomblock.cpp PRIVATE blocks/goombablock.cpp + PRIVATE blocks/fireball.cpp PRIVATE scenes/load_scene.cpp PRIVATE scenes/game_main_menu.cpp PRIVATE editor_visitor.cpp # TODO diff --git a/mario/blocks.cpp b/mario/blocks.cpp index 1a3e4cc..1104aa4 100644 --- a/mario/blocks.cpp +++ b/mario/blocks.cpp @@ -559,7 +559,7 @@ createBlockById(uint64_t id, int x, int y, break; case MARIO_ID: result = std::static_pointer_cast( - std::make_shared(x, y, renderer)); + std::make_shared(x, y, renderer, nullptr)); break; case GOOMBA_ID: result = std::static_pointer_cast( diff --git a/mario/blocks/fireball.cpp b/mario/blocks/fireball.cpp new file mode 100644 index 0000000..5addb54 --- /dev/null +++ b/mario/blocks/fireball.cpp @@ -0,0 +1,70 @@ +#include "fireball.hpp" +#include "../sprites.hpp" +#include "../global_vars.hpp" +#include "../objectids.hpp" +#include "../visitors/projectile_visitor.hpp" + +Fireball::Fireball(int x, int y, std::shared_ptr &renderer) + : MarioBlock(x, y, renderer, g_items_texture, FIRE_BALL_ANIM[3]) { + setHidden(true); + ensureCollision(); + setSize({BLOCK_SIZE/2, BLOCK_SIZE/2}); + setId(FIREBALL_ID); + setBouncable(true); + setAnimationFrames(FIRE_BALL_ANIM); + setAnimationSpeed(16); + resumeAnimation(); + setOnGround(false); + + auto bottom_detect = SDLPP::RectColider(0.2, 1, 0.6, 0, NPC_FLOOR_DETECT); + bottom_detect.setColor("#FF0000"); + bottom_detect.setOutlineColor("#FF0000"); + bottom_detect.setMinHeight(1); + addCollision(bottom_detect); + addCollision(SDLPP::RectColider(0, 0.25, 0.1, 0.6, NPC_LEFT_SIDE_DETECT)); + addCollision( + SDLPP::RectColider(0.9, 0.25, 0.1, 0.6, NPC_RIGHT_SIDE_DETECT)); + jump_movement = movementSpeed; +} + +void Fireball::custom_move(int ticks) { + ticks_till_death -= ticks; + if (ticks_till_death <= 0) { + destroy(); + } + gravity(ticks); + MarioBlock::custom_move(ticks); +} + +void Fireball::setMovementDir(bool left) { + setMovement(movementSpeed / 2 * (left ? -1 : 1), 0); +} + +void Fireball::handleVisitor(SDLPP::Visitor &visitor) { +#ifndef EDITOR + // TODO - + // https://web.archive.org/web/20130807122227/http://i276.photobucket.com/albums/kk21/jdaster64/smb_playerphysics.png + auto &p_visitor = dynamic_cast(visitor); + // handle gravity + setOnGround(p_visitor.isOnGround()); + if(p_visitor.isOnGround() && jump_movement > movementSpeed/16) { + setMovement(getMovement().getX(), -jump_movement); + setPos(getPos() - SDLPP::Vec2D(0, jump_movement * BLOCK_SIZE)); + jump_movement /= 2; + setOnGround(false); + } + if (p_visitor.canGoLeft() != p_visitor.canGoRight()) { + if(p_visitor.canGoLeft()) { + // we only want to be the size of the fireball left of the blockage + setPos(-1 * getDoubleRect().second.getX() + p_visitor.getMovementBlockage().getX(), getPos().getY()); + } else { + // we want to be size of the blockage away from the blockage + setPos(BLOCK_SIZE + p_visitor.getMovementBlockage().getX(), getPos().getY()); + } + setMovementDir(getMovement().getX() > 0); + } + if (p_visitor.getDeath()) { + destroy(); + } +#endif +} \ No newline at end of file diff --git a/mario/blocks/fireball.hpp b/mario/blocks/fireball.hpp new file mode 100644 index 0000000..27b3d4b --- /dev/null +++ b/mario/blocks/fireball.hpp @@ -0,0 +1,18 @@ +#ifndef FIREBALL_HPP +#define FIREBALL_HPP + +#include "../blocks.hpp" + +class Fireball : public MarioBlock { +public: + Fireball(int x, int y, std::shared_ptr &renderer); + void custom_move(int ticks) override; + void handleVisitor(SDLPP::Visitor &visitor) override; + void setMovementDir(bool left); +private: + double jump_movement; + bool jumping = false; + long ticks_till_death = 3100; +}; + +#endif diff --git a/mario/blocks/goombablock.cpp b/mario/blocks/goombablock.cpp index 6e6bd5b..77531e0 100644 --- a/mario/blocks/goombablock.cpp +++ b/mario/blocks/goombablock.cpp @@ -72,9 +72,12 @@ void GoombaBlock::handleVisitor(SDLPP::Visitor &visitor) { startDeath(); // destroy(); } + if (g_visitor.instantDeath()) { + destroy(); + } #endif } void GoombaBlock::startDeath() { death_started = true; -} +} \ No newline at end of file diff --git a/mario/global_vars.cpp b/mario/global_vars.cpp index 1e5c235..c1cb65b 100644 --- a/mario/global_vars.cpp +++ b/mario/global_vars.cpp @@ -5,6 +5,7 @@ std::shared_ptr g_terrain_texture{}; std::shared_ptr g_mario_texture{}; std::shared_ptr g_mod_texture{}; std::shared_ptr g_enemies_texture{}; +std::shared_ptr g_items_texture{}; std::shared_ptr g_translucent_terrain_texture{}; std::shared_ptr g_translucent_mod_texture{}; std::shared_ptr g_translucent_enemies_texture; diff --git a/mario/global_vars.hpp b/mario/global_vars.hpp index e555b08..13fc3b9 100644 --- a/mario/global_vars.hpp +++ b/mario/global_vars.hpp @@ -7,6 +7,7 @@ extern std::shared_ptr g_terrain_texture; extern std::shared_ptr g_mario_texture; extern std::shared_ptr g_mod_texture; extern std::shared_ptr g_enemies_texture; +extern std::shared_ptr g_items_texture; extern std::shared_ptr g_translucent_terrain_texture; extern std::shared_ptr g_translucent_mod_texture; extern std::shared_ptr g_translucent_enemies_texture; diff --git a/mario/main.cpp b/mario/main.cpp index 9e2ce81..cb3f3d5 100644 --- a/mario/main.cpp +++ b/mario/main.cpp @@ -72,6 +72,9 @@ void handleKeyDown(SDL_Keycode key, SDLPP::Scene &scene) { if (fps) { fps->setHidden(!fps->getHidden()); } + case SDLK_RETURN: + mario->fire(); + break; default: break; } @@ -261,6 +264,24 @@ void mainGameAdditional(std::shared_ptr & /*UNUSED*/) { } } +void addObjectToScene(std::shared_ptr &object, bool moving) { + game_scenes.back().scene->addObject(object); + object->setAlignment(SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER); + if(moving) { + moving_objects.push_back(object); + } +} + +void addObjectToSceneTop(std::shared_ptr &object, bool moving) { + addObjectToScene(object, moving); + game_scenes.back().scene->moveZTop(object); +} + +void addObjectToSceneBack(std::shared_ptr &object, bool moving) { + addObjectToScene(object, moving); + game_scenes.back().scene->moveZJustAboveBackground(object); +} + SceneStruct mainGameScene(const std::string &level_path) { auto scene = std::make_shared(renderer); g_playground = scene; @@ -272,7 +293,7 @@ SceneStruct mainGameScene(const std::string &level_path) { scene->addObject(bg); mario.reset(); - mario = std::make_shared(renderer); + mario = std::make_shared(renderer, addObjectToSceneTop); scene->addObject(mario); auto defeat = @@ -390,6 +411,8 @@ int main() { renderer, "sprites/terrain.png", MARIO_OVERWORLD_COLORKEY); g_enemies_texture = std::make_shared( renderer, "sprites/enemies.png", MARIO_OVERWORLD_COLORKEY); + g_items_texture = std::make_shared( + renderer, "sprites/items.png", MARIO_OVERWORLD_COLORKEY); g_mario_texture = std::make_shared( renderer, "sprites/mario.png", MARIO_OVERWORLD_COLORKEY); diff --git a/mario/maploader.cpp b/mario/maploader.cpp index 9f37c6e..61f5ac2 100644 --- a/mario/maploader.cpp +++ b/mario/maploader.cpp @@ -2,6 +2,7 @@ #include "../sdlpp/sdlpp_rectrenderer.hpp" #include #include +#include "mario.hpp" #include "sprites.hpp" #include "blocks.hpp" #include "objectids.hpp" @@ -188,10 +189,13 @@ void loadMapV01(std::shared_ptr &scene, if (block.hasCharacter()) { if (block.getCharacterId() == MARIO_ID) { if (editor) { - scene->addObject(createMario(block.getCharacterType(), - renderer, i, j, true)); - mario = - scene->getObject(scene->getObjects().size() - 1); + auto mario2 = createMario(block.getCharacterType(), + renderer, i, j, true); + scene->addObject(mario2); +#ifndef EDITOR + std::dynamic_pointer_cast(mario2)->setAddObjFunc(std::dynamic_pointer_cast(mario)->getAddObjFunc()); +#endif + mario = mario2; } else { mario->setPos(i * BLOCK_SIZE, 1 - (16 - j) * BLOCK_SIZE); diff --git a/mario/mario.cpp b/mario/mario.cpp index f5522ec..224c5b0 100644 --- a/mario/mario.cpp +++ b/mario/mario.cpp @@ -4,9 +4,10 @@ #include "objectids.hpp" #include "sprites.hpp" #include "visitors/mario_visitor.hpp" +#include "blocks/fireball.hpp" -Mario::Mario(int x, int y, const std::shared_ptr &renderer) - : MarioBlock(x, y, renderer, g_mario_texture, MARIO_STANDING_SRC) { +Mario::Mario(int x, int y, const std::shared_ptr &renderer, std::function&, bool)> addObject) + : MarioBlock(x, y, renderer, g_mario_texture, MARIO_STANDING_SRC), _addObject(addObject) { setAnimationFrames(*walk_anim); setId(MARIO_ID); setAlignment(SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER); @@ -32,8 +33,8 @@ Mario::Mario(int x, int y, const std::shared_ptr &renderer) setStatic(false); bounce_speed *= 4; } -Mario::Mario(const std::shared_ptr &renderer) - : Mario(0, 0, renderer) {} +Mario::Mario(const std::shared_ptr &renderer, std::function&, bool)> addObject) + : Mario(0, 0, renderer, addObject) {} void Mario::walkLeft() { if (!controllable) { return; @@ -107,9 +108,7 @@ void Mario::handleVisitor(SDLPP::Visitor &visitor) { // TODO more readable function names if (m_visitor.isStopped()) { setPos(m_visitor.getStopX(), getPos().getY()); - } else if (m_visitor.canGoLeft() != m_visitor.canGoRight() && - !(on_ground && m_visitor.getMovementBlockage().getY() > - getPos().getY() + BLOCK_SIZE / 2)) { + } else if (m_visitor.canGoLeft() != m_visitor.canGoRight()) { // only stop mario on ground if the block obstructs at least half of him // (important for bug when mario lands from a high jump and is // teleported if visitor is fired at wrong moment) @@ -169,6 +168,26 @@ void Mario::jump() { pauseAnimation(); } +#ifndef EDITOR +void Mario::fire() { + if (!hasFire()) { + return; + } + auto fireball = std::make_shared(0, 0, renderer); + fireball->setPos(getPos() + SDLPP::Vec2D((faces_right ? 1 : -1) * BLOCK_SIZE, BLOCK_SIZE)); + fireball->setMovementDir(!faces_right); + auto fireball_m = std::static_pointer_cast(fireball); + fireball->setHidden(false); + _addObject(fireball_m, true); +} +void Mario::setAddObjFunc(std::function&, bool)> func) { + _addObject = func; +} +std::function&, bool)> Mario::getAddObjFunc() { + return _addObject; +} +#endif + void Mario::stopJump() { stop_jump = true; } diff --git a/mario/mario.hpp b/mario/mario.hpp index aa732ef..f271948 100644 --- a/mario/mario.hpp +++ b/mario/mario.hpp @@ -11,13 +11,18 @@ class Mario : public MarioBlock { public: - Mario(int x, int y, const std::shared_ptr &renderer); - Mario(const std::shared_ptr &renderer); + Mario(int x, int y, const std::shared_ptr &renderer, std::function&, bool)> addObject); + Mario(const std::shared_ptr &renderer, std::function&, bool)> addObject); void walkLeft(); void walkRight(); void setStanding(); void handleVisitor(SDLPP::Visitor &visitor) override; void jump(); +#ifndef EDITOR + void fire(); + void setAddObjFunc(std::function&, bool)> func); + std::function&, bool)> getAddObjFunc(); +#endif void stopJump(); void custom_move(int ticks) override; void visit(SDLPP::Visitor &visitor) override; @@ -48,6 +53,7 @@ public: } private: + std::function&, bool)> _addObject; void setDeath(bool dead = true) { _death = dead; } diff --git a/mario/objectids.hpp b/mario/objectids.hpp index a84625c..e0304b8 100644 --- a/mario/objectids.hpp +++ b/mario/objectids.hpp @@ -90,6 +90,9 @@ #define NPC_RIGHT_SIDE_DETECT 0x200A #define NPC_TOP_DETECT 0x200B +// projectiles +#define FIREBALL_ID 0x3001 + // GUI #define BUTTON_ID 0xA000 diff --git a/mario/sprites.cpp b/mario/sprites.cpp index 92b3dac..a0c7b90 100644 --- a/mario/sprites.cpp +++ b/mario/sprites.cpp @@ -28,6 +28,12 @@ const std::vector MARIO_WALK_FIRE_ANIM = { { 43, 157, 16, 32 }, const SDL_Rect MARIO_CHANGE_DIR_FIRE_SRC = { 98, 157, 16, 32 }; const SDL_Rect MARIO_JUMP_FIRE_SRC = { 119, 157, 16, 32 }; +extern const std::vector FIRE_BALL_ANIM = { {96, 144, 8, 8}, + {104, 144, 8, 8}, + {96, 152, 8, 8}, + {104, 152, 8, 8}, +}; + const SDL_Rect FLOOR_SRC = { 1, 131, 16, 16 }; const SDL_Rect HILL_INCLINE_SRC = { 137, 97, 16, 16 }; const SDL_Rect HILL_DECLINE_SRC = { 205, 97, 16, 16 }; diff --git a/mario/sprites.hpp b/mario/sprites.hpp index d2dcbc2..262b9dc 100644 --- a/mario/sprites.hpp +++ b/mario/sprites.hpp @@ -32,6 +32,8 @@ extern const SDL_Rect MARIO_DEATH_FIRE_SRC; extern const std::vector MARIO_WALK_FIRE_ANIM; extern const SDL_Rect MARIO_CHANGE_DIR_FIRE_SRC; extern const SDL_Rect MARIO_JUMP_FIRE_SRC; +//------------------ FIRE BALL ---------------------- +extern const std::vector FIRE_BALL_ANIM; //------------------ TERRAIN ------------------------ extern const SDL_Rect FLOOR_SRC; diff --git a/mario/visitors/goomba_visitor.cpp b/mario/visitors/goomba_visitor.cpp index 59e5fb8..5eca6f8 100644 --- a/mario/visitors/goomba_visitor.cpp +++ b/mario/visitors/goomba_visitor.cpp @@ -57,6 +57,9 @@ void GoombaVisitor::visit(const SDLPP::RenderObject &obj) { } } break; + case FIREBALL_ID: + instant_death = true; + break; default: break; } diff --git a/mario/visitors/goomba_visitor.hpp b/mario/visitors/goomba_visitor.hpp index 34518a6..df1413f 100644 --- a/mario/visitors/goomba_visitor.hpp +++ b/mario/visitors/goomba_visitor.hpp @@ -17,6 +17,9 @@ public: bool isDead() const { return death; } + bool instantDeath() const { + return instant_death; + } void setFromId(uint64_t id) override { from = id; } @@ -54,6 +57,7 @@ private: double groundY = 0; uint64_t _type{}; bool death = false; + bool instant_death = false; uint64_t from = -1; bool left = false; bool right = false; diff --git a/mario/visitors/projectile_visitor.cpp b/mario/visitors/projectile_visitor.cpp new file mode 100644 index 0000000..7406d5e --- /dev/null +++ b/mario/visitors/projectile_visitor.cpp @@ -0,0 +1,54 @@ +#include "projectile_visitor.hpp" +#include "../../sdlpp/sdlpp_renderobject.hpp" +#include "../objectids.hpp" +#include "../sprites.hpp" + +void ProjectileVisitor::visit(const SDLPP::RenderObject &obj) { + auto id = obj.getId(); + switch (id) { + case FLOOR_ID: + case BRICK_ID: + case BRICK_TOP_ID: + 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 GOOMBA_ID: + std::cout << "DEATH" << std::endl; + death = true; + default: + break; + } +} diff --git a/mario/visitors/projectile_visitor.hpp b/mario/visitors/projectile_visitor.hpp new file mode 100644 index 0000000..54e8cf4 --- /dev/null +++ b/mario/visitors/projectile_visitor.hpp @@ -0,0 +1,60 @@ +#ifndef PROJECTILE_VISITOR_H +#define PROJECTILE_VISITOR_H + +#include "../../sdlpp/sdlpp_visitor.hpp" +#include "../../sdlpp/sdlpp_geometry.hpp" +#include "../../sdlpp/sdlpp_scene.hpp" +#include "../blocks.hpp" + +class ProjectileVisitor : public SDLPP::Visitor { +public: + ProjectileVisitor() = default; + void visit(const SDLPP::RenderObject &obj) override; + bool isOnGround() const { + return onGround; + } + void setFromId(uint64_t id) override { + from = id; + } + uint64_t getFromId() const override { + return from; + } + void setVisitorType(uint64_t type) override { + _type = type; + } + uint64_t getVisitorType() const override { + return _type; + } + bool canGoLeft() const { + return !left; + } + bool canGoRight() const { + return !right; + } + double getGroundY() const { + return groundY; + } + const SDLPP::Vec2D &getMovementBlockage() { + return movement_blockage; + } + bool getDeath() { + return death; + } + double getValidXPos() { + return validXPos; + } + +private: + bool onGround = false; + double groundY = 0; + double validXPos = 0; + bool stop = false; + bool left = false; + bool right = false; + SDLPP::Vec2D movement_blockage; + uint64_t from{}; + uint64_t _type{}; + bool death = false; +}; + +#endif diff --git a/mario/visitors/visitor_generator.cpp b/mario/visitors/visitor_generator.cpp index a5c06a5..4597380 100644 --- a/mario/visitors/visitor_generator.cpp +++ b/mario/visitors/visitor_generator.cpp @@ -3,6 +3,7 @@ #include "mario_visitor.hpp" #include "mushroom_visitor.hpp" #include "goomba_visitor.hpp" +#include "projectile_visitor.hpp" #include "../mario.hpp" std::shared_ptr @@ -28,6 +29,10 @@ getVisitor(const MarioBlock &block, SDLPP::Scene &scene, result = std::static_pointer_cast( std::make_shared(block.getPos())); break; + case FIREBALL_ID: + result = std::static_pointer_cast( + std::make_shared()); + break; default: break; }