Skip to content
Snippets Groups Projects
Commit b493e7ca authored by PierreEVEN's avatar PierreEVEN
Browse files

added comments

parent e057dc16
Branches
No related merge requests found
......@@ -7,11 +7,6 @@ namespace pm
{
double Cell::draw_scale = 1.;
Cell::Cell()
: type(ECellType::Void)
{
}
void Cell::set_pos(const Vector2I& in_pos)
{
pos = in_pos;
......
......@@ -7,6 +7,21 @@
namespace pm
{
/*
* This is the representation of a cell of pacman game's terrain
*/
enum class ECellType
{
Void,
Wall,
Gum,
Item,
BiGum,
Door,
};
// Specialized item type informations
enum class EItemType
{
Cherry,
......@@ -19,21 +34,11 @@ enum class EItemType
Key
};
enum class ECellType
{
Void,
Wall,
Gum,
Item,
BiGum,
Door,
};
class Cell
{
public:
static double draw_scale;
using WallMask = int32_t;
static constexpr WallMask WALL_MASK_NORTH = 0b0001;
static constexpr WallMask WALL_MASK_WEST = 0b0010;
......@@ -44,7 +49,7 @@ public:
public:
static Cell from_char(char chr);
Cell();
Cell() = default;
void set_pos(const Vector2I& in_pos);
void set_item(EItemType in_item_type);
......@@ -63,21 +68,20 @@ public:
void draw(int32_t terrain_unit_scale, SDL_Surface* surface_override = nullptr) const;
private:
SpriteHandle sprite_handle;
SpriteHandle sprite_handle = {};
Vector2I pos{0, 0};
ECellType type = ECellType::Void;
union
class InternalWallMask
{
EItemType item_type;
struct
{
WallMask pos;
WallMask neg;
} wall_masks;
public:
WallMask pos = 0;
WallMask neg = 0;
};
EItemType item_type = EItemType::Cherry;
InternalWallMask wall_masks;
};
}
......@@ -2,14 +2,13 @@
#include "vector2.hpp"
#include <vector>
namespace std
{
constexpr int sign(auto a) { return a < 0 ? -1 : 1; }
constexpr auto clamp(auto val, auto min, auto max) { return val < min ? min : val > max ? max : val; }
}
namespace pm
{
/*
* Represent a direction (left, right, up, down, and None for {0, 0})
* We don't use an enum because it's cleaner and we had to convert it to Vector2I anyways during the process.
* (C++ is not as practical as Rust for enumerations)
*/
struct Direction
{
public:
......@@ -18,6 +17,7 @@ public:
{
}
// Automatically normalize given vector to the closest direction
Direction(Vector2I dir)
: internal_dir(normalize(dir))
{
......@@ -28,8 +28,10 @@ public:
{
}
// Enumerate all the possible 4 directions (excluding NONE)
[[nodiscard]] static const std::vector<Direction>& enumerate();
// Give and index for the given direction
[[nodiscard]] int8_t index() const
{
if (internal_dir == NONE.internal_dir)
......@@ -45,12 +47,14 @@ public:
return -1;
}
// Main directions
static const Direction RIGHT;
static const Direction LEFT;
static const Direction UP;
static const Direction DOWN;
static const Direction NONE;
// Getter and comparisons
Direction& operator=(const Vector2I& in_dir)
{
internal_dir = normalize(in_dir);
......@@ -62,7 +66,13 @@ public:
internal_dir = normalize(in_dir.rounded().cast<Vector2I>());
return *this;
}
bool operator==(const Direction& other) const
{
return internal_dir == other.internal_dir;
}
// Get internal vector
const Vector2I& operator*() const { return internal_dir; }
const Vector2I* operator->() const { return &internal_dir; }
......@@ -79,9 +89,8 @@ public:
[[nodiscard]] Direction opposite() const;
bool operator==(const Direction& other) const { return internal_dir == other.internal_dir; }
private:
// we don't use Vector2::normalize() as the behavior for normalizing a direction is quite different (and also way faster)
static Vector2I normalize(const Vector2I& input)
{
if (input.l1_length() == 0)
......
......@@ -8,48 +8,66 @@ struct SDL_Surface;
namespace pm
{
// Extend this class to implement your one game mode.
class GamemodeBase
{
public:
virtual ~GamemodeBase() = default;
virtual void tick(double delta_seconds) {}
virtual void draw() {}
private:
};
/*
* Root of the system.
* Engine can be accessed anywhere using Engine::get()
*
* The goal of this class is to handle rendering and internal times
* It also contains a reference to the instanced game mode.
*/
class Engine
{
public:
// Initialize the engine. Gamemode_T should extend GamemodeBase and will be instanced once the engine will be initialized.
template<typename Gamemode_T>
static Engine& init(const std::string& app_name = "SDL_App", uint32_t width = 800, uint32_t height = 600)
static Engine& init(const std::string& app_name = "Empty Engine", uint32_t width = 800, uint32_t height = 600)
{
auto& engine = init_internal(app_name, width, height);
engine.gamemode = std::make_unique<Gamemode_T>();
return engine;
}
static Engine& get();
[[nodiscard]] bool is_init() const { return gamemode != nullptr; }
// Get reference to instanced engine. WARNING : Engine::init() should have been called first
static Engine& get();
virtual ~Engine();
// SDL handles
[[nodiscard]] SDL_Window* get_window_handle() const { return window_handle; }
[[nodiscard]] SDL_Surface* get_surface_handle() const { return surface_handle; }
// Get elapsed time in seconds since last frame
[[nodiscard]] double get_delta_second() const { return delta_second; }
// Get elapsed time since game start
[[nodiscard]] std::chrono::steady_clock::duration get_world_time() const { return std::chrono::steady_clock::now() - start_time; }
// Get instanced gamemode.
template<typename Gamemode_T = GamemodeBase>
[[nodiscard]] Gamemode_T& get_gamemode() { return *static_cast<Gamemode_T*>(&*gamemode); }
// Complete this frame and submit to display
// return true while shutdown() have not been called
bool next_frame();
// Stop render loop and exit game.
void shutdown();
// Accurate randoms
int32_t random_int(int32_t min = INT32_MIN, int32_t max = INT32_MAX);
double random_double(double min = 0.0, double max = 1.0);
[[nodiscard]] bool is_init() const { return gamemode != nullptr; }
private:
static Engine& init_internal(const std::string& app_name = "SDL_App", uint32_t width = 800, uint32_t height = 600);
......@@ -64,7 +82,7 @@ private:
std::chrono::steady_clock::time_point start_time;
std::unique_ptr<GamemodeBase> gamemode;
// Random management
std::random_device random_device;
std::mt19937 mt;
};
......
......@@ -10,25 +10,33 @@ namespace pm
{
class Terrain;
/*
* Main class.
* Extend this to implement an object that will move on a given terrain.
* An entity have a position and a look direction and will draw the corresponding sprite.
*/
class Entity
{
public:
Entity(std::shared_ptr<Terrain> terrain);
virtual ~Entity() = default;
// Set the sprite used for the given direction. All the 5 directions (including NONE) should be initialized.
void set_direction_sprite(const Direction direction, const SpriteHandle& new_sprite);
virtual void set_look_direction(const Direction new_direction);
[[nodiscard]] virtual Direction get_look_direction() const
{
return looking_direction;
}
virtual void draw();
virtual void tick()
{
}
virtual void draw();
/*
* There are different kind of coordinates :
* - Absolute mean a position in pixel on screen (1 unit per pixel)
* - Cell mean a position in grid space (1 unit per cell)
* - Discrete give the corresponding rounded position to closest integer value
* - Linear give the raw position (or eventually in cell space)
*/
void set_absolute_linear_position(const Vector2D& new_pos) { linear_pos = new_pos; }
void set_absolute_discrete_position(const Vector2I& new_pos) { linear_pos = new_pos.cast<Vector2D>(); }
......@@ -40,25 +48,33 @@ public:
[[nodiscard]] Vector2I get_cell_discrete_pos() const { return (linear_pos / terrain->get_unit_length()).rounded().cast<Vector2I>(); }
[[nodiscard]] Vector2D get_cell_linear_pos() const { return linear_pos / terrain->get_unit_length(); }
// Set entity's direction. It is mainly used to select which sprite to render when draw is called.
virtual void set_look_direction(const Direction new_direction);
[[nodiscard]] virtual Direction get_look_direction() const { return looking_direction; }
// Return true if one of the neighbors cells is free
[[nodiscard]] bool is_at_intersection() const;
[[nodiscard]] Terrain& get_terrain() const { return *terrain; }
void pause_animation(bool paused);
[[nodiscard]] bool is_at_intersection() const;
// Hide entity
void hide(bool in_hide) { hidden = in_hide; }
virtual void reset() {}
// Reset entity to it's default state and position when game start
virtual void reset()
{
}
protected:
// Pause animations
void pause_animation(bool paused);
protected:
bool hidden = false;
private:
Vector2D linear_pos;
private:
std::array<std::optional<SpriteHandle>, 5> direction_sprite;
Direction looking_direction;
std::shared_ptr<Terrain> terrain;
// Entity position is internally handled using double coordinates.
Vector2D linear_pos;
};
}
......@@ -70,12 +70,12 @@ public:
{
}
Return_T execute(Args_T&...inArgs)
Return_T execute(Args_T&... inArgs) override
{
return (object_ptr->*function_ptr)(inArgs...);
}
bool operator==(const void* objPtr) const
bool operator==(const void* objPtr) const override
{
return object_ptr == objPtr;
}
......
......@@ -17,7 +17,7 @@
#define INFO(format_str, ...) ::pm::Logger::get().message(::pm::ELogLevel::INFO, std::format_2(format_str, __VA_ARGS__), __FILE__, ##__FUNCTION__, __LINE__)
#define WARNING(format_str, ...) ::pm::Logger::get().message(::pm::ELogLevel::WARNING, std::format_2(format_str, __VA_ARGS__), __FILE__, ##__FUNCTION__, __LINE__)
#define ERROR(format_str, ...) ::pm::Logger::get().message(::pm::ELogLevel::ERROR, std::format_2(format_str, __VA_ARGS__), __FILE__, ##__FUNCTION__, __LINE__)
#if !defined(NDEBUG) || _DEBUG
#if !defined(NDEBUG) || defined(_DEBUG)
#define FATAL(format_str, ...) do { ::pm::Logger::get().message(::pm::ELogLevel::FATAL, std::format_2(format_str, __VA_ARGS__), __FILE__, ##__FUNCTION__, __LINE__); __debugbreak(); exit(EXIT_FAILURE); } while (0)
#else
#define FATAL(format_str, ...) do { ::pm::Logger::get().message(::pm::ELogLevel::FATAL, std::format(format_str, __VA_ARGS__), __FILE__, ##__FUNCTION__, __LINE__); exit(EXIT_FAILURE); } while (0)
......
......@@ -49,6 +49,7 @@ bool PathFinder::find_path(const Vector2I& from, Vector2I to)
const auto index_of = [width](const Vector2I& pt) { return pt.x() + pt.y() * width; };
const auto point_valid = [width, height](const Vector2I& pt) { return pt.x() >= 0 && pt.y() >= 0 && pt.x() < static_cast<int>(width) && pt.y() < static_cast<int>(height); };
// A* body
do
{
const auto old_sp = study_points;
......
......@@ -65,7 +65,6 @@ void SpriteSheet::render_sprite(const SpriteHandle& sprite, Vector2I pos, double
}
// Chose flip-book index based on world time and animation speed (0 is default offset)
const auto elapsed = std::chrono::steady_clock::now() - info->second.last_time;
if (!info->second.paused)
info->second.internal_time += static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count()) / 1000000.0;
......
......@@ -4,6 +4,14 @@
#include "engine/engine.hpp"
#include "engine/terrain.hpp"
namespace std
{
constexpr int sign(auto a)
{
return a < 0 ? -1 : 1;
}
} // namespace std
namespace pm
{
void Character::tick()
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment