#include "mario.hpp" #include "blocks.hpp" #include "global_vars.hpp" #include "objectids.hpp" #include "sprites.hpp" #include "visitors/mario_visitor.hpp" Mario::Mario(int x, int y, const std::shared_ptr &renderer) : MarioBlock(x, y, renderer, g_mario_texture, MARIO_STANDING_SRC) { setAnimationFrames(MARIO_WALK_ANIM); setId(MARIO_ID); setAlignment(SDLPP::OBJ_CENTER, SDLPP::OBJ_CENTER); setAnimationSpeed(12.5); pauseAnimation(); setMovement(0, 0); setMovementSpeed(1); auto bottom_detect = SDLPP::RectColider(0.2, 1, 0.6, 0, MARIO_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, MARIO_LEFT_SIDE_DETECT)); addCollision( SDLPP::RectColider(0.9, 0.25, 0.1, 0.6, MARIO_RIGHT_SIDE_DETECT)); addCollision(SDLPP::RectColider(0, 0, 0.1, 0.1, MARIO_TOP_LEFT_DETECT)); addCollision(SDLPP::RectColider(0.9, 0, 0.1, 0.1, MARIO_TOP_LEFT_DETECT)); top_collision = std::make_shared(0.5, 0, 0.2, 0.15, MARIO_TOP_DETECT); addCollision(top_collision); addCollision(SDLPP::RectColider(0, 1, 1, 0.2, MARIO_ENEMY_DETECT)); setColiderColor("#FF0000"); setStatic(false); bounce_speed *= 4; } Mario::Mario(const std::shared_ptr &renderer) : Mario(0, 0, renderer) {} void Mario::walkLeft() { if (!controllable) { return; } if (on_ground) resumeAnimation(); addMovement(-side_movement, 0); if (getMovement().getX() < 0 && faces_right) { flipHorizontally(); top_collision->setPos(0.3, 0); updateSizeAndPosition(); faces_right = false; } } void Mario::walkRight() { if (!controllable) { return; } if (on_ground) resumeAnimation(); addMovement(side_movement, 0); if (getMovement().getX() > 0 && !faces_right) { flipHorizontally(); top_collision->setPos(0.5, 0); updateSizeAndPosition(); faces_right = true; } } void Mario::setStanding() { if (getMovement().getX() == 0) { pauseAnimation(); } } void Mario::handleVisitor(SDLPP::Visitor &visitor) { #ifndef EDITOR // TODO - // https://web.archive.org/web/20130807122227/http://i276.photobucket.com/albums/kk21/jdaster64/smb_playerphysics.png auto &m_visitor = dynamic_cast(visitor); // handle gravity on_ground = m_visitor.isOnGround(); if (!jumping && on_ground) { resetMovementY(); setBaseRect(MARIO_STANDING_SRC); if (!controllable) { setDeath(); } if (getMovement().getX() != 0) resumeAnimation(); // for some reason falling of the edge causes on_ground to be true, but // visitor ground_y is 0 if (m_visitor.getGroundY() != 0) { setPos(getPos().getX(), m_visitor.getGroundY() - BLOCK_SIZE); } } // if we just left ground gravity didn't work in custom_move if (!on_ground && !jumping && getMovement().getY() == 0) { addMovement(0, 2 * gravity_add_falling); } if (m_visitor.topBlock() && getMovement().getY() < 0) { resetMovementY(); stop_jump = true; } if (m_visitor.shouldBounce()) { addMovement(0, -bounce_speed); } // make sure Mario isn't stuck inside a wall // 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)) { // 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) SDLPP::Vec2D next_pos = { m_visitor.getMovementBlockage().getX() + (m_visitor.canGoLeft() * -1 + m_visitor.canGoRight() * 1) * BLOCK_SIZE, getPos().getY() }; setPos(next_pos); } else if (m_visitor.moveTop() && jumping && !stop_jump) { auto objPos = m_visitor.getRightLeftPos(); if (objPos.getX() < getPos().getX()) { setPos(objPos.getX() + BLOCK_SIZE, getPos().getY()); } else { setPos(objPos.getX() - BLOCK_SIZE, getPos().getY()); } } if (m_visitor.hasMushroom()) { setType(LandType::UNDERWORLD); } if (m_visitor.levelEnd() && controllable) { if (std::abs(getPos().getX() - m_visitor.getEndPos().getX()) < BLOCK_SIZE / 8) { setPos(m_visitor.getEndPos().getX(), getPos().getY()); stopMovement(); } } #endif } void Mario::jump() { if (!controllable) { return; } if (!on_ground) return; jumping = true; stop_jump = false; max_jump = getPos().getY() - 3 * BLOCK_SIZE; min_jump = getPos().getY() - 1 * BLOCK_SIZE; slow_jump = getPos().getY() - 2 * BLOCK_SIZE; addMovement(0, -jump_movement); ticks_till_gravity = base_gravity_ticks; setBaseRect(MARIO_JUMP_SRC); pauseAnimation(); } void Mario::stopJump() { stop_jump = true; } void Mario::custom_move(int ticks) { MarioBlock::custom_move(ticks); if (!jumping && on_ground) return; if (getMovement().getY() >= 1.0625 * jump_movement) return; ticks_till_gravity -= ticks; if (ticks_till_gravity < 0) { if (getMovement().getY() > 0) { jumping = false; addMovement(0, gravity_add_jumping); } else { if (stop_jump) { addMovement(0, gravity_add_falling); } else { addMovement(0, gravity_add_jumping); } } ticks_till_gravity += base_gravity_ticks; } } void Mario::visit(SDLPP::Visitor &visitor) { // TODO visitor.visit(*this); } void Mario::setWorldTypeSrc(LandType::Value /*UNUSED*/) { MarioBlock::setWorldTypeSrc(LandType::OVERWORLD); // TODO } void Mario::stopMovement() { controllable = false; setMovement(0, getMovement().getY()); }