mirror of
https://github.com/Nimac0/SDL_Minigame
synced 2026-01-12 10:13:42 +00:00
parent
d10afe1e07
commit
efd8cc6616
@ -5,6 +5,7 @@
|
||||
#include <SDL_mixer.h>
|
||||
#include <vector>
|
||||
|
||||
#include "Manager.h"
|
||||
#include "Vector2D.h"
|
||||
#include "Entity.h"
|
||||
|
||||
@ -12,6 +13,7 @@ class AssetManager;
|
||||
class CollisionHandler;
|
||||
class TextureManager;
|
||||
class SoundManager;
|
||||
class Map;
|
||||
|
||||
class Game
|
||||
{
|
||||
@ -28,13 +30,29 @@ public:
|
||||
void clean();
|
||||
bool running() const;
|
||||
|
||||
static void addTile(unsigned long id, int x, int y);
|
||||
static SDL_Renderer* renderer;
|
||||
static SDL_Event event;
|
||||
static CollisionHandler* collisionHandler;
|
||||
static AssetManager* assets;
|
||||
static TextureManager* textureManager;
|
||||
static SoundManager* soundManager;
|
||||
void addTile(unsigned long id, int x, int y);
|
||||
/* static */ SDL_Renderer* renderer = nullptr;
|
||||
/* static */ SDL_Event event;
|
||||
/* static */ CollisionHandler* collisionHandler;
|
||||
/* static */ AssetManager* assets;
|
||||
/* static */ TextureManager* textureManager;
|
||||
/* static */ SoundManager* soundManager;
|
||||
|
||||
// moved globals
|
||||
Manager manager;
|
||||
Map* map; // game specific, might not be needed for all types of games
|
||||
|
||||
Entity& player1;
|
||||
Entity& player2;
|
||||
|
||||
Entity& wall;
|
||||
|
||||
std::vector<Entity*>& tiles;
|
||||
std::vector<Entity*>& players;
|
||||
std::vector<Entity*>& projectiles;
|
||||
std::vector<Entity*>& hearts;
|
||||
std::vector<Entity*>& powerups;
|
||||
// end moved globals
|
||||
|
||||
void refreshPlayers();
|
||||
Entity::TeamLabel getWinner() const;
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@ -7,9 +9,12 @@
|
||||
#include "Constants.h"
|
||||
#include "Entity.h"
|
||||
|
||||
class Game;
|
||||
class Manager
|
||||
{
|
||||
public:
|
||||
Manager(Game* game) : game(game) {};
|
||||
|
||||
void update();
|
||||
void draw();
|
||||
void refresh();
|
||||
@ -24,7 +29,10 @@ public:
|
||||
|
||||
Entity& addEntity();
|
||||
|
||||
Game* getGame() { return this->game; };
|
||||
|
||||
private:
|
||||
Game* game;
|
||||
std::vector<std::unique_ptr<Entity>> entities;
|
||||
std::array<std::vector<Entity*>, MAX_GROUPS> entitiesByGroup;
|
||||
std::array<std::vector<Entity*>, MAX_TEAMS> entitiesByTeam;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
class Game;
|
||||
class Map
|
||||
{
|
||||
public:
|
||||
@ -17,5 +18,5 @@ public:
|
||||
* \return Boolean for success
|
||||
*
|
||||
*/
|
||||
static bool loadMap(const char* path, int sizeX, int sizeY);
|
||||
static bool loadMap(const char* path, int sizeX, int sizeY, Game* game /* backreference */);
|
||||
};
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "ECS.h"
|
||||
#include "TextureManager.h"
|
||||
|
||||
enum SoundTypes
|
||||
@ -12,6 +13,7 @@ enum SoundTypes
|
||||
THROW_EGG,
|
||||
};
|
||||
|
||||
class Game;
|
||||
class SoundManager
|
||||
{
|
||||
public:
|
||||
@ -28,5 +30,6 @@ class SoundManager
|
||||
std::map<const char*, Mix_Chunk*> sound_cache;
|
||||
|
||||
Mix_Chunk* loadSound(const char* fileName);
|
||||
static void playSound(SoundTypes sound);
|
||||
static void playSound(Game* game, SoundTypes sound);
|
||||
private:
|
||||
};
|
||||
@ -22,6 +22,8 @@ private:
|
||||
SDL_Texture* texture;
|
||||
SDL_Rect srcRect, destRect;
|
||||
|
||||
const char* texturePath;
|
||||
|
||||
bool animated = false;
|
||||
uint8_t frames = 0;
|
||||
uint8_t speed = 100;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "ECS.h"
|
||||
#include <SDL_render.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@ -9,7 +10,7 @@
|
||||
class TextureManager
|
||||
{
|
||||
public:
|
||||
TextureManager() {}
|
||||
TextureManager(Manager* manager) : manager(manager) {}
|
||||
~TextureManager() {
|
||||
for (auto& it : this->texture_cache) {
|
||||
SDL_DestroyTexture(it.second);
|
||||
@ -20,5 +21,7 @@ class TextureManager
|
||||
|
||||
SDL_Texture* loadTexture(const char* fileName);
|
||||
static std::vector<SDL_Rect> splitSpriteSheet(SDL_Texture* spriteSheet, int width, int height, int spritesOnSheet);
|
||||
static void draw(SDL_Texture* texture, SDL_Rect src, SDL_Rect dest, bool flipped = false);
|
||||
static void draw(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Rect src, SDL_Rect dest, bool flipped = false);
|
||||
private:
|
||||
Manager* manager;
|
||||
};
|
||||
@ -21,12 +21,12 @@ AssetManager::AssetManager(Manager* manager) : man(manager) {}
|
||||
AssetManager::~AssetManager() {}
|
||||
|
||||
void AssetManager::addTexture(std::string id, const char* path) {
|
||||
textures.emplace(id, Game::textureManager->loadTexture(path));
|
||||
textures.emplace(id, this->man->getGame()->textureManager->loadTexture(path));
|
||||
}
|
||||
|
||||
void AssetManager::addSoundEffect(std::string id, const char* path)
|
||||
{
|
||||
soundEffects.emplace(id, Game::soundManager->loadSound(path));
|
||||
soundEffects.emplace(id, this->man->getGame()->soundManager->loadSound(path));
|
||||
}
|
||||
|
||||
SDL_Texture* AssetManager::getTexture(std::string id) {
|
||||
@ -81,7 +81,7 @@ Vector2D AssetManager::calculateSpawnPosition()
|
||||
spawnRect.x = rand() % (SCREEN_SIZE_WIDTH - spawnRect.w);
|
||||
spawnRect.y = rand() % (SCREEN_SIZE_HEIGHT - spawnRect.h);
|
||||
conflict = false;
|
||||
for (auto cc : Game::collisionHandler->getColliders({ Entity::GroupLabel::MAPTILES }))
|
||||
for (auto cc : this->man->getGame()->collisionHandler->getColliders({ Entity::GroupLabel::MAPTILES }))
|
||||
{
|
||||
if (SDL_HasIntersection(&spawnRect, &cc->collider) && strcmp(cc->tag, "projectile"))
|
||||
{
|
||||
|
||||
46
src/Game.cpp
46
src/Game.cpp
@ -13,30 +13,28 @@
|
||||
#include "StatEffectsComponent.h"
|
||||
#include "Constants.h"
|
||||
|
||||
Map* map;
|
||||
Manager manager;
|
||||
|
||||
AssetManager* Game::assets = new AssetManager(&manager);
|
||||
TextureManager* Game::textureManager = new TextureManager();
|
||||
SoundManager* Game::soundManager = new SoundManager();
|
||||
|
||||
CollisionHandler* Game::collisionHandler = new CollisionHandler(manager);
|
||||
|
||||
SDL_Renderer* Game::renderer = nullptr;
|
||||
|
||||
SDL_Event Game::event;
|
||||
|
||||
auto& player1(manager.addEntity());
|
||||
auto& player2(manager.addEntity());
|
||||
|
||||
auto& wall(manager.addEntity());
|
||||
|
||||
Game::Game() = default;
|
||||
Game::Game() :
|
||||
manager(this),
|
||||
tiles(manager.getGroup((size_t)Entity::GroupLabel::MAPTILES)),
|
||||
players(manager.getGroup((size_t)Entity::GroupLabel::PLAYERS)),
|
||||
projectiles(manager.getGroup((size_t)Entity::GroupLabel::PROJECTILE)),
|
||||
hearts(manager.getGroup((size_t)Entity::GroupLabel::HEARTS)),
|
||||
powerups(manager.getGroup((size_t)Entity::GroupLabel::POWERUPS)),
|
||||
player1(manager.addEntity()),
|
||||
player2(manager.addEntity()),
|
||||
wall(manager.addEntity())
|
||||
{
|
||||
};
|
||||
|
||||
Game::~Game() = default;
|
||||
|
||||
void Game::init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen)
|
||||
{
|
||||
Game::assets = new AssetManager(&manager);
|
||||
Game::textureManager = new TextureManager(&manager);
|
||||
Game::soundManager = new SoundManager();
|
||||
Game::collisionHandler = new CollisionHandler(manager); // why does this use a referrence, but AssetManager a pointer?
|
||||
|
||||
int flags = 0;
|
||||
if (fullscreen)
|
||||
{
|
||||
@ -140,7 +138,7 @@ void Game::init(const char* title, int xpos, int ypos, int width, int height, bo
|
||||
if (this->isRunning == false) return;
|
||||
|
||||
map = new Map();
|
||||
if (!map->loadMap("assets/SDL_map_test.txt", 25, 20)) {
|
||||
if (!map->loadMap("assets/SDL_map_test.txt", 25, 20, this)) {
|
||||
std::cout << "ERROR: Map couldnt be loaded! " << SDL_GetError() << std::endl;
|
||||
SDL_ClearError();
|
||||
};
|
||||
@ -275,12 +273,6 @@ void Game::selectCharacters(const char* &playerSprite, const char* &enemySprite)
|
||||
this->isRunning = true;
|
||||
}
|
||||
|
||||
auto& tiles(manager.getGroup((size_t)Entity::GroupLabel::MAPTILES));
|
||||
auto& players(manager.getGroup((size_t)Entity::GroupLabel::PLAYERS));
|
||||
auto& projectiles(manager.getGroup((size_t)Entity::GroupLabel::PROJECTILE));
|
||||
auto& hearts(manager.getGroup((size_t)Entity::GroupLabel::HEARTS));
|
||||
auto& powerups(manager.getGroup((size_t)Entity::GroupLabel::POWERUPS));
|
||||
|
||||
void Game::handleEvents()
|
||||
{
|
||||
SDL_PollEvent(&event);
|
||||
@ -348,7 +340,7 @@ void Game::clean()
|
||||
std::cout << "Game Cleaned!" << std::endl;
|
||||
}
|
||||
|
||||
void Game::addTile(unsigned long id, int x, int y)
|
||||
void Game::addTile(unsigned long id, int x, int y) // tile entity
|
||||
{
|
||||
auto& tile(manager.addEntity());
|
||||
tile.addComponent<TileComponent>(x, y, TILE_SIZE, TILE_SIZE, id);
|
||||
|
||||
@ -1,11 +1,15 @@
|
||||
#include "GameObject.h"
|
||||
|
||||
#include "SDL_error.h"
|
||||
#include "TextureManager.h"
|
||||
#include "Game.h"
|
||||
|
||||
GameObject::GameObject(const char* texturesheet, int x, int y)
|
||||
{
|
||||
this->objTexture = Game::textureManager->loadTexture(texturesheet);
|
||||
// seems not to be used, and was using deprecated functionality
|
||||
SDL_SetError("GameObject not implemented");
|
||||
|
||||
// this->objTexture = Game::textureManager->loadTexture(texturesheet);
|
||||
this->xPos = x;
|
||||
this->yPos = y;
|
||||
}
|
||||
@ -28,5 +32,6 @@ void GameObject::update()
|
||||
|
||||
void GameObject::render()
|
||||
{
|
||||
SDL_RenderCopy(Game::renderer, objTexture, &srcRect, &destRect);
|
||||
SDL_SetError("GameObject not implemented");
|
||||
// SDL_RenderCopy(Game::renderer, objTexture, &srcRect, &destRect);
|
||||
}
|
||||
|
||||
@ -30,24 +30,24 @@ void KeyboardController::update()
|
||||
if (keystates[this->up]) {
|
||||
transform->direction.y = -1;
|
||||
sprite->playAnimation(WALK);
|
||||
SoundManager::playSound(STEPS);
|
||||
SoundManager::playSound(this->entity->getManager().getGame(), STEPS);
|
||||
}
|
||||
if (keystates[this->left]) {
|
||||
transform->direction.x = -1;
|
||||
sprite->playAnimation(WALK);
|
||||
sprite->setDirection(Direction::LEFT);
|
||||
SoundManager::playSound(STEPS);
|
||||
SoundManager::playSound(this->entity->getManager().getGame(), STEPS);
|
||||
}
|
||||
if (keystates[this->down]) {
|
||||
transform->direction.y = 1;
|
||||
sprite->playAnimation(WALK);
|
||||
SoundManager::playSound(STEPS);
|
||||
SoundManager::playSound(this->entity->getManager().getGame(), STEPS);
|
||||
}
|
||||
if (keystates[this->right]) {
|
||||
transform->direction.x = 1;
|
||||
sprite->playAnimation(WALK);
|
||||
sprite->setDirection(Direction::RIGHT);
|
||||
SoundManager::playSound(STEPS);
|
||||
SoundManager::playSound(this->entity->getManager().getGame(), STEPS);
|
||||
}
|
||||
|
||||
if (keystates[this->fire]) {
|
||||
@ -62,12 +62,12 @@ void KeyboardController::update()
|
||||
//TODO: adding actual projectile textures
|
||||
if (fireVelocity.x > 0) {
|
||||
sprite->setDirection(Direction::RIGHT);
|
||||
Game::assets->createProjectile(Vector2D(player->position.x, player->position.y), fireVelocity,
|
||||
this->entity->getManager().getGame()->assets->createProjectile(Vector2D(player->position.x, player->position.y), fireVelocity,
|
||||
1, 180, 2, "assets/egg.png", this->entity->getTeam());
|
||||
}
|
||||
else {
|
||||
sprite->setDirection(Direction::LEFT);
|
||||
Game::assets->createProjectile(Vector2D(player->position.x, player->position.y), fireVelocity,
|
||||
this->entity->getManager().getGame()->assets->createProjectile(Vector2D(player->position.x, player->position.y), fireVelocity,
|
||||
1, 180, 2, "assets/egg.png", this->entity->getTeam());
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
#include "Game.h"
|
||||
#include "SDL_error.h"
|
||||
|
||||
bool Map::loadMap(const char* path, int sizeX, int sizeY)
|
||||
bool Map::loadMap(const char* path, int sizeX, int sizeY, Game* game /* backreference */)
|
||||
{
|
||||
std::string tileIDstr;
|
||||
char singleChar = 0;
|
||||
@ -28,7 +28,7 @@ bool Map::loadMap(const char* path, int sizeX, int sizeY)
|
||||
if (singleChar == ',' || singleChar == '\n') {
|
||||
if (tileIDstr.empty())
|
||||
continue;
|
||||
Game::addTile(std::stoi(tileIDstr), x * TILE_SIZE, y * TILE_SIZE);
|
||||
game->addTile(std::stoi(tileIDstr), x * TILE_SIZE, y * TILE_SIZE);
|
||||
tileIDstr.clear();
|
||||
x++;
|
||||
if (singleChar == '\n') {
|
||||
|
||||
@ -28,7 +28,7 @@ PowerupComponent::PowerupComponent(PowerupType type)
|
||||
void PowerupComponent::update()
|
||||
{
|
||||
Entity* player;
|
||||
if ((player = Game::collisionHandler->getAnyIntersection<Entity*>(
|
||||
if ((player = this->entity->getManager().getGame()->collisionHandler->getAnyIntersection<Entity*>(
|
||||
entity,
|
||||
Vector2D(0, 0),
|
||||
{ Entity::GroupLabel::PLAYERS },
|
||||
|
||||
@ -13,14 +13,14 @@ void ProjectileComponent::init()
|
||||
{
|
||||
transformComponent = &entity->getComponent<TransformComponent>();
|
||||
transformComponent->direction = direction;
|
||||
SoundManager::playSound(THROW_EGG);
|
||||
SoundManager::playSound(this->entity->getManager().getGame(), THROW_EGG);
|
||||
}
|
||||
|
||||
void ProjectileComponent::update()
|
||||
{
|
||||
distance += speed;
|
||||
|
||||
IntersectionBitSet boundsIntersection = Game::collisionHandler->getIntersectionWithBounds(entity);
|
||||
IntersectionBitSet boundsIntersection = this->entity->getManager().getGame()->collisionHandler->getIntersectionWithBounds(entity);
|
||||
|
||||
if ((boundsIntersection | IntersectionBitSet("1100")).all() || (boundsIntersection | IntersectionBitSet("0011")).all()) {
|
||||
this->entity->destroy();
|
||||
@ -31,7 +31,7 @@ void ProjectileComponent::update()
|
||||
}
|
||||
|
||||
Entity* player;
|
||||
if ((player = Game::collisionHandler->getAnyIntersection<Entity*>(
|
||||
if ((player = this->entity->getManager().getGame()->collisionHandler->getAnyIntersection<Entity*>(
|
||||
entity,
|
||||
Vector2D(0,0),
|
||||
{Entity::GroupLabel::PLAYERS},
|
||||
|
||||
@ -27,7 +27,7 @@ Mix_Chunk* SoundManager::loadSound(const char* fileName)
|
||||
return sound;
|
||||
}
|
||||
|
||||
void SoundManager::playSound(SoundTypes sound)
|
||||
void SoundManager::playSound(Game* game, SoundTypes sound)
|
||||
{
|
||||
switch (sound)
|
||||
{
|
||||
@ -35,14 +35,14 @@ void SoundManager::playSound(SoundTypes sound)
|
||||
if (Mix_Playing(-1) != 0)
|
||||
break;
|
||||
|
||||
if (Mix_PlayChannel(-1, Game::assets->getSound("steps"), 0) == -1) {
|
||||
if (Mix_PlayChannel(-1, game->assets->getSound("steps"), 0) == -1) {
|
||||
std::cerr << "Error playing sound 'steps': " << Mix_GetError() << std::endl;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SoundTypes::THROW_EGG:
|
||||
if (Mix_PlayChannel(-1, Game::assets->getSound("throw_egg"), 0) == -1) {
|
||||
if (Mix_PlayChannel(-1, game->assets->getSound("throw_egg"), 0) == -1) {
|
||||
std::cerr << "Error playing sound 'throw_egg': " << Mix_GetError() << std::endl;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include "SpriteComponent.h"
|
||||
|
||||
#include <SDL_timer.h>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include "AnimationHandler.h"
|
||||
@ -9,10 +10,11 @@
|
||||
#include "Entity.h"
|
||||
#include "TransformComponent.h"
|
||||
#include "Game.h"
|
||||
#include "Manager.h"
|
||||
|
||||
SpriteComponent::SpriteComponent(const char* path)
|
||||
{
|
||||
setTexture(path);
|
||||
this->texturePath = path;
|
||||
}
|
||||
|
||||
SpriteComponent::SpriteComponent(const char* path, bool isAnimated)
|
||||
@ -24,7 +26,7 @@ SpriteComponent::SpriteComponent(const char* path, bool isAnimated)
|
||||
|
||||
playAnimation(IDLE);
|
||||
|
||||
setTexture(path);
|
||||
this->texturePath = path;
|
||||
}
|
||||
|
||||
SpriteComponent::~SpriteComponent()
|
||||
@ -34,11 +36,13 @@ SpriteComponent::~SpriteComponent()
|
||||
|
||||
void SpriteComponent::setTexture(const char* path)
|
||||
{
|
||||
this->texture = Game::textureManager->loadTexture(path);
|
||||
this->texture = this->entity->getManager().getGame()->textureManager->loadTexture(path);
|
||||
}
|
||||
|
||||
void SpriteComponent::init()
|
||||
{
|
||||
setTexture(this->texturePath);
|
||||
|
||||
this->transform = &entity->getComponent<TransformComponent>();
|
||||
|
||||
this->srcRect.x = this->srcRect.y = 0;
|
||||
@ -64,7 +68,7 @@ void SpriteComponent::update()
|
||||
|
||||
void SpriteComponent::draw()
|
||||
{
|
||||
Game::textureManager->draw(this->texture, this->srcRect, this->destRect, this->animated && this->flipped);
|
||||
this->entity->getManager().getGame()->textureManager->draw(this->entity->getManager().getGame()->renderer, this->texture, this->srcRect, this->destRect, this->animated && this->flipped);
|
||||
}
|
||||
|
||||
void SpriteComponent::playAnimation(AnimationType type)
|
||||
|
||||
@ -12,15 +12,15 @@ SDL_Texture* TextureManager::loadTexture(const char* fileName)
|
||||
if (it != this->texture_cache.end()) {
|
||||
return it->second;
|
||||
}
|
||||
auto texture = IMG_LoadTexture(Game::renderer, fileName);
|
||||
auto texture = IMG_LoadTexture(this->manager->getGame()->renderer, fileName);
|
||||
if (texture == NULL) throw std::runtime_error(std::string("Couldn't load texture '") + fileName + "'");
|
||||
this->texture_cache.emplace(std::string(fileName), texture);
|
||||
printf("Loaded texture at '%s'\n", fileName);
|
||||
return texture;
|
||||
}
|
||||
|
||||
void TextureManager::draw(SDL_Texture* texture, SDL_Rect src, SDL_Rect dest, bool flipped)
|
||||
void TextureManager::draw(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Rect src, SDL_Rect dest, bool flipped)
|
||||
{
|
||||
SDL_RendererFlip flip = flipped ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
|
||||
SDL_RenderCopyEx(Game::renderer, texture, &src, &dest, 0, NULL, flip);
|
||||
SDL_RenderCopyEx(renderer, texture, &src, &dest, 0, NULL, flip);
|
||||
}
|
||||
@ -65,10 +65,10 @@ void TransformComponent::update()
|
||||
if (this->entity->hasGroup((size_t)Entity::GroupLabel::PLAYERS)) {
|
||||
IntersectionBitSet intersections =
|
||||
(CollisionHandler::getIntersectionWithBounds(entity, Vector2D(positionChange.x, 0)) |
|
||||
(Game::collisionHandler->getAnyIntersection<IntersectionBitSet>(entity, Vector2D(positionChange.x, 0), { Entity::GroupLabel::MAPTILES, Entity::GroupLabel::COLLIDERS })) &
|
||||
(this->entity->getManager().getGame()->collisionHandler->getAnyIntersection<IntersectionBitSet>(entity, Vector2D(positionChange.x, 0), { Entity::GroupLabel::MAPTILES, Entity::GroupLabel::COLLIDERS })) &
|
||||
IntersectionBitSet("0011")) |
|
||||
(CollisionHandler::getIntersectionWithBounds(entity, Vector2D(0, positionChange.y)) |
|
||||
(Game::collisionHandler->getAnyIntersection<IntersectionBitSet>(entity, Vector2D(0, positionChange.y), { Entity::GroupLabel::MAPTILES, Entity::GroupLabel::COLLIDERS })) &
|
||||
(this->entity->getManager().getGame()->collisionHandler->getAnyIntersection<IntersectionBitSet>(entity, Vector2D(0, positionChange.y), { Entity::GroupLabel::MAPTILES, Entity::GroupLabel::COLLIDERS })) &
|
||||
IntersectionBitSet("1100"));
|
||||
|
||||
if (intersections.test((size_t)Direction::LEFT) || intersections.test((size_t)Direction::RIGHT))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user