diff --git a/assets/pacman/ghost.ascii b/assets/pacman/ghost.ascii new file mode 100644 index 0000000..4ccb979 --- /dev/null +++ b/assets/pacman/ghost.ascii @@ -0,0 +1,4 @@ +A% +B: +C +D \ No newline at end of file diff --git a/assets/pacman/ghost.png b/assets/pacman/ghost.png new file mode 100644 index 0000000..c5dca68 Binary files /dev/null and b/assets/pacman/ghost.png differ diff --git a/assets/pacman/map.ascii b/assets/pacman/map.ascii new file mode 100644 index 0000000..82bdf6f --- /dev/null +++ b/assets/pacman/map.ascii @@ -0,0 +1,30 @@ +########################### +# # # +# #### ##### # ##### #### # +#?#### ##### # ##### ####?# +# #### ##### # ##### #### # +# # +# #### # ######### # #### # +# #### # ######### # #### # +# # # # # +###### ##### # ##### ###### +<<<<<# ##### # ##### # +<<<<<# # # # +<<<<<# # ####_#### # # +###### # #wwwwwww# # ###### + #wwwwwww# +###### # #wwwwwww# # ###### +<<<<<# # #wwwwwww# # # +<<<<<# # ######### # # +<<<<<# # # # +###### # ######### # ###### +# # # +# #### ##### # ##### #### # +# #### ##### # ##### #### # +# ## o ## # +### ## ## ####### ## ## ### +# ## # ## # +#?########## # ##########?# +# ########## # ########## # +# # +########################### \ No newline at end of file diff --git a/assets/pacman/map.png b/assets/pacman/map.png new file mode 100644 index 0000000..920ef23 Binary files /dev/null and b/assets/pacman/map.png differ diff --git a/assets/pacman/pacman.ascii b/assets/pacman/pacman.ascii new file mode 100644 index 0000000..dc06697 --- /dev/null +++ b/assets/pacman/pacman.ascii @@ -0,0 +1,4 @@ +<<< +>>> +^^^ +vvv \ No newline at end of file diff --git a/assets/pacman/pacman.png b/assets/pacman/pacman.png new file mode 100644 index 0000000..d9b75f5 Binary files /dev/null and b/assets/pacman/pacman.png differ diff --git a/assets/pacman/point.ascii b/assets/pacman/point.ascii new file mode 100644 index 0000000..7b9d05c --- /dev/null +++ b/assets/pacman/point.ascii @@ -0,0 +1 @@ +.0 \ No newline at end of file diff --git a/assets/pacman/point.png b/assets/pacman/point.png new file mode 100644 index 0000000..a70378f Binary files /dev/null and b/assets/pacman/point.png differ diff --git a/games/CMakeLists.txt b/games/CMakeLists.txt index aecae1b..1188170 100644 --- a/games/CMakeLists.txt +++ b/games/CMakeLists.txt @@ -1,2 +1,3 @@ +add_subdirectory(pacman) add_subdirectory(snake) add_subdirectory(nibbler) diff --git a/games/pacman/CMakeLists.txt b/games/pacman/CMakeLists.txt new file mode 100644 index 0000000..204e6fa --- /dev/null +++ b/games/pacman/CMakeLists.txt @@ -0,0 +1,22 @@ +project(pacman) +add_library(${PROJECT_NAME} SHARED + export.cpp + src/PacmanGame.cpp + src/PacmanGame.hpp + src/PacmanGameProvider.cpp + src/PacmanGameProvider.hpp + src/entities/map/MapEntity.cpp + src/entities/map/MapEntity.hpp + src/entities/player/PlayerEntity.cpp + src/entities/player/PlayerEntity.hpp + src/entities/player/components/HeadKeyboardComponent.cpp + src/entities/player/components/HeadKeyboardComponent.hpp + src/entities/map/PointEntity.cpp + src/entities/map/PointEntity.hpp + src/entities/ghost/GhostEntity.cpp + src/entities/ghost/GhostEntity.hpp +) +add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/../common PRIVATE) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../..) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/..) diff --git a/games/pacman/export.cpp b/games/pacman/export.cpp new file mode 100644 index 0000000..b6c8cdc --- /dev/null +++ b/games/pacman/export.cpp @@ -0,0 +1,22 @@ +/* +** EPITECH PROJECT, 2024 +** arcade-shared +** File description: +** export +*/ + +#include "PacmanGameProvider.hpp" +#include "shared/types/Libraries.hpp" + +using namespace shared::games; +using namespace shared::types; + +extern "C" { +LibraryType SHARED_LIBRARY_TYPE_GETTER_NAME(void) { + return LibraryType::GAME; +} + +IGameProvider *SHARED_GAME_PROVIDER_GETTER_NAME(void) { + return new arcade::games::pacman::PacmanGameProvider(); +} +} diff --git a/games/pacman/src/PacmanGame.cpp b/games/pacman/src/PacmanGame.cpp new file mode 100644 index 0000000..e4885a9 --- /dev/null +++ b/games/pacman/src/PacmanGame.cpp @@ -0,0 +1,160 @@ +/* +** EPITECH PROJECT, 2024 +** PacmanGame.cpp +** File description: +** PacmanGame class +*/ + +#include +#include "PacmanGame.hpp" +#include "entities/map/MapEntity.hpp" +#include "entities/ghost/GhostEntity.hpp" + +using namespace arcade::games; + +const shared::games::GameManifest pacman::PacmanGame::manifest = { + .name = "pacman", + .description = "The pacman arcade game", + .version = "1.0.0", + .authors = { + { + .name = "TekMath", + .email = "matheo.coquet@epitech.eu", + .website = "https://github.com/tekmath" + } + } +}; + +pacman::PacmanGame::PacmanGame() : common::AGame(Vector2u(27, 30), 60), + _player(std::make_unique(Vector2i(13, 23))), + _map(std::make_unique()) { + + for (const auto &entity: this->_map->generateWalls(MAP_PATH)) { + this->_registerEntity(entity); + } + + this->_currentScore = 0; + + for (unsigned int i = 0; i < 4; i++) { + this->_ghosts.push_back(std::make_unique(i)); + this->_registerEntity(this->_ghosts[i]); + } + + this->_registerEntity(this->_map); + this->_registerEntity(this->_player); + this->_clock = std::chrono::milliseconds(0); +} + +const shared::games::GameManifest &pacman::PacmanGame::getManifest() const noexcept { + return this->manifest; +} + +void pacman::PacmanGame::compute(shared::games::DeltaTime dt) { + this->_clock += dt; + + if (this->_canEatGhost && this->_stopEatGhostTime < this->_clock) { + this->_canEatGhost = false; + for (auto ghost : this->_ghosts) { + ghost->disableCanBeEat(); + } + } + + if (this->_clock > std::chrono::milliseconds(100) + this->_player->lastMove) { + this->_player->lastMove = this->_clock; + if (this->_map->mapData[this->_player->getPosition().y + this->_player->direction.y][ + this->_player->getPosition().x + this->_player->direction.x] != '#') { + this->_player->forward(); + } + } + + for (auto ghost : this->_ghosts) { + if (this->_clock > std::chrono::milliseconds(100) + ghost->lastMove) { + if (ghost->direction.x == 0 && ghost->direction.y == 0) { + ghost->direction = Vector2i(0, -1); + ghost->position = Vector2i(13, 12); + } + if (this->_map->mapData[ghost->position.y + ghost->direction.y][ + ghost->position.x + ghost->direction.x] != '#') { + ghost->lastMove = this->_clock; + ghost->forward(); + } else { + this->_redirectGhost(ghost); + } + } + } +} + + + +void pacman::PacmanGame::addNewPoint(Vector2i position) { + this->_entities.erase(std::remove_if(this->_entities.begin(), this->_entities.end(), + [&position](const shared::games::entity::EntityPtr &entity) { + auto tail = std::dynamic_pointer_cast(entity); + if (tail) { + return tail->position.x == position.x && + tail->position.y == position.y; + } + return false; + }), this->_entities.end()); + + this->_currentScore += 5; +} + +void pacman::PacmanGame::_redirectGhost(std::shared_ptr ghost) { + std::vector pos; + + if (this->_map->mapData[ghost->position.y - 1][ + ghost->position.x] == ' ') + pos.push_back(Vector2i(0, -1)); + if (this->_map->mapData[ghost->position.y + 1][ + ghost->position.x] == ' ') + pos.push_back(Vector2i(0, 1)); + if (this->_map->mapData[ghost->position.y][ + ghost->position.x - 1] == ' ') + pos.push_back(Vector2i(-1, 0)); + if (this->_map->mapData[ghost->position.y][ + ghost->position.x + 1] == ' ') + pos.push_back(Vector2i(1, 0)); + + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution dis(0, pos.size() - 1); + + ghost->direction = pos[dis(gen)]; +} + +void pacman::PacmanGame::eatPlayer(Vector2i position) { + if (this->_canEatGhost) { + unsigned int index = 0; + + for (auto ghost : this->_ghosts) { + if (ghost->position.x == position.x && ghost->position.y == position.y) { + ghost->reset(index); + return; + } + index++; + } + } + + this->_clock = std::chrono::milliseconds(0); + this->_player->reset(Vector2i(13, 23)); + if (this->_currentScore > this->_score) + this->_score = this->_currentScore; + this->_currentScore = 0; + + unsigned int index = 0; + for (auto ghost : this->_ghosts) { + ghost->reset(index); + index++; + } + +} + +void pacman::PacmanGame::canEatGhosts() { + this->_canEatGhost = true; + this->_stopEatGhostTime = this->_clock + std::chrono::seconds(5); + + for (auto ghost : this->_ghosts) { + ghost->enableCanBeEat(); + } +} diff --git a/games/pacman/src/PacmanGame.hpp b/games/pacman/src/PacmanGame.hpp new file mode 100644 index 0000000..c09be68 --- /dev/null +++ b/games/pacman/src/PacmanGame.hpp @@ -0,0 +1,78 @@ +/* +** EPITECH PROJECT, 2024 +** PacmanGame.hpp +** File description: +** PacmanGame class +*/ + +#pragma once + +#include "common/game/AGame.hpp" +#include "entities/player/PlayerEntity.hpp" +#include "entities/map/MapEntity.hpp" +#include "entities/ghost/GhostEntity.hpp" + +#define MAP_PATH "assets/pacman/map.ascii" + +namespace arcade::games::pacman { + class PacmanGame; +} + +class arcade::games::pacman::PacmanGame : public arcade::games::common::AGame { +public: + PacmanGame(); + + ~PacmanGame() override = default; + + /** + * @brief Game manifest + * + */ + static const shared::games::GameManifest manifest; + + /** + * @brief Get the manifest object + * + * @return const shared::games::GameManifest& + */ + const shared::games::GameManifest &getManifest() const noexcept override; + + /** + * @brief Allow game possible actions + * + * @param dt Delta time from last frame + */ + void compute(shared::games::DeltaTime dt) override; + + /** + * @brief Add new point to player + */ + void addNewPoint(Vector2i position); + + /** + * @brief When a ghost eat a player + */ + void eatPlayer(Vector2i position); + + /** + * @brief Enable the ghost mode + */ + void canEatGhosts(); + +protected: + shared::games::DeltaTime _clock; + std::shared_ptr _player; + std::shared_ptr _map; + std::vector> _ghosts; + + bool _canEatGhost; + shared::games::DeltaTime _stopEatGhostTime; + + /** + * @brief Redirect the ghost when he is blocked + * @param ghost + */ + void _redirectGhost(std::shared_ptr ghost); + + int _currentScore; +}; diff --git a/games/pacman/src/PacmanGameProvider.cpp b/games/pacman/src/PacmanGameProvider.cpp new file mode 100644 index 0000000..f3356bd --- /dev/null +++ b/games/pacman/src/PacmanGameProvider.cpp @@ -0,0 +1,19 @@ +/* +** EPITECH PROJECT, 2024 +** PacmanGameProvider.cpp +** File description: +** PacmanGameProvider class +*/ + +#include "PacmanGame.hpp" +#include "PacmanGameProvider.hpp" + +using namespace arcade::games; + +const shared::games::GameManifest &pacman::PacmanGameProvider::getManifest() const noexcept { + return PacmanGame::manifest; +} + +std::shared_ptr pacman::PacmanGameProvider::createInstance() { + return std::make_shared(); +} diff --git a/games/pacman/src/PacmanGameProvider.hpp b/games/pacman/src/PacmanGameProvider.hpp new file mode 100644 index 0000000..a9b041d --- /dev/null +++ b/games/pacman/src/PacmanGameProvider.hpp @@ -0,0 +1,35 @@ +/* +** EPITECH PROJECT, 2024 +** PacmanGameProvider.hpp +** File description: +** PacmanGameProvider class +*/ + +#pragma once + +#include "shared/games/IGameProvider.hpp" + +namespace arcade::games::pacman { + class PacmanGameProvider; +} + +class arcade::games::pacman::PacmanGameProvider : public shared::games::IGameProvider { +public: + PacmanGameProvider() = default; + + ~PacmanGameProvider() override = default; + + /** + * @brief Provides the game manifest + * + * @return Manifest of current game + */ + const shared::games::GameManifest &getManifest() const noexcept override; + + /** + * @brief Provides a new instance of the game + * + * @return Created game instance + */ + std::shared_ptr createInstance() override; +}; diff --git a/games/pacman/src/entities/ghost/GhostEntity.cpp b/games/pacman/src/entities/ghost/GhostEntity.cpp new file mode 100644 index 0000000..d263306 --- /dev/null +++ b/games/pacman/src/entities/ghost/GhostEntity.cpp @@ -0,0 +1,104 @@ +/* +** EPITECH PROJECT, 2024 +** GhostEntity.cpp +** File description: +** GhostEntity class +*/ + +#include "../../PacmanGame.hpp" +#include "GhostEntity.hpp" +#include "common/components/TextureComponent.hpp" +#include "common/components/CollidableComponent.hpp" + +using namespace arcade::games::pacman; +using namespace arcade::games::common::components; +using namespace shared::types; + +GhostEntity::GhostEntity(unsigned int asset): position(11 + asset , 14), direction(0, 0), _defaultOrigin(Vector2u(0, asset)) { + this->lastMove = std::chrono::seconds(10 + asset * 2); + this->_spawnGhost(asset); +} + +void GhostEntity::_spawnGhost(unsigned int asset) { + shared::games::components::TextureProps textureProps = { + .sources = { + .ascii = "assets/pacman/ghost.ascii", + .bin = "assets/pacman/ghost.png", + .binTileSize = Vector2f(35, 35) + }, + .origin = Vector2u(0, asset) + }; + std::shared_ptr collision = std::make_shared(*this, this->_onCollide); + std::shared_ptr texture = std::make_shared(*this, Vector2u(1, 1), 15, + textureProps); + + collision->getPosition().x = this->position.x; + collision->getPosition().y = this->position.y; + this->_components.push_back(collision); + texture->getPosition().x = this->position.x; + texture->getPosition().y = this->position.y; + this->_components.push_back(texture); +} + +void GhostEntity::forward() { + this->position.x += this->direction.x; + this->position.y += this->direction.y; + + if (this->position.y == 14) { + if (this->position.x < -1) { + this->position.x = 27; + } + if (this->position.x > 28) { + this->position.x = 1; + } + } + + for (auto &component: this->_components) { + auto posCmp = std::dynamic_pointer_cast(component); + if (posCmp == nullptr) continue; + + posCmp->getPosition().x = this->position.x; + posCmp->getPosition().y = this->position.y; + } +} + +void GhostEntity::_onCollide(std::shared_ptr ctx, + std::shared_ptr target) { + auto game = std::dynamic_pointer_cast(ctx); + auto entity = dynamic_cast(&target->getEntity()); + + if (!game) + return; + if (entity) { + game->eatPlayer(entity->getPosition()); + } +} + +void GhostEntity::reset(unsigned int index) { + this->lastMove = std::chrono::seconds(10 + index * 2); + this->position = Vector2i(11 + index , 14); + this->direction = Vector2i(0, 0); + this->forward(); +} + +void GhostEntity::enableCanBeEat() { + this->_canBeEat = true; + + for (auto &component: this->_components) { + auto txtCmp = std::dynamic_pointer_cast(component); + if (txtCmp == nullptr) continue; + + txtCmp->getTextureProps().origin = Vector2u(1, 0); + } +} + +void GhostEntity::disableCanBeEat() { + this->_canBeEat = false; + + for (auto &component: this->_components) { + auto txtCmp = std::dynamic_pointer_cast(component); + if (txtCmp == nullptr) continue; + + txtCmp->getTextureProps().origin = this->_defaultOrigin; + } +} diff --git a/games/pacman/src/entities/ghost/GhostEntity.hpp b/games/pacman/src/entities/ghost/GhostEntity.hpp new file mode 100644 index 0000000..347cedb --- /dev/null +++ b/games/pacman/src/entities/ghost/GhostEntity.hpp @@ -0,0 +1,70 @@ +/* +** EPITECH PROJECT, 2024 +** GhostEntity.hpp +** File description: +** GhostEntity class +*/ + +#pragma once + +#include "common/game/AGame.hpp" +#include "common/entity/AEntity.hpp" +#include "shared/types/Vector.hpp" +#include "shared/games/components/ICollidableComponent.hpp" + +namespace arcade::games::pacman { + class GhostEntity; +} + +class arcade::games::pacman::GhostEntity : public common::AEntity { +public: + ~GhostEntity() override = default; + + /** + * @brief Create a ghost + * @param asset Index of the ghost + */ + GhostEntity(unsigned int asset); + + /** + * @brief Update the position of the ghost + */ + void forward(); + + /** + * @brief Reset ghost position + */ + void reset(unsigned int index); + + /** + * @brief set ghost can be eat + */ + void enableCanBeEat(); + + /** + * @brief set ghost cant be eat + */ + void disableCanBeEat(); + + shared::games::DeltaTime lastMove; + shared::types::Vector2i direction; + shared::types::Vector2i position; + +protected: + bool _canBeEat; + shared::types::Vector2u _defaultOrigin; + + /** + * @brief Spawn player on the map + * @param asset Index of the ghost + */ + void _spawnGhost(unsigned int asset); + + /** + * @brief When a ghost enter in contact with a player + * @param ctx Game + * @param target Component target + */ + static void _onCollide(std::shared_ptr ctx, + std::shared_ptr target); +}; diff --git a/games/pacman/src/entities/map/MapEntity.cpp b/games/pacman/src/entities/map/MapEntity.cpp new file mode 100644 index 0000000..78434a3 --- /dev/null +++ b/games/pacman/src/entities/map/MapEntity.cpp @@ -0,0 +1,70 @@ +/* +** EPITECH PROJECT, 2024 +** MapEntity.cpp +** File description: +** MapEntity class +*/ + +#include +#include "MapEntity.hpp" +#include "common/components/TextureComponent.hpp" +#include "common/components/CollidableComponent.hpp" + +using namespace arcade::games::pacman; +using namespace arcade::games::common::components; +using namespace shared::types; + +std::vector> MapEntity::generateWalls(std::string mapFile) { + std::vector> list; + std::vector map; + + std::ifstream file(mapFile); + char part = '\0'; + Vector2i position = Vector2i(0, 0); + + if (!file) + return list; + map.push_back(""); + while (file.get(part)) { + if (part == '\n') { + map.push_back(""); + position.x = 0; + position.y++; + continue; + } + map[position.y].push_back(part); + if (part == '#') + this->_createWall(position); + if (part == ' ') { + list.push_back(std::make_shared(position, false)); + } + if (part == '?') { + list.push_back(std::make_shared(position, true)); + } + position.x++; + } + file.close(); + this->mapData = map; + return list; +} + +void MapEntity::_createWall(shared::types::Vector2i position) { + shared::games::components::TextureProps textureProps = { + .sources = { + .ascii = "assets/pacman/map.ascii", + .bin = "assets/pacman/map.png", + .binTileSize = Vector2f(40, 40) + }, + .origin = Vector2u(0, 0) + }; + std::shared_ptr collision = std::make_shared(*this, nullptr); + std::shared_ptr texture = std::make_shared(*this, Vector2u(1, 1), 1, + textureProps); + + collision->getPosition().x = position.x; + collision->getPosition().y = position.y; + this->_components.push_back(collision); + texture->getPosition().x = position.x; + texture->getPosition().y = position.y; + this->_components.push_back(texture); +} diff --git a/games/pacman/src/entities/map/MapEntity.hpp b/games/pacman/src/entities/map/MapEntity.hpp new file mode 100644 index 0000000..c680ccd --- /dev/null +++ b/games/pacman/src/entities/map/MapEntity.hpp @@ -0,0 +1,37 @@ +/* +** EPITECH PROJECT, 2024 +** MapEntity.hpp +** File description: +** MapEntity class +*/ + +#pragma once + +#include "common/entity/AEntity.hpp" +#include "shared/types/Vector.hpp" +#include "PointEntity.hpp" + +namespace arcade::games::pacman { + class MapEntity; +} + +class arcade::games::pacman::MapEntity : public common::AEntity { +public: + ~MapEntity() override = default; + MapEntity() = default; + + /** + * Generate all wall of the map + * @param mapFile Path of the map + * @return List of points + */ + std::vector> generateWalls(std::string mapFile); + + std::vector mapData; +protected: + /** + * @brief Create a wall (part of) (Component creation) + * @param position Position of the wall + */ + void _createWall(shared::types::Vector2i position); +}; diff --git a/games/pacman/src/entities/map/PointEntity.cpp b/games/pacman/src/entities/map/PointEntity.cpp new file mode 100644 index 0000000..9310b2f --- /dev/null +++ b/games/pacman/src/entities/map/PointEntity.cpp @@ -0,0 +1,42 @@ +/* +** EPITECH PROJECT, 2024 +** PointEntity.cpp +** File description: +** PointEntity class +*/ + +#include "PointEntity.hpp" +#include "common/components/TextureComponent.hpp" +#include "common/components/CollidableComponent.hpp" + +using namespace arcade::games::pacman; +using namespace arcade::games::common::components; +using namespace shared::types; + +arcade::games::pacman::PointEntity::PointEntity(shared::types::Vector2i position, bool ghostBonus): position(0, 0) { + this->ghostBonus = ghostBonus; + this->_spawn(position); +} + +void PointEntity::_spawn(shared::types::Vector2i position) { + shared::games::components::TextureProps textureProps = { + .sources = { + .ascii = "assets/pacman/point.ascii", + .bin = "assets/pacman/point.png", + .binTileSize = Vector2f(100, 100) + }, + .origin = Vector2u(this->ghostBonus ? 1 : 0, 0) + }; + std::shared_ptr collision = std::make_shared(*this, nullptr); + std::shared_ptr texture = std::make_shared(*this, Vector2u(1, 1), 11, + textureProps); + + collision->getPosition().x = position.x; + collision->getPosition().y = position.y; + this->_components.push_back(collision); + texture->getPosition().x = position.x; + texture->getPosition().y = position.y; + this->_components.push_back(texture); + + this->position = position; +} diff --git a/games/pacman/src/entities/map/PointEntity.hpp b/games/pacman/src/entities/map/PointEntity.hpp new file mode 100644 index 0000000..25d7267 --- /dev/null +++ b/games/pacman/src/entities/map/PointEntity.hpp @@ -0,0 +1,37 @@ +/* +** EPITECH PROJECT, 2024 +** PointEntity.hpp +** File description: +** PointEntity class +*/ + +#pragma once + +#include "common/entity/AEntity.hpp" +#include "shared/types/Vector.hpp" + +namespace arcade::games::pacman { + class PointEntity; +} + +class arcade::games::pacman::PointEntity : public common::AEntity { +public: + ~PointEntity() override = default; + + /** + * @brief Create a point + * @param position Position + * @param ghostBonus If the point is a bonus that let the player eat ghost + */ + explicit PointEntity(shared::types::Vector2i position, bool ghostBonus); + + shared::types::Vector2i position; + + bool ghostBonus; +protected: + /** + * @brief Spawn the point on the map + * @param position + */ + void _spawn(shared::types::Vector2i position); +}; diff --git a/games/pacman/src/entities/player/PlayerEntity.cpp b/games/pacman/src/entities/player/PlayerEntity.cpp new file mode 100644 index 0000000..c4a30dd --- /dev/null +++ b/games/pacman/src/entities/player/PlayerEntity.cpp @@ -0,0 +1,106 @@ +/* +** EPITECH PROJECT, 2024 +** PlayerEntity.cpp +** File description: +** PlayerEntity class +*/ + +#include "PlayerEntity.hpp" +#include "common/components/TextureComponent.hpp" +#include "common/components/CollidableComponent.hpp" +#include "components/HeadKeyboardComponent.hpp" +#include "../../PacmanGame.hpp" +#include "../map/PointEntity.hpp" + +using namespace arcade::games::pacman; +using namespace arcade::games::common::components; +using namespace shared::types; + +PlayerEntity::PlayerEntity(shared::types::Vector2i defaultPosition): _position(defaultPosition), direction(1, 0), + _origin(0, 0) { + this->lastMove = std::chrono::milliseconds(900); + this->_spawnPlayer(); + + std::shared_ptr keyboard = std::make_shared( + *this); + this->_components.push_back(keyboard); +} + +void PlayerEntity::_spawnPlayer() { + shared::games::components::TextureProps textureProps = { + .sources = { + .ascii = "assets/pacman/pacman.ascii", + .bin = "assets/pacman/pacman.png", + .binTileSize = Vector2f(100, 100) + }, + .origin = this->_origin + }; + std::shared_ptr collision = std::make_shared(*this, this->_onCollide); + std::shared_ptr texture = std::make_shared(*this, Vector2u(1, 1), 5, + textureProps); + + collision->getPosition().x = this->_position.x; + collision->getPosition().y = this->_position.y; + this->_components.push_back(collision); + texture->getPosition().x = this->_position.x; + texture->getPosition().y = this->_position.y; + this->_components.push_back(texture); +} + +void PlayerEntity::forward() { + this->_position.x += this->direction.x; + this->_position.y += this->direction.y; + + if (this->_position.y == 14) { + if (this->_position.x < -1) { + this->_position.x = 27; + } + if (this->_position.x > 28) { + this->_position.x = 1; + } + } + + for (auto &component: this->_components) { + auto posCmp = std::dynamic_pointer_cast(component); + if (posCmp == nullptr) continue; + + posCmp->getPosition().x = this->_position.x; + posCmp->getPosition().y = this->_position.y; + + auto textureCmp = std::dynamic_pointer_cast(component); + if (textureCmp == nullptr) continue; + + textureCmp->getTextureProps().origin = Vector2u(this->_origin.x, 0); + if (this->direction.y == -1) + textureCmp->getTextureProps().origin.y = 3; + if (this->direction.y == 1) + textureCmp->getTextureProps().origin.y = 2; + if (this->direction.x == -1) + textureCmp->getTextureProps().origin.y = 1; + } +} + +void PlayerEntity::_onCollide(std::shared_ptr ctx, + std::shared_ptr target) { + auto game = std::dynamic_pointer_cast(ctx); + auto entity = dynamic_cast(&target->getEntity()); + + if (!game) + return; + if (entity) { + game->addNewPoint(entity->position); + if (entity->ghostBonus) { + game->canEatGhosts(); + } + } +} + +shared::types::Vector2i PlayerEntity::getPosition() const { + return this->_position; +} + +void PlayerEntity::reset(shared::types::Vector2i defaultPosition) { + this->_position = defaultPosition; + this->forward(); + this->lastMove = std::chrono::milliseconds(900); +} diff --git a/games/pacman/src/entities/player/PlayerEntity.hpp b/games/pacman/src/entities/player/PlayerEntity.hpp new file mode 100644 index 0000000..e9a2ae6 --- /dev/null +++ b/games/pacman/src/entities/player/PlayerEntity.hpp @@ -0,0 +1,63 @@ +/* +** EPITECH PROJECT, 2024 +** PlayerEntity.hpp +** File description: +** PlayerEntity class +*/ + +#pragma once + +#include "common/game/AGame.hpp" +#include "common/entity/AEntity.hpp" +#include "shared/types/Vector.hpp" +#include "shared/games/components/ICollidableComponent.hpp" + +namespace arcade::games::pacman { + class PlayerEntity; +} + +class arcade::games::pacman::PlayerEntity : public common::AEntity { +public: + ~PlayerEntity() override = default; + + /** + * @brief Create a player + * @param defaultPosition Default position of the player + */ + explicit PlayerEntity(shared::types::Vector2i defaultPosition); + + /** + * @brief Update the position of the player + */ + void forward(); + + /** + * @brief Get position of the player + * @return the player position + */ + shared::types::Vector2i getPosition() const; + + /** + * @brief Reset player + */ + void reset(shared::types::Vector2i defaultPosition); + + shared::games::DeltaTime lastMove; + shared::types::Vector2i direction; +protected: + /** + * @brief Spawn player on the map + */ + void _spawnPlayer(); + + shared::types::Vector2i _position; + shared::types::Vector2u _origin; + + /** + * @brief When a player enter in contact with a point + * @param ctx Game + * @param target Component target + */ + static void _onCollide(std::shared_ptr ctx, + std::shared_ptr target); +}; diff --git a/games/pacman/src/entities/player/components/HeadKeyboardComponent.cpp b/games/pacman/src/entities/player/components/HeadKeyboardComponent.cpp new file mode 100644 index 0000000..6a6acf0 --- /dev/null +++ b/games/pacman/src/entities/player/components/HeadKeyboardComponent.cpp @@ -0,0 +1,48 @@ +/* +** EPITECH PROJECT, 2024 +** KeyboardComponent.cpp +** File description: +** HeadKeyboardComponent class +*/ + +#include "HeadKeyboardComponent.hpp" + +using namespace arcade::games::pacman::components; +using namespace shared::games::components; + +HeadKeyboardComponent::HeadKeyboardComponent(PlayerEntity &entity) : AComponent(KEYBOARD, entity), _parent(entity) {} + +void HeadKeyboardComponent::onKeyPress(std::shared_ptr ctx, + shared::games::components::IKeyboardComponent::KeyData keyData) { + if (keyData.type == ARROW) { + if (keyData.code.arrow == UP) { + this->_parent.direction = Vector2i(0, -1); + } + if (keyData.code.arrow == DOWN) { + this->_parent.direction = Vector2i(0, 1); + } + if (keyData.code.arrow == LEFT) { + this->_parent.direction = Vector2i(-1, 0); + } + if (keyData.code.arrow == RIGHT) { + this->_parent.direction = Vector2i(1, 0); + } + } + if (keyData.type == CHAR) { + if (keyData.code.character == 'z') { + this->_parent.direction = Vector2i(0, -1); + } + if (keyData.code.character == 's') { + this->_parent.direction = Vector2i(0, 1); + } + if (keyData.code.character == 'q') { + this->_parent.direction = Vector2i(-1, 0); + } + if (keyData.code.character == 'd') { + this->_parent.direction = Vector2i(1, 0); + } + } +} + +void HeadKeyboardComponent::onKeyRelease(std::shared_ptr ctx, + shared::games::components::IKeyboardComponent::KeyData keyData) {} diff --git a/games/pacman/src/entities/player/components/HeadKeyboardComponent.hpp b/games/pacman/src/entities/player/components/HeadKeyboardComponent.hpp new file mode 100644 index 0000000..85c0178 --- /dev/null +++ b/games/pacman/src/entities/player/components/HeadKeyboardComponent.hpp @@ -0,0 +1,45 @@ +/* +** EPITECH PROJECT, 2024 +** HeadKeyboardComponent.hpp +** File description: +** HeadKeyboardComponent class +*/ + +#pragma once + +#include "shared/games/components/IKeyboardComponent.hpp" +#include "common/components/AComponent.hpp" +#include "../PlayerEntity.hpp" + +namespace arcade::games::pacman::components { + class HeadKeyboardComponent; +} + +class arcade::games::pacman::components::HeadKeyboardComponent + : public common::components::AComponent, public virtual shared::games::components::IKeyboardComponent { +public: + ~HeadKeyboardComponent() override = default; + + /** + * @brief Create a keyboard component + * @param entity + */ + explicit HeadKeyboardComponent(PlayerEntity &entity); + + /** + * @brief On key pressed event handler for the entity + * @param ctx Context of the game + * @param keyData Key data of key pressed + */ + void onKeyPress(std::shared_ptr ctx, shared::games::components::IKeyboardComponent::KeyData keyData) override; + + /** + * @brief On key release event handler for the entity + * @param ctx Context of the game + * @param keyData Key data of key released + */ + void onKeyRelease(std::shared_ptr ctx, shared::games::components::IKeyboardComponent::KeyData keyData) override; + +protected: + PlayerEntity &_parent; +}; diff --git a/games/snake/src/SnakeGame.cpp b/games/snake/src/SnakeGame.cpp index a2be7f0..40c7f5d 100644 --- a/games/snake/src/SnakeGame.cpp +++ b/games/snake/src/SnakeGame.cpp @@ -5,12 +5,10 @@ ** SnakeGame.cpp */ -#include #include "SnakeGame.hpp" #include "entities/wall/WallEntity.hpp" #include "entities/background/BackgroundEntity.hpp" #include "entities/apple/AppleEntity.hpp" -#include "common/components/TextureComponent.hpp" #include "entities/snake/components/HeadKeyboardComponent.hpp" using namespace arcade::games; diff --git a/games/snake/src/entities/snake/HeadEntity.cpp b/games/snake/src/entities/snake/HeadEntity.cpp index 687ccf8..362ad7d 100644 --- a/games/snake/src/entities/snake/HeadEntity.cpp +++ b/games/snake/src/entities/snake/HeadEntity.cpp @@ -7,7 +7,6 @@ #include "SnakeGame.hpp" #include "HeadEntity.hpp" -#include "../apple/AppleEntity.hpp" #include "../wall/WallEntity.hpp" #include "components/HeadKeyboardComponent.hpp" diff --git a/output b/output deleted file mode 100755 index 4c7da4e..0000000 Binary files a/output and /dev/null differ