From 381e95eaf405d3a252ea16d493a1f63594996ef0 Mon Sep 17 00:00:00 2001 From: Matheo Coquet Date: Fri, 5 Apr 2024 09:50:56 +0200 Subject: [PATCH 01/11] feat(pacman): init game --- games/CMakeLists.txt | 1 + games/pacman/CMakeLists.txt | 12 +++++++ games/pacman/export.cpp | 22 +++++++++++++ games/pacman/src/PacmanGame.cpp | 35 ++++++++++++++++++++ games/pacman/src/PacmanGame.hpp | 44 +++++++++++++++++++++++++ games/pacman/src/PacmanGameProvider.cpp | 19 +++++++++++ games/pacman/src/PacmanGameProvider.hpp | 35 ++++++++++++++++++++ games/snake/src/SnakeGame.cpp | 3 -- 8 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 games/pacman/CMakeLists.txt create mode 100644 games/pacman/export.cpp create mode 100644 games/pacman/src/PacmanGame.cpp create mode 100644 games/pacman/src/PacmanGame.hpp create mode 100644 games/pacman/src/PacmanGameProvider.cpp create mode 100644 games/pacman/src/PacmanGameProvider.hpp diff --git a/games/CMakeLists.txt b/games/CMakeLists.txt index 4c39731..ebc7d12 100644 --- a/games/CMakeLists.txt +++ b/games/CMakeLists.txt @@ -1 +1,2 @@ +add_subdirectory(pacman) add_subdirectory(snake) diff --git a/games/pacman/CMakeLists.txt b/games/pacman/CMakeLists.txt new file mode 100644 index 0000000..f569b40 --- /dev/null +++ b/games/pacman/CMakeLists.txt @@ -0,0 +1,12 @@ +project(pacman) +add_library(${PROJECT_NAME} SHARED + export.cpp + src/PacmanGame.cpp + src/PacmanGame.hpp + src/PacmanGameProvider.cpp + src/PacmanGameProvider.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..86bc925 --- /dev/null +++ b/games/pacman/src/PacmanGame.cpp @@ -0,0 +1,35 @@ +/* +** EPITECH PROJECT, 2024 +** PacmanGame.cpp +** File description: +** PacmanGame class +*/ + +#include "PacmanGame.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) { + +} + +const shared::games::GameManifest &pacman::PacmanGame::getManifest() const noexcept { + return this->manifest; +} + +void pacman::PacmanGame::compute(shared::games::DeltaTime dt) { + this->_clock += dt; +} diff --git a/games/pacman/src/PacmanGame.hpp b/games/pacman/src/PacmanGame.hpp new file mode 100644 index 0000000..0c0f84d --- /dev/null +++ b/games/pacman/src/PacmanGame.hpp @@ -0,0 +1,44 @@ +/* +** EPITECH PROJECT, 2024 +** PacmanGame.hpp +** File description: +** PacmanGame class +*/ + +#pragma once + +#include "common/game/AGame.hpp" + +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; + +protected: + shared::games::DeltaTime _clock; +}; 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/snake/src/SnakeGame.cpp b/games/snake/src/SnakeGame.cpp index 0bd6501..8b43a04 100644 --- a/games/snake/src/SnakeGame.cpp +++ b/games/snake/src/SnakeGame.cpp @@ -5,13 +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; From 40111d04f14853458e5044bb127b5fd4d0d63054 Mon Sep 17 00:00:00 2001 From: Matheo Coquet Date: Fri, 5 Apr 2024 15:56:06 +0200 Subject: [PATCH 02/11] feat(pacman): add map and points --- assets/pacman/map.ascii | 30 +++++++ assets/pacman/map.png | Bin 0 -> 176 bytes assets/pacman/pacman.png | Bin 0 -> 12861 bytes assets/pacman/point.ascii | 1 + assets/pacman/point.png | Bin 0 -> 514 bytes games/pacman/CMakeLists.txt | 4 + games/pacman/src/PacmanGame.cpp | 3 +- games/pacman/src/PacmanGame.hpp | 2 + games/pacman/src/entities/map/MapEntity.cpp | 83 ++++++++++++++++++ games/pacman/src/entities/map/MapEntity.hpp | 45 ++++++++++ .../src/entities/player/PlayerEntity.cpp | 8 ++ .../src/entities/player/PlayerEntity.hpp | 12 +++ 12 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 assets/pacman/map.ascii create mode 100644 assets/pacman/map.png create mode 100644 assets/pacman/pacman.png create mode 100644 assets/pacman/point.ascii create mode 100644 assets/pacman/point.png create mode 100644 games/pacman/src/entities/map/MapEntity.cpp create mode 100644 games/pacman/src/entities/map/MapEntity.hpp create mode 100644 games/pacman/src/entities/player/PlayerEntity.cpp create mode 100644 games/pacman/src/entities/player/PlayerEntity.hpp diff --git a/assets/pacman/map.ascii b/assets/pacman/map.ascii new file mode 100644 index 0000000..5842cac --- /dev/null +++ b/assets/pacman/map.ascii @@ -0,0 +1,30 @@ +########################### +# # # +# #### ##### # ##### #### # +# #### ##### # ##### #### # +# #### ##### # ##### #### # +# # +# #### # ######### # #### # +# #### # ######### # #### # +# # # # # +###### ##### # ##### ###### +<<<<<# ##### # ##### # +<<<<<# # # # +<<<<<# # ####_#### # # +###### # # # # ###### + # # +###### # # # # ###### +<<<<<# # # # # # +<<<<<# # ######### # # +<<<<<# # # # +###### # ######### # ###### +# # # +# #### ##### # ##### #### # +# #### ##### # ##### #### # +# ## ## +### ## ## ####### ## ## ### +# ## # ## # +# ########## # ########## # +# ########## # ########## # +# # +########################### \ No newline at end of file diff --git a/assets/pacman/map.png b/assets/pacman/map.png new file mode 100644 index 0000000000000000000000000000000000000000..920ef23ea547db72075a227fc87986d627f99274 GIT binary patch literal 176 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEoCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBzN@E;V@L(#+jEAD2NW0%7?}0Wnc;4$l>P7cCb@r~Ry-(Hi)UF>&3NpA@6j(?|NVsycZ&i?xklB%t9zA`G z4qUNXYzYSbVSbX;{DOppP4w_VMvD7Q23$n`q9P-KRM1bk1^hrY6NiW+Ar*&W-x{JJ zA#o4Oy%kq;M&3(+1nG`dXMVW5%)0#S?PSDfn`}pk)QKI@kz*2W80AF{{71Ybb9x+bjQ#0_gX@{TC=Nh;-O; ze0*H#y0E|Fwsj+aV0E%_KQT5xaUgo{3N@XWT@~J-BE<6zNdj%^e6Kxoezy z_RAma%&l$Tii28_k-XDM%@LUwXZO)NX-P*(R7hfvi4CIfP6Y6fnwWaMpvj@JW0t49 zW|Tobx)Sb$r=C4Dvj!M1Q5$#mXc00PFJkSHl>FD4`{#qOJ3qusiBMwmvb%etCh9_U zw);vD310k$zGzDBYvQV#LD&O-HttE_$jI2qWZc^L=3mJEeihOY-ghiw94$h^O0Gbu zJhm|~FF4=UxF2tZ5IkIyW+4sNYifzNYKkC0itunpQwqxCq~^ZQPp36NCSHjM>^z`^ zV?GROrX##g_0QM))#WEA3-7QT>5#Bm@?Q6~;$SBWD%KvhT?$0_kdugEx|YJ7zAiLu zw>0gtVwh?mtzB|)%FlRwUx(QtA&F{I&qk~~({o05f60#D?{MLO*?s}|Mm8E_qxRmg z`b`bp#|~tqHlx@;wX|l==k83=7)(C7BpIcpWs!p4-rq3@Y)0QR735<4Z?F6R@_6pq z@}~{afMt*5f!*>JaHtp$;B;E@#~MgsIH>GMvgnUUkmy^>!0vtezds38C{_toK&oOn zh-`MEn=ktG?f1vI6lYH_xL{Sg1&HpmhUmGgz~24gpUoFn*u8i6xZ57o6`K*%j5kF* z$m@=fnyG}yJJ5|p>TkEN-3h|=tNnH5tF$zyMN%{`7L_ilZ;T$_?cW?E*~PnRw;j~& z%w{E3uRhEw^VxHt$YzdbY2MjFS4Gp9xQFpVxG2n?1MOj&wa3$21zlhF%N_lnpMI)8 z*}g_>ynAw5gytH>G#PO?*lgjn+HFz!SyHI2YqF}jx_Zt_5O%(2&m-hI`A8)93B7?F z&Ypc4`BPabEXKdnIn-gmIsL=KJ>?#}qKsdNoCh{C(RhXV@WA#8hk=7~5KbTw==Kzpiz zEb?(lGE~b=gHRk|>(4EQky$^#=nOa)@a4BnWi|r~$b59BfIf4Y=;xx?$gH6iQ$P`i zv+O$h(Kxjs!g1+B=C*I*q#_+&)D_veGHdQmi%%V<}9Q2D!P~}AsVQz|tYLTPZDbbLbhe*u z`oUG8mr1&oNtcN?_4h%+^{Zk)q&|pIns z#?)zjK;_E}1>gId%X(Z+sLI2%xUQFCZxV&eZ)2c(stz)zhrJw?p|*5=35I)i*lQD@nb>V7KASAAOyyw6_fj=dmuae&XdJ9Ji*1^lqqJP)Sh7s(~8QQ8kI*nEN= zyb)U|eScq#Y-I|j@GP^K5(rT{&GrmfsnKMRPMIaO9#6wO?kH`-={=9C4DN0CtTB;> zqnYvzv8+-^{nIqnB9fY9QcJ+VdVclK&^dHLkbPU3n9av7DIM-7Wm*w*e}959PWqdi zFJ6VoHFs(fBl@(dceU@VP^7gFQ4RBm=&Q#KBdPQf-Qk3wvjBElW6Ivg=Aj|mh zcJj0xdeNQ4EGYTy&v=o&X${Y1@y3YYJ_E_PC8HOEp(BOWMYQ*5(JgO*@6TsN?36dx zK;Wu}8VLkcxoCiVKTzakj{Qs(>ZH42IPe^sr5GOr2|49ik?1C*b3s4#RS`GU1fYp@ zq?D%YH-KSr*LC@Z)u0;{f>L|x1}^wcIK>ALIY@FK-%$5e8RbY|_yAR`7|ky*2&(9j2rT^Oy)~mSk*}j&PyYVd6fDntP6T2M6nF zbLG%fSpm1Xi>uEq*X+Z40$CUfs&H5a;9&dBWkEYLjhGI&rRj^z2Yv{k}(wIc|4M5+B5j2}A|M-31oD3DNjVoDA#Ue@R3nHp0Fr-47=n z%!oX#NBB^GS32%a8^i(gqmB_xzwPO5f3>|7zl3)?NRj48V?X1XsP6M9dVH(#pig1i zS<|FKM}A9c{?*PCEOPN?u$1lsG7j+WA@a0s?%6L6o@x`CDX=q1&;A6NLUbsN0(uGrveYU;=6TVZ+la4gYA0Z%Q|8c;YR5E*Q|lBN zm!559OW(6CGm|Gz*Z5ad>cLqy-;d2ECgIp3J!wLZ0!W;DJ^u-qPpPCy32|p5}+y-I-Da`iaBSBf^uqLS{pdc^C8PY9tgsgBzOsG|Bl%`i{_I< z%wMv@$V&Tts8=w{c?Gdf$rRs8CYSQ9LDtUF}rW`fqYm0Qi9lcofqIE65d`m~(*Ts&sJMFYzKcbMrIrreR=> z>nPSe>&x#q9%zxei;(2cRawnPVxiA~bb2|McK(f@?PY7Sape|Rf5;f^w8#fvgmt3G zm%MDusn&4+aA@bQyc%r~MFhSC#^*u?Zx)pm1kiDxMwBr;TwGMew?ziqD-#E07yGO7aJ6k*yHs&hSqzp64HedDU~6gU`chxZ+qg zN&W(cvFtHHE!6tV;|}nS){rpiiuL{A1BywbY~Dz}>mL`Hi0F0C8#*Y&n~Umu{ucs- zEb_t)%S<1zOnS)=YUcXvsmz^y-iLePibWLTTAQs@U-e>5TKY~iTjB+#o=RICCEXcy z@3}cQ-{7*T|5aO5*-WF=WWsW9LCAtNP4+QWQznZ|%sjH>1F)I~fE5pYP-crCb%LeZ zuL25V{s&{K!aGpLUlN)w%(DO+kgg|o((7b0<|an4qL@*I^a13MVQaL?{;t+lwQ=0= zo++M75%ae5dD*FvmWr4`N_cRumC@o76fhr0z_FsyC)GgNZ$lc_B!n6NH?3W|v zrxh2_1Ew9o-x_#*AY*p3`I{!;ru7Q^T@3rHy&O^Gh9UIPpS?KyQXwXk-`Q2G3W<8l zWb==beMD;Dm}WIeT6SECO)vArvA-t&@Nm!Y039xx99XdiJWd;&v;2!v!P}LXAJ8~< zJs1UsHJVE3+AQh+0HEi*^xcO)o+RgDk>wWj22^hZp$h(ECN0c)W#nZ=7;!<2mQBMH zx7B8ukU5ihKW~@K;+_1wJYe2I`lOus302OQJ;b29p|Y>%G?{bjkSzdY*6#EiLh3n| zo#q|(M+S6;AB58do6R(8EN_Bi#uk=b^#f|Q_4y$KYm~u2q6JRHBpPm7@X$My#@M+vQ z9STJKFhwq3l>J9?ra&86GRlaat-0{vvUJ?2(VCN3q~SMnmH!8;zC?77n1AMlScC&> zp!y-Q2P}~<_msoX`ZPcSPAV~EB+OmjB^G(4HkNMJd z8i>P3uJ|6px<_cqaXr-drqX!kt(|R5C!Kbd-@M+0qsuufDjdSj!2_&KZrtcRLtP=$ zpBJEC`w$OIoxGuft`Dx7^rH}ZYu6DFU&_N=%W6aEjug&oqbjx{uKA$)uS;tT1vV5C zyvkHxo?)F`7z7!4KUfOHRic9pLzdR;MdwXrZ=w_)q1Za%KhAr~>O==DOhP+X6^#w+ z`!Ee5WZlLydU?|iDotc-k41VVB9EiS=r4byNyN(dbk#a3*sCZ(!?kTLzB;nkDvdo( zkwTACOABIDuHZq(7~`rEx?n%Whd0hvv&F0HA)O(|*1c(XP;@(Lh<y_%OneLe7 zY;4Wf+%8@Tyc4ZD(+2H?&J?eJZ4i%;+3}OKF2~FBh{-#dYrWrF%^WPj^to_1H{=&!G60CgyZ(#8G4(`e21s>1Ed*6QI`hV@XmnmH*rR@9sD ziF=0CGPwHPVGQUk-X2o7_fZ z$=MZ5_$d#)9-C_y3Sy^H+fca!3zcgk-yaUOD?B}PGdGkPs0b5C>`n|y+T#p}iVoz} z{)h;9hpK5h@)68iRIPVsc;cyczT)O}qn?-$7CL%~(r~6P}SD7Y*MN)54TWf>Y%Q&|nUa0dW!YZ;j-Hpax9rpx|e5oCA z`#kMO5@$FhxE(4C(Ry0M7wEb?#4^$wc0xK5ZwTdmPhQ&XNU(4@n2HU){k3Wl@vSK$ z_IwUBB@nSD_VY7~2Sy#hAZWDGlg-}gSX$w-jm?SX@xqrRT;4fkzquTwYbP&-Y6-Ny zGn^8@W828j!*e(&u%TJp01SX*Bf3WDf4KjgF0mzct%|o)vjzh+rlCwJ+!;aV<3vL| z)MnpgsU5j7Rk?ze*G#U?wugR-HRlg(*oN{^Yz+jL*&c-yA2)fCivD@<^6J*7UcV)Y z>X2CLnaQh;ERt)@ce#HzwaZmCM{k3&IUun2UEg(FaITo6-nTFFDBs7X|LV?mf)~Nh zoGZ7&%U)k!$eTNjuvzFJynvH_ie0h>gJ`CE}>~}!`;_CN=-^Hf=)WvEj2id)mu1~ z0+OpN9m&kgj>g1c`2BvyVZSSKBtgjN?Zw^I`sC+pST2DC5J+>R$swNoMbkAiAJC!r zx+<>SCq9M5uDwL>fSW9envgmf!XFt^Q8q-%!MQs#J2hO~-r{PT3~4bhqDaWiRT4|$ zoZ}5GVzZ{BEY(bYA)D9>{X0@dPLCvgtUQ>_+j;Hi{PaKH=;39b6Fm77iJGn4R`>E} zuW;u`+giCfPhxJITB6|=4ZTM2dP-+Ot%mTaa~+IL%E)1Z(geH>h^xf?FH8;ai z`e+@tput%bL)_q25!_%5ty$SfAUNWg^912TEC)V3<)(qfU1WQAJnv8#Wgay0$$SXD zPk~HU?aTk?+dbvFO;WS{<>nb;y3S&-B?R!qvLX?HNq@U(*E7u#OBs28lgVc{H?)=Z zV*Ji`L;@gBsb*ToqFg}5(N3!-LR~^MugT_`2N&WW0I*e@7{|y@4al~U+o+ft5`R-M_G146Mx1$|aCt7tqLu2JV3Xm?!!5t|$0^RdVrzP4yAbr>k8 zFI{|jeK(d8Un2ewu*f#6vFbz2@{Y(siA0oKl~4X?@4ewceLz81sCkC@KBBY58$ab3 zXXR~K>s%sr4a-RGr?{eL=lw{p8=YqUVi3__-SjtAp`Uv87OZwC957Q*Ci&X;dV~xf z=GKhwc%<&@J){QUc-3I65$G3_2h6c5O#uWf*1zEqohNIcSKIUiF;(N0YL>C6f?$CS4A9T236okHqYDO*S z_bzN=$^2T&D(>4=>l#AyZH#Ms6Mn(wjmo{Nle{ubS&>W(pB$Y5GSXwb-{}9};Pb!1 zsJ<34NCMPJ+)EWUSGRw5ey{M_tNDiX4RTXZT0FAO03%+y)X6h8%@)WB)PCVgnyqX9jv;drcz2;E)%{JA=(EUnJm+MADgCkI35a zE{*wg-X}@U6v~j20Ykq?Vnzl_cgcsd-aFsc+;k6RsP9=C5sf!^&P@{A`&07%`WntH1BUOHi}v?Z zadMYaEi`LGir;(C7XNFN^sM3vgVb2n6d6=-4M z0s5zQ%JF(SXd6WLGucOc*Bz9*B4Xem9u%bJNrGOCg2?upa35pf<^h1~gKGcArs~0- z55l+R%M1oNzw)kSW5StZ3MW|*Mg&6Q*s#kJpmqvJymGO%8n=tFXSet6nYhrgs#64` zyX?zW;?j*8}JY8z1x+S2us-u^1YkvlFTn zoTg<*+Y!ucApEzQ3MFuW5W&$m#hNFcQR3fz=5@GJzG@te<2$q2Qp&~_%1diQ^_rDe z#YBYxF$V;&-UZkfk##b!%!a?kRUc}kK1KuU(-7@Hq?t#Z&bilVD!)eXh>e0|Vnx1RCW6`hInSBEq z-n8@5lcfuC6Fx>TD?EioUC;bV6HbA6iU$xqm~k9+CX+Mt-jMW5)Qfbvm$EJrj0CsJ zi6sc;voadjDC=p~F8b$9v}>5LVuv#PJ(p=kcE8fz@W}Z$u;Zu%69AR~1yT@Jt$ET? zM&~V>Zk@#qCB3ffHW7|W0s&@Q2}mV58-x{V=a`!&6(UkN<7usbpMG?rDb!4Rc9 ze)9q?;5u!PneCaT8;GN}aDO#NYD6HLIqzU{-xh~kR^%HaK`%nqCl$ebIy$gdViod1 z0avebF#f7DWTqjne?rhG?D|rkHu^4{P^zPNP!4{rAq>!D>GA*Ia;kueTBsmO`5-or}=~I zlD^#$X>Sh1Rhk5_ic9I^1uvTHV4j8)aOuJZhn8SF5izBq<~^=OPLzw z7*5enr%)A8X+bDjXWtD8vqWHNuvWxWU$wagO3rBPSYDRe&Lly_-_SoT!lU76d|!}A z>))!?{KFkhRF2VL4KQoDJ;pj|d5{FXx3T=03pwmi%BHF0SV3bfBcYrG18x2lPeGF? zthqdzcs^GC$AgmaJeVV6wyId==<=ttNLT!-_g+C(hDCMkh4EtW%QTMFs~11W)rZu5 zl{KdGhYwVC8U-xFN{u_5@{Q`APREIBc68QysB2O7>wioVKMne$PgzM{ zrrntvFE(A%W*hK#Dljg#O2tn@VnA#=BumQcc3%QGyAB@w0YP9u`^nyU zs2mjfdWYBJaW837y4cVW8)cDEy+h&D&jUXT4x{5wFsAe!ASwEpFI_ItP4v4i<7$w?y7ST7DvT;QuTgHdNMtsXM^FBg1gN&t zWT2=sM|wZJ6NtW=LbD*cve$2k&~s)82i5L4?EfwGv)>-{?X>3NqQ$5T*wa2pLN+`y zK?9@S;@{|_OL6P030`>k6Cli=y$8ZSVSpd?MP*dL7@#5n2Oho%iR}q(h4?r2t^T)q zBpvT)$wlvmq=86p*Q63H;y62iLXZdS!3HxHikQjXnP2Ef+(H2f$wrI>OC!Jz3jx{h zS+8Z;o{%O8U2I=ZS3ZHQ6&6a(QRxIy%`kmUf+pkz@?0e>XqwX_(YV-6Q#pU?@p+qc zP+_b0MfCEr{;b}N`L?f@r^{HeGwJB^SSCIj$YU3TmZryh7~8R`;T1p@A05=FY!_eo z1k{;=`$&x0aos9B+MMf|&s9E=(ICu;L~oUE=-!JEgo1SMJOt0{5-h&VkzfQ%Mm7uh zihrx1_qMSGa-@IFU(uztb+f$&wQeH_>CA_;DZMfB08;_(HybC9tqGFE8SN7aw@@RL z$7rluVnAw#&OI&$hqQ`SwFj)!C}(1tLZj9vnRZFyvN&M;RRj56SjcSBjP|ShT~dVT z22(xx5~5!9j{72*uUPH0U^%p6afD|6Q8e?5fM_no+sd8t1D}(=t3dGn(gCD8_*p<~ zmsU~FW5ci!v*`MyikBm7val7a?~qvr2z*5wyAT;n{B#ZWTZgCETdOZC>GefMBdaN0 zUPsrVby#aX#RBL)aDn`&acXncY2$Y9qa%c<*L$$#YZIZ=+v7L<;`KJxJO#YIdUJ*`r|Wz z*AYIpoJ>_!c%b>RI;v07SH03{jN`k$z#q8Jw(t9)jiHTqpGj?^Kq?HrAkP80n}qzY z1$PX~T2@f9_H81x)0>^8k|K!S&o}6pE@hv`k`nA5b!+T}s{L3C)hb+%k^&Rf2OI?y z?<7ip-drr3f!&*cytL~r>#SPAb`x^n8}U%LT((XMc-i#G0kc}}1X!ug?~ zt+%G!6ucFhjm*YxLZ9~xMU>f+KqP3J48MDaEC1k5^h!F|I*f6Xsi!_N6D5Yw2MY~yd0+hRnY;X#ZCoj4joUY|>)0=UyuV<%uI{?T!{%1E%*C%nvyyD^-ERYl( z4z=SzuDv8IwjY|LbhXbNB9D1W^;qK*N*-=1!x2YiXRIY2jljs6SUJfs^xrk|VqprW zgzOX{%6#@_OpTX>s%?INN&|Ct8c~eVr)D$_9R1(JJi5S=j!8zUtWQrD~bHUMckDKA&0&GDCetohEmBM{+4o|BG2GdOpe0u<* zE0K~{XRn<5C-T^OM$}@RFn~c7)7u@*O&ufGFs^PL>;aB3=;G7G(OI$o@#80Ii&X9+ z9@THVM#RC0%|&JAYzMADyivo4g~x8;+q3)K{9GzOEH(9rtw)J zcy~dD!sN}jLs(q((**KyGIVh2IUfFpv6;7+>09LQsi*#YC@uK)*4ipe+`je`D|39^ z{mj|jLM^20F;M&7=V}g^Wvny4G5K^tjHxbhLBD<=-@JHlboIh~l?)ojL|x9+{{mE1o%IUpWqw^Cnw1O2Ju~(( zs*rx9`e<}x7>9v>o1P%B?NFwOAq9tL|9Q=q0nhkGgVImA9uw2wDE&h9LiIku-zAbr zRj-{}&1cbD;UQYDE)l zJPmJt^T*$9g|<+V(Lp%%$?dnalLMPsTeCoQf7+p8tVWw2<)h0*H9u2uTxmIWsV(Kl z)X1?C@D>9Hr$Hmw(b~KEKDH;)CtW_*ecV&YOwU^#!YewNAbhx-}22 zG#hNvkK{0E5ZM{&TwZ_nEcKN1RnIeVQk!Vfw6*XPLN(JP)Zo5y4u%5CuKwX-Drp5E z*83PyT)V|)Q~mSZM$T348399rgc^dtuOfAsM6R!^;&%B)G}_+LvZ!>@{7e!~LRW5@ zbb@{9ZK<9^@EXc{WhayKM&4u_w`<_x@e1nF>LLAz6;nyi1+j|oKgTJ7*?vLZQF3pA zv3qSU{19;zH4QCwYEM$`jO*?MOj8-7$w;bGLRW^Q{dnVr=u^V~fa7JJCs^@%JFzO| zzTyX=`*&L^0m=wQLfPEEj1t!(41ke%x3sg3yd za5VQ~KIzys9^N>rhBT5q$0f9L{3Vl+JYv#>75ny=?$0bZ=v}Z4j@ND=vvUxIs;n2K zWzkl}c5%1Ynn@`yK`cEggfUEwWhYccA;2(9!$)}`A7=$f*qMDPM|pN0Sw4(QN?G&N z?-mW-1p;W&aLkCDUOiCKA4r7WFS|rhz@e-%&-{cft8r?=Mw$K;5f$Ei=Zbg~Ww;#yt=Q0J$*aEk(h)~wukskCPmq%h4#5NWn7o9D6SDylc9%fY}#6`p=0RXBe__B zsitcXp<|vAoK_}2dsEp1Kyyv?A3VI7Uvbg2mUi5v!I<>WfFR?PaGM_5=hMh>!m@pS z;_MuGZ*$1U6|_6f9n#7(9#jID7>P!uig}1pGx-NOO!ebzfP}4L1N2xU6Uz_>R?ye=8Hz zu-MJB3Ih`GYjlU-Lo3ft1XoM`eEeKq^h->|)N0Nh+Dz*JxaA{M1ETBo5#h<(U4?RG zMB}I9TjHcNf4d-bD4Pg6Mu~pnHEQv>$eu|@*GnTICn!(3Z?EJ==%6L3CG>nML0(5f?n)2J2RV#W3Wl#}JRh8jT!_|Ywuog!T}&!VZe9&2{^h{1syZ?omEgyz=t!AcvYn-mGt|s~j+bV3vz;`ZB&I?KaN}BUUtGI|+&m9>1&_() zOMk(eXzNG~5j+=uvxR~}DJ)F-rvaB~N)%-u!+HqK7Z)vL8T0yOyGHBgzFeKtG$a#7|2V66p-a zmR4C{;=ZUVNx=I;Tm*mi*2l3oAEzZtye*K4gi5V*<1$=qTNNOl6H3vzM)g0%FR4M$ z7bULzqq{Ea9EAQ10U`QJ?mptVL@l(-lbJ<8u&Jg`h zdWP`V{S8#>uRCbQm>4?ANPSPq;Z@iexQ(U9Gt}De`W9Ltd^MP9zj;b=&4K zUkdYADxe$J6yMwiB%e=gIRdSqafFqXF;oL4)KtQf4g1(j@4M>(dfC55s`EL|^+(Ev%RB2@HZ?=^cSf~ z#?+d8;mtUY65T|59>y3`xOshv33SD1$W|{-T|7~Ngu=Sogb{XMUc%i@N ze^&!}{P5sFk?&C49njtp*~7@=uQysYNI-$rS8;xj!1o<8ZFfIOGA2EZh3I0s#IYiC zt1=$2vKCr0byYR&jnzfJ`oBjd@ybs$Vl-H1v_}|54E4FbTB%Q(9?JY}=`r6cNKGsM zlL)nge6GF3`(>}32|6_|B^^mcL1+X5$0z9M#ew!yl}KEW4$$``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBx#^xRjv*C{Z*M*HJ!~M*_HexqgLDgL0~p>4 zy|E&PL3oSLggggxi*sIr9r3xs(eYQmPxSkF@zk`MqM}ZJCZL%Z;CaR}VG%+8%F0t3 z*YzG3eZOp$ytjM%&75y~S0;Bxqk;FGT>qt|x(iiq{&{YGi(!P`Q^^rF@;Y+98#SMWd=y%uUIi_5MVJ)SXvf9q#W<37&FRdc5m zzistbPm5W-Cj9F4q`qd$`nve1Ps2(h-t`^&Y5T;r^wcGzXNwDVNbK@ic5LS_3Bx(7 z{jWaRAaJbvVa?wD$5X`?`OOHMa=JrX`(j6_WHK*RVA9ks?ZTnx_registerEntity(std::make_unique(MAP_PATH)); } const shared::games::GameManifest &pacman::PacmanGame::getManifest() const noexcept { diff --git a/games/pacman/src/PacmanGame.hpp b/games/pacman/src/PacmanGame.hpp index 0c0f84d..2288447 100644 --- a/games/pacman/src/PacmanGame.hpp +++ b/games/pacman/src/PacmanGame.hpp @@ -9,6 +9,8 @@ #include "common/game/AGame.hpp" +#define MAP_PATH "assets/pacman/map.ascii" + namespace arcade::games::pacman { class PacmanGame; } diff --git a/games/pacman/src/entities/map/MapEntity.cpp b/games/pacman/src/entities/map/MapEntity.cpp new file mode 100644 index 0000000..3563970 --- /dev/null +++ b/games/pacman/src/entities/map/MapEntity.cpp @@ -0,0 +1,83 @@ +/* +** 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; + +MapEntity::MapEntity(std::string mapFile) { + this->_generateWalls(mapFile); +} + +void MapEntity::_generateWalls(std::string &mapFile) { + std::ifstream file(mapFile); + char part = '\0'; + Vector2i position = Vector2i(0, 0); + + if (!file) + return; + while (file.get(part)) { + if (part == '\n') { + position.x = 0; + position.y++; + continue; + } + if (part == '#') + this->_createWall(position); + if (part == ' ') + this->_createPoint(position); + position.x++; + } + file.close(); +} + +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), 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); +} + +void MapEntity::_createPoint(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(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); +} diff --git a/games/pacman/src/entities/map/MapEntity.hpp b/games/pacman/src/entities/map/MapEntity.hpp new file mode 100644 index 0000000..54ada4c --- /dev/null +++ b/games/pacman/src/entities/map/MapEntity.hpp @@ -0,0 +1,45 @@ +/* +** EPITECH PROJECT, 2024 +** MapEntity.hpp +** File description: +** MapEntity class +*/ + +#pragma once + +#include "common/entity/AEntity.hpp" +#include "shared/types/Vector.hpp" + +namespace arcade::games::pacman { + class MapEntity; +} + +class arcade::games::pacman::MapEntity : public common::AEntity { +public: + ~MapEntity() override = default; + + /** + * @brief Create a map + * @param mapFile Path of the map + */ + explicit MapEntity(std::string mapFile); + +protected: + /** + * Generate all wall of the map + * @param mapFile Path of the map + */ + void _generateWalls(std::string &mapFile); + + /** + * @brief Create a wall (part of) (Component creation) + * @param position Position of the wall + */ + void _createWall(shared::types::Vector2i position); + + /** + * @brief Create a point on the map + * @param position Position of the point + */ + void _createPoint(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..7edccf1 --- /dev/null +++ b/games/pacman/src/entities/player/PlayerEntity.cpp @@ -0,0 +1,8 @@ +/* +** EPITECH PROJECT, 2024 +** PlayerEntity.cpp +** File description: +** PlayerEntity class +*/ + +#include "PlayerEntity.hpp" diff --git a/games/pacman/src/entities/player/PlayerEntity.hpp b/games/pacman/src/entities/player/PlayerEntity.hpp new file mode 100644 index 0000000..4bd9fab --- /dev/null +++ b/games/pacman/src/entities/player/PlayerEntity.hpp @@ -0,0 +1,12 @@ +/* +** EPITECH PROJECT, 2024 +** PlayerEntity.hpp +** File description: +** PlayerEntity class +*/ + +#pragma once + +class PlayerEntity { + +}; From 2a72889def62784adb253739e17de0b4aea1e8ae Mon Sep 17 00:00:00 2001 From: Matheo Coquet Date: Sun, 7 Apr 2024 20:37:25 +0200 Subject: [PATCH 03/11] feat(pacman): add collisions --- assets/pacman/map.ascii | 10 +- assets/pacman/pacman.ascii | 4 + assets/pacman/pacman.png | Bin 12861 -> 12125 bytes games/pacman/CMakeLists.txt | 4 + games/pacman/src/PacmanGame.cpp | 33 ++++++- games/pacman/src/PacmanGame.hpp | 9 ++ games/pacman/src/entities/map/MapEntity.cpp | 42 +++------ games/pacman/src/entities/map/MapEntity.hpp | 20 ++-- games/pacman/src/entities/map/PointEntity.cpp | 41 ++++++++ games/pacman/src/entities/map/PointEntity.hpp | 35 +++++++ .../src/entities/player/PlayerEntity.cpp | 89 ++++++++++++++++++ .../src/entities/player/PlayerEntity.hpp | 48 +++++++++- .../components/HeadKeyboardComponent.cpp | 48 ++++++++++ .../components/HeadKeyboardComponent.hpp | 45 +++++++++ games/snake/src/entities/snake/HeadEntity.cpp | 1 - 15 files changed, 377 insertions(+), 52 deletions(-) create mode 100644 assets/pacman/pacman.ascii create mode 100644 games/pacman/src/entities/map/PointEntity.cpp create mode 100644 games/pacman/src/entities/map/PointEntity.hpp create mode 100644 games/pacman/src/entities/player/components/HeadKeyboardComponent.cpp create mode 100644 games/pacman/src/entities/player/components/HeadKeyboardComponent.hpp diff --git a/assets/pacman/map.ascii b/assets/pacman/map.ascii index 5842cac..b8a8b7e 100644 --- a/assets/pacman/map.ascii +++ b/assets/pacman/map.ascii @@ -11,17 +11,17 @@ <<<<<# ##### # ##### # <<<<<# # # # <<<<<# # ####_#### # # -###### # # # # ###### - # # -###### # # # # ###### -<<<<<# # # # # # +###### # #wwwwwww# # ###### + #wwwwwww# +###### # #wwwwwww# # ###### +<<<<<# # #wwwwwww# # # <<<<<# # ######### # # <<<<<# # # # ###### # ######### # ###### # # # # #### ##### # ##### #### # # #### ##### # ##### #### # -# ## ## +# ## o ## ### ## ## ####### ## ## ### # ## # ## # # ########## # ########## # 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 index 511cb683a109bac0953d4b09fbf8f47ce1160aec..d9b75f51906378a5be6e635dfe3148763d198124 100644 GIT binary patch literal 12125 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
4c~6*E*JhD3avL&ms~1OeJ%q5*W=-7Jg1 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::make_unique(MAP_PATH)); +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->_registerEntity(this->_map); + this->_registerEntity(this->_player); } const shared::games::GameManifest &pacman::PacmanGame::getManifest() const noexcept { @@ -33,4 +41,25 @@ const shared::games::GameManifest &pacman::PacmanGame::getManifest() const noexc void pacman::PacmanGame::compute(shared::games::DeltaTime dt) { this->_clock += dt; + + 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] == '#') { + return; + } + this->_player->forward(); + } +} + +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()); } diff --git a/games/pacman/src/PacmanGame.hpp b/games/pacman/src/PacmanGame.hpp index 2288447..ab9eab8 100644 --- a/games/pacman/src/PacmanGame.hpp +++ b/games/pacman/src/PacmanGame.hpp @@ -8,6 +8,8 @@ #pragma once #include "common/game/AGame.hpp" +#include "entities/player/PlayerEntity.hpp" +#include "entities/map/MapEntity.hpp" #define MAP_PATH "assets/pacman/map.ascii" @@ -41,6 +43,13 @@ class arcade::games::pacman::PacmanGame : public arcade::games::common::AGame { */ void compute(shared::games::DeltaTime dt) override; + /** + * @brief Add new point to player + */ + void addNewPoint(Vector2i position); + protected: shared::games::DeltaTime _clock; + std::shared_ptr _player; + std::shared_ptr _map; }; diff --git a/games/pacman/src/entities/map/MapEntity.cpp b/games/pacman/src/entities/map/MapEntity.cpp index 3563970..c8d9194 100644 --- a/games/pacman/src/entities/map/MapEntity.cpp +++ b/games/pacman/src/entities/map/MapEntity.cpp @@ -14,30 +14,35 @@ using namespace arcade::games::pacman; using namespace arcade::games::common::components; using namespace shared::types; -MapEntity::MapEntity(std::string mapFile) { - this->_generateWalls(mapFile); -} +std::vector> MapEntity::generateWalls(std::string mapFile) { + std::vector> list; + std::vector map; -void MapEntity::_generateWalls(std::string &mapFile) { std::ifstream file(mapFile); char part = '\0'; Vector2i position = Vector2i(0, 0); if (!file) - return; + 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 == ' ') - this->_createPoint(position); + if (part == ' ') { + list.push_back(std::make_shared(position)); + } position.x++; } file.close(); + this->mapData = map; + return list; } void MapEntity::_createWall(shared::types::Vector2i position) { @@ -50,28 +55,7 @@ void MapEntity::_createWall(shared::types::Vector2i position) { .origin = Vector2u(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); -} - -void MapEntity::_createPoint(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(0, 0) - }; - std::shared_ptr collision = std::make_shared(*this, nullptr); - std::shared_ptr texture = std::make_shared(*this, Vector2u(1, 1), 11, + std::shared_ptr texture = std::make_shared(*this, Vector2u(1, 1), 1, textureProps); collision->getPosition().x = position.x; diff --git a/games/pacman/src/entities/map/MapEntity.hpp b/games/pacman/src/entities/map/MapEntity.hpp index 54ada4c..c680ccd 100644 --- a/games/pacman/src/entities/map/MapEntity.hpp +++ b/games/pacman/src/entities/map/MapEntity.hpp @@ -9,6 +9,7 @@ #include "common/entity/AEntity.hpp" #include "shared/types/Vector.hpp" +#include "PointEntity.hpp" namespace arcade::games::pacman { class MapEntity; @@ -17,29 +18,20 @@ namespace arcade::games::pacman { class arcade::games::pacman::MapEntity : public common::AEntity { public: ~MapEntity() override = default; + MapEntity() = default; - /** - * @brief Create a map - * @param mapFile Path of the map - */ - explicit MapEntity(std::string mapFile); - -protected: /** * Generate all wall of the map * @param mapFile Path of the map + * @return List of points */ - void _generateWalls(std::string &mapFile); + 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); - - /** - * @brief Create a point on the map - * @param position Position of the point - */ - void _createPoint(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..7a95612 --- /dev/null +++ b/games/pacman/src/entities/map/PointEntity.cpp @@ -0,0 +1,41 @@ +/* +** 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): position(0, 0) { + 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(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..f639363 --- /dev/null +++ b/games/pacman/src/entities/map/PointEntity.hpp @@ -0,0 +1,35 @@ +/* +** 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 + */ + explicit PointEntity(shared::types::Vector2i position); + + shared::types::Vector2i position; + +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 index 7edccf1..78f8b9f 100644 --- a/games/pacman/src/entities/player/PlayerEntity.cpp +++ b/games/pacman/src/entities/player/PlayerEntity.cpp @@ -6,3 +6,92 @@ */ #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); + } +} + +shared::types::Vector2i PlayerEntity::getPosition() { + return this->_position; +} diff --git a/games/pacman/src/entities/player/PlayerEntity.hpp b/games/pacman/src/entities/player/PlayerEntity.hpp index 4bd9fab..a0cf3d8 100644 --- a/games/pacman/src/entities/player/PlayerEntity.hpp +++ b/games/pacman/src/entities/player/PlayerEntity.hpp @@ -7,6 +7,52 @@ #pragma once -class PlayerEntity { +#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(); + + 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/entities/snake/HeadEntity.cpp b/games/snake/src/entities/snake/HeadEntity.cpp index e744697..c75662f 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" From 2a6862b3d2c44e6b5f86d7c5f11c5729e6f62b11 Mon Sep 17 00:00:00 2001 From: Matheo Coquet Date: Sun, 7 Apr 2024 20:51:46 +0200 Subject: [PATCH 04/11] feat(pacman): add ghost bonus points --- assets/pacman/map.ascii | 6 +++--- assets/pacman/point.ascii | 2 +- assets/pacman/point.png | Bin 514 -> 1199 bytes games/pacman/src/entities/map/MapEntity.cpp | 5 ++++- games/pacman/src/entities/map/PointEntity.cpp | 5 +++-- games/pacman/src/entities/map/PointEntity.hpp | 5 ++++- 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/assets/pacman/map.ascii b/assets/pacman/map.ascii index b8a8b7e..82bdf6f 100644 --- a/assets/pacman/map.ascii +++ b/assets/pacman/map.ascii @@ -1,7 +1,7 @@ ########################### # # # # #### ##### # ##### #### # -# #### ##### # ##### #### # +#?#### ##### # ##### ####?# # #### ##### # ##### #### # # # # #### # ######### # #### # @@ -21,10 +21,10 @@ # # # # #### ##### # ##### #### # # #### ##### # ##### #### # -# ## o ## +# ## o ## # ### ## ## ####### ## ## ### # ## # ## # -# ########## # ########## # +#?########## # ##########?# # ########## # ########## # # # ########################### \ No newline at end of file diff --git a/assets/pacman/point.ascii b/assets/pacman/point.ascii index 41694cc..0eb4e05 100644 --- a/assets/pacman/point.ascii +++ b/assets/pacman/point.ascii @@ -1 +1 @@ -• \ No newline at end of file +•0 \ No newline at end of file diff --git a/assets/pacman/point.png b/assets/pacman/point.png index 90a8e3bffe3a53efe7117bf4bc217d1a6c273bb4..a70378fc536bfdf40ea7e1af7b20fab697d91549 100644 GIT binary patch delta 1164 zcmV;71atd>1g{ApiBL{Q4GJ0x0000DNk~Le0002U0001F2nGNE0K`| zc3@^x`dFp%I2Hf*Nh-%n`Qkd2e|h=*kji`iJUTj>1@tBb#VVE8scdaO+f>d{IT6sh zRFR*jvbHiV{rd&9#_|(mYjtc16f_}K)XB;{F@EO4a()BElPc%SRIco>{P#}Hd9W{qmUQj5%Ga!Q zbGpBegs&{GD&5{cpJM^se@)Bv>&bH!*2ELUa#HEz;Jc33&&m@`vj&!~qbKG)?ZMcj zd-_xbh0j6KP5oPW#ATlwJNb8{?`pm8y)(<3lX}~rR6G|69Ux1EKG(yHxcGNmECDy7 zm+Di|MlWm^%gT+_R~<)>!umS#}@I-@H8k?>9fAy$TgBP-kwTwbk4@D%Jo*43L_w-5(mmq`nnv0K$!8rEbra>a}>+Y4qcFbGe_zA^nN`mRjiL7dnN>){0C}%^ zK57iTHv~gHLEfsKn!j~OpVYTv4PCeZS+>c}DsLWWOK$H^kc|q7I*Rp5<<4Yo<@I~MmHAiKI$Vd0mWq}JYBKHnZYYj>W+`9Ab>jqQK+W$dTN zw~T}1_Gb0oT3cF`J@zdhJ?fjCeD8>lblp69bXJ~?f6LLM-&?NTTJ3vLqesB&4+fNi z!~(xmsOG@M`okmQhK1lDx6DyisLzu?A=D;!2#T2@p6*tIR|j3R4GsGVb;Fw!+-x&Kt!o> z`nkmyb{K2R^E5zg_Umik_OZ2b4iiUDmO#0*GS7zhi?`Wq_Ab7ppgVqE47roI#`9DYufAXF)kTDV5mYR?>}z lxBVrpq?3UJ6d2%Cd;_8%> MapEntity::generateWalls(std::string m if (part == '#') this->_createWall(position); if (part == ' ') { - list.push_back(std::make_shared(position)); + list.push_back(std::make_shared(position, false)); + } + if (part == '?') { + list.push_back(std::make_shared(position, true)); } position.x++; } diff --git a/games/pacman/src/entities/map/PointEntity.cpp b/games/pacman/src/entities/map/PointEntity.cpp index 7a95612..21ce95e 100644 --- a/games/pacman/src/entities/map/PointEntity.cpp +++ b/games/pacman/src/entities/map/PointEntity.cpp @@ -13,7 +13,8 @@ using namespace arcade::games::pacman; using namespace arcade::games::common::components; using namespace shared::types; -arcade::games::pacman::PointEntity::PointEntity(shared::types::Vector2i position): position(0, 0) { +arcade::games::pacman::PointEntity::PointEntity(shared::types::Vector2i position, bool ghostBonus): position(0, 0) { + this->_ghostBonus = ghostBonus; this->_spawn(position); } @@ -24,7 +25,7 @@ void PointEntity::_spawn(shared::types::Vector2i position) { .bin = "assets/pacman/point.png", .binTileSize = Vector2f(100, 100) }, - .origin = Vector2u(0, 0) + .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, diff --git a/games/pacman/src/entities/map/PointEntity.hpp b/games/pacman/src/entities/map/PointEntity.hpp index f639363..261658a 100644 --- a/games/pacman/src/entities/map/PointEntity.hpp +++ b/games/pacman/src/entities/map/PointEntity.hpp @@ -21,8 +21,9 @@ class arcade::games::pacman::PointEntity : public common::AEntity { /** * @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); + explicit PointEntity(shared::types::Vector2i position, bool ghostBonus); shared::types::Vector2i position; @@ -32,4 +33,6 @@ class arcade::games::pacman::PointEntity : public common::AEntity { * @param position */ void _spawn(shared::types::Vector2i position); + + bool _ghostBonus; }; From 45f73f1fdff89977324808d296c243f0a81e0224 Mon Sep 17 00:00:00 2001 From: Matheo Coquet Date: Sun, 7 Apr 2024 22:19:41 +0200 Subject: [PATCH 05/11] feat(pacman): add ghost spawn and movements --- assets/pacman/ghost.ascii | 4 ++ assets/pacman/ghost.png | Bin 0 -> 2239 bytes games/pacman/CMakeLists.txt | 2 + games/pacman/src/PacmanGame.cpp | 53 ++++++++++++++- games/pacman/src/PacmanGame.hpp | 8 +++ .../pacman/src/entities/ghost/GhostEntity.cpp | 62 ++++++++++++++++++ .../pacman/src/entities/ghost/GhostEntity.hpp | 52 +++++++++++++++ 7 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 assets/pacman/ghost.ascii create mode 100644 assets/pacman/ghost.png create mode 100644 games/pacman/src/entities/ghost/GhostEntity.cpp create mode 100644 games/pacman/src/entities/ghost/GhostEntity.hpp 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 0000000000000000000000000000000000000000..c5dca68ebbd72c5213e3d2596429770c3a227823 GIT binary patch literal 2239 zcmV;w2tfCVP)tlsf@TF3F zsj1onhZHUqLL6{7wCbS}p@LAUila6X&<4eX{7DIMcXmDT*gJ1__Q&?PnooMNGdpj+ zd4BKB+nLci0suwufMLq0M89;YZ!PKUG$0mpznVfJ4Rdn_c%cO}Tp}Rwm}E&<5}Y<3 zIa9_tZ8`AArcFs`YfDzOC9HNgR#tMRR9?;Ua?WbUh=PD5$b}82o8+|Tz#qgYGGW7m z7>{Q_kzsTwA#g*gJ#7Trmh>Zc|x`yk4RDSp0QSy zFH2v%(Scn?hZ2Ic$J7JuF-?F{bqtTNt6bTB${Qx^Dp$6jl7{Knyb2v{tJeFOCz~C| zd%Bh!ZDI7AUv7o@rB>^`l7=}y_$Q=}Kd|2SeSFGseCn&Kj0n$)~nmf0qw^kTC7`GxV*6Pb3zb!xrny0tDj0GUwVP7tJ6~bWX~rH`CP{mtt^*5x&$W%PPq0P z`DO&J{d^6Y70(_M+Y*D`9lcWhni=tqs<)C3BkbP38)QiAOE}tccXKfPcp91kVJKxk z&BD-;Aqb1}U!I5T%`7wnx{g6`cnk@hTVL39LaaR&YOW|O7ND?Du)=BZ^FdGj}BY!RZYknp(IMQYvyd< z-+h&BQFG?;)hTerO;^=~tdlQ-u#S1M-3)_v{xQ}Qy8dy7m8>q-r_l%vL-NB~D}J0F zd)^YRt_t|tQT6CiW!sS*<}G`hKi$WV!85mSJNMBXJ{$)bWOY3o=Eer^_x}_||&OWYP}9_|c8ls>+qcp2kqG8WwLgTee@uB?MZ%E-aMu!l6U9 z?)rMclAyXxQ{c_d7c60EZ?}aYT8#6f+cbt@85_%jUu1QgCY0)p9bNcB?z?r=@ld7dsl73q3j4_b9o52<5_m@9*%p5cml;YHeyiaGP= zyB{m&LLb{t8Fca$Q1m2*QMBUAO-Mhl=T->qF$m(D$YjzMmP7)iApH!ZvMrahrAY`L zHnQR#Udo_D34y;ku^uxK5pKz%OdX>=2BDmMd5M-GHRo*0bb=IIU7DB`O~{po868DC zrZ^A4kv0rZm;EdS4WmN|L1-8f0#kWgc+g|KPzj=|0@`B`LV2p$1Sy7-K6QOO)vO+b z@>H_|S>#Ll)b;UHvwEOI2_agSDpv#X>0<` zl(x<-9|Tw#2thZZj>`xQ!@{da`XrZ{rF9iDj1DCPX^*K3+GEs58wNoe20iVBTlr1ZvTei>5iT$ z>#ArN9ZCqo;hKa1@7t#2-}upbjm=(hc#o{^Tvt7QWZpa4V-Ujm0nJ@zj_UEJ`@i05 z7CSC)7`@f3$%)pZ$`wIMgw%2S8jxzZA!v_5aCxfPJ%Cwz7^XvS#gAZ?jvajcUZ}b% z5HUkZY6g$i9W3!b-Uk_Eb #include "PacmanGame.hpp" #include "entities/map/MapEntity.hpp" +#include "entities/ghost/GhostEntity.hpp" using namespace arcade::games; @@ -31,6 +33,11 @@ pacman::PacmanGame::PacmanGame() : common::AGame(Vector2u(27, 30), 60), this->_registerEntity(entity); } + 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); } @@ -45,13 +52,30 @@ void pacman::PacmanGame::compute(shared::games::DeltaTime dt) { 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] == '#') { - return; + 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); + } } - this->_player->forward(); } } + + 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) { @@ -63,3 +87,26 @@ void pacman::PacmanGame::addNewPoint(Vector2i position) { return false; }), this->_entities.end()); } + +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)]; +} diff --git a/games/pacman/src/PacmanGame.hpp b/games/pacman/src/PacmanGame.hpp index ab9eab8..8ff5371 100644 --- a/games/pacman/src/PacmanGame.hpp +++ b/games/pacman/src/PacmanGame.hpp @@ -10,6 +10,7 @@ #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" @@ -52,4 +53,11 @@ class arcade::games::pacman::PacmanGame : public arcade::games::common::AGame { shared::games::DeltaTime _clock; std::shared_ptr _player; std::shared_ptr _map; + std::vector> _ghosts; + + /** + * @brief Redirect the ghost when he is blocked + * @param ghost + */ + void _redirectGhost(std::shared_ptr ghost); }; diff --git a/games/pacman/src/entities/ghost/GhostEntity.cpp b/games/pacman/src/entities/ghost/GhostEntity.cpp new file mode 100644 index 0000000..0105443 --- /dev/null +++ b/games/pacman/src/entities/ghost/GhostEntity.cpp @@ -0,0 +1,62 @@ +/* +** EPITECH PROJECT, 2024 +** GhostEntity.cpp +** File description: +** GhostEntity class +*/ + +#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) { + 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, nullptr); + 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; + } +} diff --git a/games/pacman/src/entities/ghost/GhostEntity.hpp b/games/pacman/src/entities/ghost/GhostEntity.hpp new file mode 100644 index 0000000..1aa533b --- /dev/null +++ b/games/pacman/src/entities/ghost/GhostEntity.hpp @@ -0,0 +1,52 @@ +/* +** 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(); + + shared::games::DeltaTime lastMove; + shared::types::Vector2i direction; + shared::types::Vector2i position; + +protected: + /** + * @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); +}; From 6cd519097dde627d83fd8c1a9b1902e5cd1f3f7a Mon Sep 17 00:00:00 2001 From: Matheo Coquet Date: Sun, 7 Apr 2024 22:35:19 +0200 Subject: [PATCH 06/11] feat(pacman): add ghost eat collision --- games/pacman/src/PacmanGame.cpp | 12 ++++++++++ games/pacman/src/PacmanGame.hpp | 5 +++++ .../pacman/src/entities/ghost/GhostEntity.cpp | 22 ++++++++++++++++++- .../pacman/src/entities/ghost/GhostEntity.hpp | 5 +++++ .../src/entities/player/PlayerEntity.cpp | 6 +++++ .../src/entities/player/PlayerEntity.hpp | 5 +++++ 6 files changed, 54 insertions(+), 1 deletion(-) diff --git a/games/pacman/src/PacmanGame.cpp b/games/pacman/src/PacmanGame.cpp index c631cb4..d54bc4e 100644 --- a/games/pacman/src/PacmanGame.cpp +++ b/games/pacman/src/PacmanGame.cpp @@ -40,6 +40,7 @@ pacman::PacmanGame::PacmanGame() : common::AGame(Vector2u(27, 30), 60), this->_registerEntity(this->_map); this->_registerEntity(this->_player); + this->_clock = std::chrono::milliseconds(0); } const shared::games::GameManifest &pacman::PacmanGame::getManifest() const noexcept { @@ -110,3 +111,14 @@ void pacman::PacmanGame::_redirectGhost(std::shared_ptr ghost) { ghost->direction = pos[dis(gen)]; } + +void pacman::PacmanGame::eatPlayer() { + this->_clock = std::chrono::milliseconds(0); + this->_player->reset(Vector2i(13, 23)); + + unsigned int index = 0; + for (auto ghost : this->_ghosts) { + ghost->reset(index); + index++; + } +} diff --git a/games/pacman/src/PacmanGame.hpp b/games/pacman/src/PacmanGame.hpp index 8ff5371..24bf8f8 100644 --- a/games/pacman/src/PacmanGame.hpp +++ b/games/pacman/src/PacmanGame.hpp @@ -49,6 +49,11 @@ class arcade::games::pacman::PacmanGame : public arcade::games::common::AGame { */ void addNewPoint(Vector2i position); + /** + * @brief When a ghost eat a player + */ + void eatPlayer(); + protected: shared::games::DeltaTime _clock; std::shared_ptr _player; diff --git a/games/pacman/src/entities/ghost/GhostEntity.cpp b/games/pacman/src/entities/ghost/GhostEntity.cpp index 0105443..2b14400 100644 --- a/games/pacman/src/entities/ghost/GhostEntity.cpp +++ b/games/pacman/src/entities/ghost/GhostEntity.cpp @@ -5,6 +5,7 @@ ** GhostEntity class */ +#include "../../PacmanGame.hpp" #include "GhostEntity.hpp" #include "common/components/TextureComponent.hpp" #include "common/components/CollidableComponent.hpp" @@ -27,7 +28,7 @@ void GhostEntity::_spawnGhost(unsigned int asset) { }, .origin = Vector2u(0, asset) }; - std::shared_ptr collision = std::make_shared(*this, nullptr); + std::shared_ptr collision = std::make_shared(*this, this->_onCollide); std::shared_ptr texture = std::make_shared(*this, Vector2u(1, 1), 15, textureProps); @@ -60,3 +61,22 @@ void GhostEntity::forward() { 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(); + } +} + +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(); +} diff --git a/games/pacman/src/entities/ghost/GhostEntity.hpp b/games/pacman/src/entities/ghost/GhostEntity.hpp index 1aa533b..b815458 100644 --- a/games/pacman/src/entities/ghost/GhostEntity.hpp +++ b/games/pacman/src/entities/ghost/GhostEntity.hpp @@ -31,6 +31,11 @@ class arcade::games::pacman::GhostEntity : public common::AEntity { */ void forward(); + /** + * @brief Reset ghost position + */ + void reset(unsigned int index); + shared::games::DeltaTime lastMove; shared::types::Vector2i direction; shared::types::Vector2i position; diff --git a/games/pacman/src/entities/player/PlayerEntity.cpp b/games/pacman/src/entities/player/PlayerEntity.cpp index 78f8b9f..ed914d2 100644 --- a/games/pacman/src/entities/player/PlayerEntity.cpp +++ b/games/pacman/src/entities/player/PlayerEntity.cpp @@ -95,3 +95,9 @@ void PlayerEntity::_onCollide(std::shared_ptr ctx, shared::types::Vector2i PlayerEntity::getPosition() { 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 index a0cf3d8..5a81881 100644 --- a/games/pacman/src/entities/player/PlayerEntity.hpp +++ b/games/pacman/src/entities/player/PlayerEntity.hpp @@ -37,6 +37,11 @@ class arcade::games::pacman::PlayerEntity : public common::AEntity { */ shared::types::Vector2i getPosition(); + /** + * @brief Reset player + */ + void reset(shared::types::Vector2i defaultPosition); + shared::games::DeltaTime lastMove; shared::types::Vector2i direction; protected: From f36a0a84eb021960b0b5414e3f4e30017bd13d8a Mon Sep 17 00:00:00 2001 From: Matheo Coquet Date: Sun, 7 Apr 2024 22:53:34 +0200 Subject: [PATCH 07/11] feat(pacman): add ghost eat system --- games/pacman/src/PacmanGame.cpp | 31 ++++++++++++++++++- games/pacman/src/PacmanGame.hpp | 10 +++++- .../pacman/src/entities/ghost/GhostEntity.cpp | 26 ++++++++++++++-- .../pacman/src/entities/ghost/GhostEntity.hpp | 13 ++++++++ games/pacman/src/entities/map/PointEntity.cpp | 4 +-- games/pacman/src/entities/map/PointEntity.hpp | 3 +- .../src/entities/player/PlayerEntity.cpp | 5 ++- .../src/entities/player/PlayerEntity.hpp | 2 +- 8 files changed, 84 insertions(+), 10 deletions(-) diff --git a/games/pacman/src/PacmanGame.cpp b/games/pacman/src/PacmanGame.cpp index d54bc4e..90e7f32 100644 --- a/games/pacman/src/PacmanGame.cpp +++ b/games/pacman/src/PacmanGame.cpp @@ -50,6 +50,13 @@ const shared::games::GameManifest &pacman::PacmanGame::getManifest() const noexc 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][ @@ -112,7 +119,19 @@ void pacman::PacmanGame::_redirectGhost(std::shared_ptr ghost) { ghost->direction = pos[dis(gen)]; } -void pacman::PacmanGame::eatPlayer() { +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)); @@ -121,4 +140,14 @@ void pacman::PacmanGame::eatPlayer() { 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 index 24bf8f8..e8f8762 100644 --- a/games/pacman/src/PacmanGame.hpp +++ b/games/pacman/src/PacmanGame.hpp @@ -52,7 +52,12 @@ class arcade::games::pacman::PacmanGame : public arcade::games::common::AGame { /** * @brief When a ghost eat a player */ - void eatPlayer(); + void eatPlayer(Vector2i position); + + /** + * @brief Enable the ghost mode + */ + void canEatGhosts(); protected: shared::games::DeltaTime _clock; @@ -60,6 +65,9 @@ class arcade::games::pacman::PacmanGame : public arcade::games::common::AGame { std::shared_ptr _map; std::vector> _ghosts; + bool _canEatGhost; + shared::games::DeltaTime _stopEatGhostTime; + /** * @brief Redirect the ghost when he is blocked * @param ghost diff --git a/games/pacman/src/entities/ghost/GhostEntity.cpp b/games/pacman/src/entities/ghost/GhostEntity.cpp index 2b14400..d263306 100644 --- a/games/pacman/src/entities/ghost/GhostEntity.cpp +++ b/games/pacman/src/entities/ghost/GhostEntity.cpp @@ -14,7 +14,7 @@ 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) { +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); } @@ -70,7 +70,7 @@ void GhostEntity::_onCollide(std::shared_ptr ctx, if (!game) return; if (entity) { - game->eatPlayer(); + game->eatPlayer(entity->getPosition()); } } @@ -80,3 +80,25 @@ void GhostEntity::reset(unsigned int index) { 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 index b815458..347cedb 100644 --- a/games/pacman/src/entities/ghost/GhostEntity.hpp +++ b/games/pacman/src/entities/ghost/GhostEntity.hpp @@ -36,11 +36,24 @@ class arcade::games::pacman::GhostEntity : public common::AEntity { */ 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 diff --git a/games/pacman/src/entities/map/PointEntity.cpp b/games/pacman/src/entities/map/PointEntity.cpp index 21ce95e..9310b2f 100644 --- a/games/pacman/src/entities/map/PointEntity.cpp +++ b/games/pacman/src/entities/map/PointEntity.cpp @@ -14,7 +14,7 @@ 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->ghostBonus = ghostBonus; this->_spawn(position); } @@ -25,7 +25,7 @@ void PointEntity::_spawn(shared::types::Vector2i position) { .bin = "assets/pacman/point.png", .binTileSize = Vector2f(100, 100) }, - .origin = Vector2u(this->_ghostBonus ? 1 : 0, 0) + .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, diff --git a/games/pacman/src/entities/map/PointEntity.hpp b/games/pacman/src/entities/map/PointEntity.hpp index 261658a..25d7267 100644 --- a/games/pacman/src/entities/map/PointEntity.hpp +++ b/games/pacman/src/entities/map/PointEntity.hpp @@ -27,12 +27,11 @@ class arcade::games::pacman::PointEntity : public common::AEntity { shared::types::Vector2i position; + bool ghostBonus; protected: /** * @brief Spawn the point on the map * @param position */ void _spawn(shared::types::Vector2i position); - - bool _ghostBonus; }; diff --git a/games/pacman/src/entities/player/PlayerEntity.cpp b/games/pacman/src/entities/player/PlayerEntity.cpp index ed914d2..c4a30dd 100644 --- a/games/pacman/src/entities/player/PlayerEntity.cpp +++ b/games/pacman/src/entities/player/PlayerEntity.cpp @@ -89,10 +89,13 @@ void PlayerEntity::_onCollide(std::shared_ptr ctx, return; if (entity) { game->addNewPoint(entity->position); + if (entity->ghostBonus) { + game->canEatGhosts(); + } } } -shared::types::Vector2i PlayerEntity::getPosition() { +shared::types::Vector2i PlayerEntity::getPosition() const { return this->_position; } diff --git a/games/pacman/src/entities/player/PlayerEntity.hpp b/games/pacman/src/entities/player/PlayerEntity.hpp index 5a81881..e9a2ae6 100644 --- a/games/pacman/src/entities/player/PlayerEntity.hpp +++ b/games/pacman/src/entities/player/PlayerEntity.hpp @@ -35,7 +35,7 @@ class arcade::games::pacman::PlayerEntity : public common::AEntity { * @brief Get position of the player * @return the player position */ - shared::types::Vector2i getPosition(); + shared::types::Vector2i getPosition() const; /** * @brief Reset player From 42365d0204b71d0873a04ae18a0e8d1c9eae0e84 Mon Sep 17 00:00:00 2001 From: Yann Date: Sun, 7 Apr 2024 23:01:51 +0200 Subject: [PATCH 08/11] fix(pacman): add include --- games/snake/src/SnakeGame.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/games/snake/src/SnakeGame.cpp b/games/snake/src/SnakeGame.cpp index bccaf96..40c7f5d 100644 --- a/games/snake/src/SnakeGame.cpp +++ b/games/snake/src/SnakeGame.cpp @@ -9,6 +9,7 @@ #include "entities/wall/WallEntity.hpp" #include "entities/background/BackgroundEntity.hpp" #include "entities/apple/AppleEntity.hpp" +#include "entities/snake/components/HeadKeyboardComponent.hpp" using namespace arcade::games; From 07fde43386888dca9d9510347e6a9f5d96c67604 Mon Sep 17 00:00:00 2001 From: Matheo Coquet Date: Sun, 7 Apr 2024 23:09:38 +0200 Subject: [PATCH 09/11] fix(pacman): update point texture --- assets/pacman/point.ascii | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/pacman/point.ascii b/assets/pacman/point.ascii index 0eb4e05..7b9d05c 100644 --- a/assets/pacman/point.ascii +++ b/assets/pacman/point.ascii @@ -1 +1 @@ -•0 \ No newline at end of file +.0 \ No newline at end of file From ff25c8fb8247ecb46484252f7527b5f84f4be90a Mon Sep 17 00:00:00 2001 From: Yann Date: Sun, 7 Apr 2024 23:19:39 +0200 Subject: [PATCH 10/11] feat(pacman): add points --- games/pacman/src/PacmanGame.cpp | 7 +++++++ games/pacman/src/PacmanGame.hpp | 2 ++ 2 files changed, 9 insertions(+) diff --git a/games/pacman/src/PacmanGame.cpp b/games/pacman/src/PacmanGame.cpp index 90e7f32..e4885a9 100644 --- a/games/pacman/src/PacmanGame.cpp +++ b/games/pacman/src/PacmanGame.cpp @@ -33,6 +33,8 @@ pacman::PacmanGame::PacmanGame() : common::AGame(Vector2u(27, 30), 60), 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]); @@ -94,6 +96,8 @@ void pacman::PacmanGame::addNewPoint(Vector2i position) { } return false; }), this->_entities.end()); + + this->_currentScore += 5; } void pacman::PacmanGame::_redirectGhost(std::shared_ptr ghost) { @@ -134,6 +138,9 @@ void pacman::PacmanGame::eatPlayer(Vector2i position) { 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) { diff --git a/games/pacman/src/PacmanGame.hpp b/games/pacman/src/PacmanGame.hpp index e8f8762..c09be68 100644 --- a/games/pacman/src/PacmanGame.hpp +++ b/games/pacman/src/PacmanGame.hpp @@ -73,4 +73,6 @@ class arcade::games::pacman::PacmanGame : public arcade::games::common::AGame { * @param ghost */ void _redirectGhost(std::shared_ptr ghost); + + int _currentScore; }; From a0c1850bcac8fac7d6b4818f11f77fb7b1a345bb Mon Sep 17 00:00:00 2001 From: Yann Date: Sun, 7 Apr 2024 23:36:23 +0200 Subject: [PATCH 11/11] fix: remove useless file --- output | Bin 17064 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100755 output diff --git a/output b/output deleted file mode 100755 index 4c7da4ebd58c7bf3e070b70f73151074b86c8b7e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17064 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