Mario: Fireball works
Some checks reported errors
continuous-integration/drone/push Build encountered an error

This commit is contained in:
zv0n 2022-11-12 21:32:18 +01:00
parent 3cde73d1ed
commit 7bd652f4e9
19 changed files with 300 additions and 16 deletions

View File

@ -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

View File

@ -559,7 +559,7 @@ createBlockById(uint64_t id, int x, int y,
break;
case MARIO_ID:
result = std::static_pointer_cast<MarioBlock>(
std::make_shared<Mario>(x, y, renderer));
std::make_shared<Mario>(x, y, renderer, nullptr));
break;
case GOOMBA_ID:
result = std::static_pointer_cast<MarioBlock>(

70
mario/blocks/fireball.cpp Normal file
View File

@ -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<SDLPP::Renderer> &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<ProjectileVisitor &>(visitor);
// handle gravity
setOnGround(p_visitor.isOnGround());
if(p_visitor.isOnGround() && jump_movement > movementSpeed/16) {
setMovement(getMovement().getX(), -jump_movement);
setPos(getPos() - SDLPP::Vec2D<double>(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
}

18
mario/blocks/fireball.hpp Normal file
View File

@ -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<SDLPP::Renderer> &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

View File

@ -72,6 +72,9 @@ void GoombaBlock::handleVisitor(SDLPP::Visitor &visitor) {
startDeath();
// destroy();
}
if (g_visitor.instantDeath()) {
destroy();
}
#endif
}

View File

@ -5,6 +5,7 @@ std::shared_ptr<SDLPP::Texture> g_terrain_texture{};
std::shared_ptr<SDLPP::Texture> g_mario_texture{};
std::shared_ptr<SDLPP::Texture> g_mod_texture{};
std::shared_ptr<SDLPP::Texture> g_enemies_texture{};
std::shared_ptr<SDLPP::Texture> g_items_texture{};
std::shared_ptr<SDLPP::Texture> g_translucent_terrain_texture{};
std::shared_ptr<SDLPP::Texture> g_translucent_mod_texture{};
std::shared_ptr<SDLPP::Texture> g_translucent_enemies_texture;

View File

@ -7,6 +7,7 @@ extern std::shared_ptr<SDLPP::Texture> g_terrain_texture;
extern std::shared_ptr<SDLPP::Texture> g_mario_texture;
extern std::shared_ptr<SDLPP::Texture> g_mod_texture;
extern std::shared_ptr<SDLPP::Texture> g_enemies_texture;
extern std::shared_ptr<SDLPP::Texture> g_items_texture;
extern std::shared_ptr<SDLPP::Texture> g_translucent_terrain_texture;
extern std::shared_ptr<SDLPP::Texture> g_translucent_mod_texture;
extern std::shared_ptr<SDLPP::Texture> g_translucent_enemies_texture;

View File

@ -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<SDLPP::Scene> & /*UNUSED*/) {
}
}
void addObjectToScene(std::shared_ptr<MarioBlock> &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<MarioBlock> &object, bool moving) {
addObjectToScene(object, moving);
game_scenes.back().scene->moveZTop(object);
}
void addObjectToSceneBack(std::shared_ptr<MarioBlock> &object, bool moving) {
addObjectToScene(object, moving);
game_scenes.back().scene->moveZJustAboveBackground(object);
}
SceneStruct mainGameScene(const std::string &level_path) {
auto scene = std::make_shared<SDLPP::Scene>(renderer);
g_playground = scene;
@ -272,7 +293,7 @@ SceneStruct mainGameScene(const std::string &level_path) {
scene->addObject(bg);
mario.reset();
mario = std::make_shared<Mario>(renderer);
mario = std::make_shared<Mario>(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<SDLPP::Texture>(
renderer, "sprites/enemies.png", MARIO_OVERWORLD_COLORKEY);
g_items_texture = std::make_shared<SDLPP::Texture>(
renderer, "sprites/items.png", MARIO_OVERWORLD_COLORKEY);
g_mario_texture = std::make_shared<SDLPP::Texture>(
renderer, "sprites/mario.png", MARIO_OVERWORLD_COLORKEY);

View File

@ -2,6 +2,7 @@
#include "../sdlpp/sdlpp_rectrenderer.hpp"
#include <array>
#include <fstream>
#include "mario.hpp"
#include "sprites.hpp"
#include "blocks.hpp"
#include "objectids.hpp"
@ -188,10 +189,13 @@ void loadMapV01(std::shared_ptr<SDLPP::Scene> &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<Mario>(mario2)->setAddObjFunc(std::dynamic_pointer_cast<Mario>(mario)->getAddObjFunc());
#endif
mario = mario2;
} else {
mario->setPos(i * BLOCK_SIZE,
1 - (16 - j) * BLOCK_SIZE);

View File

@ -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<SDLPP::Renderer> &renderer)
: MarioBlock(x, y, renderer, g_mario_texture, MARIO_STANDING_SRC) {
Mario::Mario(int x, int y, const std::shared_ptr<SDLPP::Renderer> &renderer, std::function<void(std::shared_ptr<MarioBlock>&, 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<SDLPP::Renderer> &renderer)
setStatic(false);
bounce_speed *= 4;
}
Mario::Mario(const std::shared_ptr<SDLPP::Renderer> &renderer)
: Mario(0, 0, renderer) {}
Mario::Mario(const std::shared_ptr<SDLPP::Renderer> &renderer, std::function<void(std::shared_ptr<MarioBlock>&, 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<Fireball>(0, 0, renderer);
fireball->setPos(getPos() + SDLPP::Vec2D<double>((faces_right ? 1 : -1) * BLOCK_SIZE, BLOCK_SIZE));
fireball->setMovementDir(!faces_right);
auto fireball_m = std::static_pointer_cast<MarioBlock>(fireball);
fireball->setHidden(false);
_addObject(fireball_m, true);
}
void Mario::setAddObjFunc(std::function<void(std::shared_ptr<MarioBlock>&, bool)> func) {
_addObject = func;
}
std::function<void(std::shared_ptr<MarioBlock>&, bool)> Mario::getAddObjFunc() {
return _addObject;
}
#endif
void Mario::stopJump() {
stop_jump = true;
}

View File

@ -11,13 +11,18 @@
class Mario : public MarioBlock {
public:
Mario(int x, int y, const std::shared_ptr<SDLPP::Renderer> &renderer);
Mario(const std::shared_ptr<SDLPP::Renderer> &renderer);
Mario(int x, int y, const std::shared_ptr<SDLPP::Renderer> &renderer, std::function<void(std::shared_ptr<MarioBlock>&, bool)> addObject);
Mario(const std::shared_ptr<SDLPP::Renderer> &renderer, std::function<void(std::shared_ptr<MarioBlock>&, bool)> addObject);
void walkLeft();
void walkRight();
void setStanding();
void handleVisitor(SDLPP::Visitor &visitor) override;
void jump();
#ifndef EDITOR
void fire();
void setAddObjFunc(std::function<void(std::shared_ptr<MarioBlock>&, bool)> func);
std::function<void(std::shared_ptr<MarioBlock>&, 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<void(std::shared_ptr<MarioBlock>&, bool)> _addObject;
void setDeath(bool dead = true) {
_death = dead;
}

View File

@ -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

View File

@ -28,6 +28,12 @@ const std::vector<SDL_Rect> 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<SDL_Rect> 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 };

View File

@ -32,6 +32,8 @@ extern const SDL_Rect MARIO_DEATH_FIRE_SRC;
extern const std::vector<SDL_Rect> 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<SDL_Rect> FIRE_BALL_ANIM;
//------------------ TERRAIN ------------------------
extern const SDL_Rect FLOOR_SRC;

View File

@ -57,6 +57,9 @@ void GoombaVisitor::visit(const SDLPP::RenderObject &obj) {
}
}
break;
case FIREBALL_ID:
instant_death = true;
break;
default:
break;
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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<double> &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<double> movement_blockage;
uint64_t from{};
uint64_t _type{};
bool death = false;
};
#endif

View File

@ -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<SDLPP::Visitor>
@ -28,6 +29,10 @@ getVisitor(const MarioBlock &block, SDLPP::Scene &scene,
result = std::static_pointer_cast<SDLPP::Visitor>(
std::make_shared<GoombaVisitor>(block.getPos()));
break;
case FIREBALL_ID:
result = std::static_pointer_cast<SDLPP::Visitor>(
std::make_shared<ProjectileVisitor>());
break;
default:
break;
}