From cdd155890c911ffd59d31c381c0dda0ddf17b0f0 Mon Sep 17 00:00:00 2001 From: Yann Date: Thu, 4 Apr 2024 15:42:59 +0200 Subject: [PATCH 01/18] feat: add core menu --- assets/menu/fonts/kenvector_future_thin.ttf | Bin 0 -> 34100 bytes assets/menu/img/checkBox.ascii | 1 + assets/menu/img/checkBox.png | Bin 0 -> 648 bytes assets/menu/img/icon.png | Bin 0 -> 13397 bytes core/src/CMakeLists.txt | 1 + core/src/Core.cpp | 37 ++++- core/src/Core.hpp | 11 +- core/src/menu/CMakeLists.txt | 7 + core/src/menu/Menu.cpp | 149 ++++++++++++++++++++ core/src/menu/Menu.hpp | 104 ++++++++++++++ core/src/menu/checkBox/CMakeLists.txt | 4 + core/src/menu/checkBox/CheckBox.cpp | 47 ++++++ core/src/menu/checkBox/CheckBox.hpp | 63 +++++++++ core/src/menu/entity/CMakeLists.txt | 2 + core/src/menu/entity/text/CMakeLists.txt | 4 + core/src/menu/entity/text/Text.cpp | 32 +++++ core/src/menu/entity/text/Text.hpp | 49 +++++++ core/src/menu/entity/texture/CMakeLists.txt | 4 + core/src/menu/entity/texture/Texture.cpp | 32 +++++ core/src/menu/entity/texture/Texture.hpp | 57 ++++++++ core/src/types/CMakeLists.txt | 1 + core/src/types/Stages.hpp | 19 +++ 22 files changed, 618 insertions(+), 6 deletions(-) create mode 100644 assets/menu/fonts/kenvector_future_thin.ttf create mode 100644 assets/menu/img/checkBox.ascii create mode 100644 assets/menu/img/checkBox.png create mode 100644 assets/menu/img/icon.png create mode 100644 core/src/menu/CMakeLists.txt create mode 100644 core/src/menu/Menu.cpp create mode 100644 core/src/menu/Menu.hpp create mode 100644 core/src/menu/checkBox/CMakeLists.txt create mode 100644 core/src/menu/checkBox/CheckBox.cpp create mode 100644 core/src/menu/checkBox/CheckBox.hpp create mode 100644 core/src/menu/entity/CMakeLists.txt create mode 100644 core/src/menu/entity/text/CMakeLists.txt create mode 100644 core/src/menu/entity/text/Text.cpp create mode 100644 core/src/menu/entity/text/Text.hpp create mode 100644 core/src/menu/entity/texture/CMakeLists.txt create mode 100644 core/src/menu/entity/texture/Texture.cpp create mode 100644 core/src/menu/entity/texture/Texture.hpp create mode 100644 core/src/types/Stages.hpp diff --git a/assets/menu/fonts/kenvector_future_thin.ttf b/assets/menu/fonts/kenvector_future_thin.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9f4b4fa59ac2211aabf9cb60c6f7caf441d087ef GIT binary patch literal 34100 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 KTY$`k7yb_mr&(bD literal 0 HcmV?d00001 diff --git a/assets/menu/img/checkBox.ascii b/assets/menu/img/checkBox.ascii new file mode 100644 index 0000000..18a2f8b --- /dev/null +++ b/assets/menu/img/checkBox.ascii @@ -0,0 +1 @@ +☐☑ \ No newline at end of file diff --git a/assets/menu/img/checkBox.png b/assets/menu/img/checkBox.png new file mode 100644 index 0000000000000000000000000000000000000000..69bcfbe780d7c7921b0ec4cee89f0f7c642bb905 GIT binary patch literal 648 zcmV;30(bq1P)+7YZrJtXl{QUg&_4V%V?(gsK_xJbx{r$|$%<%B= z^Yioc^z_H$yNc6k*5}XO>DhYERddZtxZkFc)pO?Sh()#{yR$wSYsnKZoejm<+k7YKDWicL1(}a2~)3hHQ zRz`_({u7n7+P6@K1u%GaU987*-Qf#B$5E$P7e*YV8NWhTo$7(_;pB~Ts%Ogi`wY1c zJynX?FvrQ1Bw0*w4z?=AEa3P-(kyWdmMX;n5a~h?0aU5>HEf1HI1*|VgjGuGWS>zS zud9@fEQr%=L?g0ooF_^ekR@@EosMjO$Z8Lx!WD@7W#X7WFM`4qh4**1&JT2?=?~SEjP?OZWed4$f!?p|I+dk=l5&(`5cWbx+0000F!b_C6pSZ1p(=fp~r2{@AI5p#Ase5m8z0F z@bLKawf%cC00?5L$jj>bEgoh2r>{SwYAAV%l(#txot&EEsOiCuV!Ei8dzUFV1D z^ntW(ceK5#EaJ0nRcS~=`}O{Bv7H=b51yHmyVbjnwG-cy>$#s#z@7a+d}*N#+T66s zTNTaK+Vyd9WU4aOMhRYo9(3-7PE{dZAptUGDuvK74aTexOfwoAw)l3&`I1=Fk&BreU7o6NFU3>0V8Kdy3!_lwHTRm!T&7H{0LmRjQ00 zSf(BTz?x~uImct=(H=c??Le#hW8DXTpouYgLHig50RD_sTIpZWyRz{hs2tx}W>fWV z)&(g_Pet4;z@z}6dQe}pnqbV}39Wv_I!Stj+2l`;J@RF4;2pDKuce+m!UTz=Jb8ms zr_k@S#8Y6x#t=HiFziNC4E^e5*qC{o8>3T&q<=KL#0l>c;%-MK-(2(5WgkB*Pi==Boj$wXA$4-6X{-Jr zaxBsEqy6ux(du=ZUWY+w8 z>%X(bpx1NQ9lwG6O?OSot?2Ag?phza<#NnVmB0q@=r}pjQqQkW(iqT#`6&Yw#J56x zww6mV^lJW$y!YJlz4GsDRYSTp5B%BKJOu#wGFKmRiqty_KX$o6`ht7Z(r!0?j~8cx z*!d2egnU>z3WoCc9w6l59bY7#0eDt6_NTavc`vkIt)Hlj!CZ;DTMpPvD47je`m@iC zbmdzs(sh0uU>J$FeU!ij@Z`?NNSTBPEEtL38Qb6!b&HF2)HL=4_YElT#SiOWUB&^x zJ3Km7yDF{*xzoGYnl8-Q!87x}<#$ZSp@Twy2o*uAV3i+k&QD37mENmq@%C1FEAJ@K z(e6_e_|~#bcbFB5g9L(`XGuezV0nyiqjU!~ETe^RZxd`(Uc zGDU%u*hY$u)SsL5;|a{!n6r1i2mDe@dX#-u3)l=O0IiJQ=nsVi+Qjsz+k^!hM)`wY zzd-K2JLmiL)VpUayvP6w`sFc)@b5pLniB?MX6@RnXW6BH*Jk1JgIpBGyR^7FbFRJ^ zN}aeR+X>4{vF(9*GBKb5U*8wMY=HX&& z9(e29d`-2oNCa=tc7`bo{qrSWI=P`#d9u&t*db&^OiN# zwu(0l0QQIVrEun5?ao#U4X40O{X4R1n>U{u^}uQ31>xNfXIxeNNAUXx!#8yfBpL3UX0C$<(OAf(5oA;jhB~Q*`kazx)*zYFt#_01XyGC(GE5>xae|H#I8FWnks_EP)tGd-1D zw!up}D8}f<#{F;v?w*ic780Nv)0XEVE3lFq%OSqLNpt;tW&MgVI7`r~*;bJPq$eoG z#+7#jL1n->omyc;fG7!f?0839A{wB@R1kWQ9YJuMdB`na((AXOmX_;_2(>BzWjgk4 zS^vK1F7$c)V$EvAHTS?eP7rvvk1?l-#k9;rBTlK!&euUZH>3n}fjrLmFgf`=LPH!{ zWOJSK%>=)Y;ANE_e8*-J3SIU=qXJ|i>KnJq+h~m(vpj)&YRM zpn^+4mvwUNq6q&RzjX_X+5C;l@-?|T01y+z+6qJv9OZPFMQf+mOpEMI4X37C^@1x# zU$`ByrM#U(>wlc2S80SGOw49d1lRfj-{Pb*or&$~fTx<-JdSPC{gP={QXNpUTc=C* zX}sV+qJOTs;F7$mC;uogl)#p|j_t3q3wa!@?068Aua*BikE-L4?0AHTsIswfkBs3N z@YTv=iK#@|Kfv0szdaLeGijsp`yXN27YjdYYva#AL{S+_R<++kPfscvf?;RIeW3dYN>{6_Ioj%Y6H2-EcGH5T*3xk%1>b@k}{KVz74}N;$FTn#EdzRyNUtk4>wA z{~m*B=)mIueCXDNa&2(F7Qub;o_X(nfnTaAVXiHlg_C1$^l<=P$V^1=bMoti-{UgX z=k7~?mzK>R7G_`Y=L3L)^g)K$uEE<=3Olp@jZZ~79SY<}P|tUdr#RPWPCX*YJ<7J# zLOj~~pTV>2EuW!=Q~b(tfuu)Xx$rXkC6X-4FSso|(VJfwdaK=xcF%OWz!1j>yt}DU zNIEe9d8c)oP@Ti{B&+V90tX`KJsk?51?eq%TRAZ}khyhc;RI)TX-0p+6`JM6QC3*TjTeYy;Iiw!Hv= z0;GGlw;KKosaqj7nhe-bGtiz)dR?$KsEh=lqks6o0Vy$Zs@c5zJ~b)PbWpLNL0o7B z_f}w)O@3+vovqKwdRT4yY+t$GzY#bY$TsTsn zQ$U6c&`JtaIjSljntwaCh#BrhrmJxe=r7+A(oZ{Y8dN(dj6(t5X~h^^6^4vau=KsZ z$GG<7*g?^+_p*Zti<&1{?l}oS-OS$fEbN^(=qeM@TCT5rv-Sp=2^|1{p8MlEoxiG?^bWFA~9xtw|qPOYCBW- zuL(Coq{`wR-2tR}DpNap3yzm4HavqqRYa}DpEysvLjAj;8L_GN36xvDdnbpl7Pru$ z$B;Wm{`BWt8pwcrbWrlSMgMT-4?n&IsjUuU4gLH6E&c1`Z!;X<=5h<+fBIjyA6Hhg z&283|*jL^=FTVlaMbqD!kL%VM5hhMdEKK~ZJ@I;3)PI*50lQsD^<1IJ4OP@m{8=?w zHFGj~GLx%)JhEQ^dma9Vd|4ax?!LCKxVU~=I;oTq)QHjTkCULQV^+H9xl&EdkGyxi z6S;Gp`Da!GyR)#WF{Sh+0KQ^;4qu~Dop((Ni*GGuW4^>Wsq5sU&OO*jcml{1HApAj z7d_mW7~m}7)VO6&)TQ3>&V+-`l-yPQSQ^TMSnei`9pc8>a7_KYi5iiB41}9hcbMv* zk1N#*>`+SwG)pudXssyNTl(d;x?b`(edE~42=a;H*;^ZXR2N3gmv)2FBWY_v$3Z2f zx$;|hT4!JEa877N;ORi!%EbtNQ(0igzFgr80q0zv&JD5Sx=ml_d-FT&NOcK`(57aSoPd8WKO!mvg|)`C>&KGP`o$-CmhGLei9y zRJBKAdex!S>8oewbyHW_a&cO0QS!IMgCkQ{u2NXPtpK;_^)M2WJ@Y~nuX*; z#tWZZ-%Fa7@sRFeDcPTXv#E1~o$Wt^yM?OQZ+G<6VZxt86CHcsgM@*@NIhP#*;eAK zq7%}#yd}m#SC`xIqZHGip+^%Ic|*Dqo+@ONL4-6MQVd>Uz33ow5mr?E#^B2hj%7qd z4L2$!*}UMdpUZBVTULN@)x!&OgJrFPY?=#fho*X6buW?!o4FsolX$J~=tjo@9~f6G z($Qz0xv=<3fTkHw_h(HFumKKbsY*m!0|3ei@$HnFJ z7bqW?fcc$6?soMc`oTz)56UcNwt#YpYL8_4U@ z^?bEZ)D)I~iQg+*P#7C?OMO6~1HV4_8oMtyFAQXxp>UXlSqjCvIY)kkjY;EB7IYT! z;CnbW@`@t?8ZsY|p{ky(qCx?I+h!8M)tmCGPN3AWX*!XaR!eqEi=SzjitGSy&#Mt- z=honFD*Q*sIiBBrpR-E57byc}w%>mBJ&Hq7iwm+IJd{@C1_bjgZCM)d^^*`a9?1~M zPI+tK`n%Q?DXXluOe2`^ONGud$1yLoD|e>?;49l(S6{Sq7gEiXOiqbXMnm+un3^2Y zY9njX1RH*dp#ija1McQ&$+}HgF-pVgp9d4lCHPu2Q5@S}4N@S)#V!{2Rb^`#AoP}> z_J*Tv#iZiA0CXt{-=Yowz@n(3E5eIq?yFZxm6eusrqXlrC~6i2NyPKY-adBXWPbrX zaYp~_viS0(kr4ZRpBk-in{jT$pHN%*DcORJx)m`2IkNBIWJ+`WT&_=BW~QpwtVcp|?K z;*a7gxQ(yU(Lz&6=(FF|lJq~#3#gw+&rcM@y6N#8)}wz}e*F^ZHq3UEYBT1^yA1qT z+aeH7TNXBFw~F2z3*JNjzSCbY*_s{qtqkK`h`UT*V{SBYD%mfaViL@;L&z=p5n{V0z@@5HIJ$MTiZ2~dRO|c z)O`F1*x)l?46EljY7%cEIO#gfEh_!2kTNosuiB)hG}TwQ?I7?p8T`t=z93X?D*oFR zB?DBnrv_u|e^K9ZO9nEl0Ba&_7FQ@7o}%?Jga}MU-M0+h65LdPdRU8@GV5RN?1IR zj13A$6D{r~i&~OwlPDd^=+P6z$4WQ79}ztsE)Gpu$dZ2nI(aCv@6J(rLaOVy;Eskm z)oB)9eg+kO<*%p!V;=)chMAl!_W=}u4!m8+2S60HK@_>GA5r{`F&87OW0tL`KGJ`& z#g$&)KY$IqHzmm0OMQCjT$^_J7F19F3U`8_3coxIPLjz@6)CLqsbtPBuvJRA2tWrw z=8FMA>e-T>*thwLlNUP{@R~_BoTK-e^8~IP6R)e(ugj8-{1u5YdGGi6mD+VC%q$MO zMC!FC^NVnfe|grvK{gB1iu(pPwWP6Iivx^+H(jvZ>d|`TIqL8kh4jwRwnhNDftQte zWlv;$iZ)Vz@XdMJE3RyHbEIO7=A(0{Uqs67{ls*RN;aml54r)7wMKbAyBp$9On`S| zT*5K!IG`KFwP?tOJ9n+N!d;8+(JBMO-2TCTqiKVtw-3A_9Xw+-7ySzj2F1`4A< zcp3ROIZ#EG45(Vn=M#tclQ;G0Qd6dkN9lOn;ll%p>}E0XDR)2Q=>wzVP=0;T6;t0? z;T~#&?0;+o&vAsCo(qGJ>mfW*dEV28_1&5g!N?JR17!a&%bC3iD;x_^I-vN<{P-fB zuQAcV*KWXY;!vRc9t3e?tJQ3zCE5CR`Ny(21_pwD$O9p|?(a^4IiGx!v@n}UN%uka z^&?@8Jf4N)56OoE+u)`+!(#&taVSd)^5RoEyo{k!FBLy1TN@EpP`Z#_eXv~;FdB6p z4|k(8ZD>s7_d@t7TgWXf7FpYfMiXUcr+fasQtRZcf&A+os2UdkW120wLp)_)GexY}VlnnHDbUQ$6ADA2n;vDQF}N0TE_NNnKTJXqy9m8n?l zzo&1k%Y=D{DCcq2O4F(#axlC~+Ii&)eJcj<{z$C;A>p5NDA`{#n=YOZFHuxzKAd4oZM7J>LUv#zlC*x zcoyn$?mmJAO^RkSum6t8^Fr+Mf!x++yTD9gS>+ra`Y(#55t?zW{Lgj-7jTmRju@{g8lf<@bHxVxG~2$!Q>)(ECh#v5B5kSPXD zSC7J;K1ayG@*Nloc?us{ic(m|Ih~H5OE+S6_OJYE&K{z6g*z$Jg_MyTRJ8*MNcJk~ z%<(9PA~zmcYGdAs{@u|w{K4j+iH8t2VG)<3CSid#BXl%h+NHQZcT>x`L~vwd#hQ4L z?%x#Ks=mx!|HhpN0*o_<pwjn(tu_8+4)dyo!x0K_O?=x{w{r4Uw}Hb0 zYT{}r7|n0m&-d0rl90}&l51x}+*=1!)^Uf?YN4kZaonvR?qYSIFCZ7Rd*@NYRteb0 zm*FnL1y{Q0q}nH1C)$^^@hovrywLhL4BmU>1xL(%o~_XmBAH79&!0sYs>d4cE#)90 z-R(!G>BCwWt-j;ZnSwJ%6dhXV!Nax<^5N$nnbAJOVzm8uL6h@2_WN3_tA~+KugRz< zwVI=yFUl$yz!`|SUe4x%xp~E*`}}Qw{(#=S-7oto4eQr_@uBz)ke{{^W@zP2hS~S^ zcJ?spHJbT*q3~GrB&?`yvTqRefG)wNM8vmdPCvskFYw4_cz*Y(@Oys#K1XU`hceCT zqvA;Qs~VWc6Igh(8@{Y3V#0LF){enDSJaJ)aY`xr%T^oAv>$6chpnqFV$F<1(&@fY zziEEg8SCezJS@7a#ZCEml1g{m^U83!_TgO|4bnN&u`Q>oEqKTd^2j#R2R{_4C-htU zUZ(^iPK$5b&giaflY@_Q)vj9}#*RH6f{K=cZN;}b+~(c|F3eZA^7A6D7$NL8X2#RC zyXB7nXv>v-JSJutu1geWMuiw8{(adl`PRa;l)RET^vJ{*JI2yEdiK?V>WAmhBXdUj zOPbo}$4b`?EsyCdX}>qBgJ;87jW7`!>EYl9tC72JB`Fds$=oJw7s}DJu#dE+@~ov6 zGm5V~UX$|_f9g-V(k7w}f6On7oRTsv2;gwFVqFCkqtzXgr?MN@cJ4@f+f3h`{64FV zC{6kEuiJBZ&Ng7#%(e1|34OZ61GuHBft5b5yd5rh`*nAuMX2smYptGjq` z#D)P99#5xSydo!p-c&v%zpn1ouUkQSzTIS;$7=)ahLnNUG$IZ8o_~pampn~z@w>8h z2U3(aIJV%U;0?)LfOu|{97d1*EgQnoIU8i*Yc~vLDc$u;;9k4snfe# zX}E&CW3J<;TsN~=aD4u0WEf6=&u|{imwk1^i3iOQS67L({;|FMKFqX?tDEP6a_(qw zg=rTB#YXLWq6l=CjkAL=2OiyQ`BrY*s)WDgWwPtu2aC@{X0+$^%rzYpK@H}^$>%H) zmXshw?sR%51Bo!jj-1ngvO-LHV;(xuZ%`k;4Jx(Zbd zK&1&7OVda9Nnz7v8Ly{6B)xaTpX3-YYVds91E zSafy7c6qIZE`H@M`rO$%s=sHAFHPLYVcGXAks69f>HsnEHkRrrUl5-8SF7>4&fy#Z zU`*QHPH&l5A}(oobK^S$F%%mY;bILm3Q^CD&>Z%mU^g}}3v54Gwbi|P8?&C5I?>Xg zJ?R-pLB*{xso*KPurff;xxLwKXW@=I@z4c-n zH!QY^H-mVI*XdA}R*wMzEm%D5RLy_>g0dJi@9yBLOE~p|^bRx`o`ToC9DdUHmC@*F z;-9}`&qjGe^DBpCSH72cm8h-ld)4{Q?S}X|y)EV zAfsSCEY5Bmcm3j4C~y#ALbjRn`PVliw&LbK8(aA_f++W>PdRS!@lIL&g{nplFq4jV zw(SKSmUV2@4VYY=Y0%-22U~B_3W)icj%yq7jj47?IMX?CchYOGE&4aM@mI;-9G0J` zdP~KgAwCwn>4|H3g~~!`biEZA?FWJ{O!%L#weJ(ZnyzED4w|F0;G6MWfcZ|kwNIF? zH;wOK(^rTc_LAC%bF9O?gB*^X(7z0tYt}M=&du@fmN|d)p64GFZq}~KO?5;N#^R^g zq2H5{pcvnN`Q-)2GZ!JDUb;K&Un_n5WoIWYv; z-Yp1`Rvl`g+)f{UK^Sh>LhUQq*d^r{y|4S50XR6L@+F$0+U$**-w`6fo zz6)+vz-RccWBjOjzWuzgsVl?p)lB;0V81kG_D7o8(KBqGG#gD4V%JeS z&(?`7E!>wV;bnsn2Yb(^y(Y=m$B*u z=_6E~Kkl&2;P~RK)fGXAP2uPYw%xG|1_jz&*wu9vEiTt z4tV(xFB{IZbG}Bhww9ve<7=cMgWQ>YyM?j5acf2Ix)%jU{B2R+r9If?t-}786tAnx zz;!)eTC|lQyWna33}ee2Wesb(p57=ks-e)1&mg;9_0fMeC%%N(obz^IV6 z_Mr|6EW#l~7RVhpzIaD(if*vCa>D<|3r~OgE&)sFYo0u#och+2fbSk(AtU1RxrEKH`;V-e(3;nAVx;^ljLaZ*FYLk?VxZLJl zum(OD3e}=O_Tlb981Lormqm`ftIn%`{vH)f->c!hsq=e-afN|N8Mr9+Tk1$H*j)KB zcEZeT+U5pW#)k^Vl{gUCUS3tZW?Z+V*N}b zdvXTdK6$>Z-fz{60k!ge_drWiz*H2SUebj$-YHNPjGp#=e`?yZ+(`=Spx|3}@0axE zlyo06gW=4N9$CCmt8t>lv{xWnR$^ha)ey`XerXWx8YDHmMDNyUI|LE_g zcau3&6AJ#ed0Qe~o%t|ted(iPrJjI-pZJ!<698qv^&@HFtB^SxA16?LL?Vl9_dlTdCiX))vp-K2tc(0C!+8^(8DoSm$+=a-=*f zJ%@F}i-vbQEZ`CfOkm7YDF#)K9zeYX?*cgS*-&Xo4029dhP~~~GB!7r{2vYn3HfT~ z{*3QTC?JvU+G5!AVBzBjGDE&aO}?_h2_UOeU+9Sjkxlf(Ril117>EZ?{^5s_A;aL1@|z+ zn7KMBnGBNbl7aywfu0_OO%68Xg&5HFz&y+{=!QL|kYeOx2!8mZ(s^(aMua6Ua|K7ihvjn!1=$=EMp9-|zpwVl+S%oI*s9B%(vDbwNIC4s$m;aW&iO`&xh zVJin7_n>=3W!0m1R1CMZwb0$|!@)g#<7Ob+)yAxij5O83XDXV%L|J@2JCegTmvW`n zfF5km>Q_;5IKwJ0qrzCLc`flFs@sey4cUES!WLtAI^t!AFA`}2I=cSW1|S06kFd~A z-R%3GhliwaXr*|!`o~|{Z;JVgztSZWe0;2;!qbH;0-f7rlX=Brce{|~N?^dz`=a+3 z^_B4a!9^1!i4SfLai*6F={mW2kn?0X$J-o|8@>R_raT)k;@ZplC_704|0 zd9qkaZkgMIO2>HWc4Mi9z*qVmKT0R#Jwa#GTaP#+gHh*#A~5Th5r1*EpXa2!qkAM1 zwJo@|P-R#XeX#lz89pC^oLV>_J@;G5mJx{q>2_7FDYa|%B9s; zqhg=yd8KX3r_gQQnPx^Hahiqy_~wH2sih@QpZk{)c~WY;&Ck$IKD&h~IefX-W?!T= zT^7fK$}%^*TI@M(_bFbt>Pss53s9CQm<`PuLLP{#1-FmdEiZb1Ne@xYA zhr0XgjdkL$H?)n(2$*vfsgt{27lu|r(xu^s%PppC%?!h>WDPEUCM)lovI*@z8GiK^qiu@ z4?my0S^0fQylpAoyTg6`H#dEibKD<1)v}N3p9MC_#+IKf}};1uLP;^{E%w3Wf{J zs8j}nUz?wU&!{`$Pi$m2Xj-=G^}xwRPu4s8^k{Dq=imKwzIN(Xr1E&c9C|lqR5mm% zknyQKH$BbEg*%HgzboR9{(?VDJ^16$XzDKkP@)rxC5W+3P}_n&$AOnV|6ErZ?%fKz z;Ej>m4+l^ElDTmGgqs$#II=~1|7Jyxgl%d9Ufpn?eAR_L9A+uYoP(~3TF$f2qWfYm z`MhI9%}`4MdP}0;ru%W(aoz}Anlc@={#>)&{~8(~g5PI$2X&uohphD8DR{_7R&dHeQFkIX~D}YT|*!8=?zzE%Zoz^Rl_cM(D)@@kNN9(Ms7djXBABG3u1n*YV*R$ zhG8q4IyPRHfg&BGfAwny3W}Tbr-jDxeTcq!d-7vh>favWo0$B}C?Dmm?96A&TzjFc zro&QG>o#A5g=dx>OK)_(1_^U5%+>l`sr1->XL`E08oq>zl4Cfs${|IT%h&WPFQ!?W zz6j&h^+)#8&t=BNXQk8}{708*dC99}Yfq$45p1x314F5dZbr@Ut_f$Vw zc5SEG4Jmb&!s2wpl%8*nvc7AwSsD{cBSSEdI zBZDqrV(WbC;s5*Q{ou>5wsTprMCAm5D<(f3YHJePk0*X5HHFVD3G9r17OWpq;~;C_ z9eDoWdq;6+d`Ep}en);&SB!!^E9Q1HlKvM%{KW*M9W{_S`dRbQz8Ev|KNez+tPmdjrp zr58Pmy&Y&Pv0R~7y+}*42OO9zp})P8qXd{Lam1VoqN5`c?42h>h{|1eP#v)rP`@@h z%|wkZD>@8HB&HQ8g)bdh&CDOktv?fb^48vHK~Ws3n4{mhAjEDR&L>(Oj!Ta(-Gqf- zj?X78EFRhCaXi!a(A}L{H$Vg66ntm#)mV+#AZ6yJx|#hr$$@_X*5AM+Df45=!u(q( zn2sVxrj;?Am3K7nqULQ%ghzZp|04Bz^$0$Zvqwi<{@9;I{)D#cvB#_}ewtxRdUtSx zn+lz5(l3zNxmYu!*-Wx1{@>5o8FfVf9lyq~at+-1Y&O->4)-=5Z~pz2+G~2lY&#cH z$}6?!&G`I)OtcE4N9#E^RsT>^V#W`}kHsc$d)o3W{ar|pj>fPxC1vXEET@Wubymzk zy^m;E3Jv2o~BFUc|&AGE&*P_R-!#OXkb_2=qQQ$lO*g8M+b&faCKI`dPMt^z@jDL zWp1$O-cJG;Pv0ooSsFywb>R+cvKsM_m!RSfri->qO&K#?sl9-vl^qx>D*2vfJ?XMn z&P{JhY#HuVe3d*U$xYQ;B$ZqT^=;)PD8H@GlYT56><|DSe=ekpiJZXCR0&C+T_%~h z;Z<)pK#V>6m7rkJGo%pbLI-uJFBu)Mt@DJ4=lCN0V9O{rTh0X}HHi-5fkg%BmUoJj z+Y;hM;{NAgs~ka0y15FcD9`o;{^r-Wr>SZ0o-xihSd=2`8x3D!gw+=fTP6T1+^u) zG6H=nfADL|$N44Z)=jZI{pE)Wl57B87x|Yu_9s_DphHV2*33c-GYi5BWCqZYO@xe8 z3g@rYld_oy7qFkq`ZdMsRppsxYhxd89L)&g} z&UVY!Z#Qm!{Tecg3kA@*q@~+k#BEEq}83`8U^dZFd)Gm;4WEmTK=TRen$`Yj^^%NC%J1yKc zg&@4Lbss)4Fcc884rCr4@)pQP`f4BDzjFgx@TW9qhScTiMB{>(1)1suU90hn0^yt{ z?=c*KFmO~&`AB%cjK2y#Wl6@8fVa;W#ex76!Bu>Xp>R($DlkC!SmqbjarrB(QwMXK z9y*c(3)Fir`q5DVR#^Bh=OFgsYi5;3B~#Jqm$)@USo+4x+?yF>n6spuj@z^hU|*6v z7`BD~=1~;ZX}4lvB2gG+H#BO1yh>jbuyq}6H3Pe;kxT?*Uh&^O6V_px7qDfog|s;L z9Oc_`^gQ-l>NgG&tm`G2p76RO$j(hg^%*z}Z<=r}DVGFR^5*ob_%^VCuloh#BVd)> z-iaaAC_cp!l&!KHB}E9xWNVQ=OJ{1+NIJQ*d(ud@|4sLz4)=m9W32jk&hh))=fua} zKA&T?{=&}PiljIieyI_U>pvkiNyb?3(|%=$njQMKw#E%F()@HRoQq3D1|}>yhxZcM zdwpMdgp4qjl##B#Bl0LHB;{20(TQCjEzT`@(Xbn=__8}dtt#G}0qm)e>C)n$e@&V& zT5a=}i)rh^fvrJ15oT`S8+&*`cj9|s-$NXo3K=h$djcBVJ3KtFKh-+sFlwf>IIOpm z&SnsYj*`-x#5aNXME;k9ALIV`L~h}W*V!kRzGUL{xmM$wcSjyLWEcQI_i}l-?kxNc zcLuL|&CHl6lkH4J*WjZp+XWf<;)X`FWBXW&7tO0XLZScte}~C@ygTZKVt&r@Q<1LJ zPQ3@aV@W_};4BDlW9(KvYxgByOVp*bogvsJ#+aUUFhpbLABci-012ox;)EXTjDd}1 zIjPP%6!(Ei{~n@xd*}$tqNZgnq;G$Sf_fEXg9=Sj)E(|@U&E=Y>(WY{&no8=51a1f2-TR+ zo>~5W9%8rr*D+nY-R~PcZ&UWcGXT(IqPCbXN&OgL_vJ#(jQSJAqC|kP%8(w>W~RW+ zi^11i}e0Q!_gameProvider, this->_graphicsProvider, this->_sceneStage) +{ + this->_sceneStage = MENU; + this->_gameProvider = nullptr; + this->_graphicsProvider = nullptr; +} Core::~Core() {} void Core::_initGame() { this->_game = this->_gameProvider->createInstance(); + this->_sceneStage = RESUME; } void Core::_initWindow() @@ -35,6 +41,7 @@ void Core::_initWindow() }; this->_window = this->_graphicsProvider->createWindow(windowInitProps); + this->_sceneStage = PLAY; } std::shared_ptr Core::_getTexture(std::string bin, std::string ascii) @@ -180,12 +187,20 @@ components::IKeyboardComponent::KeyData Core::_convertKeyPressData(events::IKeyE return keyCodeData; } -void Core::_preventWindowClose(std::vector events) +void Core::_preventWindowEvents(std::vector events) { for (auto &event : events) { auto type = event->getType(); if (type == events::WINDOW_CLOSE) this->_handleWindowClose(); + if (type == events::KEY_PRESS) { + auto keyEvent = std::dynamic_pointer_cast(event); + auto keyCode = keyEvent->getKeyCode(); + auto keyType = keyEvent->getKeyType(); + if (keyType == events::IKeyEvent::CHAR && keyCode.character == 27) { + this->_sceneStage = MENU; + } + } } } @@ -374,7 +389,9 @@ void Core::_handleEvents() { auto gameEvents = this->_window->getEvents(); - this->_preventWindowClose(gameEvents); + this->_preventWindowEvents(gameEvents); + if (this->_sceneStage == MENU) + return; for (auto &entity : this->_gameEntities) { auto components = entity->getComponents(); for (auto &component : components) { @@ -387,6 +404,9 @@ void Core::run() { auto previousTime = std::chrono::high_resolution_clock::now(); + this->_menu.run(); + if (!this->_gameProvider || !this->_graphicsProvider) + return; this->_initGame(); this->_initWindow(); while (this->_window->isOpen()) { @@ -394,6 +414,17 @@ void Core::run() auto deltaTime = std::chrono::duration_cast(currentTime - previousTime); previousTime = currentTime; + if (this->_sceneStage == MENU) { + this->_handleWindowClose(); + this->_menu.run(); + previousTime = std::chrono::high_resolution_clock::now(); + } + if (this->_sceneStage == EXIT) + return; + if (this->_sceneStage == NEWGAME) + this->_initGame(); + if (this->_sceneStage == RESUME) + this->_initWindow(); this->_game->compute(deltaTime); this->_gameEntities = this->_game->getEntities(); this->_handleEvents(); diff --git a/core/src/Core.hpp b/core/src/Core.hpp index bcab8cc..614d2ed 100644 --- a/core/src/Core.hpp +++ b/core/src/Core.hpp @@ -8,6 +8,7 @@ #pragma once #include +#include "types/Stages.hpp" #include "types/Providers.hpp" #include "shared/graphics/ISound.hpp" #include "shared/graphics/events/IKeyEvent.hpp" @@ -20,6 +21,8 @@ #include "shared/games/components/ICollidableComponent.hpp" #include "shared/games/components/ISoundComponent.hpp" +#include "menu/Menu.hpp" + using namespace shared::graphics; using namespace shared::games; @@ -44,14 +47,16 @@ class Core { std::shared_ptr _game; std::shared_ptr _window; - std::shared_ptr &_gameProvider; - std::shared_ptr &_graphicsProvider; + std::shared_ptr _gameProvider; + std::shared_ptr _graphicsProvider; std::map> _fonts; std::map> _textures; std::map _sounds; GameProviders &_gameProviders; GraphicsProviders &_graphicsProviders; entity::EntitiesMap _gameEntities; + arcade::core::SceneStage _sceneStage; + Menu _menu; /** * @brief Initialize the window @@ -239,7 +244,7 @@ class Core { * * @param events The events */ - void _preventWindowClose(std::vector events); + void _preventWindowEvents(std::vector events); /** * @brief Handle the key press event diff --git a/core/src/menu/CMakeLists.txt b/core/src/menu/CMakeLists.txt new file mode 100644 index 0000000..9d298bb --- /dev/null +++ b/core/src/menu/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(arcade PRIVATE + Menu.cpp + Menu.hpp +) + +add_subdirectory(checkBox) +add_subdirectory(entity) diff --git a/core/src/menu/Menu.cpp b/core/src/menu/Menu.cpp new file mode 100644 index 0000000..288d27f --- /dev/null +++ b/core/src/menu/Menu.cpp @@ -0,0 +1,149 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Menu +*/ + +#include +#include "Menu.hpp" + +Menu::Menu(GameProviders &gameProviders, GraphicsProviders &graphicsProviders, + std::shared_ptr &gameProvider, std::shared_ptr &graphicsProvider, arcade::core::SceneStage &sceneStage) : + _gameProviders(gameProviders), _graphicsProviders(graphicsProviders), + _gameProvider(gameProvider), _graphicsProvider(graphicsProvider), _sceneStage(sceneStage) {} + +Menu::~Menu() {} + +void Menu::_initCheckBoxes() +{ + if (!this->_graphicsProvider) { + if (this->_graphicsProviders.empty()) { + throw std::runtime_error("No graphics provider found"); + } + this->_graphicsProvider = this->_graphicsProviders.at(0); + std::cout << "No graphics provider found, using default provider" << std::endl; + } + int index = 8; + + this->_checkBoxes.clear(); + for (auto gameProvider : this->_gameProviders) { + std::cout << "Game: " << gameProvider->getManifest().name << std::endl; + auto checkBox = std::make_shared(gameProvider->getManifest(), this->_graphicsProvider, Vector2i{15, index}); + this->_checkBoxes.push_back(checkBox); + index += 2; + } +} + +void Menu::_initWindow() +{ + IWindow::WindowInitProps windowInitProps { + .size = {50, 20}, + .mode = IWindow::WindowMode::WINDOWED, + .fps = 60, + .title = "Menu", + .icon = "assets/menu/img/icon.png" + }; + + this->_initCheckBoxes(); + this->_window = this->_graphicsProvider->createWindow(windowInitProps); +} + +void Menu::_handleSelectUpperCheckBox() +{ + for (auto checkBox : this->_checkBoxes) { + if (checkBox->isChecked()) { + checkBox->uncheck(); + auto index = std::distance(this->_checkBoxes.begin(), std::find(this->_checkBoxes.begin(), this->_checkBoxes.end(), checkBox)); + if (index == 0) { + this->_checkBoxes.at(this->_checkBoxes.size() - 1)->check(); + break; + } + this->_checkBoxes.at(index - 1)->check(); + break; + } + } +} + +void Menu::_handleSelectLowerCheckBox() +{ + for (auto checkBox : this->_checkBoxes) { + if (checkBox->isChecked()) { + checkBox->uncheck(); + auto index = std::distance(this->_checkBoxes.begin(), std::find(this->_checkBoxes.begin(), this->_checkBoxes.end(), checkBox)); + if (index == this->_checkBoxes.size() - 1) { + this->_checkBoxes.at(0)->check(); + break; + } + this->_checkBoxes.at(index + 1)->check(); + break; + } + } +} + +void Menu::_handleKeyboardEvents(std::shared_ptr key) +{ + auto type = key->getKeyType(); + auto code = key->getKeyCode(); + + if (type == events::IKeyEvent::KeyType::ARROW) { + if (code.arrow == events::IKeyEvent::ArrowCode::DOWN) + this->_handleSelectLowerCheckBox(); + if (code.arrow == events::IKeyEvent::ArrowCode::UP) + this->_handleSelectUpperCheckBox(); + } + if (type == events::IKeyEvent::KeyType::CHAR) { + if (code.character == '\n') + this->_exitWithNewGame(); + if (code.character == 27) + this->_exitAndPlayOldGame(); + } +} + +void Menu::_exitAndPlayOldGame() +{ + this->_sceneStage = RESUME; + this->_window->close(); +} + +void Menu::_exitWithNewGame() +{ + for (auto checkBox : this->_checkBoxes) { + if (checkBox->isChecked()) { + this->_gameProvider = this->_gameProviders.at(std::distance(this->_checkBoxes.begin(), std::find(this->_checkBoxes.begin(), this->_checkBoxes.end(), checkBox))); + break; + } + } + this->_sceneStage = NEWGAME; + this->_window->close(); +} + +void Menu::_handleEvents() +{ + auto events = this->_window->getEvents(); + + for (auto event : events) { + auto type = event->getType(); + if (type == events::WINDOW_CLOSE) + this->_window->close(); + if (type == events::KEY_PRESS) { + auto key = std::dynamic_pointer_cast(event); + this->_handleKeyboardEvents(key); + } + } +} + +void Menu::run() +{ + this->_sceneStage = MENU; + this->_initWindow(); + this->_checkBoxes.at(0)->check(); + while (this->_window->isOpen()) { + this->_handleEvents(); + this->_window->clear(); + for (auto checkBox : this->_checkBoxes) { + checkBox->draw(this->_window); + } + this->_window->display(); + } +} diff --git a/core/src/menu/Menu.hpp b/core/src/menu/Menu.hpp new file mode 100644 index 0000000..1b41bcd --- /dev/null +++ b/core/src/menu/Menu.hpp @@ -0,0 +1,104 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Menu +*/ + +#pragma once + +#include +#include "types/Stages.hpp" +#include "types/Providers.hpp" +#include "checkBox/CheckBox.hpp" + +using namespace arcade::core; +using namespace shared::games; +using namespace shared::graphics; + +class Menu { + public: + + /** + * @brief Construct a new Menu object + * + * @param gameProviders GameProviders + * @param graphicsProviders GraphicsProviders + * @param gameProvider gameProvider + * @param graphicsProvider graphicsProvider + */ + Menu(GameProviders &gameProviders, GraphicsProviders &graphicsProviders, std::shared_ptr &gameProvider, std::shared_ptr &graphicsProvider, SceneStage &sceneStage); + ~Menu(); + + /** + * @brief Run the menu + * + */ + void run(); + + private: + std::shared_ptr _window; + SceneStage &_sceneStage; + GameProviders &_gameProviders; + GraphicsProviders &_graphicsProviders; + std::shared_ptr &_gameProvider; + std::shared_ptr &_graphicsProvider; + std::vector> _checkBoxes; + std::vector> _texts; + std::vector> _textures; + + /** + * @brief Initialize the window + * + */ + void _initWindow(); + + /** + * @brief Handle events + * + */ + void _handleEvents(); + + /** + * @brief Handle checkbox events + * + * @param key Key event + */ + void _handleKeyboardEvents(std::shared_ptr key); + + /** + * @brief Handle select upper checkbox + * + */ + void _handleSelectUpperCheckBox(); + + /** + * @brief Handle select lower checkbox + * + */ + void _handleSelectLowerCheckBox(); + + /** + * @brief Exit the menu + * + */ + void _exitWithNewGame(); + + /** + * @brief Exit and play old game + * + */ + void _exitAndPlayOldGame(); + + /** + * @brief Initialize checkboxes + * + */ + void _initCheckBoxes(); + + /** + * @brief Initialize textures + * + */ + void _initTextures(); +}; diff --git a/core/src/menu/checkBox/CMakeLists.txt b/core/src/menu/checkBox/CMakeLists.txt new file mode 100644 index 0000000..5db4b4c --- /dev/null +++ b/core/src/menu/checkBox/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(arcade PRIVATE + CheckBox.cpp + CheckBox.hpp +) diff --git a/core/src/menu/checkBox/CheckBox.cpp b/core/src/menu/checkBox/CheckBox.cpp new file mode 100644 index 0000000..0c94492 --- /dev/null +++ b/core/src/menu/checkBox/CheckBox.cpp @@ -0,0 +1,47 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** CheckBox +*/ + +#include "CheckBox.hpp" + +CheckBox::CheckBox(const GameManifest manifest, std::shared_ptr graphicsProvider, + Vector2i position, unsigned int fontSize, Vector2u size) : + _manifest(manifest) +{ + auto font = graphicsProvider->createFont("assets/menu/fonts/kenvector_future_thin.ttf"); + auto texture = graphicsProvider->createTexture("assets/menu/img/checkBox.png", "assets/menu/img/checkBox.ascii"); + + this->_checked = false; + this->_name = std::make_shared(font, fontSize, _manifest.name, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{size.x - 1, size.y}, Vector2i{position.x + 2, position.y}); + this->_checkbox = std::make_shared(texture, Vector2f{36, 38}, Vector2u{0, 0}, Vector2u{1, 1}, position); +} + +CheckBox::~CheckBox() {} + +void CheckBox::draw(std::shared_ptr &window) +{ + if (this->_checked) + this->_checkbox->setOrigin({1, 0}); + else + this->_checkbox->setOrigin({0, 0}); + this->_checkbox->draw(window); + this->_name->draw(window); +} + +void CheckBox::check() +{ + this->_checked = true; +} + +void CheckBox::uncheck() +{ + this->_checked = false; +} + +bool CheckBox::isChecked() const +{ + return this->_checked; +} \ No newline at end of file diff --git a/core/src/menu/checkBox/CheckBox.hpp b/core/src/menu/checkBox/CheckBox.hpp new file mode 100644 index 0000000..aee5300 --- /dev/null +++ b/core/src/menu/checkBox/CheckBox.hpp @@ -0,0 +1,63 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** CheckBox +*/ + +#pragma once + +#include +#include +#include "menu/entity/text/Text.hpp" +#include "menu/entity/texture/Texture.hpp" +#include "shared/types/Libraries.hpp" +#include "shared/graphics/events/IKeyEvent.hpp" + +using namespace shared::games; +using namespace shared::graphics; + +class CheckBox { +public: + + CheckBox(const GameManifest manifest, std::shared_ptr graphicsProvider, + Vector2i position, unsigned int fontSize = 10, Vector2u size = {20, 1}); + + /** + * @brief Destructor for CheckBox object + */ + ~CheckBox(); + + /** + * @brief Draw the checkbox + * + * @param window Window to draw on + */ + void draw(std::shared_ptr &window); + + /** + * @brief Check the checkbox + * + */ + void check(); + + /** + * @brief Uncheck the checkbox + * + */ + void uncheck(); + + /** + * @brief Check if the checkbox is checked + * + * @return true if checked + * @return false if not checked + */ + bool isChecked() const; + +private: + const GameManifest _manifest; + std::shared_ptr _name; + std::shared_ptr _checkbox; + bool _checked; +}; diff --git a/core/src/menu/entity/CMakeLists.txt b/core/src/menu/entity/CMakeLists.txt new file mode 100644 index 0000000..c609d44 --- /dev/null +++ b/core/src/menu/entity/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(text) +add_subdirectory(texture) diff --git a/core/src/menu/entity/text/CMakeLists.txt b/core/src/menu/entity/text/CMakeLists.txt new file mode 100644 index 0000000..385ef2d --- /dev/null +++ b/core/src/menu/entity/text/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(arcade PRIVATE + Text.cpp + Text.hpp +) diff --git a/core/src/menu/entity/text/Text.cpp b/core/src/menu/entity/text/Text.cpp new file mode 100644 index 0000000..358dd9a --- /dev/null +++ b/core/src/menu/entity/text/Text.cpp @@ -0,0 +1,32 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Text +*/ + +#include "Text.hpp" + +Text::Text(std::shared_ptr font, unsigned int fontSize, std::string content, + TextAlign align, TextVerticalAlign verticalAlign, Color color, Vector2u size, + Vector2i position) : + font(font), fontSize(fontSize), content(content), align(align), verticalAlign(verticalAlign), + color(color), size(size), position(position) {} + +Text::~Text() {} + +void Text::draw(std::shared_ptr &window) +{ + TextProps textProps = { + .font = this->font, + .fontSize = this->fontSize, + .content = this->content, + .align = this->align, + .verticalAlign = this->verticalAlign, + .color = this->color, + .size = this->size, + .position = this->position + }; + + window->render(textProps); +} diff --git a/core/src/menu/entity/text/Text.hpp b/core/src/menu/entity/text/Text.hpp new file mode 100644 index 0000000..5f8dcc7 --- /dev/null +++ b/core/src/menu/entity/text/Text.hpp @@ -0,0 +1,49 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Text +*/ + +#pragma once + +#include +#include +#include "shared/types/Libraries.hpp" +#include "shared/graphics/events/IKeyEvent.hpp" + +using namespace shared::graphics; + +class Text { +public: + Text(std::shared_ptr font, + unsigned int fontSize, + std::string content, + TextAlign align, + TextVerticalAlign verticalAlign, + Color color, + Vector2u size, + Vector2i position); + + /** + * @brief Destructor for Text object + */ + ~Text(); + + /** + * @brief Draw the checkbox + * + * @param window Window to draw on + */ + void draw(std::shared_ptr &window); + +private: + std::shared_ptr font; + unsigned int fontSize; + std::string content; + TextAlign align; + TextVerticalAlign verticalAlign; + Color color; + Vector2u size; + Vector2i position; +}; diff --git a/core/src/menu/entity/texture/CMakeLists.txt b/core/src/menu/entity/texture/CMakeLists.txt new file mode 100644 index 0000000..074023d --- /dev/null +++ b/core/src/menu/entity/texture/CMakeLists.txt @@ -0,0 +1,4 @@ +target_sources(arcade PRIVATE + Texture.cpp + Texture.hpp +) diff --git a/core/src/menu/entity/texture/Texture.cpp b/core/src/menu/entity/texture/Texture.cpp new file mode 100644 index 0000000..7ade851 --- /dev/null +++ b/core/src/menu/entity/texture/Texture.cpp @@ -0,0 +1,32 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Texture +*/ + +#include "Texture.hpp" + +Texture::Texture(std::shared_ptr texture, Vector2f binTileSize, Vector2u origin, + Vector2u size, Vector2i position) : _texture(texture), _binTileSize(binTileSize), _origin(origin), + _size(size), _position(position) {} + +Texture::~Texture() {} + +void Texture::draw(std::shared_ptr &window) +{ + TextureProps textureProps = { + .texture = this->_texture, + .binTileSize = this->_binTileSize, + .origin = this->_origin, + .size = this->_size, + .position = this->_position + }; + + window->render(textureProps); +} + +void Texture::setOrigin(Vector2u origin) +{ + this->_origin = origin; +} diff --git a/core/src/menu/entity/texture/Texture.hpp b/core/src/menu/entity/texture/Texture.hpp new file mode 100644 index 0000000..03bbe55 --- /dev/null +++ b/core/src/menu/entity/texture/Texture.hpp @@ -0,0 +1,57 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Texture +*/ + +#pragma once + +#include +#include +#include "shared/types/Libraries.hpp" +#include "shared/graphics/events/IKeyEvent.hpp" + +using namespace shared::games; +using namespace shared::graphics; + +class Texture { +public: + + /** + * @brief Construct a new Texture object + * + * @param texture Texture + * @param binTileSize BinTileSize + * @param origin Origin + * @param size Size + */ + Texture(std::shared_ptr texture, Vector2f binTileSize, Vector2u origin, + Vector2u size, Vector2i position); + + /** + * @brief Destructor for Texture object + */ + ~Texture(); + + /** + * @brief Draw the checkbox + * + * @param window Window to draw on + */ + void draw(std::shared_ptr &window); + + /** + * @brief Set the Position object + * + * @param position Position + */ + void setOrigin(Vector2u origin); + +private: + std::shared_ptr _texture; + Vector2f _binTileSize; + Vector2u _origin; + Vector2u _size; + Vector2i _position; +}; diff --git a/core/src/types/CMakeLists.txt b/core/src/types/CMakeLists.txt index 3904d4b..98b5ffd 100644 --- a/core/src/types/CMakeLists.txt +++ b/core/src/types/CMakeLists.txt @@ -1,3 +1,4 @@ target_sources(arcade PRIVATE Providers.hpp + Stages.hpp ) diff --git a/core/src/types/Stages.hpp b/core/src/types/Stages.hpp new file mode 100644 index 0000000..ab109a4 --- /dev/null +++ b/core/src/types/Stages.hpp @@ -0,0 +1,19 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Stages +*/ + +#pragma once + +namespace arcade::core { + typedef enum { + MENU, + PAUSE, + RESUME, + PLAY, + NEWGAME, + EXIT, + } SceneStage; +} From 9e01923d77c1998e4592de652d4d0d353c08304b Mon Sep 17 00:00:00 2001 From: Yann Date: Thu, 4 Apr 2024 17:10:20 +0200 Subject: [PATCH 02/18] feat(core): add 3 tristate on checkbox --- assets/menu/img/yellow.ascii | 0 assets/menu/img/yellow.png | Bin 0 -> 1220 bytes core/src/menu/Menu.cpp | 100 ++++++++++++++++++---------- core/src/menu/Menu.hpp | 16 ++++- core/src/menu/checkBox/CheckBox.cpp | 29 ++++++-- core/src/menu/checkBox/CheckBox.hpp | 25 ++++++- core/src/menu/entity/text/Text.cpp | 25 ++++--- core/src/menu/entity/text/Text.hpp | 23 ++++--- 8 files changed, 154 insertions(+), 64 deletions(-) create mode 100644 assets/menu/img/yellow.ascii create mode 100644 assets/menu/img/yellow.png diff --git a/assets/menu/img/yellow.ascii b/assets/menu/img/yellow.ascii new file mode 100644 index 0000000..e69de29 diff --git a/assets/menu/img/yellow.png b/assets/menu/img/yellow.png new file mode 100644 index 0000000000000000000000000000000000000000..636139eba0b48306bc3b29060247311e99fe9bfe GIT binary patch literal 1220 zcmeAS@N?(olHy`uVBq!ia0vp^DImc}*5j~)MBDvkQ@gfU+;BXi=q$>9FhcbFqPMqNnQ7 zn7UA&eM%0-Jr-&yY1f{sX!4%_SjsPd|9z6p>D}+n3x;v4G1n*+HeKcIu4t}EyS%FS zo_gPgO>2ba3;RozI6iV;r>(cYP|s55!bS?x)r{ zr?sBzo{QRg(CYgWeIC&-Q&ZPnmU89lj%Z>LplZ}`+kY%{ zvj_Z*w^xcV89Fdj{Nq+GY;Hf0y4|XkiU0BbnX`9#Z%uzHce3B$+vn!R`t4kglVAFj zS#WXcFJU&7?#}2JQp@j(VGaGroDJQvG$@ z)>G}1$Lzc62ItzZyzbGi7E%S9{QkHsJ+;K`nul2T z-rB$MJWtx|?`r4QiZa=|9r0o25j}RCAxh%)^&>A5J_gSFC4b#AE}B_m&hMHnf1i4> z@Gvd8T&v9RXLDr9M!nK2w|?z^o2bEL#1JTw8uj1ec$}NLK5K_iXU=a`>7A!;dI>oC zpdeuv0R%e2B8Y?x9a)eNb+kRvX}ZENt8nqPD$jS8-qX2O8aZsfxnfJamf!~Nfc2r< z7(9B`>OWqh=+O48KZ<3Z6<2LX2 zX1C(&_|HH8smS-o=Rv}!OT9(;`FV$q?h0S~>*3i~tCuoO$Y$He*Drth^8b122Sl0J znSY*-6KOkk{L;*Q4>cy9u)6s_e)Gi@a&lp2-b>4+>!)sC)+n>V!u0rBh7CsN3pi{T z)>&O&xkVy;hjH=rEQ`v__*1$MsuQGshgNZ2Htk)qDLuPh Q1Cuv{r>mdKI;Vst0HVAS=Kufz literal 0 HcmV?d00001 diff --git a/core/src/menu/Menu.cpp b/core/src/menu/Menu.cpp index 288d27f..91dafb2 100644 --- a/core/src/menu/Menu.cpp +++ b/core/src/menu/Menu.cpp @@ -17,24 +17,23 @@ Menu::~Menu() {} void Menu::_initCheckBoxes() { - if (!this->_graphicsProvider) { - if (this->_graphicsProviders.empty()) { - throw std::runtime_error("No graphics provider found"); - } - this->_graphicsProvider = this->_graphicsProviders.at(0); - std::cout << "No graphics provider found, using default provider" << std::endl; - } int index = 8; - this->_checkBoxes.clear(); + this->_gamesCheckBoxes.clear(); for (auto gameProvider : this->_gameProviders) { std::cout << "Game: " << gameProvider->getManifest().name << std::endl; - auto checkBox = std::make_shared(gameProvider->getManifest(), this->_graphicsProvider, Vector2i{15, index}); - this->_checkBoxes.push_back(checkBox); + auto checkBox = std::make_shared(gameProvider->getManifest().name, this->_graphicsProvider, Vector2i{15, index}); + this->_gamesCheckBoxes.push_back(checkBox); index += 2; } } +void Menu::_initTextures() +{ + auto texture = this->_graphicsProvider->createTexture("assets/menu/img/yellow.png", "assets/menu/img/yellow.ascii"); + this->_textures.push_back(std::make_shared(texture, Vector2f{1, 1}, Vector2u{5, 5}, Vector2u{50, 20}, Vector2i{0, 0})); +} + void Menu::_initWindow() { IWindow::WindowInitProps windowInitProps { @@ -45,21 +44,27 @@ void Menu::_initWindow() .icon = "assets/menu/img/icon.png" }; + if (!this->_graphicsProvider) { + if (this->_graphicsProviders.empty()) + throw std::runtime_error("No graphics provider found"); + this->_graphicsProvider = this->_graphicsProviders.at(0); + std::cout << "No graphics provider found, using default provider" << std::endl; + } + this->_initTextures(); this->_initCheckBoxes(); this->_window = this->_graphicsProvider->createWindow(windowInitProps); } void Menu::_handleSelectUpperCheckBox() { - for (auto checkBox : this->_checkBoxes) { - if (checkBox->isChecked()) { - checkBox->uncheck(); - auto index = std::distance(this->_checkBoxes.begin(), std::find(this->_checkBoxes.begin(), this->_checkBoxes.end(), checkBox)); - if (index == 0) { - this->_checkBoxes.at(this->_checkBoxes.size() - 1)->check(); - break; - } - this->_checkBoxes.at(index - 1)->check(); + for (auto checkBox : this->_gamesCheckBoxes) { + if (checkBox->isHovered()) { + checkBox->unhover(); + auto index = std::distance(this->_gamesCheckBoxes.begin(), std::find(this->_gamesCheckBoxes.begin(), this->_gamesCheckBoxes.end(), checkBox)); + if (index == 0) + this->_gamesCheckBoxes.at(this->_gamesCheckBoxes.size() - 1)->hover(); + else + this->_gamesCheckBoxes.at(index - 1)->hover(); break; } } @@ -67,15 +72,14 @@ void Menu::_handleSelectUpperCheckBox() void Menu::_handleSelectLowerCheckBox() { - for (auto checkBox : this->_checkBoxes) { - if (checkBox->isChecked()) { - checkBox->uncheck(); - auto index = std::distance(this->_checkBoxes.begin(), std::find(this->_checkBoxes.begin(), this->_checkBoxes.end(), checkBox)); - if (index == this->_checkBoxes.size() - 1) { - this->_checkBoxes.at(0)->check(); - break; - } - this->_checkBoxes.at(index + 1)->check(); + for (auto checkBox : this->_gamesCheckBoxes) { + if (checkBox->isHovered()) { + checkBox->unhover(); + auto index = std::distance(this->_gamesCheckBoxes.begin(), std::find(this->_gamesCheckBoxes.begin(), this->_gamesCheckBoxes.end(), checkBox)); + if (index == this->_gamesCheckBoxes.size() - 1) + this->_gamesCheckBoxes.at(0)->hover(); + else + this->_gamesCheckBoxes.at(index + 1)->hover(); break; } } @@ -83,6 +87,8 @@ void Menu::_handleSelectLowerCheckBox() void Menu::_handleKeyboardEvents(std::shared_ptr key) { + if (!key) + return; auto type = key->getKeyType(); auto code = key->getKeyCode(); @@ -94,12 +100,23 @@ void Menu::_handleKeyboardEvents(std::shared_ptr key) } if (type == events::IKeyEvent::KeyType::CHAR) { if (code.character == '\n') - this->_exitWithNewGame(); + this->_selectGame(); if (code.character == 27) this->_exitAndPlayOldGame(); } } +void Menu::_selectGame() +{ + for (auto checkBox : this->_gamesCheckBoxes) { + if (checkBox->isHovered()) { + checkBox->check(); + } else { + checkBox->uncheck(); + } + } +} + void Menu::_exitAndPlayOldGame() { this->_sceneStage = RESUME; @@ -108,9 +125,9 @@ void Menu::_exitAndPlayOldGame() void Menu::_exitWithNewGame() { - for (auto checkBox : this->_checkBoxes) { + for (auto checkBox : this->_gamesCheckBoxes) { if (checkBox->isChecked()) { - this->_gameProvider = this->_gameProviders.at(std::distance(this->_checkBoxes.begin(), std::find(this->_checkBoxes.begin(), this->_checkBoxes.end(), checkBox))); + this->_gameProvider = this->_gameProviders.at(std::distance(this->_gamesCheckBoxes.begin(), std::find(this->_gamesCheckBoxes.begin(), this->_gamesCheckBoxes.end(), checkBox))); break; } } @@ -133,17 +150,26 @@ void Menu::_handleEvents() } } +void Menu::_render() +{ + this->_window->clear(); + for (auto texture : this->_textures) { + texture->draw(this->_window); + } + for (auto checkBox : this->_gamesCheckBoxes) { + checkBox->draw(this->_window); + } + this->_window->display(); +} + void Menu::run() { this->_sceneStage = MENU; this->_initWindow(); - this->_checkBoxes.at(0)->check(); + this->_gamesCheckBoxes.at(0)->check(); + this->_gamesCheckBoxes.at(0)->hover(); while (this->_window->isOpen()) { this->_handleEvents(); - this->_window->clear(); - for (auto checkBox : this->_checkBoxes) { - checkBox->draw(this->_window); - } - this->_window->display(); + this->_render(); } } diff --git a/core/src/menu/Menu.hpp b/core/src/menu/Menu.hpp index 1b41bcd..3dc8e4a 100644 --- a/core/src/menu/Menu.hpp +++ b/core/src/menu/Menu.hpp @@ -43,7 +43,9 @@ class Menu { GraphicsProviders &_graphicsProviders; std::shared_ptr &_gameProvider; std::shared_ptr &_graphicsProvider; - std::vector> _checkBoxes; + std::vector> _gamesCheckBoxes; + std::vector> _graphicsCheckBoxes; + std::shared_ptr _startGameCheckBox; std::vector> _texts; std::vector> _textures; @@ -53,6 +55,12 @@ class Menu { */ void _initWindow(); + /** + * @brief Render the menu + * + */ + void _render(); + /** * @brief Handle events * @@ -78,6 +86,12 @@ class Menu { */ void _handleSelectLowerCheckBox(); + /** + * @brief Select the hovered game + * + */ + void _selectGame(); + /** * @brief Exit the menu * diff --git a/core/src/menu/checkBox/CheckBox.cpp b/core/src/menu/checkBox/CheckBox.cpp index 0c94492..89cb5c3 100644 --- a/core/src/menu/checkBox/CheckBox.cpp +++ b/core/src/menu/checkBox/CheckBox.cpp @@ -7,16 +7,16 @@ #include "CheckBox.hpp" -CheckBox::CheckBox(const GameManifest manifest, std::shared_ptr graphicsProvider, - Vector2i position, unsigned int fontSize, Vector2u size) : - _manifest(manifest) +CheckBox::CheckBox(const std::string &name, std::shared_ptr graphicsProvider, + Vector2i position, unsigned int fontSize, Vector2u size) { auto font = graphicsProvider->createFont("assets/menu/fonts/kenvector_future_thin.ttf"); auto texture = graphicsProvider->createTexture("assets/menu/img/checkBox.png", "assets/menu/img/checkBox.ascii"); this->_checked = false; - this->_name = std::make_shared(font, fontSize, _manifest.name, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{size.x - 1, size.y}, Vector2i{position.x + 2, position.y}); - this->_checkbox = std::make_shared(texture, Vector2f{36, 38}, Vector2u{0, 0}, Vector2u{1, 1}, position); + this->_hovered = false; + this->_name = std::make_shared(font, fontSize, name, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{0, 0, 0, 255}, Vector2u{size.x - 1, size.y}, Vector2i{position.x + 2, position.y}); + this->_checkbox = std::make_shared(texture, Vector2f{38, 36}, Vector2u{0, 0}, Vector2u{1, 1}, position); } CheckBox::~CheckBox() {} @@ -27,6 +27,10 @@ void CheckBox::draw(std::shared_ptr &window) this->_checkbox->setOrigin({1, 0}); else this->_checkbox->setOrigin({0, 0}); + if (this->_hovered) + this->_name->setColor(Color{53, 186, 243, 255}); + else + this->_name->setColor(Color{0, 0, 0, 255}); this->_checkbox->draw(window); this->_name->draw(window); } @@ -44,4 +48,19 @@ void CheckBox::uncheck() bool CheckBox::isChecked() const { return this->_checked; +} + +void CheckBox::hover() +{ + this->_hovered = true; +} + +void CheckBox::unhover() +{ + this->_hovered = false; +} + +bool CheckBox::isHovered() const +{ + return this->_hovered; } \ No newline at end of file diff --git a/core/src/menu/checkBox/CheckBox.hpp b/core/src/menu/checkBox/CheckBox.hpp index aee5300..8f70638 100644 --- a/core/src/menu/checkBox/CheckBox.hpp +++ b/core/src/menu/checkBox/CheckBox.hpp @@ -14,13 +14,12 @@ #include "shared/types/Libraries.hpp" #include "shared/graphics/events/IKeyEvent.hpp" -using namespace shared::games; using namespace shared::graphics; class CheckBox { public: - CheckBox(const GameManifest manifest, std::shared_ptr graphicsProvider, + CheckBox(const std::string &name, std::shared_ptr graphicsProvider, Vector2i position, unsigned int fontSize = 10, Vector2u size = {20, 1}); /** @@ -55,9 +54,29 @@ class CheckBox { */ bool isChecked() const; + /** + * @brief Hover the checkbox + * + */ + void hover(); + + /** + * @brief Unhover the checkbox + * + */ + void unhover(); + + /** + * @brief Check if the checkbox is hovered + * + * @return true if hovered + * @return false if not hovered + */ + bool isHovered() const; + private: - const GameManifest _manifest; std::shared_ptr _name; std::shared_ptr _checkbox; bool _checked; + bool _hovered; }; diff --git a/core/src/menu/entity/text/Text.cpp b/core/src/menu/entity/text/Text.cpp index 358dd9a..5ee385c 100644 --- a/core/src/menu/entity/text/Text.cpp +++ b/core/src/menu/entity/text/Text.cpp @@ -10,23 +10,28 @@ Text::Text(std::shared_ptr font, unsigned int fontSize, std::string content, TextAlign align, TextVerticalAlign verticalAlign, Color color, Vector2u size, Vector2i position) : - font(font), fontSize(fontSize), content(content), align(align), verticalAlign(verticalAlign), - color(color), size(size), position(position) {} + _font(font), _fontSize(fontSize), _content(content), _align(align), _verticalAlign(verticalAlign), + _color(color), _size(size), _position(position) {} Text::~Text() {} void Text::draw(std::shared_ptr &window) { TextProps textProps = { - .font = this->font, - .fontSize = this->fontSize, - .content = this->content, - .align = this->align, - .verticalAlign = this->verticalAlign, - .color = this->color, - .size = this->size, - .position = this->position + .font = this->_font, + .fontSize = this->_fontSize, + .content = this->_content, + .align = this->_align, + .verticalAlign = this->_verticalAlign, + .color = this->_color, + .size = this->_size, + .position = this->_position }; window->render(textProps); } + +void Text::setColor(Color color) +{ + this->_color = color; +} diff --git a/core/src/menu/entity/text/Text.hpp b/core/src/menu/entity/text/Text.hpp index 5f8dcc7..e8542be 100644 --- a/core/src/menu/entity/text/Text.hpp +++ b/core/src/menu/entity/text/Text.hpp @@ -37,13 +37,20 @@ class Text { */ void draw(std::shared_ptr &window); + /** + * @brief Set the Color object + * + * @param color + */ + void setColor(Color color); + private: - std::shared_ptr font; - unsigned int fontSize; - std::string content; - TextAlign align; - TextVerticalAlign verticalAlign; - Color color; - Vector2u size; - Vector2i position; + std::shared_ptr _font; + unsigned int _fontSize; + std::string _content; + TextAlign _align; + TextVerticalAlign _verticalAlign; + Color _color; + Vector2u _size; + Vector2i _position; }; From 5630667703a2f1bb913a57ff372f8c70f2d76963 Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 5 Apr 2024 02:18:34 +0200 Subject: [PATCH 03/18] refactor(core): refactor menu --- assets/menu/fonts/arcade.ttf | Bin 0 -> 26500 bytes .../img/{yellow.ascii => background.ascii} | 0 assets/menu/img/background.png | Bin 0 -> 11820 bytes assets/menu/img/checkBox.ascii | 1 - assets/menu/img/checkBox.png | Bin 648 -> 0 bytes assets/menu/img/middle.ascii | 17 +++ assets/menu/img/middle.png | Bin 0 -> 229 bytes assets/menu/img/space-invader.ascii | 1 + assets/menu/img/space-invader.png | Bin 0 -> 6216 bytes assets/menu/img/title.ascii | 4 + assets/menu/img/title.png | Bin 0 -> 15485 bytes assets/menu/img/yellow.png | Bin 1220 -> 0 bytes core/src/menu/Menu.cpp | 122 ++++++++++++++++-- core/src/menu/Menu.hpp | 23 +++- core/src/menu/checkBox/CheckBox.cpp | 28 +--- core/src/menu/checkBox/CheckBox.hpp | 22 ++-- core/src/menu/entity/text/Text.cpp | 2 +- core/src/menu/entity/text/Text.hpp | 2 +- core/src/menu/entity/texture/Texture.cpp | 2 +- core/src/menu/entity/texture/Texture.hpp | 2 +- 20 files changed, 173 insertions(+), 53 deletions(-) create mode 100644 assets/menu/fonts/arcade.ttf rename assets/menu/img/{yellow.ascii => background.ascii} (100%) create mode 100644 assets/menu/img/background.png delete mode 100644 assets/menu/img/checkBox.ascii delete mode 100644 assets/menu/img/checkBox.png create mode 100644 assets/menu/img/middle.ascii create mode 100644 assets/menu/img/middle.png create mode 100644 assets/menu/img/space-invader.ascii create mode 100644 assets/menu/img/space-invader.png create mode 100644 assets/menu/img/title.ascii create mode 100644 assets/menu/img/title.png delete mode 100644 assets/menu/img/yellow.png diff --git a/assets/menu/fonts/arcade.ttf b/assets/menu/fonts/arcade.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4730e445880b94d8fe957bc1b8d3aee574c8965c GIT binary patch literal 26500 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 DYCMz1 literal 0 HcmV?d00001 diff --git a/assets/menu/img/yellow.png b/assets/menu/img/yellow.png deleted file mode 100644 index 636139eba0b48306bc3b29060247311e99fe9bfe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1220 zcmeAS@N?(olHy`uVBq!ia0vp^DImc}*5j~)MBDvkQ@gfU+;BXi=q$>9FhcbFqPMqNnQ7 zn7UA&eM%0-Jr-&yY1f{sX!4%_SjsPd|9z6p>D}+n3x;v4G1n*+HeKcIu4t}EyS%FS zo_gPgO>2ba3;RozI6iV;r>(cYP|s55!bS?x)r{ zr?sBzo{QRg(CYgWeIC&-Q&ZPnmU89lj%Z>LplZ}`+kY%{ zvj_Z*w^xcV89Fdj{Nq+GY;Hf0y4|XkiU0BbnX`9#Z%uzHce3B$+vn!R`t4kglVAFj zS#WXcFJU&7?#}2JQp@j(VGaGroDJQvG$@ z)>G}1$Lzc62ItzZyzbGi7E%S9{QkHsJ+;K`nul2T z-rB$MJWtx|?`r4QiZa=|9r0o25j}RCAxh%)^&>A5J_gSFC4b#AE}B_m&hMHnf1i4> z@Gvd8T&v9RXLDr9M!nK2w|?z^o2bEL#1JTw8uj1ec$}NLK5K_iXU=a`>7A!;dI>oC zpdeuv0R%e2B8Y?x9a)eNb+kRvX}ZENt8nqPD$jS8-qX2O8aZsfxnfJamf!~Nfc2r< z7(9B`>OWqh=+O48KZ<3Z6<2LX2 zX1C(&_|HH8smS-o=Rv}!OT9(;`FV$q?h0S~>*3i~tCuoO$Y$He*Drth^8b122Sl0J znSY*-6KOkk{L;*Q4>cy9u)6s_e)Gi@a&lp2-b>4+>!)sC)+n>V!u0rBh7CsN3pi{T z)>&O&xkVy;hjH=rEQ`v__*1$MsuQGshgNZ2Htk)qDLuPh Q1Cuv{r>mdKI;Vst0HVAS=Kufz diff --git a/core/src/menu/Menu.cpp b/core/src/menu/Menu.cpp index 91dafb2..fe432ae 100644 --- a/core/src/menu/Menu.cpp +++ b/core/src/menu/Menu.cpp @@ -15,41 +15,115 @@ Menu::Menu(GameProviders &gameProviders, GraphicsProviders &graphicsProviders, Menu::~Menu() {} +void Menu::_initHiddenTextures(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) +{ + int score = 154; + auto nameSize = 20 - static_cast(gameManifest.name.size()); + std::string truncatName = gameManifest.name.substr(0, 17); + + if (nameSize < 0) + truncatName += "..."; + else + truncatName = gameManifest.name; + auto nameText = std::make_shared(font, 10, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2i{25, 8}); + this->_hiddenTexts[checkBox].push_back(nameText); + auto scoreString = std::to_string(score); + + auto descSize = 23 - static_cast(gameManifest.description.size()); + std::string truncatDesc = gameManifest.description.substr(0, 17); + + if (nameSize < 0) + truncatDesc += "..."; + else + truncatDesc = gameManifest.description; + auto descriptionText = std::make_shared(font, 10, truncatDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2i{25, 10}); + this->_hiddenTexts[checkBox].push_back(descriptionText); + + while (scoreString.length() < 5) + scoreString = "0" + scoreString; + auto scoreText = std::make_shared(font, 10, scoreString, TextAlign::RIGHT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{14, 1}, Vector2i{34, 12}); + this->_hiddenTexts[checkBox].push_back(scoreText); + + auto authors = gameManifest.authors; + int index = 15; + for (auto author : authors) { + auto authorNameText = std::make_shared(font, 7, author.name, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2i{27, index}); + auto authorMailText = std::make_shared(font, 7, author.email, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2i{27, index + 1}); + auto authorSiteText = std::make_shared(font, 7, author.website, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2i{27, index + 2}); + this->_hiddenTexts[checkBox].push_back(authorNameText); + this->_hiddenTexts[checkBox].push_back(authorMailText); + this->_hiddenTexts[checkBox].push_back(authorSiteText); + index += 4; + } +} + void Menu::_initCheckBoxes() { + auto texture = this->_graphicsProvider->createTexture("assets/menu/img/space-invader.png", "assets/menu/img/space-invader.ascii"); + auto font = this->_graphicsProvider->createFont("assets/menu/fonts/arcade.ttf"); int index = 8; - this->_gamesCheckBoxes.clear(); for (auto gameProvider : this->_gameProviders) { - std::cout << "Game: " << gameProvider->getManifest().name << std::endl; - auto checkBox = std::make_shared(gameProvider->getManifest().name, this->_graphicsProvider, Vector2i{15, index}); + auto marginRight = 20 - static_cast(gameProvider->getManifest().name.size()); + std::string truncatedName = gameProvider->getManifest().name.substr(0, 17); + if (marginRight < 0) { + truncatedName += "..."; + marginRight = 0; + } else { + truncatedName = gameProvider->getManifest().name; + } + auto textCheckBox = std::make_shared(font, 10, truncatedName, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{20, 1}, Vector2i{3 + marginRight, index}); + auto textureCheckBox = std::make_shared(texture, Vector2f{360, 360}, Vector2u{0, 0}, Vector2u{1, 1}, Vector2i{1 + marginRight, index}); + auto checkBox = std::make_shared(textureCheckBox, textCheckBox); + this->_texts.push_back(textCheckBox); + this->_textures.push_back(textureCheckBox); this->_gamesCheckBoxes.push_back(checkBox); + this->_initHiddenTextures(gameProvider->getManifest(), checkBox, font); index += 2; } } void Menu::_initTextures() { - auto texture = this->_graphicsProvider->createTexture("assets/menu/img/yellow.png", "assets/menu/img/yellow.ascii"); - this->_textures.push_back(std::make_shared(texture, Vector2f{1, 1}, Vector2u{5, 5}, Vector2u{50, 20}, Vector2i{0, 0})); + auto backgroundTexture = this->_graphicsProvider->createTexture("assets/menu/img/background.png", "assets/menu/img/background.ascii"); + this->_textures.push_back(std::make_shared(backgroundTexture, Vector2f{12, 12}, Vector2u{0, 0}, Vector2u{50, 25}, Vector2i{0, 0})); + auto titleTexture = this->_graphicsProvider->createTexture("assets/menu/img/title.png", "assets/menu/img/title.ascii"); + this->_textures.push_back(std::make_shared(titleTexture, Vector2f{17, 17}, Vector2u{0, 0}, Vector2u{31, 5}, Vector2i{10, 1})); + auto middleTexture = this->_graphicsProvider->createTexture("assets/menu/img/middle.png", "assets/menu/img/middle.ascii"); + this->_textures.push_back(std::make_shared(middleTexture, Vector2f{12, 12}, Vector2u{0, 0}, Vector2u{1, 17}, Vector2i{24, 7})); +} + +void Menu::_initTexts() +{ + auto font = this->_graphicsProvider->createFont("assets/menu/fonts/arcade.ttf"); + + auto score = std::make_shared(font, 10, "HI-SCORE", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2i{26, 12}); + this->_texts.push_back(score); + + auto authors = std::make_shared(font, 8, "Authors:", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2i{26, 14}); + this->_texts.push_back(authors); } void Menu::_initWindow() { IWindow::WindowInitProps windowInitProps { - .size = {50, 20}, + .size = {50, 25}, .mode = IWindow::WindowMode::WINDOWED, .fps = 60, .title = "Menu", .icon = "assets/menu/img/icon.png" }; + this->_texts.clear(); + this->_textures.clear(); + this->_gamesCheckBoxes.clear(); if (!this->_graphicsProvider) { if (this->_graphicsProviders.empty()) throw std::runtime_error("No graphics provider found"); this->_graphicsProvider = this->_graphicsProviders.at(0); std::cout << "No graphics provider found, using default provider" << std::endl; } + this->_initTexts(); this->_initTextures(); this->_initCheckBoxes(); this->_window = this->_graphicsProvider->createWindow(windowInitProps); @@ -109,11 +183,12 @@ void Menu::_handleKeyboardEvents(std::shared_ptr key) void Menu::_selectGame() { for (auto checkBox : this->_gamesCheckBoxes) { - if (checkBox->isHovered()) { + if (checkBox->isHovered() && checkBox->isChecked()) + this->_exitWithNewGame(); + if (checkBox->isHovered()) checkBox->check(); - } else { + else checkBox->uncheck(); - } } } @@ -156,18 +231,41 @@ void Menu::_render() for (auto texture : this->_textures) { texture->draw(this->_window); } + for (auto text : this->_texts) { + text->draw(this->_window); + } for (auto checkBox : this->_gamesCheckBoxes) { - checkBox->draw(this->_window); + if (checkBox->isHovered()) { + for (auto text : this->_hiddenTexts[checkBox]) { + text->draw(this->_window); + } + } } this->_window->display(); } +void Menu::_previousSelectedGame() +{ + for (auto gameProvider : this->_gameProviders) { + if (this->_gameProvider == gameProvider) { + auto index = std::distance(this->_gameProviders.begin(), std::find(this->_gameProviders.begin(), this->_gameProviders.end(), gameProvider)); + auto checkBox = this->_gamesCheckBoxes.at(index); + checkBox->check(); + checkBox->hover(); + return; + } + } + if (this->_gamesCheckBoxes.empty()) + throw std::runtime_error("No games found"); + this->_gamesCheckBoxes.at(0)->check(); + this->_gamesCheckBoxes.at(0)->hover(); +} + void Menu::run() { this->_sceneStage = MENU; this->_initWindow(); - this->_gamesCheckBoxes.at(0)->check(); - this->_gamesCheckBoxes.at(0)->hover(); + this->_previousSelectedGame(); while (this->_window->isOpen()) { this->_handleEvents(); this->_render(); diff --git a/core/src/menu/Menu.hpp b/core/src/menu/Menu.hpp index 3dc8e4a..306079d 100644 --- a/core/src/menu/Menu.hpp +++ b/core/src/menu/Menu.hpp @@ -44,10 +44,9 @@ class Menu { std::shared_ptr &_gameProvider; std::shared_ptr &_graphicsProvider; std::vector> _gamesCheckBoxes; - std::vector> _graphicsCheckBoxes; - std::shared_ptr _startGameCheckBox; std::vector> _texts; std::vector> _textures; + std::map, std::vector>> _hiddenTexts; /** * @brief Initialize the window @@ -115,4 +114,24 @@ class Menu { * */ void _initTextures(); + + /** + * @brief Initialize hidden textures + * + * @param gameManifest GameManifest + * @param checkBox CheckBox + */ + void _initHiddenTextures(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font); + + /** + * @brief Initialize texts + * + */ + void _initTexts(); + + /** + * @brief Define the previous selected game + * + */ + void _previousSelectedGame(); }; diff --git a/core/src/menu/checkBox/CheckBox.cpp b/core/src/menu/checkBox/CheckBox.cpp index 89cb5c3..69618e8 100644 --- a/core/src/menu/checkBox/CheckBox.cpp +++ b/core/src/menu/checkBox/CheckBox.cpp @@ -7,42 +7,26 @@ #include "CheckBox.hpp" -CheckBox::CheckBox(const std::string &name, std::shared_ptr graphicsProvider, - Vector2i position, unsigned int fontSize, Vector2u size) +CheckBox::CheckBox(std::shared_ptr texture, std::shared_ptr text) : + _texture(texture), _text(text) { - auto font = graphicsProvider->createFont("assets/menu/fonts/kenvector_future_thin.ttf"); - auto texture = graphicsProvider->createTexture("assets/menu/img/checkBox.png", "assets/menu/img/checkBox.ascii"); - this->_checked = false; this->_hovered = false; - this->_name = std::make_shared(font, fontSize, name, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{0, 0, 0, 255}, Vector2u{size.x - 1, size.y}, Vector2i{position.x + 2, position.y}); - this->_checkbox = std::make_shared(texture, Vector2f{38, 36}, Vector2u{0, 0}, Vector2u{1, 1}, position); + this->_texture->setOrigin({1, 0}); } CheckBox::~CheckBox() {} -void CheckBox::draw(std::shared_ptr &window) -{ - if (this->_checked) - this->_checkbox->setOrigin({1, 0}); - else - this->_checkbox->setOrigin({0, 0}); - if (this->_hovered) - this->_name->setColor(Color{53, 186, 243, 255}); - else - this->_name->setColor(Color{0, 0, 0, 255}); - this->_checkbox->draw(window); - this->_name->draw(window); -} - void CheckBox::check() { this->_checked = true; + this->_texture->setOrigin({0, 0}); } void CheckBox::uncheck() { this->_checked = false; + this->_texture->setOrigin({1, 0}); } bool CheckBox::isChecked() const @@ -53,11 +37,13 @@ bool CheckBox::isChecked() const void CheckBox::hover() { this->_hovered = true; + this->_text->setColor(Color{53, 186, 243, 255}); } void CheckBox::unhover() { this->_hovered = false; + this->_text->setColor(Color{255, 255, 255, 255}); } bool CheckBox::isHovered() const diff --git a/core/src/menu/checkBox/CheckBox.hpp b/core/src/menu/checkBox/CheckBox.hpp index 8f70638..fdcc72e 100644 --- a/core/src/menu/checkBox/CheckBox.hpp +++ b/core/src/menu/checkBox/CheckBox.hpp @@ -14,25 +14,21 @@ #include "shared/types/Libraries.hpp" #include "shared/graphics/events/IKeyEvent.hpp" -using namespace shared::graphics; - class CheckBox { public: - CheckBox(const std::string &name, std::shared_ptr graphicsProvider, - Vector2i position, unsigned int fontSize = 10, Vector2u size = {20, 1}); - /** - * @brief Destructor for CheckBox object + * @brief Construct a new CheckBox object + * + * @param texture + * @param text */ - ~CheckBox(); + CheckBox(std::shared_ptr texture, std::shared_ptr text); /** - * @brief Draw the checkbox - * - * @param window Window to draw on + * @brief Destructor for CheckBox object */ - void draw(std::shared_ptr &window); + ~CheckBox(); /** * @brief Check the checkbox @@ -75,8 +71,8 @@ class CheckBox { bool isHovered() const; private: - std::shared_ptr _name; - std::shared_ptr _checkbox; bool _checked; bool _hovered; + std::shared_ptr _text; + std::shared_ptr _texture; }; diff --git a/core/src/menu/entity/text/Text.cpp b/core/src/menu/entity/text/Text.cpp index 5ee385c..d959e69 100644 --- a/core/src/menu/entity/text/Text.cpp +++ b/core/src/menu/entity/text/Text.cpp @@ -15,7 +15,7 @@ Text::Text(std::shared_ptr font, unsigned int fontSize, std::string conte Text::~Text() {} -void Text::draw(std::shared_ptr &window) +void Text::draw(std::shared_ptr window) { TextProps textProps = { .font = this->_font, diff --git a/core/src/menu/entity/text/Text.hpp b/core/src/menu/entity/text/Text.hpp index e8542be..10d074f 100644 --- a/core/src/menu/entity/text/Text.hpp +++ b/core/src/menu/entity/text/Text.hpp @@ -35,7 +35,7 @@ class Text { * * @param window Window to draw on */ - void draw(std::shared_ptr &window); + void draw(std::shared_ptr window); /** * @brief Set the Color object diff --git a/core/src/menu/entity/texture/Texture.cpp b/core/src/menu/entity/texture/Texture.cpp index 7ade851..2c8fe2b 100644 --- a/core/src/menu/entity/texture/Texture.cpp +++ b/core/src/menu/entity/texture/Texture.cpp @@ -13,7 +13,7 @@ Texture::Texture(std::shared_ptr texture, Vector2f binTileSize, Vector Texture::~Texture() {} -void Texture::draw(std::shared_ptr &window) +void Texture::draw(std::shared_ptr window) { TextureProps textureProps = { .texture = this->_texture, diff --git a/core/src/menu/entity/texture/Texture.hpp b/core/src/menu/entity/texture/Texture.hpp index 03bbe55..a914ac7 100644 --- a/core/src/menu/entity/texture/Texture.hpp +++ b/core/src/menu/entity/texture/Texture.hpp @@ -39,7 +39,7 @@ class Texture { * * @param window Window to draw on */ - void draw(std::shared_ptr &window); + void draw(std::shared_ptr window); /** * @brief Set the Position object From 00c86c513f0b85ca2b34de1afac9b0b831a0473f Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 5 Apr 2024 02:53:05 +0200 Subject: [PATCH 04/18] refactor(core): refactor menu --- core/src/menu/Menu.cpp | 49 +++++++++++++++++++++--------------------- core/src/menu/Menu.hpp | 3 +++ 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/core/src/menu/Menu.cpp b/core/src/menu/Menu.cpp index fe432ae..27c9de5 100644 --- a/core/src/menu/Menu.cpp +++ b/core/src/menu/Menu.cpp @@ -15,30 +15,30 @@ Menu::Menu(GameProviders &gameProviders, GraphicsProviders &graphicsProviders, Menu::~Menu() {} -void Menu::_initHiddenTextures(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) +std::string Menu::_truncString(const std::string &str, int size) { - int score = 154; - auto nameSize = 20 - static_cast(gameManifest.name.size()); - std::string truncatName = gameManifest.name.substr(0, 17); + auto strPadding = size - static_cast(str.size()); + std::string newString = str.substr(0, size - 3); - if (nameSize < 0) - truncatName += "..."; + if (strPadding < 0) + newString += "..."; else - truncatName = gameManifest.name; - auto nameText = std::make_shared(font, 10, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2i{25, 8}); - this->_hiddenTexts[checkBox].push_back(nameText); - auto scoreString = std::to_string(score); + newString = str; + return newString; +} - auto descSize = 23 - static_cast(gameManifest.description.size()); - std::string truncatDesc = gameManifest.description.substr(0, 17); +void Menu::_initHiddenTextures(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) +{ + auto truncatName = this->_truncString(gameManifest.name, 23); + auto nameText = std::make_shared(font, 11, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2i{25, 8}); + this->_hiddenTexts[checkBox].push_back(nameText); - if (nameSize < 0) - truncatDesc += "..."; - else - truncatDesc = gameManifest.description; - auto descriptionText = std::make_shared(font, 10, truncatDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2i{25, 10}); + std::string truncatDesc = this->_truncString(gameManifest.description, 23); + auto descriptionText = std::make_shared(font, 9, truncatDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2i{25, 10}); this->_hiddenTexts[checkBox].push_back(descriptionText); + int score = 154; + auto scoreString = std::to_string(score); while (scoreString.length() < 5) scoreString = "0" + scoreString; auto scoreText = std::make_shared(font, 10, scoreString, TextAlign::RIGHT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{14, 1}, Vector2i{34, 12}); @@ -47,9 +47,9 @@ void Menu::_initHiddenTextures(const GameManifest &gameManifest, std::shared_ptr auto authors = gameManifest.authors; int index = 15; for (auto author : authors) { - auto authorNameText = std::make_shared(font, 7, author.name, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2i{27, index}); - auto authorMailText = std::make_shared(font, 7, author.email, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2i{27, index + 1}); - auto authorSiteText = std::make_shared(font, 7, author.website, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2i{27, index + 2}); + auto authorNameText = std::make_shared(font, 7, this->_truncString(author.name, 22) , TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2i{27, index}); + auto authorMailText = std::make_shared(font, 7, this->_truncString(author.email, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2i{27, index + 1}); + auto authorSiteText = std::make_shared(font, 7, this->_truncString(author.website, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2i{27, index + 2}); this->_hiddenTexts[checkBox].push_back(authorNameText); this->_hiddenTexts[checkBox].push_back(authorMailText); this->_hiddenTexts[checkBox].push_back(authorSiteText); @@ -64,13 +64,14 @@ void Menu::_initCheckBoxes() int index = 8; for (auto gameProvider : this->_gameProviders) { - auto marginRight = 20 - static_cast(gameProvider->getManifest().name.size()); - std::string truncatedName = gameProvider->getManifest().name.substr(0, 17); + auto marginRight = 23 - static_cast(gameProvider->getManifest().name.size()); + std::string truncatedName = gameProvider->getManifest().name.substr(0, 20); if (marginRight < 0) { truncatedName += "..."; marginRight = 0; } else { truncatedName = gameProvider->getManifest().name; + marginRight -= 3; } auto textCheckBox = std::make_shared(font, 10, truncatedName, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{20, 1}, Vector2i{3 + marginRight, index}); auto textureCheckBox = std::make_shared(texture, Vector2f{360, 360}, Vector2u{0, 0}, Vector2u{1, 1}, Vector2i{1 + marginRight, index}); @@ -119,7 +120,7 @@ void Menu::_initWindow() this->_gamesCheckBoxes.clear(); if (!this->_graphicsProvider) { if (this->_graphicsProviders.empty()) - throw std::runtime_error("No graphics provider found"); + throw ArcadeError("No graphics provider found"); this->_graphicsProvider = this->_graphicsProviders.at(0); std::cout << "No graphics provider found, using default provider" << std::endl; } @@ -256,7 +257,7 @@ void Menu::_previousSelectedGame() } } if (this->_gamesCheckBoxes.empty()) - throw std::runtime_error("No games found"); + throw ArcadeError("No games found"); this->_gamesCheckBoxes.at(0)->check(); this->_gamesCheckBoxes.at(0)->hover(); } diff --git a/core/src/menu/Menu.hpp b/core/src/menu/Menu.hpp index 306079d..ea07aca 100644 --- a/core/src/menu/Menu.hpp +++ b/core/src/menu/Menu.hpp @@ -11,6 +11,7 @@ #include "types/Stages.hpp" #include "types/Providers.hpp" #include "checkBox/CheckBox.hpp" +#include "exception/ArcadeError.hpp" using namespace arcade::core; using namespace shared::games; @@ -134,4 +135,6 @@ class Menu { * */ void _previousSelectedGame(); + + std::string _truncString(const std::string &str, int size); }; From 2a31ef1005aea05fb96edae50062a0071d4ab0f7 Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 5 Apr 2024 10:40:53 +0200 Subject: [PATCH 05/18] feat(core): add menu mouse hover --- assets/pacman/apple.ascii | 1 + assets/pacman/apple.png | Bin 0 -> 718 bytes assets/pacman/head.ascii | 1 + assets/pacman/head.png | Bin 0 -> 1868 bytes assets/pacman/tail.ascii | 3 + assets/pacman/tail.png | Bin 0 -> 2048 bytes assets/pacman/wall.ascii | 1 + assets/pacman/wall.png | Bin 0 -> 237 bytes core/src/menu/Menu.cpp | 52 +++++++++ core/src/menu/Menu.hpp | 15 +++ core/src/menu/checkBox/CheckBox.cpp | 11 ++ core/src/menu/checkBox/CheckBox.hpp | 9 ++ core/src/menu/entity/text/Text.cpp | 10 ++ core/src/menu/entity/text/Text.hpp | 12 ++ games/CMakeLists.txt | 1 + games/pacman/CMakeLists.txt | 24 ++++ games/pacman/export.cpp | 22 ++++ games/pacman/src/PacmanGame.cpp | 104 ++++++++++++++++++ games/pacman/src/PacmanGame.hpp | 70 ++++++++++++ games/pacman/src/PacmanGameProvider.cpp | 19 ++++ games/pacman/src/PacmanGameProvider.hpp | 35 ++++++ .../pacman/src/entities/apple/AppleEntity.cpp | 65 +++++++++++ .../pacman/src/entities/apple/AppleEntity.hpp | 52 +++++++++ .../entities/background/BackgroundEntity.cpp | 43 ++++++++ .../entities/background/BackgroundEntity.hpp | 35 ++++++ .../pacman/src/entities/pacman/HeadEntity.cpp | 89 +++++++++++++++ .../pacman/src/entities/pacman/HeadEntity.hpp | 66 +++++++++++ games/pacman/src/entities/pacman/Pacman.cpp | 75 +++++++++++++ games/pacman/src/entities/pacman/Pacman.hpp | 67 +++++++++++ .../pacman/src/entities/pacman/TailEntity.cpp | 56 ++++++++++ .../pacman/src/entities/pacman/TailEntity.hpp | 51 +++++++++ .../components/HeadKeyboardComponent.cpp | 54 +++++++++ .../components/HeadKeyboardComponent.hpp | 45 ++++++++ games/pacman/src/entities/wall/WallEntity.cpp | 56 ++++++++++ games/pacman/src/entities/wall/WallEntity.hpp | 40 +++++++ graphics/sfml/src/window/Window.cpp | 3 +- 36 files changed, 1186 insertions(+), 1 deletion(-) create mode 100644 assets/pacman/apple.ascii create mode 100644 assets/pacman/apple.png create mode 100644 assets/pacman/head.ascii create mode 100644 assets/pacman/head.png create mode 100644 assets/pacman/tail.ascii create mode 100644 assets/pacman/tail.png create mode 100644 assets/pacman/wall.ascii create mode 100644 assets/pacman/wall.png 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 create mode 100644 games/pacman/src/entities/apple/AppleEntity.cpp create mode 100644 games/pacman/src/entities/apple/AppleEntity.hpp create mode 100644 games/pacman/src/entities/background/BackgroundEntity.cpp create mode 100644 games/pacman/src/entities/background/BackgroundEntity.hpp create mode 100644 games/pacman/src/entities/pacman/HeadEntity.cpp create mode 100644 games/pacman/src/entities/pacman/HeadEntity.hpp create mode 100644 games/pacman/src/entities/pacman/Pacman.cpp create mode 100644 games/pacman/src/entities/pacman/Pacman.hpp create mode 100644 games/pacman/src/entities/pacman/TailEntity.cpp create mode 100644 games/pacman/src/entities/pacman/TailEntity.hpp create mode 100644 games/pacman/src/entities/pacman/components/HeadKeyboardComponent.cpp create mode 100644 games/pacman/src/entities/pacman/components/HeadKeyboardComponent.hpp create mode 100644 games/pacman/src/entities/wall/WallEntity.cpp create mode 100644 games/pacman/src/entities/wall/WallEntity.hpp diff --git a/assets/pacman/apple.ascii b/assets/pacman/apple.ascii new file mode 100644 index 0000000..60a89ed --- /dev/null +++ b/assets/pacman/apple.ascii @@ -0,0 +1 @@ +O \ No newline at end of file diff --git a/assets/pacman/apple.png b/assets/pacman/apple.png new file mode 100644 index 0000000000000000000000000000000000000000..1bb1a638577716032def9fd93d851cff035e3994 GIT binary patch literal 718 zcmV;<0x|uGP)JN z6G0Tm-`iLfL9-|x#nn>9lNG&q%6c%QC+lBe`X2=JSRsEx1@AUDFVfx&y%?`vG$4q- z=t6rb?P0forGiH zfF)*YuFr=TF^ccA)vMF}ad*j^bia76F3$z9g@}1_gg#MqLBdBwpMW@uT6e7pba-+~ zPowv*Z$SCY^?-`)uE$qcMD=cz+V0N4_6=^Imb8Z0&f)HQc z{~Rvr#u*7r*Bt!-#cdseDCSzpYcfy`GAc9a15v0rNjb}_MC)MY-ZEH%UA&`mQR|?r zb6}AYiiT!>HCYk12cfSDo2t-zR^Ik1Q>zgA$n4N(iMK&?WWg&3SBB+X`_L|I-XMgrwka{pF` zLcxa4J&AFdNt;WYfkH6vsB_i9G-)Do*xMcD5huxAsAcjv`O6~jgF`L(y*%P1xqsF5 zk~FijpG#Y&qq>r=taGxIn5?%GLACLZ7;zTa1LF(Kax@MzC;$Ke07*qoM6N<$g0C_< AjsO4v literal 0 HcmV?d00001 diff --git a/assets/pacman/head.ascii b/assets/pacman/head.ascii new file mode 100644 index 0000000..71c4a23 --- /dev/null +++ b/assets/pacman/head.ascii @@ -0,0 +1 @@ +@@@@ \ No newline at end of file diff --git a/assets/pacman/head.png b/assets/pacman/head.png new file mode 100644 index 0000000000000000000000000000000000000000..f369b2a2f9686b3eea791b5e79ea3bdd2c0cddf9 GIT binary patch literal 1868 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 } +void Menu::_handleMouseMouveEvents(std::shared_ptr mouse) +{ + if (!mouse) + return; + auto position = mouse->getPosition(); + std::shared_ptr lastHoveredCheckBox = nullptr; + bool hoveredAtLeastOne = false; + + for (auto checkBox : this->_gamesCheckBoxes) { + if (checkBox->isHovered()) { + lastHoveredCheckBox = checkBox; + break; + } + } + for (auto checkBox : this->_gamesCheckBoxes) { + if (checkBox->isHovered()) + checkBox->unhover(); + if (checkBox->isHovered(position)) { + checkBox->hover(); + hoveredAtLeastOne = true; + } + } + if (!hoveredAtLeastOne && lastHoveredCheckBox) + lastHoveredCheckBox->hover(); +} + +void Menu::_handleMouseButtonEvents(std::shared_ptr mouse) +{ + if (!mouse) + return; + auto position = mouse->getPosition(); + auto button = mouse->getButton(); + + if (button != events::IMouseButtonEvent::MouseButton::LEFT) + return; + std::cout << "Left click" << std::endl; + std::cout << "Position: " << position.x << " " << position.y << std::endl; + for (auto checkBox : this->_gamesCheckBoxes) { + if (checkBox->isHovered(position)) + this->_selectGame(); + } +} + void Menu::_handleEvents() { auto events = this->_window->getEvents(); @@ -223,6 +266,15 @@ void Menu::_handleEvents() auto key = std::dynamic_pointer_cast(event); this->_handleKeyboardEvents(key); } + if (type == events::MOUSE_MOVE) { + auto mouse = std::dynamic_pointer_cast(event); + this->_handleMouseMouveEvents(mouse); + } + if (type == events::MOUSE_BTN_PRESS) { + auto mouse = std::dynamic_pointer_cast(event); + this->_handleMouseButtonEvents(mouse); + } + } } diff --git a/core/src/menu/Menu.hpp b/core/src/menu/Menu.hpp index ea07aca..f085f0c 100644 --- a/core/src/menu/Menu.hpp +++ b/core/src/menu/Menu.hpp @@ -12,6 +12,7 @@ #include "types/Providers.hpp" #include "checkBox/CheckBox.hpp" #include "exception/ArcadeError.hpp" +#include "shared/graphics/events/IMouseButtonEvent.hpp" using namespace arcade::core; using namespace shared::games; @@ -67,6 +68,20 @@ class Menu { */ void _handleEvents(); + /** + * @brief Handle mouse mouve events + * + * @param mouse Mouse event + */ + void _handleMouseMouveEvents(std::shared_ptr mouse); + + /** + * @brief Handle mouse button events + * + * @param mouse Mouse event + */ + void _handleMouseButtonEvents(std::shared_ptr mouse); + /** * @brief Handle checkbox events * diff --git a/core/src/menu/checkBox/CheckBox.cpp b/core/src/menu/checkBox/CheckBox.cpp index 69618e8..d764289 100644 --- a/core/src/menu/checkBox/CheckBox.cpp +++ b/core/src/menu/checkBox/CheckBox.cpp @@ -49,4 +49,15 @@ void CheckBox::unhover() bool CheckBox::isHovered() const { return this->_hovered; +} + +bool CheckBox::isHovered(const Vector2i &mousePos) const +{ + auto pos = this->_text->getPosition(); + auto size = this->_text->getSize(); + + if (mousePos.x >= pos.x && mousePos.x <= pos.x + size.x && + mousePos.y >= pos.y && mousePos.y <= pos.y + size.y) + return true; + return false; } \ No newline at end of file diff --git a/core/src/menu/checkBox/CheckBox.hpp b/core/src/menu/checkBox/CheckBox.hpp index fdcc72e..f540035 100644 --- a/core/src/menu/checkBox/CheckBox.hpp +++ b/core/src/menu/checkBox/CheckBox.hpp @@ -70,6 +70,15 @@ class CheckBox { */ bool isHovered() const; + /** + * @brief Check if the checkbox is hovered by the mouse + * + * @param mousePos Mouse event + * @return true if hovered + * @return false if not hovered + */ + bool isHovered(const shared::types::Vector2i &mousePos) const; + private: bool _checked; bool _hovered; diff --git a/core/src/menu/entity/text/Text.cpp b/core/src/menu/entity/text/Text.cpp index d959e69..5306b02 100644 --- a/core/src/menu/entity/text/Text.cpp +++ b/core/src/menu/entity/text/Text.cpp @@ -35,3 +35,13 @@ void Text::setColor(Color color) { this->_color = color; } + +Vector2u Text::getSize() const +{ + return this->_size; +} + +Vector2i Text::getPosition() const +{ + return this->_position; +} diff --git a/core/src/menu/entity/text/Text.hpp b/core/src/menu/entity/text/Text.hpp index 10d074f..19d1cec 100644 --- a/core/src/menu/entity/text/Text.hpp +++ b/core/src/menu/entity/text/Text.hpp @@ -44,6 +44,18 @@ class Text { */ void setColor(Color color); + /** + * @brief Get the size of the text + * + */ + Vector2u getSize() const; + + /** + * @brief Get the position of the text + * + */ + Vector2i getPosition() const; + private: std::shared_ptr _font; unsigned int _fontSize; diff --git a/games/CMakeLists.txt b/games/CMakeLists.txt index 4c39731..d1e7754 100644 --- a/games/CMakeLists.txt +++ b/games/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(snake) +add_subdirectory(pacman) diff --git a/games/pacman/CMakeLists.txt b/games/pacman/CMakeLists.txt new file mode 100644 index 0000000..b0db33a --- /dev/null +++ b/games/pacman/CMakeLists.txt @@ -0,0 +1,24 @@ +project(pacman) +add_library(${PROJECT_NAME} SHARED + export.cpp + src/PacmanGameProvider.cpp + src/PacmanGame.cpp + src/entities/pacman/Pacman.cpp + src/entities/pacman/Pacman.hpp + src/entities/pacman/TailEntity.cpp + src/entities/pacman/TailEntity.hpp + src/entities/pacman/HeadEntity.cpp + src/entities/pacman/HeadEntity.hpp + src/entities/pacman/components/HeadKeyboardComponent.cpp + src/entities/pacman/components/HeadKeyboardComponent.hpp + src/entities/wall/WallEntity.cpp + src/entities/wall/WallEntity.hpp + src/entities/background/BackgroundEntity.cpp + src/entities/background/BackgroundEntity.hpp + src/entities/apple/AppleEntity.cpp + src/entities/apple/AppleEntity.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..82e0a3b --- /dev/null +++ b/games/pacman/src/PacmanGame.cpp @@ -0,0 +1,104 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** PacmanGame.cpp +*/ + +#include +#include "PacmanGame.hpp" +#include "entities/wall/WallEntity.hpp" +#include "entities/background/BackgroundEntity.hpp" +#include "entities/apple/AppleEntity.hpp" +#include "common/components/TextureComponent.hpp" +#include "entities/pacman/components/HeadKeyboardComponent.hpp" + +using namespace arcade::games; + +const shared::games::GameManifest pacman::PacmanGame::manifest = { + .name = "pacman really really good good good game", + .description = "The pacman original game", + .version = "1.0.0", + .authors = { + { + .name = "TekMath", + .email = "matheo.coquet@epitech.eu", + .website = "https://github.com/tekmath" + }, + { + .name = "Yann Masson", + .email = "flavienchenu@epitech.eu", + .website = "https://github.com/flavien-chenu" + } + } +}; + +pacman::PacmanGame::PacmanGame() : common::AGame(Vector2u(20, 20), 60) { + this->_pacman = std::make_unique(4); + this->_registerEntity(this->_pacman->head); + + for (auto &tail: this->_pacman->getTails()) { + this->_registerEntity(tail); + } + + this->_registerEntity(std::make_unique(this->getSize())); + this->_registerEntity(std::make_unique(this->getSize())); + + this->_apple = std::make_unique(this->getSize()); + this->_registerEntity(this->_apple); + + this->_clock = std::chrono::milliseconds(0); + this->_looseGame = false; + this->speedTime = 100; + this->speedBoost = 0; +} + +const shared::games::GameManifest &pacman::PacmanGame::getManifest() const noexcept { + return PacmanGame::manifest; +} + +void pacman::PacmanGame::compute(shared::games::DeltaTime dt) { + unsigned int speed = this->speedTime; + this->_clock += dt; + + if (this->_looseGame) { + return this->_loose(); + } + if (this->speedBoost > 0) { + speed = 0; + this->speedBoost -= 1; + } + if (this->_clock > std::chrono::milliseconds(speed) + this->_pacman->lastMove) { + this->_pacman->lastMove = this->_clock; + this->_pacman->forward(); + } +} + +void pacman::PacmanGame::_loose() { + this->_clock = std::chrono::milliseconds(0); + this->_pacman->lastMove = std::chrono::milliseconds(900); + + this->_entities.erase(std::remove_if(this->_entities.begin(), this->_entities.end(), [](const shared::games::entity::EntityPtr& entity) { + auto tail = std::dynamic_pointer_cast(entity); + return !(tail == nullptr); + }), this->_entities.end()); + + this->_pacman->reset(); + for (auto &tail: this->_pacman->getTails()) { + this->_registerEntity(tail); + } + + this->_looseGame = false; +} + +void pacman::PacmanGame::setLooseGame(bool state) { + this->_looseGame = state; +} + +void pacman::PacmanGame::addNewPoint() { + std::shared_ptr newTail = this->_pacman->addTail(); + + this->_registerEntity(newTail); + this->_apple->generateApple(); + this->speedTime -= 2; +} diff --git a/games/pacman/src/PacmanGame.hpp b/games/pacman/src/PacmanGame.hpp new file mode 100644 index 0000000..940051b --- /dev/null +++ b/games/pacman/src/PacmanGame.hpp @@ -0,0 +1,70 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** PacmanGame.hpp +*/ + +#pragma once + +#include "common/game/AGame.hpp" +#include "games/pacman/src/entities/pacman/Pacman.hpp" +#include "entities/apple/AppleEntity.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; + + /** + * @brief Set loose game state + * + * @param state If the game is loose or not + */ + void setLooseGame(bool state); + + /** + * @brief Add new point to player and re-generate an apple + */ + void addNewPoint(); + + unsigned int speedTime; + + unsigned int speedBoost; + +protected: + /** + * @brief Execute the process of the end of the game when the player _loose + */ + void _loose(); + + std::unique_ptr _pacman; + std::shared_ptr _apple; + shared::games::DeltaTime _clock; + bool _looseGame; +}; diff --git a/games/pacman/src/PacmanGameProvider.cpp b/games/pacman/src/PacmanGameProvider.cpp new file mode 100644 index 0000000..963aaf3 --- /dev/null +++ b/games/pacman/src/PacmanGameProvider.cpp @@ -0,0 +1,19 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** PacmanGameProvider.cpp +*/ + +#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..a15f5b5 --- /dev/null +++ b/games/pacman/src/PacmanGameProvider.hpp @@ -0,0 +1,35 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** PacmanGameProvider.hpp +*/ + +#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/apple/AppleEntity.cpp b/games/pacman/src/entities/apple/AppleEntity.cpp new file mode 100644 index 0000000..1407030 --- /dev/null +++ b/games/pacman/src/entities/apple/AppleEntity.cpp @@ -0,0 +1,65 @@ +/* +** EPITECH PROJECT, 2024 +** AppleEntity.cpp +** File description: +** AppleEntity class +*/ + +#include +#include "AppleEntity.hpp" +#include "common/components/CollidableComponent.hpp" +#include "common/components/TextureComponent.hpp" +#include "../pacman/HeadEntity.hpp" +#include "../pacman/TailEntity.hpp" +#include "../../PacmanGame.hpp" + +using namespace arcade::games::pacman; +using namespace arcade::games::common::components; + +arcade::games::pacman::AppleEntity::AppleEntity(shared::types::Vector2u size): _mapSize(size) { + this->_create(); + this->generateApple(); +} + +void AppleEntity::generateApple() { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution dis(1, this->_mapSize.x - 2); + Vector2i randomPosition = Vector2i(dis(gen), dis(gen)); + + for (auto &component: this->_components) { + auto posCmp = std::dynamic_pointer_cast(component); + if (posCmp == nullptr) continue; + + posCmp->getPosition().x = randomPosition.x; + posCmp->getPosition().y = randomPosition.y; + } +} + +void AppleEntity::_create() { + shared::games::components::TextureProps textureProps = { + .sources = { + .ascii = "assets/pacman/apple.ascii", + .bin = "assets/pacman/apple.png", + .binTileSize = Vector2f(40, 40) + }, + .origin = Vector2u(0, 0) + }; + std::shared_ptr collision = std::make_shared(*this, this->_onCollide); + std::shared_ptr texture = std::make_shared(*this, Vector2u(1, 1), 9, + textureProps); + + this->_components.push_back(collision); + this->_components.push_back(texture); +} + +void arcade::games::pacman::AppleEntity::_onCollide(std::shared_ptr ctx, + std::shared_ptr target) { + auto game = std::dynamic_pointer_cast(ctx); + + if (!game) + return; + if (dynamic_cast(&target->getEntity()) || dynamic_cast(&target->getEntity())) { + game->addNewPoint(); + } +} diff --git a/games/pacman/src/entities/apple/AppleEntity.hpp b/games/pacman/src/entities/apple/AppleEntity.hpp new file mode 100644 index 0000000..79ba676 --- /dev/null +++ b/games/pacman/src/entities/apple/AppleEntity.hpp @@ -0,0 +1,52 @@ +/* +** EPITECH PROJECT, 2024 +** AppleEntity.hpp +** File description: +** AppleEntity class +*/ + +#pragma once + +#include "common/entity/AEntity.hpp" +#include "shared/types/Vector.hpp" +#include "shared/games/components/ICollidableComponent.hpp" + +namespace arcade::games::pacman { + class AppleEntity; +} + +class arcade::games::pacman::AppleEntity : public common::AEntity { +public: + ~AppleEntity() override = default; + + /** + * @brief Create the apple entity + * @param size Size of the map + */ + explicit AppleEntity(shared::types::Vector2u + size); + + /** + * @brief Update the position of the apple on the map + * (As a new apple reward for the player) + */ + void generateApple(); + +protected: + /** + * @brief Create the apple components + */ + void _create(); + + /** + * @brief Represent the function that will be executed + * when the apple will collide with an other collidable component + * @param ctx Context of the game + * @param target Target component + */ + static void _onCollide(std::shared_ptr ctx, + std::shared_ptr target); + + + shared::types::Vector2u _mapSize; +}; diff --git a/games/pacman/src/entities/background/BackgroundEntity.cpp b/games/pacman/src/entities/background/BackgroundEntity.cpp new file mode 100644 index 0000000..faab65e --- /dev/null +++ b/games/pacman/src/entities/background/BackgroundEntity.cpp @@ -0,0 +1,43 @@ +/* +** EPITECH PROJECT, 2024 +** BackgroundEntity.cpp +** File description: +** BackgroundEntity class +*/ + +#include "BackgroundEntity.hpp" +#include "common/components/TextureComponent.hpp" + +using namespace arcade::games::pacman; +using namespace arcade::games::common::components; + +arcade::games::pacman::BackgroundEntity::BackgroundEntity(shared::types::Vector2u size) { + unsigned int textureOriginX = 1; + unsigned int textureOriginY = 1; + + for (std::size_t x = 1; x < size.x - 1; x++) { + for (std::size_t y = 1; y < size.y - 1; y++) { + this->_addColor(Vector2i(x, y), Vector2u(textureOriginY, 0)); + textureOriginY = textureOriginY == 1 ? 2 : 1; + } + textureOriginX = textureOriginX == 1 ? 2 : 1; + textureOriginY = textureOriginX; + } +} + +void arcade::games::pacman::BackgroundEntity::_addColor(shared::types::Vector2i position, shared::types::Vector2u origin) { + shared::games::components::TextureProps textureProps = { + .sources = { + .ascii = "assets/pacman/wall.ascii", + .bin = "assets/pacman/wall.png", + .binTileSize = Vector2f(40, 40) + }, + .origin = origin + }; + std::shared_ptr texture = std::make_shared(*this, Vector2u(1, 1), 2, + textureProps); + + texture->getPosition().x = position.x; + texture->getPosition().y = position.y; + this->_components.push_back(texture); +} diff --git a/games/pacman/src/entities/background/BackgroundEntity.hpp b/games/pacman/src/entities/background/BackgroundEntity.hpp new file mode 100644 index 0000000..3402541 --- /dev/null +++ b/games/pacman/src/entities/background/BackgroundEntity.hpp @@ -0,0 +1,35 @@ +/* +** EPITECH PROJECT, 2024 +** WallEntity.hpp +** File description: +** WallEntity class +*/ + +#pragma once + +#include +#include "common/entity/AEntity.hpp" +#include "shared/types/Vector.hpp" + +namespace arcade::games::pacman { + class BackgroundEntity; +} + +class arcade::games::pacman::BackgroundEntity : public common::AEntity { +public: + ~BackgroundEntity() override = default; + + /** + * @brief Create a background to the game + * @param size Size of the game + */ + explicit BackgroundEntity(shared::types::Vector2u size); + +protected: + /** + * @brief Add a color to the background (create a texture composent) + * @param position Position of the wall + * @param origin Origin of the texture + */ + void _addColor(shared::types::Vector2i position, shared::types::Vector2u origin); +}; diff --git a/games/pacman/src/entities/pacman/HeadEntity.cpp b/games/pacman/src/entities/pacman/HeadEntity.cpp new file mode 100644 index 0000000..93c5a13 --- /dev/null +++ b/games/pacman/src/entities/pacman/HeadEntity.cpp @@ -0,0 +1,89 @@ +/* +** EPITECH PROJECT, 2024 +** HeadEntity.cpp +** File description: +** HeadEntity class +*/ + +#include "PacmanGame.hpp" +#include "HeadEntity.hpp" +#include "../apple/AppleEntity.hpp" +#include "../wall/WallEntity.hpp" +#include "components/HeadKeyboardComponent.hpp" + +using namespace arcade::games::common::components; +using namespace shared::games::components; + +arcade::games::pacman::HeadEntity::HeadEntity() : _textureProps( + arcade::games::pacman::HeadEntity::_defaultTextureProps()), + direction(1, 0), + position(6, 10) { + std::shared_ptr collide = std::make_shared(*this, HeadEntity::_onCollide); + std::shared_ptr texture = std::make_shared(*this, Vector2u(1, 1), 10, + this->_textureProps); + std::shared_ptr keyboard = std::make_shared( + *this); + + this->_components.push_back(collide); + this->_components.push_back(texture); + this->_components.push_back(keyboard); + this->reset(); +} + +shared::games::components::TextureProps arcade::games::pacman::HeadEntity::_defaultTextureProps() { + return { + .sources = { + .ascii = "assets/pacman/head.ascii", + .bin = "assets/pacman/head.png", + .binTileSize = Vector2f(40, 40) + }, + .origin = Vector2u(3, 0) + }; +} + +void arcade::games::pacman::HeadEntity::forward() { + this->position.x += this->direction.x; + this->position.y += this->direction.y; + + for (auto &component: this->_components) { + auto posCmp = std::dynamic_pointer_cast(component); + if (posCmp == nullptr) continue; + + posCmp->getPosition().x += this->direction.x; + posCmp->getPosition().y += this->direction.y; + + auto textureCmp = std::dynamic_pointer_cast(component); + if (textureCmp == nullptr) continue; + + textureCmp->getTextureProps().origin = Vector2u(0, 0); + if (this->direction.y == 0) + textureCmp->getTextureProps().origin.x = 2; + if (this->direction.x > 0) + textureCmp->getTextureProps().origin.x += 1; + if (this->direction.y > 0) + textureCmp->getTextureProps().origin.x += 1; + } +} + +void arcade::games::pacman::HeadEntity::_onCollide(std::shared_ptr ctx, + std::shared_ptr target) { + auto game = std::dynamic_pointer_cast(ctx); + + if (!game) + return; + if (dynamic_cast(&target->getEntity()) || dynamic_cast(&target->getEntity())) { + game->setLooseGame(true); + } +} + +void arcade::games::pacman::HeadEntity::reset() { + this->direction = Vector2i(1, 0); + this->position = Vector2i(6, 10); + for (auto &component: this->_components) { + std::shared_ptr 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/pacman/HeadEntity.hpp b/games/pacman/src/entities/pacman/HeadEntity.hpp new file mode 100644 index 0000000..c2b9688 --- /dev/null +++ b/games/pacman/src/entities/pacman/HeadEntity.hpp @@ -0,0 +1,66 @@ +/* +** EPITECH PROJECT, 2024 +** HeadEntity.hpp +** File description: +** HeadEntity class +*/ + +#pragma once + +#include "common/entity/AEntity.hpp" +#include "common/components/CollidableComponent.hpp" +#include "common/components/TextureComponent.hpp" + +namespace arcade::games::pacman { + class PacmanGame; + + class HeadEntity; +} + +class arcade::games::pacman::HeadEntity : public common::AEntity { +public: + ~HeadEntity() override = default; + + /** + * @brief Create the head of a pacman + */ + explicit HeadEntity(); + + /** + * @brief Update the position of the head of the pacman + */ + void forward(); + + /** + * @brief Direction of the pacman head + */ + Vector2i direction; + + /** + * @brief Position of the pacman head + */ + Vector2i position; + + /** + * @brief Set the head at default position + */ + void reset(); + +protected: + /** + * @brief Get default texture props + * @return Texture props + */ + static shared::games::components::TextureProps _defaultTextureProps(); + + /** + * @brief Represent the function that will be executed + * when the pacman will collide with an other collidable component + * @param ctx Context of the game + * @param target Target component + */ + static void _onCollide(std::shared_ptr ctx, + std::shared_ptr target); + + shared::games::components::TextureProps _textureProps; +}; diff --git a/games/pacman/src/entities/pacman/Pacman.cpp b/games/pacman/src/entities/pacman/Pacman.cpp new file mode 100644 index 0000000..317ea30 --- /dev/null +++ b/games/pacman/src/entities/pacman/Pacman.cpp @@ -0,0 +1,75 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** pacman.cpp +*/ + +#include "Pacman.hpp" +#include "TailEntity.hpp" +#include "HeadEntity.hpp" + +using namespace shared::games::entity; +using namespace arcade::games::pacman; + +Pacman::Pacman(unsigned int tails) { + this->lastMove = std::chrono::milliseconds(900); + this->head = std::make_shared(); + this->_baseTails = tails; + + this->reset(); +} + +Pacman::~Pacman() = default; + +std::vector> &Pacman::getTails() { + return this->_tails; +} + +std::shared_ptr Pacman::addTail() { + std::shared_ptr newTail = std::make_shared(); + + this->_tails.push_back(newTail); + return newTail; +} + +void Pacman::forward() { + Vector2i oldPosition = this->head->position; + Vector2i tempOldPosition = oldPosition; + int at = -1; + + this->head->forward(); + for (auto &tail: this->_tails) { + at += 1; + tempOldPosition = tail->getPosition(); + tail->setPosition(oldPosition); + oldPosition = tempOldPosition; + + Vector2i old = at > 0 ? this->_tails.at(at - 1)->getPosition() : this->head->position; + if (tail == this->_tails.back()) { + if (tail->getPosition().y < old.y) + tail->setTextureOrigin(Vector2u(0, 1)); + if (tail->getPosition().y > old.y) + tail->setTextureOrigin(Vector2u(1, 1)); + if (tail->getPosition().x < old.x) + tail->setTextureOrigin(Vector2u(2, 1)); + if (tail->getPosition().x > old.x) + tail->setTextureOrigin(Vector2u(3, 1)); + continue; + } + if (tail->getPosition().y == old.y) + tail->setTextureOrigin(Vector2u(1, 0)); + else + tail->setTextureOrigin(Vector2u(0, 0)); + } +} + +void Pacman::reset() { + this->head->reset(); + this->_tails.clear(); + + for (size_t i = 0; i < this->_baseTails; i++) { + this->addTail(); + this->forward(); + } +} diff --git a/games/pacman/src/entities/pacman/Pacman.hpp b/games/pacman/src/entities/pacman/Pacman.hpp new file mode 100644 index 0000000..05af76e --- /dev/null +++ b/games/pacman/src/entities/pacman/Pacman.hpp @@ -0,0 +1,67 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** pacman.hpp +*/ + +#pragma once + +#include +#include +#include + +#include "common/game/AGame.hpp" +#include "shared/games/IEntity.hpp" +#include "HeadEntity.hpp" +#include "TailEntity.hpp" + +namespace arcade::games::pacman { + class Pacman; +} + +class arcade::games::pacman::Pacman { +public: + explicit Pacman(unsigned int tails); + ~Pacman(); + + /** + * @brief Head of the pacman + * + */ + std::shared_ptr head; + + /** + * @brief Add a tail to the pacman body + * + * @return The entity to the new tail + */ + std::shared_ptr addTail(); + + /** + * Get tails of the pacman + * + * @return Vector of tails + */ + std::vector> &getTails(); + + /** + * @brief Reset the pacman + */ + void reset(); + + /** + * @brief Update the position of the pacman + */ + void forward(); + + shared::games::DeltaTime lastMove; +protected: + /** + * @brief Entities that compose the pacman + * + */ + std::vector> _tails; + + unsigned int _baseTails; +}; diff --git a/games/pacman/src/entities/pacman/TailEntity.cpp b/games/pacman/src/entities/pacman/TailEntity.cpp new file mode 100644 index 0000000..f6c43fa --- /dev/null +++ b/games/pacman/src/entities/pacman/TailEntity.cpp @@ -0,0 +1,56 @@ +/* +** EPITECH PROJECT, 2024 +** TailEntity.cpp +** File description: +** TailEntity class +*/ + +#include "TailEntity.hpp" + +using namespace arcade::games::common::components; +using namespace shared::games::components; + +arcade::games::pacman::TailEntity::TailEntity() : _textureProps( + arcade::games::pacman::TailEntity::_defaultTextureProps()), _position(0, 0) { + std::shared_ptr collide = std::make_shared(*this, nullptr); + std::shared_ptr texture = std::make_shared(*this, Vector2u(1, 1), 10, + this->_textureProps); + this->_components.push_back(collide); + this->_components.push_back(texture); +} + +shared::games::components::TextureProps arcade::games::pacman::TailEntity::_defaultTextureProps() { + return { + .sources = { + .ascii = "assets/pacman/tail.ascii", + .bin = "assets/pacman/tail.png", + .binTileSize = Vector2f(40, 40) + }, + .origin = Vector2u(0, 0) + }; +} + +void arcade::games::pacman::TailEntity::setPosition(Vector2i position) { + this->_position = position; + + for (auto &component: this->_components) { + auto posCmp = std::dynamic_pointer_cast(component); + if (posCmp == nullptr) continue; + + posCmp->getPosition().x = position.x; + posCmp->getPosition().y = position.y; + } +} + +void arcade::games::pacman::TailEntity::setTextureOrigin(shared::types::Vector2u origin) { + for (auto &component: this->_components) { + auto txCmp = std::dynamic_pointer_cast(component); + if (txCmp == nullptr) continue; + + txCmp->getTextureProps().origin = origin; + } +} + +Vector2i arcade::games::pacman::TailEntity::getPosition() { + return this->_position; +} diff --git a/games/pacman/src/entities/pacman/TailEntity.hpp b/games/pacman/src/entities/pacman/TailEntity.hpp new file mode 100644 index 0000000..e7d60e8 --- /dev/null +++ b/games/pacman/src/entities/pacman/TailEntity.hpp @@ -0,0 +1,51 @@ +/* +** EPITECH PROJECT, 2024 +** TailEntity.hpp +** File description: +** TailEntity class +*/ + +#pragma once + +#include "common/entity/AEntity.hpp" +#include "common/components/CollidableComponent.hpp" +#include "common/components/TextureComponent.hpp" + +namespace arcade::games::pacman { + class TailEntity; +} + +class arcade::games::pacman::TailEntity : public common::AEntity { +public: + ~TailEntity() override = default; + + explicit TailEntity(); + + /** + * @brief Set position of the tail + * @param position + */ + void setPosition(Vector2i position); + + /** + * @brief Set texture origin for direction of the tail + * @param origin + */ + void setTextureOrigin(Vector2u origin); + + /** + * @brief Get position of the tail + * @return Vector of the position + */ + Vector2i getPosition(); + +protected: + /** + * @brief Get default texture props + * @return Texture props + */ + static shared::games::components::TextureProps _defaultTextureProps(); + + shared::games::components::TextureProps _textureProps; + Vector2i _position; +}; diff --git a/games/pacman/src/entities/pacman/components/HeadKeyboardComponent.cpp b/games/pacman/src/entities/pacman/components/HeadKeyboardComponent.cpp new file mode 100644 index 0000000..f5afa50 --- /dev/null +++ b/games/pacman/src/entities/pacman/components/HeadKeyboardComponent.cpp @@ -0,0 +1,54 @@ +/* +** EPITECH PROJECT, 2024 +** KeyboardComponent.cpp +** File description: +** HeadKeyboardComponent class +*/ + +#include "HeadKeyboardComponent.hpp" +#include "../../../PacmanGame.hpp" + +using namespace arcade::games::pacman::components; +using namespace shared::games::components; + +HeadKeyboardComponent::HeadKeyboardComponent(HeadEntity &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.y != 1) { + this->_parent.direction = Vector2i(0, -1); + } + if (keyData.code.arrow == DOWN && this->_parent.direction.y != -1) { + this->_parent.direction = Vector2i(0, 1); + } + if (keyData.code.arrow == LEFT && this->_parent.direction.x != 1) { + this->_parent.direction = Vector2i(-1, 0); + } + if (keyData.code.arrow == RIGHT && this->_parent.direction.x != -1) { + this->_parent.direction = Vector2i(1, 0); + } + } + if (keyData.type == CHAR) { + if (keyData.code.character == 'z' && this->_parent.direction.y != 1) { + this->_parent.direction = Vector2i(0, -1); + } + if (keyData.code.character == 's' && this->_parent.direction.y != -1) { + this->_parent.direction = Vector2i(0, 1); + } + if (keyData.code.character == 'q' && this->_parent.direction.x != 1) { + this->_parent.direction = Vector2i(-1, 0); + } + if (keyData.code.character == 'd' && this->_parent.direction.x != -1) { + this->_parent.direction = Vector2i(1, 0); + } + } + if (keyData.type == CHAR && keyData.code.character == ' ') { + auto game = std::dynamic_pointer_cast(ctx); + + game->speedBoost = 3; + } +} + +void HeadKeyboardComponent::onKeyRelease(std::shared_ptr ctx, + shared::games::components::IKeyboardComponent::KeyData keyData) {} diff --git a/games/pacman/src/entities/pacman/components/HeadKeyboardComponent.hpp b/games/pacman/src/entities/pacman/components/HeadKeyboardComponent.hpp new file mode 100644 index 0000000..dd92c9f --- /dev/null +++ b/games/pacman/src/entities/pacman/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 "../HeadEntity.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(HeadEntity &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: + HeadEntity &_parent; +}; diff --git a/games/pacman/src/entities/wall/WallEntity.cpp b/games/pacman/src/entities/wall/WallEntity.cpp new file mode 100644 index 0000000..0c4bbad --- /dev/null +++ b/games/pacman/src/entities/wall/WallEntity.cpp @@ -0,0 +1,56 @@ +/* +** EPITECH PROJECT, 2024 +** WallEntity.cpp +** File description: +** WallEntity class +*/ + +#include "WallEntity.hpp" +#include "common/components/CollidableComponent.hpp" +#include "common/components/TextureComponent.hpp" + +using namespace arcade::games::pacman; +using namespace arcade::games::common::components; + +WallEntity::WallEntity(shared::types::Vector2u size) { + if (size.x < 3 || size.y < 3) + throw WallException("Invalid size of map"); + + for (std::size_t y = 0; y < size.y; y++) { + this->_createWall(Vector2i(0, y)); + } + for (std::size_t x = 1; x < size.x - 1; x++) { + this->_createWall(Vector2i(x, 0)); + this->_createWall(Vector2i(x, size.y - 1)); + } + for (std::size_t y = 0; y < size.y; y++) { + this->_createWall(Vector2i(size.x - 1, y)); + } +} + +void WallEntity::_createWall(shared::types::Vector2i position) { + shared::games::components::TextureProps textureProps = { + .sources = { + .ascii = "assets/pacman/wall.ascii", + .bin = "assets/pacman/wall.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); +} + +WallEntity::WallException::WallException(const std::string &message) : _message(message) {} + +const char *WallEntity::WallException::what() const noexcept { + return this->_message.c_str(); +} diff --git a/games/pacman/src/entities/wall/WallEntity.hpp b/games/pacman/src/entities/wall/WallEntity.hpp new file mode 100644 index 0000000..693cde6 --- /dev/null +++ b/games/pacman/src/entities/wall/WallEntity.hpp @@ -0,0 +1,40 @@ +/* +** EPITECH PROJECT, 2024 +** WallEntity.hpp +** File description: +** WallEntity class +*/ + +#pragma once + +#include +#include "common/entity/AEntity.hpp" +#include "shared/types/Vector.hpp" + +namespace arcade::games::pacman { + class WallEntity; +} + +class arcade::games::pacman::WallEntity : public common::AEntity { +public: + ~WallEntity() override = default; + + explicit WallEntity(shared::types::Vector2u size); + + class WallException : public std::exception { + public: + WallException(const std::string &message); + + const char *what() const noexcept override; + + private: + const std::string &_message; + }; + +protected: + /** + * @brief Create a wall (part of) (Component creation) + * @param position Position of the wall + */ + void _createWall(shared::types::Vector2i position); +}; diff --git a/graphics/sfml/src/window/Window.cpp b/graphics/sfml/src/window/Window.cpp index 1eedc47..68477f3 100644 --- a/graphics/sfml/src/window/Window.cpp +++ b/graphics/sfml/src/window/Window.cpp @@ -15,6 +15,7 @@ using namespace arcade::graphics::common::exceptions; const Vector2u Window::tileSize = { 12, 12 }; +#include Window::Window(const IWindow::WindowInitProps &props): _size(props.size), _initialSize(0, 0), @@ -181,7 +182,7 @@ void Window::onResize() _view.setCenter( static_cast(originalPixels.x) / 2, static_cast(originalPixels.y) / 2 ); - if (width < height) { + if ((static_cast(originalPixels.x) / width) > static_cast(originalPixels.y) / height) { _view.zoom(static_cast(originalPixels.x) / width); } else { _view.zoom(static_cast(originalPixels.y) / height); From 92709dd94c2598074a2f12d8a80eea031e994ab9 Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 5 Apr 2024 11:27:34 +0200 Subject: [PATCH 06/18] refactor: use float for tiles --- core/src/menu/Menu.cpp | 34 +++++++++---------- core/src/menu/checkBox/CheckBox.cpp | 2 +- core/src/menu/checkBox/CheckBox.hpp | 2 +- core/src/menu/entity/text/Text.cpp | 4 +-- core/src/menu/entity/text/Text.hpp | 6 ++-- core/src/menu/entity/texture/Texture.cpp | 2 +- core/src/menu/entity/texture/Texture.hpp | 4 +-- .../components/PositionableComponent.cpp | 2 +- .../components/PositionableComponent.hpp | 4 +-- games/common/game/AGame.cpp | 4 +++ games/common/game/AGame.hpp | 12 +++++++ .../common/events/mouse/AMouseButtonEvent.hpp | 2 +- graphics/common/events/mouse/AMouseEvent.hpp | 6 ++-- .../events/mouse/MouseButtonPressEvent.hpp | 2 +- .../common/events/mouse/MouseMoveEvent.hpp | 2 +- graphics/sfml/src/window/EventsHandler.cpp | 6 ++-- graphics/sfml/src/window/Renderer.cpp | 2 +- graphics/sfml/src/window/Renderer.hpp | 2 +- graphics/sfml/src/window/Window.cpp | 7 ++-- graphics/sfml/src/window/Window.hpp | 2 +- shared/games/IGame.hpp | 7 ++++ .../components/IPositionableComponent.hpp | 2 +- shared/graphics/events/IMouseEvent.hpp | 2 +- shared/graphics/types/TextProps.hpp | 2 +- shared/graphics/types/TextureProps.hpp | 2 +- 25 files changed, 70 insertions(+), 52 deletions(-) diff --git a/core/src/menu/Menu.cpp b/core/src/menu/Menu.cpp index 7738947..2ad8cb0 100644 --- a/core/src/menu/Menu.cpp +++ b/core/src/menu/Menu.cpp @@ -30,26 +30,26 @@ std::string Menu::_truncString(const std::string &str, int size) void Menu::_initHiddenTextures(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) { auto truncatName = this->_truncString(gameManifest.name, 23); - auto nameText = std::make_shared(font, 11, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2i{25, 8}); + auto nameText = std::make_shared(font, 11, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 8}); this->_hiddenTexts[checkBox].push_back(nameText); std::string truncatDesc = this->_truncString(gameManifest.description, 23); - auto descriptionText = std::make_shared(font, 9, truncatDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2i{25, 10}); + auto descriptionText = std::make_shared(font, 9, truncatDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 10}); this->_hiddenTexts[checkBox].push_back(descriptionText); int score = 154; auto scoreString = std::to_string(score); while (scoreString.length() < 5) scoreString = "0" + scoreString; - auto scoreText = std::make_shared(font, 10, scoreString, TextAlign::RIGHT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{14, 1}, Vector2i{34, 12}); + auto scoreText = std::make_shared(font, 10, scoreString, TextAlign::RIGHT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{14, 1}, Vector2f{34, 12}); this->_hiddenTexts[checkBox].push_back(scoreText); auto authors = gameManifest.authors; - int index = 15; + float index = 15.0; for (auto author : authors) { - auto authorNameText = std::make_shared(font, 7, this->_truncString(author.name, 22) , TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2i{27, index}); - auto authorMailText = std::make_shared(font, 7, this->_truncString(author.email, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2i{27, index + 1}); - auto authorSiteText = std::make_shared(font, 7, this->_truncString(author.website, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2i{27, index + 2}); + auto authorNameText = std::make_shared(font, 7, this->_truncString(author.name, 22) , TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index}); + auto authorMailText = std::make_shared(font, 7, this->_truncString(author.email, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index + 1}); + auto authorSiteText = std::make_shared(font, 7, this->_truncString(author.website, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index + 2}); this->_hiddenTexts[checkBox].push_back(authorNameText); this->_hiddenTexts[checkBox].push_back(authorMailText); this->_hiddenTexts[checkBox].push_back(authorSiteText); @@ -61,10 +61,10 @@ void Menu::_initCheckBoxes() { auto texture = this->_graphicsProvider->createTexture("assets/menu/img/space-invader.png", "assets/menu/img/space-invader.ascii"); auto font = this->_graphicsProvider->createFont("assets/menu/fonts/arcade.ttf"); - int index = 8; + float index = 8.0; for (auto gameProvider : this->_gameProviders) { - auto marginRight = 23 - static_cast(gameProvider->getManifest().name.size()); + auto marginRight = 23 - static_cast(gameProvider->getManifest().name.size()); std::string truncatedName = gameProvider->getManifest().name.substr(0, 20); if (marginRight < 0) { truncatedName += "..."; @@ -73,8 +73,8 @@ void Menu::_initCheckBoxes() truncatedName = gameProvider->getManifest().name; marginRight -= 3; } - auto textCheckBox = std::make_shared(font, 10, truncatedName, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{20, 1}, Vector2i{3 + marginRight, index}); - auto textureCheckBox = std::make_shared(texture, Vector2f{360, 360}, Vector2u{0, 0}, Vector2u{1, 1}, Vector2i{1 + marginRight, index}); + auto textCheckBox = std::make_shared(font, 10, truncatedName, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{20, 1}, Vector2f{3 + marginRight, index}); + auto textureCheckBox = std::make_shared(texture, Vector2f{360, 360}, Vector2u{0, 0}, Vector2u{1, 1}, Vector2f{1 + marginRight, index}); auto checkBox = std::make_shared(textureCheckBox, textCheckBox); this->_texts.push_back(textCheckBox); this->_textures.push_back(textureCheckBox); @@ -87,21 +87,21 @@ void Menu::_initCheckBoxes() void Menu::_initTextures() { auto backgroundTexture = this->_graphicsProvider->createTexture("assets/menu/img/background.png", "assets/menu/img/background.ascii"); - this->_textures.push_back(std::make_shared(backgroundTexture, Vector2f{12, 12}, Vector2u{0, 0}, Vector2u{50, 25}, Vector2i{0, 0})); + this->_textures.push_back(std::make_shared(backgroundTexture, Vector2f{12, 12}, Vector2u{0, 0}, Vector2u{50, 25}, Vector2f{0, 0})); auto titleTexture = this->_graphicsProvider->createTexture("assets/menu/img/title.png", "assets/menu/img/title.ascii"); - this->_textures.push_back(std::make_shared(titleTexture, Vector2f{17, 17}, Vector2u{0, 0}, Vector2u{31, 5}, Vector2i{10, 1})); + this->_textures.push_back(std::make_shared(titleTexture, Vector2f{17, 17}, Vector2u{0, 0}, Vector2u{31, 5}, Vector2f{10, 1})); auto middleTexture = this->_graphicsProvider->createTexture("assets/menu/img/middle.png", "assets/menu/img/middle.ascii"); - this->_textures.push_back(std::make_shared(middleTexture, Vector2f{12, 12}, Vector2u{0, 0}, Vector2u{1, 17}, Vector2i{24, 7})); + this->_textures.push_back(std::make_shared(middleTexture, Vector2f{12, 12}, Vector2u{0, 0}, Vector2u{1, 17}, Vector2f{24, 7})); } void Menu::_initTexts() { auto font = this->_graphicsProvider->createFont("assets/menu/fonts/arcade.ttf"); - auto score = std::make_shared(font, 10, "HI-SCORE", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2i{26, 12}); + auto score = std::make_shared(font, 10, "HI-SCORE", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 12}); this->_texts.push_back(score); - auto authors = std::make_shared(font, 8, "Authors:", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2i{26, 14}); + auto authors = std::make_shared(font, 8, "Authors:", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 14}); this->_texts.push_back(authors); } @@ -246,8 +246,6 @@ void Menu::_handleMouseButtonEvents(std::shared_ptr m if (button != events::IMouseButtonEvent::MouseButton::LEFT) return; - std::cout << "Left click" << std::endl; - std::cout << "Position: " << position.x << " " << position.y << std::endl; for (auto checkBox : this->_gamesCheckBoxes) { if (checkBox->isHovered(position)) this->_selectGame(); diff --git a/core/src/menu/checkBox/CheckBox.cpp b/core/src/menu/checkBox/CheckBox.cpp index d764289..ba85fc0 100644 --- a/core/src/menu/checkBox/CheckBox.cpp +++ b/core/src/menu/checkBox/CheckBox.cpp @@ -51,7 +51,7 @@ bool CheckBox::isHovered() const return this->_hovered; } -bool CheckBox::isHovered(const Vector2i &mousePos) const +bool CheckBox::isHovered(const Vector2f &mousePos) const { auto pos = this->_text->getPosition(); auto size = this->_text->getSize(); diff --git a/core/src/menu/checkBox/CheckBox.hpp b/core/src/menu/checkBox/CheckBox.hpp index f540035..00bd49c 100644 --- a/core/src/menu/checkBox/CheckBox.hpp +++ b/core/src/menu/checkBox/CheckBox.hpp @@ -77,7 +77,7 @@ class CheckBox { * @return true if hovered * @return false if not hovered */ - bool isHovered(const shared::types::Vector2i &mousePos) const; + bool isHovered(const shared::types::Vector2f &mousePos) const; private: bool _checked; diff --git a/core/src/menu/entity/text/Text.cpp b/core/src/menu/entity/text/Text.cpp index 5306b02..5d181fe 100644 --- a/core/src/menu/entity/text/Text.cpp +++ b/core/src/menu/entity/text/Text.cpp @@ -9,7 +9,7 @@ Text::Text(std::shared_ptr font, unsigned int fontSize, std::string content, TextAlign align, TextVerticalAlign verticalAlign, Color color, Vector2u size, - Vector2i position) : + Vector2f position) : _font(font), _fontSize(fontSize), _content(content), _align(align), _verticalAlign(verticalAlign), _color(color), _size(size), _position(position) {} @@ -41,7 +41,7 @@ Vector2u Text::getSize() const return this->_size; } -Vector2i Text::getPosition() const +Vector2f Text::getPosition() const { return this->_position; } diff --git a/core/src/menu/entity/text/Text.hpp b/core/src/menu/entity/text/Text.hpp index 19d1cec..fa59e3a 100644 --- a/core/src/menu/entity/text/Text.hpp +++ b/core/src/menu/entity/text/Text.hpp @@ -23,7 +23,7 @@ class Text { TextVerticalAlign verticalAlign, Color color, Vector2u size, - Vector2i position); + Vector2f position); /** * @brief Destructor for Text object @@ -54,7 +54,7 @@ class Text { * @brief Get the position of the text * */ - Vector2i getPosition() const; + Vector2f getPosition() const; private: std::shared_ptr _font; @@ -64,5 +64,5 @@ class Text { TextVerticalAlign _verticalAlign; Color _color; Vector2u _size; - Vector2i _position; + Vector2f _position; }; diff --git a/core/src/menu/entity/texture/Texture.cpp b/core/src/menu/entity/texture/Texture.cpp index 2c8fe2b..2df1bb1 100644 --- a/core/src/menu/entity/texture/Texture.cpp +++ b/core/src/menu/entity/texture/Texture.cpp @@ -8,7 +8,7 @@ #include "Texture.hpp" Texture::Texture(std::shared_ptr texture, Vector2f binTileSize, Vector2u origin, - Vector2u size, Vector2i position) : _texture(texture), _binTileSize(binTileSize), _origin(origin), + Vector2u size, Vector2f position) : _texture(texture), _binTileSize(binTileSize), _origin(origin), _size(size), _position(position) {} Texture::~Texture() {} diff --git a/core/src/menu/entity/texture/Texture.hpp b/core/src/menu/entity/texture/Texture.hpp index a914ac7..41a03ad 100644 --- a/core/src/menu/entity/texture/Texture.hpp +++ b/core/src/menu/entity/texture/Texture.hpp @@ -27,7 +27,7 @@ class Texture { * @param size Size */ Texture(std::shared_ptr texture, Vector2f binTileSize, Vector2u origin, - Vector2u size, Vector2i position); + Vector2u size, Vector2f position); /** * @brief Destructor for Texture object @@ -53,5 +53,5 @@ class Texture { Vector2f _binTileSize; Vector2u _origin; Vector2u _size; - Vector2i _position; + Vector2f _position; }; diff --git a/games/common/components/PositionableComponent.cpp b/games/common/components/PositionableComponent.cpp index 2dd5be7..85b36ba 100644 --- a/games/common/components/PositionableComponent.cpp +++ b/games/common/components/PositionableComponent.cpp @@ -14,7 +14,7 @@ PositionableComponent::PositionableComponent(shared::games::entity::IEntity &ent _position(0, 0), _size(1, 1) { } -shared::types::Vector2i &PositionableComponent::getPosition() noexcept { +shared::types::Vector2f &PositionableComponent::getPosition() noexcept { return this->_position; } diff --git a/games/common/components/PositionableComponent.hpp b/games/common/components/PositionableComponent.hpp index 557e4f5..8c35e3f 100644 --- a/games/common/components/PositionableComponent.hpp +++ b/games/common/components/PositionableComponent.hpp @@ -29,7 +29,7 @@ class arcade::games::common::components::PositionableComponent * @brief Get position of the entity (tiles) * */ - shared::types::Vector2i &getPosition() noexcept override; + shared::types::Vector2f &getPosition() noexcept override; /** * @brief Get size of the entity (tiles) @@ -38,6 +38,6 @@ class arcade::games::common::components::PositionableComponent shared::types::Vector2u &getSize() noexcept override; protected: - shared::types::Vector2i _position; + shared::types::Vector2f _position; shared::types::Vector2u _size; }; diff --git a/games/common/game/AGame.cpp b/games/common/game/AGame.cpp index f8999bf..8841a7e 100644 --- a/games/common/game/AGame.cpp +++ b/games/common/game/AGame.cpp @@ -30,3 +30,7 @@ const unsigned int common::AGame::getFps() const noexcept { void common::AGame::_registerEntity(shared::games::entity::EntityPtr entity) { this->_entities.push_back(std::move(entity)); } + +const int common::AGame::getScore() const noexcept { + return this->_score; +} diff --git a/games/common/game/AGame.hpp b/games/common/game/AGame.hpp index db2dcd0..f7251fa 100644 --- a/games/common/game/AGame.hpp +++ b/games/common/game/AGame.hpp @@ -40,6 +40,13 @@ class arcade::games::common::AGame : public virtual shared::games::IGame { */ const unsigned int getFps() const noexcept override; + /** + * @brief Get the score of the game + * + * @return The score of the game + */ + const int getScore() const noexcept override; + protected: /** * @brief Construct a new AGame object @@ -64,6 +71,11 @@ class arcade::games::common::AGame : public virtual shared::games::IGame { */ unsigned int _fps; + /** + * @brief Game score + */ + int _score; + /** * @brief Add an entity to the game * diff --git a/graphics/common/events/mouse/AMouseButtonEvent.hpp b/graphics/common/events/mouse/AMouseButtonEvent.hpp index 0071cb0..41564a8 100644 --- a/graphics/common/events/mouse/AMouseButtonEvent.hpp +++ b/graphics/common/events/mouse/AMouseButtonEvent.hpp @@ -32,7 +32,7 @@ class arcade::graphics::common::events::AMouseButtonEvent: public AMouseEvent * @param button Targeted button */ explicit AMouseButtonEvent( - Vector2i pos, + Vector2f pos, MouseButton button ): AMouseEvent(pos), _button(button) {}; diff --git a/graphics/common/events/mouse/AMouseEvent.hpp b/graphics/common/events/mouse/AMouseEvent.hpp index 2bf413a..bb1bbbd 100644 --- a/graphics/common/events/mouse/AMouseEvent.hpp +++ b/graphics/common/events/mouse/AMouseEvent.hpp @@ -26,7 +26,7 @@ class arcade::graphics::common::events::AMouseEvent: public virtual IMouseEvent return T; } - const Vector2i getPosition() const noexcept override { + const Vector2f getPosition() const noexcept override { return _pos; } @@ -36,7 +36,7 @@ class arcade::graphics::common::events::AMouseEvent: public virtual IMouseEvent * * @param pos Position of the mouse */ - explicit AMouseEvent(Vector2i pos): _pos(pos){}; + explicit AMouseEvent(Vector2f pos): _pos(pos){}; - Vector2i _pos; + Vector2f _pos; }; diff --git a/graphics/common/events/mouse/MouseButtonPressEvent.hpp b/graphics/common/events/mouse/MouseButtonPressEvent.hpp index f2865c2..8a33b0e 100644 --- a/graphics/common/events/mouse/MouseButtonPressEvent.hpp +++ b/graphics/common/events/mouse/MouseButtonPressEvent.hpp @@ -19,6 +19,6 @@ namespace arcade::graphics::common::events { class arcade::graphics::common::events::MouseButtonPressEvent : public AMouseButtonEvent { public: - MouseButtonPressEvent(Vector2i pos, MouseButton button) : AMouseButtonEvent(pos, button){}; + MouseButtonPressEvent(Vector2f pos, MouseButton button) : AMouseButtonEvent(pos, button){}; ~MouseButtonPressEvent() override = default; }; diff --git a/graphics/common/events/mouse/MouseMoveEvent.hpp b/graphics/common/events/mouse/MouseMoveEvent.hpp index 76cefef..a2e9fe7 100644 --- a/graphics/common/events/mouse/MouseMoveEvent.hpp +++ b/graphics/common/events/mouse/MouseMoveEvent.hpp @@ -18,7 +18,7 @@ namespace arcade::graphics::common::events { class arcade::graphics::common::events::MouseMoveEvent: public AMouseEvent { public: - explicit MouseMoveEvent(const Vector2i pos): AMouseEvent(pos) {} + explicit MouseMoveEvent(const Vector2f pos): AMouseEvent(pos) {} ~MouseMoveEvent() override = default; }; diff --git a/graphics/sfml/src/window/EventsHandler.cpp b/graphics/sfml/src/window/EventsHandler.cpp index d499aa3..ccef122 100644 --- a/graphics/sfml/src/window/EventsHandler.cpp +++ b/graphics/sfml/src/window/EventsHandler.cpp @@ -207,9 +207,9 @@ EventPtr EventsHandler::_handleMouseButtonPressEvent( sf::Event &event, Window &window ) { - Vector2i pos = window.mapPositionToTile({ - event.mouseMove.x, - event.mouseMove.y + auto pos = window.mapPositionToTile({ + event.mouseButton.x, + event.mouseButton.y }); if (pos.x < 0 || pos.y < 0) diff --git a/graphics/sfml/src/window/Renderer.cpp b/graphics/sfml/src/window/Renderer.cpp index 5b93ce3..c2b78d1 100644 --- a/graphics/sfml/src/window/Renderer.cpp +++ b/graphics/sfml/src/window/Renderer.cpp @@ -125,7 +125,7 @@ void Renderer::_reset(sf::Sprite &sprite) { sprite.setOrigin(0, 0); } -Vector2f Renderer::_entityPixels(const Vector2i &position) { +Vector2f Renderer::_entityPixels(const Vector2f &position) { auto realSize = this->_window.getSize(); Vector2u originalPixels = this->_window.getPixelSizeFromTiles(realSize); diff --git a/graphics/sfml/src/window/Renderer.hpp b/graphics/sfml/src/window/Renderer.hpp index f7db849..6229b2d 100644 --- a/graphics/sfml/src/window/Renderer.hpp +++ b/graphics/sfml/src/window/Renderer.hpp @@ -60,7 +60,7 @@ class arcade::graphics::sfml::window::Renderer { * @param position Tile position * @return Pixel position */ - Vector2f _entityPixels(const Vector2i &position); + Vector2f _entityPixels(const Vector2f &position); /** * @brief Convert a tile size to pixel size diff --git a/graphics/sfml/src/window/Window.cpp b/graphics/sfml/src/window/Window.cpp index 68477f3..002d0a2 100644 --- a/graphics/sfml/src/window/Window.cpp +++ b/graphics/sfml/src/window/Window.cpp @@ -150,7 +150,7 @@ Vector2u Window::getPixelSizeFromTiles(const Vector2u &size) { return real; } -Vector2i Window::mapPositionToTile(const Vector2i &position) const { +Vector2f Window::mapPositionToTile(const Vector2i &position) const { auto pixelsPosition = _window.mapPixelToCoords({ position.x, position.y @@ -165,10 +165,7 @@ Vector2i Window::mapPositionToTile(const Vector2i &position) const { if (tilesPosition.x >= size.x || tilesPosition.y >= size.y || pixelsPosition.x < 0) return {-1, -1}; - return { - static_cast(tilesPosition.x), - static_cast(tilesPosition.y) - }; + return tilesPosition; } void Window::onResize() diff --git a/graphics/sfml/src/window/Window.hpp b/graphics/sfml/src/window/Window.hpp index 6ac8d02..78542a7 100644 --- a/graphics/sfml/src/window/Window.hpp +++ b/graphics/sfml/src/window/Window.hpp @@ -137,7 +137,7 @@ class arcade::graphics::sfml::window::Window: public shared::graphics::IWindow { * @brief Convert a position in pixels to a position in tiles * @return Converted position */ - Vector2i mapPositionToTile(const Vector2i &pixelsPosition) const; + Vector2f mapPositionToTile(const Vector2i &pixelsPosition) const; /** * @brief Get the size of a tile diff --git a/shared/games/IGame.hpp b/shared/games/IGame.hpp index bd684c8..956baab 100644 --- a/shared/games/IGame.hpp +++ b/shared/games/IGame.hpp @@ -62,4 +62,11 @@ class shared::games::IGame * @return Entities map of the game */ virtual const entity::EntitiesMap &getEntities(void) const = 0; + + /** + * @brief Get the score of the game + * + * @return The score of the game + */ + virtual const int getScore() const noexcept = 0; }; diff --git a/shared/games/components/IPositionableComponent.hpp b/shared/games/components/IPositionableComponent.hpp index 6eac1cc..8cf9edb 100644 --- a/shared/games/components/IPositionableComponent.hpp +++ b/shared/games/components/IPositionableComponent.hpp @@ -23,7 +23,7 @@ class shared::games::components::IPositionableComponent: public virtual ICompone * @brief Get position of the entity (tiles) * */ - virtual types::Vector2i &getPosition() noexcept = 0; + virtual types::Vector2f &getPosition() noexcept = 0; /** * @brief Get size of the entity (tiles) diff --git a/shared/graphics/events/IMouseEvent.hpp b/shared/graphics/events/IMouseEvent.hpp index 618e5fe..c8d6b03 100644 --- a/shared/graphics/events/IMouseEvent.hpp +++ b/shared/graphics/events/IMouseEvent.hpp @@ -23,5 +23,5 @@ class shared::graphics::events::IMouseEvent : public virtual IEvent { * * @return Position of the mouse */ - virtual const shared::types::Vector2i getPosition(void) const noexcept = 0; + virtual const shared::types::Vector2f getPosition(void) const noexcept = 0; }; diff --git a/shared/graphics/types/TextProps.hpp b/shared/graphics/types/TextProps.hpp index 9f01dc9..d405473 100644 --- a/shared/graphics/types/TextProps.hpp +++ b/shared/graphics/types/TextProps.hpp @@ -37,6 +37,6 @@ namespace shared::graphics { TextVerticalAlign verticalAlign; // Vertical alignment of the text types::Color color; // Color of the text Vector2u size; // Size of the entity - Vector2i position; // Position of the entity + Vector2f position; // Position of the entity } TextProps; } diff --git a/shared/graphics/types/TextureProps.hpp b/shared/graphics/types/TextureProps.hpp index 5847f37..5d72157 100644 --- a/shared/graphics/types/TextureProps.hpp +++ b/shared/graphics/types/TextureProps.hpp @@ -20,6 +20,6 @@ namespace shared::graphics { Vector2f binTileSize; // Size of a binary tile Vector2u origin; // Origin of the texture Vector2u size; // Size of the entity - Vector2i position; // Position of the entity + Vector2f position; // Position of the entity } TextureProps; } From 68f12a70a0a2fdc57b5ee8fa6b07f81df95e5151 Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 5 Apr 2024 13:07:17 +0200 Subject: [PATCH 07/18] feat(core): add lib switch on run time --- core/src/Core.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++++++- core/src/Core.hpp | 21 ++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/core/src/Core.cpp b/core/src/Core.cpp index 4ebfcca..e9e7205 100644 --- a/core/src/Core.cpp +++ b/core/src/Core.cpp @@ -25,12 +25,20 @@ Core::~Core() {} void Core::_initGame() { + if (!this->_gameProvider) { + if (this->_gameProviders.empty()) + throw ArcadeError("No game provider available"); + this->_gameProvider = this->_gameProviders.at(0); + std::cout << "No game provider selected, using default provider" << std::endl; + } this->_game = this->_gameProvider->createInstance(); this->_sceneStage = RESUME; } void Core::_initWindow() { + if (!this->_game) + this->_initGame(); auto gameManifest = this->_game->getManifest(); IWindow::WindowInitProps windowInitProps { this->_game->getSize(), @@ -40,6 +48,13 @@ void Core::_initWindow() gameManifest.iconPath }; + this->_handleWindowClose(); + if (!this->_graphicsProvider) { + if (this->_graphicsProviders.empty()) + throw ArcadeError("No graphic provider available"); + this->_graphicsProvider = this->_graphicsProviders.at(0); + std::cout << "No graphic provider selected, using default provider" << std::endl; + } this->_window = this->_graphicsProvider->createWindow(windowInitProps); this->_sceneStage = PLAY; } @@ -204,12 +219,55 @@ void Core::_preventWindowEvents(std::vector events) } } +void Core::_changeGraphicProvider(const unsigned char &index) +{ + if (index > this->_graphicsProviders.size() - 1) { + std::cout << "Invalid graphic provider index" << std::endl; + return; + } + auto newProvider = this->_graphicsProviders[index]; + if (newProvider == this->_graphicsProvider) + return; + this->_graphicsProvider = newProvider; + this->_initWindow(); +} + +void Core::_changeGameProvider(const unsigned char &index) +{ + if (index > this->_gameProviders.size() - 1) { + std::cout << "Invalid game provider index" << std::endl; + return; + } + auto newProvider = this->_gameProviders[index]; + if (newProvider == this->_gameProvider) + return; + this->_gameProvider = newProvider; + this->_initGame(); + this->_initWindow(); +} + +void Core::_handleFunctionKeys(std::shared_ptr &keyEvent) +{ + auto keyCode = keyEvent->getKeyCode(); + auto keyType = keyEvent->getKeyType(); + + if (keyType == events::IKeyEvent::FUNC) { + if (keyCode.func <= 6) + this->_changeGameProvider(keyCode.func - 1); + else if (keyCode.func >= 7 && keyCode.func <= 12) + this->_changeGraphicProvider(keyCode.func - 7); + else + std::cout << "Invalid function key" << std::endl; + } +} + void Core::_handleKeyPress(std::shared_ptr &keyEvent, std::shared_ptr &keyboard) { auto keyCode = keyEvent->getKeyCode(); auto keyType = keyEvent->getKeyType(); auto keyCodeData = this->_convertKeyPressData(keyType, keyCode); + this->_handleFunctionKeys(keyEvent); keyboard->onKeyPress(this->_game, keyCodeData); } @@ -259,7 +317,8 @@ void Core::_handleMouseMove(std::shared_ptr &event, std::sh void Core::_handleWindowClose() { - this->_window->close(); + if (this->_window && this->_window->isOpen()) + this->_window->close(); } void Core::_handleWindowResize() diff --git a/core/src/Core.hpp b/core/src/Core.hpp index 614d2ed..1b135db 100644 --- a/core/src/Core.hpp +++ b/core/src/Core.hpp @@ -260,6 +260,27 @@ class Core { */ void _handleKeyRelease(std::shared_ptr &event); + /** + * @brief Handle the function keys + * + * @param event The key event + */ + void _handleFunctionKeys(std::shared_ptr &event); + + /** + * @brief Change the graphic provider + * + * @param index The index of the graphic provider + */ + void _changeGraphicProvider(const unsigned char &index); + + /** + * @brief Change the game provider + * + * @param index The index of the game provider + */ + void _changeGameProvider(const unsigned char &index); + /** * @brief Convert the key press data * From 4a8aa6a4ce650ee23fbf853ee63d3f5e0f1740e3 Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 5 Apr 2024 13:43:11 +0200 Subject: [PATCH 08/18] refactor(core): change array providers to map --- core/src/Core.cpp | 28 +++++++++++++++++++++++++--- core/src/Core.hpp | 16 ++++++++++++++++ core/src/loader/Loader.cpp | 4 ++-- core/src/menu/Menu.cpp | 32 +++++++++++++++++++++++++------- core/src/menu/Menu.hpp | 23 +++++++++++++++++++++++ core/src/types/Providers.hpp | 5 +++-- 6 files changed, 94 insertions(+), 14 deletions(-) diff --git a/core/src/Core.cpp b/core/src/Core.cpp index e9e7205..6a86043 100644 --- a/core/src/Core.cpp +++ b/core/src/Core.cpp @@ -23,6 +23,28 @@ Core::Core(GameProviders &gameProviders, GraphicsProviders &graphicsProviders) : Core::~Core() {} +std::shared_ptr Core::_getGameProvider(const unsigned char &index) +{ + if (index > this->_gameProviders.size() - 1) { + std::cout << "Invalid game provider index" << std::endl; + return nullptr; + } + auto it = this->_gameProviders.begin(); + std::advance(it, index); + return it->second; +} + +std::shared_ptr Core::_getGraphicsProvider(const unsigned char &index) +{ + if (index > this->_graphicsProviders.size() - 1) { + std::cout << "Invalid game provider index" << std::endl; + return nullptr; + } + auto it = this->_graphicsProviders.begin(); + std::advance(it, index); + return it->second; +} + void Core::_initGame() { if (!this->_gameProvider) { @@ -225,7 +247,7 @@ void Core::_changeGraphicProvider(const unsigned char &index) std::cout << "Invalid graphic provider index" << std::endl; return; } - auto newProvider = this->_graphicsProviders[index]; + auto newProvider = this->_getGraphicsProvider(index); if (newProvider == this->_graphicsProvider) return; this->_graphicsProvider = newProvider; @@ -238,7 +260,7 @@ void Core::_changeGameProvider(const unsigned char &index) std::cout << "Invalid game provider index" << std::endl; return; } - auto newProvider = this->_gameProviders[index]; + auto newProvider = this->_getGameProvider(index); if (newProvider == this->_gameProvider) return; this->_gameProvider = newProvider; @@ -464,7 +486,7 @@ void Core::run() auto previousTime = std::chrono::high_resolution_clock::now(); this->_menu.run(); - if (!this->_gameProvider || !this->_graphicsProvider) + if (this->_sceneStage == EXIT) return; this->_initGame(); this->_initWindow(); diff --git a/core/src/Core.hpp b/core/src/Core.hpp index 1b135db..2622c19 100644 --- a/core/src/Core.hpp +++ b/core/src/Core.hpp @@ -296,4 +296,20 @@ class Core { * @param event The mouse button event */ void _handleSoundComponent(std::shared_ptr &component); + + /** + * @brief Get the game provider + * + * @param index The index of the game provider + * @return The game provider + */ + std::shared_ptr _getGameProvider(const unsigned char &index); + + /** + * @brief Get the graphic provider + * + * @param index The index of the graphic provider + * @return The graphic provider + */ + std::shared_ptr _getGraphicsProvider(const unsigned char &index); }; diff --git a/core/src/loader/Loader.cpp b/core/src/loader/Loader.cpp index 09c0e4a..b8df718 100644 --- a/core/src/loader/Loader.cpp +++ b/core/src/loader/Loader.cpp @@ -27,7 +27,7 @@ void Loader::_loadGameLibrary(const std::string &filepath, std::shared_ptrloadSymbol(SHARED_STRINGIFY(SHARED_GAME_PROVIDER_GETTER_NAME)); - this->_gamesLibraries.push_back(std::unique_ptr(game())); + this->_gamesLibraries.insert({filepath, std::shared_ptr(game())}); this->_libraries.push_back(dlLoader); } @@ -35,7 +35,7 @@ void Loader::_loadGraphicsLibrary(const std::string &filepath, std::shared_ptrloadSymbol(SHARED_STRINGIFY(SHARED_GRAPHICS_PROVIDER_GETTER_NAME)); - this->_graphicsLibraries.push_back(std::unique_ptr(graphics())); + this->_graphicsLibraries.insert({filepath, std::shared_ptr(graphics())}); this->_libraries.push_back(dlLoader); } diff --git a/core/src/menu/Menu.cpp b/core/src/menu/Menu.cpp index 2ad8cb0..1cadfe4 100644 --- a/core/src/menu/Menu.cpp +++ b/core/src/menu/Menu.cpp @@ -15,6 +15,24 @@ Menu::Menu(GameProviders &gameProviders, GraphicsProviders &graphicsProviders, Menu::~Menu() {} +std::shared_ptr &Menu::_getGameProvider(const unsigned char &index) +{ + if (index > this->_gameProviders.size() - 1) + throw ArcadeError("Invalid game provider index"); + auto it = this->_gameProviders.begin(); + std::advance(it, index); + return it->second; +} + +std::shared_ptr &Menu::_getGraphicsProvider(const unsigned char &index) +{ + if (index > this->_graphicsProviders.size() - 1) + throw ArcadeError("Invalid graphics provider index"); + auto it = this->_graphicsProviders.begin(); + std::advance(it, index); + return it->second; +} + std::string Menu::_truncString(const std::string &str, int size) { auto strPadding = size - static_cast(str.size()); @@ -64,13 +82,13 @@ void Menu::_initCheckBoxes() float index = 8.0; for (auto gameProvider : this->_gameProviders) { - auto marginRight = 23 - static_cast(gameProvider->getManifest().name.size()); - std::string truncatedName = gameProvider->getManifest().name.substr(0, 20); + auto marginRight = 23 - static_cast(gameProvider.second->getManifest().name.size()); + std::string truncatedName = gameProvider.second->getManifest().name.substr(0, 20); if (marginRight < 0) { truncatedName += "..."; marginRight = 0; } else { - truncatedName = gameProvider->getManifest().name; + truncatedName = gameProvider.second->getManifest().name; marginRight -= 3; } auto textCheckBox = std::make_shared(font, 10, truncatedName, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{20, 1}, Vector2f{3 + marginRight, index}); @@ -79,7 +97,7 @@ void Menu::_initCheckBoxes() this->_texts.push_back(textCheckBox); this->_textures.push_back(textureCheckBox); this->_gamesCheckBoxes.push_back(checkBox); - this->_initHiddenTextures(gameProvider->getManifest(), checkBox, font); + this->_initHiddenTextures(gameProvider.second->getManifest(), checkBox, font); index += 2; } } @@ -121,7 +139,7 @@ void Menu::_initWindow() if (!this->_graphicsProvider) { if (this->_graphicsProviders.empty()) throw ArcadeError("No graphics provider found"); - this->_graphicsProvider = this->_graphicsProviders.at(0); + this->_graphicsProvider = this->_getGraphicsProvider(0); std::cout << "No graphics provider found, using default provider" << std::endl; } this->_initTexts(); @@ -203,7 +221,7 @@ void Menu::_exitWithNewGame() { for (auto checkBox : this->_gamesCheckBoxes) { if (checkBox->isChecked()) { - this->_gameProvider = this->_gameProviders.at(std::distance(this->_gamesCheckBoxes.begin(), std::find(this->_gamesCheckBoxes.begin(), this->_gamesCheckBoxes.end(), checkBox))); + this->_gameProvider = this->_getGameProvider(std::distance(this->_gamesCheckBoxes.begin(), std::find(this->_gamesCheckBoxes.begin(), this->_gamesCheckBoxes.end(), checkBox))); break; } } @@ -298,7 +316,7 @@ void Menu::_render() void Menu::_previousSelectedGame() { for (auto gameProvider : this->_gameProviders) { - if (this->_gameProvider == gameProvider) { + if (this->_gameProvider == gameProvider.second) { auto index = std::distance(this->_gameProviders.begin(), std::find(this->_gameProviders.begin(), this->_gameProviders.end(), gameProvider)); auto checkBox = this->_gamesCheckBoxes.at(index); checkBox->check(); diff --git a/core/src/menu/Menu.hpp b/core/src/menu/Menu.hpp index f085f0c..2cbbb32 100644 --- a/core/src/menu/Menu.hpp +++ b/core/src/menu/Menu.hpp @@ -151,5 +151,28 @@ class Menu { */ void _previousSelectedGame(); + /** + * @brief Truncate a string + * + * @param str + * @param size + * @return std::string + */ std::string _truncString(const std::string &str, int size); + + /** + * @brief Get the game provider object + * + * @param index + * @return std::shared_ptr + */ + std::shared_ptr& _getGameProvider(const unsigned char &index); + + /** + * @brief Get the graphics provider object + * + * @param index + * @return std::shared_ptr + */ + std::shared_ptr& _getGraphicsProvider(const unsigned char &index); }; diff --git a/core/src/types/Providers.hpp b/core/src/types/Providers.hpp index 518f976..f0c757a 100644 --- a/core/src/types/Providers.hpp +++ b/core/src/types/Providers.hpp @@ -7,7 +7,8 @@ #pragma once +#include #include "shared/types/Libraries.hpp" -typedef std::vector> GameProviders; -typedef std::vector> GraphicsProviders; +typedef std::map> GameProviders; +typedef std::map> GraphicsProviders; From f83c399d3c2c64e8bbbce643c3a0a67a12be8ae6 Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 5 Apr 2024 14:04:30 +0200 Subject: [PATCH 09/18] feat(core): project params --- core/main.cpp | 18 ++++++++++++++---- core/src/menu/Menu.cpp | 30 ++++++++++++++++++++---------- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/core/main.cpp b/core/main.cpp index db25d09..04359e2 100644 --- a/core/main.cpp +++ b/core/main.cpp @@ -8,18 +8,28 @@ #include "Core.hpp" #include "loader/Loader.hpp" -int main(void) +int main(int ac, char **av) { Loader loader; + if (ac != 2) { + std::cerr << "Usage: ./arcade path_to_lib" << std::endl; + return 84; + } try { loader.loadLibraries("./lib"); - std::cout << "Games libraries:" << loader.getGamesLibraries().size() << std::endl; - std::cout << "Graphics libraries:" << loader.getGraphicsLibraries().size() << std::endl; - Core core(loader.getGamesLibraries(), loader.getGraphicsLibraries()); + auto &games = loader.getGamesLibraries(); + auto &graphics = loader.getGraphicsLibraries(); + auto it = graphics.find(av[1]); + if (it == graphics.end()) { + std::cerr << "Game library not found" << std::endl; + return 84; + } + Core core(games, graphics); core.run(); } catch (const std::exception &e) { std::cerr << e.what() << std::endl; + return 84; } return 0; } diff --git a/core/src/menu/Menu.cpp b/core/src/menu/Menu.cpp index 1cadfe4..1c8c151 100644 --- a/core/src/menu/Menu.cpp +++ b/core/src/menu/Menu.cpp @@ -108,19 +108,27 @@ void Menu::_initTextures() this->_textures.push_back(std::make_shared(backgroundTexture, Vector2f{12, 12}, Vector2u{0, 0}, Vector2u{50, 25}, Vector2f{0, 0})); auto titleTexture = this->_graphicsProvider->createTexture("assets/menu/img/title.png", "assets/menu/img/title.ascii"); this->_textures.push_back(std::make_shared(titleTexture, Vector2f{17, 17}, Vector2u{0, 0}, Vector2u{31, 5}, Vector2f{10, 1})); - auto middleTexture = this->_graphicsProvider->createTexture("assets/menu/img/middle.png", "assets/menu/img/middle.ascii"); - this->_textures.push_back(std::make_shared(middleTexture, Vector2f{12, 12}, Vector2u{0, 0}, Vector2u{1, 17}, Vector2f{24, 7})); + + if (!this->_gameProviders.empty()) { + auto middleTexture = this->_graphicsProvider->createTexture("assets/menu/img/middle.png", "assets/menu/img/middle.ascii"); + this->_textures.push_back(std::make_shared(middleTexture, Vector2f{12, 12}, Vector2u{0, 0}, Vector2u{1, 17}, Vector2f{24, 7})); + } } void Menu::_initTexts() { auto font = this->_graphicsProvider->createFont("assets/menu/fonts/arcade.ttf"); - auto score = std::make_shared(font, 10, "HI-SCORE", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 12}); - this->_texts.push_back(score); + if (!this->_gameProviders.empty()) { + auto score = std::make_shared(font, 10, "HI-SCORE", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 12}); + this->_texts.push_back(score); - auto authors = std::make_shared(font, 8, "Authors:", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 14}); - this->_texts.push_back(authors); + auto authors = std::make_shared(font, 8, "Authors:", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 14}); + this->_texts.push_back(authors); + } else { + auto noGames = std::make_shared(font, 12, "NO GAMES FOUND !", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{15, 1}, Vector2f{17, 12}); + this->_texts.push_back(noGames); + } } void Menu::_initWindow() @@ -324,10 +332,12 @@ void Menu::_previousSelectedGame() return; } } - if (this->_gamesCheckBoxes.empty()) - throw ArcadeError("No games found"); - this->_gamesCheckBoxes.at(0)->check(); - this->_gamesCheckBoxes.at(0)->hover(); + if (!this->_gamesCheckBoxes.empty()) { + this->_gamesCheckBoxes.at(0)->check(); + this->_gamesCheckBoxes.at(0)->hover(); + } else { + std::cout << "Can't select a previous game, no games found" << std::endl; + } } void Menu::run() From 780a7c7af08536a1223f49b9b2a7cbab0e085144 Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 5 Apr 2024 15:27:39 +0200 Subject: [PATCH 10/18] feat(core): handle properly not found textures or fonts --- core/src/Core.cpp | 62 ++++++++++++++++++++++++++------- core/src/Core.hpp | 26 ++++++++++++-- core/src/menu/Menu.cpp | 4 ++- games/pacman/src/PacmanGame.cpp | 4 +-- 4 files changed, 79 insertions(+), 17 deletions(-) diff --git a/core/src/Core.cpp b/core/src/Core.cpp index 6a86043..2732953 100644 --- a/core/src/Core.cpp +++ b/core/src/Core.cpp @@ -26,7 +26,7 @@ Core::~Core() {} std::shared_ptr Core::_getGameProvider(const unsigned char &index) { if (index > this->_gameProviders.size() - 1) { - std::cout << "Invalid game provider index" << std::endl; + std::cerr << "Invalid game provider index" << std::endl; return nullptr; } auto it = this->_gameProviders.begin(); @@ -37,7 +37,7 @@ std::shared_ptr Core::_getGameProvider(const unsigned char &index std::shared_ptr Core::_getGraphicsProvider(const unsigned char &index) { if (index > this->_graphicsProviders.size() - 1) { - std::cout << "Invalid game provider index" << std::endl; + std::cerr << "Invalid game provider index" << std::endl; return nullptr; } auto it = this->_graphicsProviders.begin(); @@ -50,7 +50,7 @@ void Core::_initGame() if (!this->_gameProvider) { if (this->_gameProviders.empty()) throw ArcadeError("No game provider available"); - this->_gameProvider = this->_gameProviders.at(0); + this->_gameProvider = this->_getGameProvider(0); std::cout << "No game provider selected, using default provider" << std::endl; } this->_game = this->_gameProvider->createInstance(); @@ -74,7 +74,7 @@ void Core::_initWindow() if (!this->_graphicsProvider) { if (this->_graphicsProviders.empty()) throw ArcadeError("No graphic provider available"); - this->_graphicsProvider = this->_graphicsProviders.at(0); + this->_graphicsProvider = this->_getGraphicsProvider(0); std::cout << "No graphic provider selected, using default provider" << std::endl; } this->_window = this->_graphicsProvider->createWindow(windowInitProps); @@ -83,6 +83,10 @@ void Core::_initWindow() std::shared_ptr Core::_getTexture(std::string bin, std::string ascii) { + for (auto &failedTexture : this->_failedTextures) { + if (failedTexture == bin + ascii) + return nullptr; + } if (this->_textures.find(bin + ascii) == this->_textures.end()) this->_textures[bin + ascii] = this->_graphicsProvider->createTexture(bin, ascii); return this->_textures[bin + ascii]; @@ -90,6 +94,10 @@ std::shared_ptr Core::_getTexture(std::string bin, std::string ascii) std::shared_ptr Core::_getFont(std::string path) { + for (auto &failedTexture : this->_failedTextures) { + if (failedTexture == path) + return nullptr; + } if (this->_fonts.find(path) == this->_fonts.end()) this->_fonts[path] = this->_graphicsProvider->createFont(path); return this->_fonts[path]; @@ -109,6 +117,22 @@ Core::SoundProps Core::_getSound(std::string path) return this->_sounds[path]; } +void Core::_loadFailed(std::shared_ptr texture) +{ + if (!texture) + return; + auto textureProps = texture->getTextureProps(); + this->_failedTextures.push_back(textureProps.sources.bin + textureProps.sources.ascii); +} + +void Core::_loadFailed(std::shared_ptr text) +{ + if (!text) + return; + auto textProps = text->getTextProps(); + this->_failedTextures.push_back(textProps.font.path); +} + TextureProps Core::_getTextureEntity(std::shared_ptr texture) { auto textureProps = texture->getTextureProps(); @@ -188,14 +212,28 @@ void Core::_renderEntities() auto components = entity->getComponents(); for (auto &component : components) { if (component->getType() == components::TEXTURE) { - auto texture = std::dynamic_pointer_cast(component); - unsigned int index = texture->getZIndex(); - entitiesTextureProps[index].push_back(this->_getTextureEntity(texture)); + try { + auto texture = std::dynamic_pointer_cast(component); + unsigned int index = texture->getZIndex(); + auto entityTextureProps = this->_getTextureEntity(texture); + if (entityTextureProps.texture) + entitiesTextureProps[index].push_back(entityTextureProps); + } catch (std::exception &e) { + std::cerr << e.what() << std::endl; + this->_loadFailed(std::dynamic_pointer_cast(component)); + } } if (component->getType() == components::TEXT) { - auto texture = std::dynamic_pointer_cast(component); - unsigned int index = texture->getZIndex(); - entitiesTextProps[index].push_back(this->_getTextEntity(texture)); + try { + auto text = std::dynamic_pointer_cast(component); + unsigned int index = text->getZIndex(); + auto entityTextProps = this->_getTextEntity(text); + if (entityTextProps.font) + entitiesTextProps[index].push_back(entityTextProps); + } catch (std::exception &e) { + std::cerr << e.what() << std::endl; + this->_loadFailed(std::dynamic_pointer_cast(component)); + } } } } @@ -279,7 +317,7 @@ void Core::_handleFunctionKeys(std::shared_ptr &keyEvent) else if (keyCode.func >= 7 && keyCode.func <= 12) this->_changeGraphicProvider(keyCode.func - 7); else - std::cout << "Invalid function key" << std::endl; + std::cerr << "Invalid function key" << std::endl; } } @@ -486,7 +524,7 @@ void Core::run() auto previousTime = std::chrono::high_resolution_clock::now(); this->_menu.run(); - if (this->_sceneStage == EXIT) + if (this->_sceneStage == EXIT || this->_sceneStage == RESUME) return; this->_initGame(); this->_initWindow(); diff --git a/core/src/Core.hpp b/core/src/Core.hpp index 2622c19..e35d21d 100644 --- a/core/src/Core.hpp +++ b/core/src/Core.hpp @@ -8,6 +8,7 @@ #pragma once #include +#include "menu/Menu.hpp" #include "types/Stages.hpp" #include "types/Providers.hpp" #include "shared/graphics/ISound.hpp" @@ -21,8 +22,6 @@ #include "shared/games/components/ICollidableComponent.hpp" #include "shared/games/components/ISoundComponent.hpp" -#include "menu/Menu.hpp" - using namespace shared::graphics; using namespace shared::games; @@ -45,12 +44,15 @@ class Core { components::SoundState previousGameState; } SoundProps; + int _playerScore; + std::string _playerName; std::shared_ptr _game; std::shared_ptr _window; std::shared_ptr _gameProvider; std::shared_ptr _graphicsProvider; std::map> _fonts; std::map> _textures; + std::vector _failedTextures; std::map _sounds; GameProviders &_gameProviders; GraphicsProviders &_graphicsProviders; @@ -76,6 +78,26 @@ class Core { */ void _renderEntities(); + /** + * @brief Save score + * + */ + void _saveScore(); + + /** + * @brief Load the failed texture + * + * @param texture The texture component + */ + void _loadFailed(std::shared_ptr texture); + + /** + * @brief Load the failed text + * + * @param text The text component + */ + void _loadFailed(std::shared_ptr text); + /** * @brief Get a texture * diff --git a/core/src/menu/Menu.cpp b/core/src/menu/Menu.cpp index 1c8c151..5582772 100644 --- a/core/src/menu/Menu.cpp +++ b/core/src/menu/Menu.cpp @@ -284,8 +284,10 @@ void Menu::_handleEvents() for (auto event : events) { auto type = event->getType(); - if (type == events::WINDOW_CLOSE) + if (type == events::WINDOW_CLOSE) { this->_window->close(); + this->_sceneStage = EXIT; + } if (type == events::KEY_PRESS) { auto key = std::dynamic_pointer_cast(event); this->_handleKeyboardEvents(key); diff --git a/games/pacman/src/PacmanGame.cpp b/games/pacman/src/PacmanGame.cpp index 82e0a3b..da5d9c5 100644 --- a/games/pacman/src/PacmanGame.cpp +++ b/games/pacman/src/PacmanGame.cpp @@ -16,8 +16,8 @@ using namespace arcade::games; const shared::games::GameManifest pacman::PacmanGame::manifest = { - .name = "pacman really really good good good game", - .description = "The pacman original game", + .name = "pacman", + .description = "Pacman original game", .version = "1.0.0", .authors = { { From 2108e022ace8fcd23c8aad3dbe3eec6093ff15ca Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 5 Apr 2024 16:27:12 +0200 Subject: [PATCH 11/18] feat(core): save score --- .gitignore | 1 + core/src/Core.cpp | 1 + core/src/Core.hpp | 8 ---- core/src/menu/Menu.cpp | 69 ++++++++++++++++++++++++++++++++- core/src/menu/Menu.hpp | 30 +++++++++++++- games/pacman/src/PacmanGame.cpp | 1 + games/snake/src/SnakeGame.cpp | 1 + 7 files changed, 100 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 07f96f0..4a7e5eb 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ lib *.gcno *.gcda *.o +*.txt diff --git a/core/src/Core.cpp b/core/src/Core.cpp index 2732953..8eed5dc 100644 --- a/core/src/Core.cpp +++ b/core/src/Core.cpp @@ -534,6 +534,7 @@ void Core::run() previousTime = currentTime; if (this->_sceneStage == MENU) { + this->_menu.updateScore(this->_game); this->_handleWindowClose(); this->_menu.run(); previousTime = std::chrono::high_resolution_clock::now(); diff --git a/core/src/Core.hpp b/core/src/Core.hpp index e35d21d..3400fb5 100644 --- a/core/src/Core.hpp +++ b/core/src/Core.hpp @@ -44,8 +44,6 @@ class Core { components::SoundState previousGameState; } SoundProps; - int _playerScore; - std::string _playerName; std::shared_ptr _game; std::shared_ptr _window; std::shared_ptr _gameProvider; @@ -78,12 +76,6 @@ class Core { */ void _renderEntities(); - /** - * @brief Save score - * - */ - void _saveScore(); - /** * @brief Load the failed texture * diff --git a/core/src/menu/Menu.cpp b/core/src/menu/Menu.cpp index 5582772..a06b18c 100644 --- a/core/src/menu/Menu.cpp +++ b/core/src/menu/Menu.cpp @@ -5,15 +5,25 @@ ** Menu */ +#include +#include #include #include "Menu.hpp" Menu::Menu(GameProviders &gameProviders, GraphicsProviders &graphicsProviders, std::shared_ptr &gameProvider, std::shared_ptr &graphicsProvider, arcade::core::SceneStage &sceneStage) : _gameProviders(gameProviders), _graphicsProviders(graphicsProviders), - _gameProvider(gameProvider), _graphicsProvider(graphicsProvider), _sceneStage(sceneStage) {} + _gameProvider(gameProvider), _graphicsProvider(graphicsProvider), _sceneStage(sceneStage) +{ + this->_score.player = "Player"; + this->_score.score = 0; + this->_readScores(); +} -Menu::~Menu() {} +Menu::~Menu() +{ + this->_writeScore(); +} std::shared_ptr &Menu::_getGameProvider(const unsigned char &index) { @@ -345,6 +355,7 @@ void Menu::_previousSelectedGame() void Menu::run() { this->_sceneStage = MENU; + this->_score.player = "Player"; this->_initWindow(); this->_previousSelectedGame(); while (this->_window->isOpen()) { @@ -352,3 +363,57 @@ void Menu::run() this->_render(); } } + +void Menu::_readScores() +{ + std::ifstream scoreFile("./scores.txt"); + + if (!scoreFile.is_open()) { + std::cout << "Can't open scores file" << std::endl; + return; + } + + std::string line; + std::getline(scoreFile, line); + + while (std::getline(scoreFile, line)) { + std::stringstream ss(line); + Score score; + ss >> score.game >> score.player >> score.score; + this->_scores.push_back(score); + } + scoreFile.close(); +} + +void Menu::_writeScore() +{ + std::ofstream scoreFile("./scores.txt"); + + if (!scoreFile.is_open()) { + std::cout << "Can't open scores file" << std::endl; + return; + } + + scoreFile << "Game\tPlayer\tScore" << std::endl; + for (auto score : this->_scores) { + scoreFile << score.game << "\t" << score.player << "\t" << score.score << std::endl; + } + scoreFile.close(); +} + +void Menu::updateScore(std::shared_ptr game) +{ + this->_score.game = game->getManifest().name; + this->_score.score = game->getScore(); + + std::cout << "Score: " << this->_score.score << std::endl; + for (auto &score : this->_scores) { + if (score.game == this->_score.game && score.player == this->_score.player) { + if (score.score < this->_score.score) + score.score = this->_score.score; + std::cout << "Score updated: " << score.score << std::endl; + return; + } + } + this->_scores.push_back(this->_score); +} diff --git a/core/src/menu/Menu.hpp b/core/src/menu/Menu.hpp index 2cbbb32..bc71ea8 100644 --- a/core/src/menu/Menu.hpp +++ b/core/src/menu/Menu.hpp @@ -38,9 +38,25 @@ class Menu { */ void run(); + /** + * @brief Update the score + * + * @param game Game + */ + void updateScore(std::shared_ptr game); + private: - std::shared_ptr _window; + + typedef struct { + std::string game; + std::string player; + int score; + } Score; + + Score _score; + std::vector _scores; SceneStage &_sceneStage; + std::shared_ptr _window; GameProviders &_gameProviders; GraphicsProviders &_graphicsProviders; std::shared_ptr &_gameProvider; @@ -175,4 +191,16 @@ class Menu { * @return std::shared_ptr */ std::shared_ptr& _getGraphicsProvider(const unsigned char &index); + + /** + * @brief Read the scores + * + */ + void _readScores(); + + /** + * @brief Write the scores + * + */ + void _writeScore(); }; diff --git a/games/pacman/src/PacmanGame.cpp b/games/pacman/src/PacmanGame.cpp index da5d9c5..b8ec2ab 100644 --- a/games/pacman/src/PacmanGame.cpp +++ b/games/pacman/src/PacmanGame.cpp @@ -101,4 +101,5 @@ void pacman::PacmanGame::addNewPoint() { this->_registerEntity(newTail); this->_apple->generateApple(); this->speedTime -= 2; + this->_score += 10; } diff --git a/games/snake/src/SnakeGame.cpp b/games/snake/src/SnakeGame.cpp index 0bd6501..b9f0b0a 100644 --- a/games/snake/src/SnakeGame.cpp +++ b/games/snake/src/SnakeGame.cpp @@ -101,4 +101,5 @@ void snake::SnakeGame::addNewPoint() { this->_registerEntity(newTail); this->_apple->generateApple(); this->speedTime -= 2; + this->_score += 10; } From 1fff82678e1d9066bf6a7a88de27166f4eb0604c Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 5 Apr 2024 17:19:54 +0200 Subject: [PATCH 12/18] feat(core): add score board --- core/src/menu/Menu.cpp | 87 +++++++++++++++++++++++++++++------------- core/src/menu/Menu.hpp | 17 ++++++++- 2 files changed, 77 insertions(+), 27 deletions(-) diff --git a/core/src/menu/Menu.cpp b/core/src/menu/Menu.cpp index a06b18c..ac4a494 100644 --- a/core/src/menu/Menu.cpp +++ b/core/src/menu/Menu.cpp @@ -15,9 +15,10 @@ Menu::Menu(GameProviders &gameProviders, GraphicsProviders &graphicsProviders, _gameProviders(gameProviders), _graphicsProviders(graphicsProviders), _gameProvider(gameProvider), _graphicsProvider(graphicsProvider), _sceneStage(sceneStage) { - this->_score.player = "Player"; + this->_score.player = "Player2"; this->_score.score = 0; this->_readScores(); + this->_textType = GAME; } Menu::~Menu() @@ -55,7 +56,25 @@ std::string Menu::_truncString(const std::string &str, int size) return newString; } -void Menu::_initHiddenTextures(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) +void Menu::_initHiddenAuthors(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) +{ + auto authorNames = std::make_shared(font, 8, "Authors:", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 8}); + this->_hiddenAuthors[checkBox].push_back(authorNames); + + auto authors = gameManifest.authors; + float index = 10.0; + for (auto author : authors) { + auto authorNameText = std::make_shared(font, 7, this->_truncString(author.name, 22) , TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index}); + auto authorMailText = std::make_shared(font, 7, this->_truncString(author.email, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index + 1}); + auto authorSiteText = std::make_shared(font, 7, this->_truncString(author.website, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index + 2}); + this->_hiddenAuthors[checkBox].push_back(authorNameText); + this->_hiddenAuthors[checkBox].push_back(authorMailText); + this->_hiddenAuthors[checkBox].push_back(authorSiteText); + index += 4; + } +} + +void Menu::_initHiddenScore(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) { auto truncatName = this->_truncString(gameManifest.name, 23); auto nameText = std::make_shared(font, 11, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 8}); @@ -65,26 +84,37 @@ void Menu::_initHiddenTextures(const GameManifest &gameManifest, std::shared_ptr auto descriptionText = std::make_shared(font, 9, truncatDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 10}); this->_hiddenTexts[checkBox].push_back(descriptionText); - int score = 154; - auto scoreString = std::to_string(score); + auto scoreHI = std::make_shared(font, 10, "HI-SCORE", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 12}); + this->_hiddenTexts[checkBox].push_back(scoreHI); + + auto score = 0; + for (auto &scoreElem : this->_scores) { + if (scoreElem.game == gameManifest.name && scoreElem.score > score) + score = scoreElem.score; + } + auto scoreString = std::to_string(score).substr(0, 5); while (scoreString.length() < 5) scoreString = "0" + scoreString; auto scoreText = std::make_shared(font, 10, scoreString, TextAlign::RIGHT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{14, 1}, Vector2f{34, 12}); this->_hiddenTexts[checkBox].push_back(scoreText); - auto authors = gameManifest.authors; - float index = 15.0; - for (auto author : authors) { - auto authorNameText = std::make_shared(font, 7, this->_truncString(author.name, 22) , TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index}); - auto authorMailText = std::make_shared(font, 7, this->_truncString(author.email, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index + 1}); - auto authorSiteText = std::make_shared(font, 7, this->_truncString(author.website, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index + 2}); - this->_hiddenTexts[checkBox].push_back(authorNameText); - this->_hiddenTexts[checkBox].push_back(authorMailText); - this->_hiddenTexts[checkBox].push_back(authorSiteText); - index += 4; + float index = 14; + for (auto &scoreElem : this->_scores) { + if (scoreElem.game == gameManifest.name) { + auto truncatPlayer = this->_truncString(scoreElem.player, 17); + auto playerText = std::make_shared(font, 8, truncatPlayer, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{17, 1}, Vector2f{26, index}); + auto scoreString = std::to_string(scoreElem.score).substr(0, 5); + while (scoreString.length() < 5) + scoreString = "0" + scoreString; + auto scoreText = std::make_shared(font, 8, scoreString, TextAlign::RIGHT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{5, 1}, Vector2f{43, index}); + this->_hiddenTexts[checkBox].push_back(playerText); + this->_hiddenTexts[checkBox].push_back(scoreText); + index += 1; + } } } + void Menu::_initCheckBoxes() { auto texture = this->_graphicsProvider->createTexture("assets/menu/img/space-invader.png", "assets/menu/img/space-invader.ascii"); @@ -107,7 +137,8 @@ void Menu::_initCheckBoxes() this->_texts.push_back(textCheckBox); this->_textures.push_back(textureCheckBox); this->_gamesCheckBoxes.push_back(checkBox); - this->_initHiddenTextures(gameProvider.second->getManifest(), checkBox, font); + this->_initHiddenAuthors(gameProvider.second->getManifest(), checkBox, font); + this->_initHiddenScore(gameProvider.second->getManifest(), checkBox, font); index += 2; } } @@ -129,13 +160,7 @@ void Menu::_initTexts() { auto font = this->_graphicsProvider->createFont("assets/menu/fonts/arcade.ttf"); - if (!this->_gameProviders.empty()) { - auto score = std::make_shared(font, 10, "HI-SCORE", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 12}); - this->_texts.push_back(score); - - auto authors = std::make_shared(font, 8, "Authors:", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 14}); - this->_texts.push_back(authors); - } else { + if (this->_gameProviders.empty()) { auto noGames = std::make_shared(font, 12, "NO GAMES FOUND !", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{15, 1}, Vector2f{17, 12}); this->_texts.push_back(noGames); } @@ -151,6 +176,8 @@ void Menu::_initWindow() .icon = "assets/menu/img/icon.png" }; + this->_hiddenAuthors.clear(); + this->_hiddenTexts.clear(); this->_texts.clear(); this->_textures.clear(); this->_gamesCheckBoxes.clear(); @@ -208,6 +235,10 @@ void Menu::_handleKeyboardEvents(std::shared_ptr key) this->_handleSelectLowerCheckBox(); if (code.arrow == events::IKeyEvent::ArrowCode::UP) this->_handleSelectUpperCheckBox(); + if (code.arrow == events::IKeyEvent::ArrowCode::RIGHT) + this->_textType = AUTHOR; + if (code.arrow == events::IKeyEvent::ArrowCode::LEFT) + this->_textType = GAME; } if (type == events::IKeyEvent::KeyType::CHAR) { if (code.character == '\n') @@ -325,8 +356,14 @@ void Menu::_render() } for (auto checkBox : this->_gamesCheckBoxes) { if (checkBox->isHovered()) { - for (auto text : this->_hiddenTexts[checkBox]) { - text->draw(this->_window); + if (this->_textType == GAME) { + for (auto text : this->_hiddenTexts[checkBox]) { + text->draw(this->_window); + } + } else { + for (auto text : this->_hiddenAuthors[checkBox]) { + text->draw(this->_window); + } } } } @@ -406,12 +443,10 @@ void Menu::updateScore(std::shared_ptr game) this->_score.game = game->getManifest().name; this->_score.score = game->getScore(); - std::cout << "Score: " << this->_score.score << std::endl; for (auto &score : this->_scores) { if (score.game == this->_score.game && score.player == this->_score.player) { if (score.score < this->_score.score) score.score = this->_score.score; - std::cout << "Score updated: " << score.score << std::endl; return; } } diff --git a/core/src/menu/Menu.hpp b/core/src/menu/Menu.hpp index bc71ea8..632fc68 100644 --- a/core/src/menu/Menu.hpp +++ b/core/src/menu/Menu.hpp @@ -53,6 +53,12 @@ class Menu { int score; } Score; + typedef enum { + GAME, + AUTHOR, + } TextType; + + TextType _textType; Score _score; std::vector _scores; SceneStage &_sceneStage; @@ -65,6 +71,7 @@ class Menu { std::vector> _texts; std::vector> _textures; std::map, std::vector>> _hiddenTexts; + std::map, std::vector>> _hiddenAuthors; /** * @brief Initialize the window @@ -153,7 +160,15 @@ class Menu { * @param gameManifest GameManifest * @param checkBox CheckBox */ - void _initHiddenTextures(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font); + void _initHiddenAuthors(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font); + + /** + * @brief Initialize hidden texts + * + * @param gameManifest GameManifest + * @param checkBox CheckBox + */ + void _initHiddenScore(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font); /** * @brief Initialize texts From 88fac3890f21fad0522924ff03306003765a5fad Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 5 Apr 2024 17:56:52 +0200 Subject: [PATCH 13/18] feat(core): add field name input --- assets/menu/img/middle.ascii | 2 -- core/main.cpp | 2 +- core/src/Core.cpp | 6 +++++- core/src/Core.hpp | 2 +- core/src/menu/Menu.cpp | 31 +++++++++++++++++++++++++------ core/src/menu/Menu.hpp | 8 ++++++++ 6 files changed, 40 insertions(+), 11 deletions(-) diff --git a/assets/menu/img/middle.ascii b/assets/menu/img/middle.ascii index 3b0cec4..4d1261c 100644 --- a/assets/menu/img/middle.ascii +++ b/assets/menu/img/middle.ascii @@ -12,6 +12,4 @@ | | | -| -| | \ No newline at end of file diff --git a/core/main.cpp b/core/main.cpp index 04359e2..0e74932 100644 --- a/core/main.cpp +++ b/core/main.cpp @@ -25,7 +25,7 @@ int main(int ac, char **av) std::cerr << "Game library not found" << std::endl; return 84; } - Core core(games, graphics); + Core core(games, graphics, av[1]); core.run(); } catch (const std::exception &e) { std::cerr << e.what() << std::endl; diff --git a/core/src/Core.cpp b/core/src/Core.cpp index 8eed5dc..dfa111a 100644 --- a/core/src/Core.cpp +++ b/core/src/Core.cpp @@ -12,13 +12,17 @@ #include "Core.hpp" #include "shared/games/components/IComponent.hpp" -Core::Core(GameProviders &gameProviders, GraphicsProviders &graphicsProviders) : +Core::Core(GameProviders &gameProviders, GraphicsProviders &graphicsProviders, const std::string &graphicNameProvider) : _gameProviders(gameProviders), _graphicsProviders(graphicsProviders), _menu(gameProviders, graphicsProviders, this->_gameProvider, this->_graphicsProvider, this->_sceneStage) { this->_sceneStage = MENU; this->_gameProvider = nullptr; this->_graphicsProvider = nullptr; + for (auto &gameProvider : this->_gameProviders) { + if (gameProvider.first == graphicNameProvider) + this->_gameProvider = gameProvider.second; + } } Core::~Core() {} diff --git a/core/src/Core.hpp b/core/src/Core.hpp index 3400fb5..2b467ec 100644 --- a/core/src/Core.hpp +++ b/core/src/Core.hpp @@ -27,7 +27,7 @@ using namespace shared::games; class Core { public: - Core(GameProviders &gameProviders, GraphicsProviders &graphicsProviders); + Core(GameProviders &gameProviders, GraphicsProviders &graphicsProviders, const std::string &graphicNameProvider); ~Core(); /** diff --git a/core/src/menu/Menu.cpp b/core/src/menu/Menu.cpp index ac4a494..53cadcf 100644 --- a/core/src/menu/Menu.cpp +++ b/core/src/menu/Menu.cpp @@ -15,7 +15,7 @@ Menu::Menu(GameProviders &gameProviders, GraphicsProviders &graphicsProviders, _gameProviders(gameProviders), _graphicsProviders(graphicsProviders), _gameProvider(gameProvider), _graphicsProvider(graphicsProvider), _sceneStage(sceneStage) { - this->_score.player = "Player2"; + this->_score.player = ""; this->_score.score = 0; this->_readScores(); this->_textType = GAME; @@ -152,7 +152,7 @@ void Menu::_initTextures() if (!this->_gameProviders.empty()) { auto middleTexture = this->_graphicsProvider->createTexture("assets/menu/img/middle.png", "assets/menu/img/middle.ascii"); - this->_textures.push_back(std::make_shared(middleTexture, Vector2f{12, 12}, Vector2u{0, 0}, Vector2u{1, 17}, Vector2f{24, 7})); + this->_textures.push_back(std::make_shared(middleTexture, Vector2f{12, 12}, Vector2u{0, 0}, Vector2u{1, 15}, Vector2f{24, 7})); } } @@ -160,6 +160,7 @@ void Menu::_initTexts() { auto font = this->_graphicsProvider->createFont("assets/menu/fonts/arcade.ttf"); + this->_font = font; if (this->_gameProviders.empty()) { auto noGames = std::make_shared(font, 12, "NO GAMES FOUND !", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{15, 1}, Vector2f{17, 12}); this->_texts.push_back(noGames); @@ -243,8 +244,12 @@ void Menu::_handleKeyboardEvents(std::shared_ptr key) if (type == events::IKeyEvent::KeyType::CHAR) { if (code.character == '\n') this->_selectGame(); - if (code.character == 27) + else if (code.character == 27) this->_exitAndPlayOldGame(); + else if (code.character == 8) + this->_score.player = this->_score.player.substr(0, this->_score.player.size() - 1); + else if (code.character >= 33 && code.character <= 126) + this->_score.player += code.character; } } @@ -341,10 +346,23 @@ void Menu::_handleEvents() auto mouse = std::dynamic_pointer_cast(event); this->_handleMouseButtonEvents(mouse); } - } } +void Menu::_renderField() +{ + if (this->_score.player.empty()) { + auto placeholder = std::make_shared(this->_font, 6, "As Guest", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{16, 1}, Vector2f{17, 23}); + this->_nameField = placeholder; + } else { + auto truncatName = this->_truncString(this->_score.player, 17); + auto name = std::make_shared(this->_font, 8, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{16, 1}, Vector2f{17, 23}); + this->_nameField = name; + } + if (this->_nameField) + this->_nameField->draw(this->_window); +} + void Menu::_render() { this->_window->clear(); @@ -367,6 +385,7 @@ void Menu::_render() } } } + this->_renderField(); this->_window->display(); } @@ -392,7 +411,6 @@ void Menu::_previousSelectedGame() void Menu::run() { this->_sceneStage = MENU; - this->_score.player = "Player"; this->_initWindow(); this->_previousSelectedGame(); while (this->_window->isOpen()) { @@ -444,7 +462,8 @@ void Menu::updateScore(std::shared_ptr game) this->_score.score = game->getScore(); for (auto &score : this->_scores) { - if (score.game == this->_score.game && score.player == this->_score.player) { + auto name = this->_score.player.empty() ? "Guest" : this->_score.player; + if (score.game == this->_score.game && score.player == name) { if (score.score < this->_score.score) score.score = this->_score.score; return; diff --git a/core/src/menu/Menu.hpp b/core/src/menu/Menu.hpp index 632fc68..cbdddb0 100644 --- a/core/src/menu/Menu.hpp +++ b/core/src/menu/Menu.hpp @@ -72,6 +72,8 @@ class Menu { std::vector> _textures; std::map, std::vector>> _hiddenTexts; std::map, std::vector>> _hiddenAuthors; + std::shared_ptr _font; + std::shared_ptr _nameField; /** * @brief Initialize the window @@ -85,6 +87,12 @@ class Menu { */ void _render(); + /** + * @brief Render the field name + * + */ + void _renderField(); + /** * @brief Handle events * From b349ad25872c3a5a3333a5618e7fa25375a6a9cb Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 5 Apr 2024 19:43:56 +0200 Subject: [PATCH 14/18] feat(core): add menu graphics lib selection --- core/src/menu/Menu.cpp | 200 ++++++++++++++++++++++++---- core/src/menu/Menu.hpp | 26 +++- core/src/menu/checkBox/CheckBox.cpp | 4 +- 3 files changed, 202 insertions(+), 28 deletions(-) diff --git a/core/src/menu/Menu.cpp b/core/src/menu/Menu.cpp index 53cadcf..f7a3f9f 100644 --- a/core/src/menu/Menu.cpp +++ b/core/src/menu/Menu.cpp @@ -114,14 +114,16 @@ void Menu::_initHiddenScore(const GameManifest &gameManifest, std::shared_ptr_graphicsProvider->createTexture("assets/menu/img/space-invader.png", "assets/menu/img/space-invader.ascii"); auto font = this->_graphicsProvider->createFont("assets/menu/fonts/arcade.ttf"); - float index = 8.0; + float index = 9.0; + int count = 0; for (auto gameProvider : this->_gameProviders) { + if (count > 5) + break; auto marginRight = 23 - static_cast(gameProvider.second->getManifest().name.size()); std::string truncatedName = gameProvider.second->getManifest().name.substr(0, 20); if (marginRight < 0) { @@ -131,7 +133,7 @@ void Menu::_initCheckBoxes() truncatedName = gameProvider.second->getManifest().name; marginRight -= 3; } - auto textCheckBox = std::make_shared(font, 10, truncatedName, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{20, 1}, Vector2f{3 + marginRight, index}); + auto textCheckBox = std::make_shared(font, 10, truncatedName, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{20 - static_cast(marginRight) - 1, 1}, Vector2f{3 + marginRight, index}); auto textureCheckBox = std::make_shared(texture, Vector2f{360, 360}, Vector2u{0, 0}, Vector2u{1, 1}, Vector2f{1 + marginRight, index}); auto checkBox = std::make_shared(textureCheckBox, textCheckBox); this->_texts.push_back(textCheckBox); @@ -139,7 +141,62 @@ void Menu::_initCheckBoxes() this->_gamesCheckBoxes.push_back(checkBox); this->_initHiddenAuthors(gameProvider.second->getManifest(), checkBox, font); this->_initHiddenScore(gameProvider.second->getManifest(), checkBox, font); - index += 2; + index += 1; + count += 1; + } +} + +void Menu::_initHiddenGraphics(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font) +{ + auto truncatName = this->_truncString(graphicsManifest.name, 23); + auto nameText = std::make_shared(font, 11, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 8}); + this->_hiddenTexts[checkBox].push_back(nameText); + + auto truncatDesc = this->_truncString(graphicsManifest.description, 23); + auto descriptionText = std::make_shared(font, 9, truncatDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 10}); + this->_hiddenTexts[checkBox].push_back(descriptionText); + + auto authors = graphicsManifest.authors; + float index = 12.0; + for (auto author : authors) { + auto authorNameText = std::make_shared(font, 7, this->_truncString(author.name, 23), TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, index}); + auto authorMailText = std::make_shared(font, 7, this->_truncString(author.email, 23), TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, index + 1}); + auto authorSiteText = std::make_shared(font, 7, this->_truncString(author.website, 23), TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, index + 2}); + this->_hiddenTexts[checkBox].push_back(authorNameText); + this->_hiddenTexts[checkBox].push_back(authorMailText); + this->_hiddenTexts[checkBox].push_back(authorSiteText); + index += 4; + } +} + +void Menu::_initCheckBoxesGraphics() +{ + auto texture = this->_graphicsProvider->createTexture("assets/menu/img/space-invader.png", "assets/menu/img/space-invader.ascii"); + auto font = this->_graphicsProvider->createFont("assets/menu/fonts/arcade.ttf"); + float index = 17.0; + int count = 0; + + for (auto graphicsProvider : this->_graphicsProviders) { + if (count > 5) + break; + auto marginRight = 23 - static_cast(graphicsProvider.second->getManifest().name.size()); + std::string truncatedName = graphicsProvider.second->getManifest().name.substr(0, 20); + if (marginRight < 0) { + truncatedName += "..."; + marginRight = 0; + } else { + truncatedName = graphicsProvider.second->getManifest().name; + marginRight -= 3; + } + auto textCheckBox = std::make_shared(font, 10, truncatedName, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{20 - static_cast(marginRight) - 1, 1}, Vector2f{3 + marginRight, index}); + auto textureCheckBox = std::make_shared(texture, Vector2f{360, 360}, Vector2u{0, 0}, Vector2u{1, 1}, Vector2f{1 + marginRight, index}); + auto checkBox = std::make_shared(textureCheckBox, textCheckBox); + this->_texts.push_back(textCheckBox); + this->_textures.push_back(textureCheckBox); + this->_graphicsCheckBoxes.push_back(checkBox); + this->_initHiddenGraphics(graphicsProvider.second->getManifest(), checkBox, font); + index += 1; + count += 1; } } @@ -164,6 +221,11 @@ void Menu::_initTexts() if (this->_gameProviders.empty()) { auto noGames = std::make_shared(font, 12, "NO GAMES FOUND !", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{15, 1}, Vector2f{17, 12}); this->_texts.push_back(noGames); + } else { + auto games = std::make_shared(font, 12, "Games", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{5, 1}, Vector2f{8, 7}); + this->_texts.push_back(games); + auto graphics = std::make_shared(font, 12, "Graphics", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{7, 15}); + this->_texts.push_back(graphics); } } @@ -182,6 +244,7 @@ void Menu::_initWindow() this->_texts.clear(); this->_textures.clear(); this->_gamesCheckBoxes.clear(); + this->_graphicsCheckBoxes.clear(); if (!this->_graphicsProvider) { if (this->_graphicsProviders.empty()) throw ArcadeError("No graphics provider found"); @@ -190,7 +253,8 @@ void Menu::_initWindow() } this->_initTexts(); this->_initTextures(); - this->_initCheckBoxes(); + this->_initCheckBoxesGames(); + this->_initCheckBoxesGraphics(); this->_window = this->_graphicsProvider->createWindow(windowInitProps); } @@ -200,10 +264,23 @@ void Menu::_handleSelectUpperCheckBox() if (checkBox->isHovered()) { checkBox->unhover(); auto index = std::distance(this->_gamesCheckBoxes.begin(), std::find(this->_gamesCheckBoxes.begin(), this->_gamesCheckBoxes.end(), checkBox)); - if (index == 0) - this->_gamesCheckBoxes.at(this->_gamesCheckBoxes.size() - 1)->hover(); - else + if (index != 0) this->_gamesCheckBoxes.at(index - 1)->hover(); + else + checkBox->hover(); + break; + } + } + for (auto checkBox : this->_graphicsCheckBoxes) { + if (checkBox->isHovered()) { + checkBox->unhover(); + auto index = std::distance(this->_graphicsCheckBoxes.begin(), std::find(this->_graphicsCheckBoxes.begin(), this->_graphicsCheckBoxes.end(), checkBox)); + if (index == 0) { + this->_gamesCheckBoxes.at(this->_gamesCheckBoxes.size() - 1)->hover(); + this->_textType = GAME; + } else { + this->_graphicsCheckBoxes.at(index - 1)->hover(); + } break; } } @@ -211,14 +288,27 @@ void Menu::_handleSelectUpperCheckBox() void Menu::_handleSelectLowerCheckBox() { + for (auto checkBox : this->_graphicsCheckBoxes) { + if (checkBox->isHovered()) { + checkBox->unhover(); + auto index = std::distance(this->_graphicsCheckBoxes.begin(), std::find(this->_graphicsCheckBoxes.begin(), this->_graphicsCheckBoxes.end(), checkBox)); + if (index != this->_graphicsCheckBoxes.size() - 1) + this->_graphicsCheckBoxes.at(index + 1)->hover(); + else + checkBox->hover(); + break; + } + } for (auto checkBox : this->_gamesCheckBoxes) { if (checkBox->isHovered()) { checkBox->unhover(); auto index = std::distance(this->_gamesCheckBoxes.begin(), std::find(this->_gamesCheckBoxes.begin(), this->_gamesCheckBoxes.end(), checkBox)); - if (index == this->_gamesCheckBoxes.size() - 1) - this->_gamesCheckBoxes.at(0)->hover(); - else + if (index == this->_gamesCheckBoxes.size() - 1) { + this->_graphicsCheckBoxes.at(0)->hover(); + this->_textType = GRAPHICS; + } else { this->_gamesCheckBoxes.at(index + 1)->hover(); + } break; } } @@ -248,20 +338,47 @@ void Menu::_handleKeyboardEvents(std::shared_ptr key) this->_exitAndPlayOldGame(); else if (code.character == 8) this->_score.player = this->_score.player.substr(0, this->_score.player.size() - 1); - else if (code.character >= 33 && code.character <= 126) + else if (this->_score.player.size() < 15 && code.character >= 33 && code.character <= 126) this->_score.player += code.character; } } void Menu::_selectGame() { - for (auto checkBox : this->_gamesCheckBoxes) { - if (checkBox->isHovered() && checkBox->isChecked()) - this->_exitWithNewGame(); - if (checkBox->isHovered()) - checkBox->check(); - else - checkBox->uncheck(); + if (this->_textType == GAME || this->_textType == AUTHOR) { + for (auto checkBox : this->_gamesCheckBoxes) { + if (checkBox->isHovered() && checkBox->isChecked()) + this->_exitWithNewGame(); + if (checkBox->isHovered()) + checkBox->check(); + else + checkBox->uncheck(); + } + } else { + for (auto checkBox : this->_graphicsCheckBoxes) { + if (checkBox->isHovered() && checkBox->isChecked()) + this->_changeGraphics(); + if (checkBox->isHovered()) + checkBox->check(); + else + checkBox->uncheck(); + } + } +} + +void Menu::_changeGraphics() +{ + for (auto checkBox : this->_graphicsCheckBoxes) { + if (checkBox->isHovered()) { + auto index = std::distance(this->_graphicsCheckBoxes.begin(), std::find(this->_graphicsCheckBoxes.begin(), this->_graphicsCheckBoxes.end(), checkBox)); + auto graphicsProvider = this->_getGraphicsProvider(index); + if (graphicsProvider != this->_graphicsProvider) { + this->_graphicsProvider = graphicsProvider; + this->_window->close(); + this->_initWindow(); + } + break; + } } } @@ -292,10 +409,12 @@ void Menu::_handleMouseMouveEvents(std::shared_ptr mouse) bool hoveredAtLeastOne = false; for (auto checkBox : this->_gamesCheckBoxes) { - if (checkBox->isHovered()) { + if (checkBox->isHovered()) + lastHoveredCheckBox = checkBox; + } + for (auto checkBox : this->_graphicsCheckBoxes) { + if (checkBox->isHovered()) lastHoveredCheckBox = checkBox; - break; - } } for (auto checkBox : this->_gamesCheckBoxes) { if (checkBox->isHovered()) @@ -305,6 +424,14 @@ void Menu::_handleMouseMouveEvents(std::shared_ptr mouse) hoveredAtLeastOne = true; } } + for (auto checkBox : this->_graphicsCheckBoxes) { + if (checkBox->isHovered()) + checkBox->unhover(); + if (checkBox->isHovered(position)) { + checkBox->hover(); + hoveredAtLeastOne = true; + } + } if (!hoveredAtLeastOne && lastHoveredCheckBox) lastHoveredCheckBox->hover(); } @@ -352,7 +479,7 @@ void Menu::_handleEvents() void Menu::_renderField() { if (this->_score.player.empty()) { - auto placeholder = std::make_shared(this->_font, 6, "As Guest", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{16, 1}, Vector2f{17, 23}); + auto placeholder = std::make_shared(this->_font, 6, "Guest", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{16, 1}, Vector2f{17, 23}); this->_nameField = placeholder; } else { auto truncatName = this->_truncString(this->_score.player, 17); @@ -385,6 +512,13 @@ void Menu::_render() } } } + for (auto checkBox : this->_graphicsCheckBoxes) { + if (checkBox->isHovered()) { + for (auto text : this->_hiddenTexts[checkBox]) { + text->draw(this->_window); + } + } + } this->_renderField(); this->_window->display(); } @@ -408,11 +542,29 @@ void Menu::_previousSelectedGame() } } +void Menu::_previousSelectedGraphics() +{ + for (auto graphicsProvider : this->_graphicsProviders) { + if (this->_graphicsProvider == graphicsProvider.second) { + auto index = std::distance(this->_graphicsProviders.begin(), std::find(this->_graphicsProviders.begin(), this->_graphicsProviders.end(), graphicsProvider)); + auto checkBox = this->_graphicsCheckBoxes.at(index); + checkBox->check(); + return; + } + } + if (!this->_graphicsCheckBoxes.empty()) { + this->_graphicsCheckBoxes.at(0)->check(); + } else { + std::cout << "Can't select a previous graphics, no graphics found" << std::endl; + } +} + void Menu::run() { this->_sceneStage = MENU; this->_initWindow(); this->_previousSelectedGame(); + this->_previousSelectedGraphics(); while (this->_window->isOpen()) { this->_handleEvents(); this->_render(); diff --git a/core/src/menu/Menu.hpp b/core/src/menu/Menu.hpp index cbdddb0..940b78a 100644 --- a/core/src/menu/Menu.hpp +++ b/core/src/menu/Menu.hpp @@ -56,6 +56,7 @@ class Menu { typedef enum { GAME, AUTHOR, + GRAPHICS } TextType; TextType _textType; @@ -68,6 +69,7 @@ class Menu { std::shared_ptr &_gameProvider; std::shared_ptr &_graphicsProvider; std::vector> _gamesCheckBoxes; + std::vector> _graphicsCheckBoxes; std::vector> _texts; std::vector> _textures; std::map, std::vector>> _hiddenTexts; @@ -151,10 +153,22 @@ class Menu { void _exitAndPlayOldGame(); /** - * @brief Initialize checkboxes + * @brief Change the text type * */ - void _initCheckBoxes(); + void _changeGraphics(); + + /** + * @brief Initialize checkboxes for games + * + */ + void _initCheckBoxesGames(); + + /** + * @brief Initialize checkboxes for graphics + * + */ + void _initCheckBoxesGraphics(); /** * @brief Initialize textures @@ -178,6 +192,8 @@ class Menu { */ void _initHiddenScore(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font); + void _initHiddenGraphics(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font); + /** * @brief Initialize texts * @@ -190,6 +206,12 @@ class Menu { */ void _previousSelectedGame(); + /** + * @brief Define the previous selected graphics + * + */ + void _previousSelectedGraphics(); + /** * @brief Truncate a string * diff --git a/core/src/menu/checkBox/CheckBox.cpp b/core/src/menu/checkBox/CheckBox.cpp index ba85fc0..68fa0b0 100644 --- a/core/src/menu/checkBox/CheckBox.cpp +++ b/core/src/menu/checkBox/CheckBox.cpp @@ -56,8 +56,8 @@ bool CheckBox::isHovered(const Vector2f &mousePos) const auto pos = this->_text->getPosition(); auto size = this->_text->getSize(); - if (mousePos.x >= pos.x && mousePos.x <= pos.x + size.x && - mousePos.y >= pos.y && mousePos.y <= pos.y + size.y) + if (mousePos.x > pos.x && mousePos.x < pos.x + size.x && + mousePos.y > pos.y && mousePos.y < pos.y + size.y) return true; return false; } \ No newline at end of file From 2076c9b83d465ab796dfeccc8dc5793e4ec2dcda Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 5 Apr 2024 22:19:18 +0200 Subject: [PATCH 15/18] feat(core): update menu responsive --- core/src/Core.cpp | 2 +- core/src/menu/Menu.cpp | 87 +++++++++++++---------------- core/src/menu/Menu.hpp | 7 ++- graphics/sfml/src/window/Window.cpp | 2 +- 4 files changed, 48 insertions(+), 50 deletions(-) diff --git a/core/src/Core.cpp b/core/src/Core.cpp index dfa111a..d34fa99 100644 --- a/core/src/Core.cpp +++ b/core/src/Core.cpp @@ -383,6 +383,7 @@ void Core::_handleWindowClose() { if (this->_window && this->_window->isOpen()) this->_window->close(); + this->_menu.updateScore(this->_game); } void Core::_handleWindowResize() @@ -538,7 +539,6 @@ void Core::run() previousTime = currentTime; if (this->_sceneStage == MENU) { - this->_menu.updateScore(this->_game); this->_handleWindowClose(); this->_menu.run(); previousTime = std::chrono::high_resolution_clock::now(); diff --git a/core/src/menu/Menu.cpp b/core/src/menu/Menu.cpp index f7a3f9f..7aab140 100644 --- a/core/src/menu/Menu.cpp +++ b/core/src/menu/Menu.cpp @@ -58,15 +58,15 @@ std::string Menu::_truncString(const std::string &str, int size) void Menu::_initHiddenAuthors(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) { - auto authorNames = std::make_shared(font, 8, "Authors:", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 8}); + auto authorNames = std::make_shared(font, 35, "Authors:", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 8}); this->_hiddenAuthors[checkBox].push_back(authorNames); auto authors = gameManifest.authors; float index = 10.0; for (auto author : authors) { - auto authorNameText = std::make_shared(font, 7, this->_truncString(author.name, 22) , TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index}); - auto authorMailText = std::make_shared(font, 7, this->_truncString(author.email, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index + 1}); - auto authorSiteText = std::make_shared(font, 7, this->_truncString(author.website, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index + 2}); + auto authorNameText = std::make_shared(font, 30, this->_truncString(author.name, 22) , TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index}); + auto authorMailText = std::make_shared(font, 30, this->_truncString(author.email, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index + 1}); + auto authorSiteText = std::make_shared(font, 30, this->_truncString(author.website, 22), TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{27, index + 2}); this->_hiddenAuthors[checkBox].push_back(authorNameText); this->_hiddenAuthors[checkBox].push_back(authorMailText); this->_hiddenAuthors[checkBox].push_back(authorSiteText); @@ -77,14 +77,14 @@ void Menu::_initHiddenAuthors(const GameManifest &gameManifest, std::shared_ptr< void Menu::_initHiddenScore(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) { auto truncatName = this->_truncString(gameManifest.name, 23); - auto nameText = std::make_shared(font, 11, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 8}); + auto nameText = std::make_shared(font, 35, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 8}); this->_hiddenTexts[checkBox].push_back(nameText); std::string truncatDesc = this->_truncString(gameManifest.description, 23); - auto descriptionText = std::make_shared(font, 9, truncatDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 10}); + auto descriptionText = std::make_shared(font, 30, truncatDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 10}); this->_hiddenTexts[checkBox].push_back(descriptionText); - auto scoreHI = std::make_shared(font, 10, "HI-SCORE", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 12}); + auto scoreHI = std::make_shared(font, 30, "HI-SCORE", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 12}); this->_hiddenTexts[checkBox].push_back(scoreHI); auto score = 0; @@ -95,18 +95,19 @@ void Menu::_initHiddenScore(const GameManifest &gameManifest, std::shared_ptr(font, 10, scoreString, TextAlign::RIGHT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{14, 1}, Vector2f{34, 12}); + auto scoreText = std::make_shared(font, 30, scoreString, TextAlign::RIGHT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{14, 1}, Vector2f{34, 12}); this->_hiddenTexts[checkBox].push_back(scoreText); float index = 14; for (auto &scoreElem : this->_scores) { if (scoreElem.game == gameManifest.name) { - auto truncatPlayer = this->_truncString(scoreElem.player, 17); - auto playerText = std::make_shared(font, 8, truncatPlayer, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{17, 1}, Vector2f{26, index}); + auto playerName = scoreElem.player.empty() ? "Guest" : scoreElem.player; + auto truncatPlayer = this->_truncString(playerName, 17); + auto playerText = std::make_shared(font, 25, truncatPlayer, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{17, 1}, Vector2f{26, index}); auto scoreString = std::to_string(scoreElem.score).substr(0, 5); while (scoreString.length() < 5) scoreString = "0" + scoreString; - auto scoreText = std::make_shared(font, 8, scoreString, TextAlign::RIGHT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{5, 1}, Vector2f{43, index}); + auto scoreText = std::make_shared(font, 25, scoreString, TextAlign::RIGHT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{5, 1}, Vector2f{43, index}); this->_hiddenTexts[checkBox].push_back(playerText); this->_hiddenTexts[checkBox].push_back(scoreText); index += 1; @@ -124,23 +125,16 @@ void Menu::_initCheckBoxesGames() for (auto gameProvider : this->_gameProviders) { if (count > 5) break; - auto marginRight = 23 - static_cast(gameProvider.second->getManifest().name.size()); std::string truncatedName = gameProvider.second->getManifest().name.substr(0, 20); - if (marginRight < 0) { - truncatedName += "..."; - marginRight = 0; - } else { - truncatedName = gameProvider.second->getManifest().name; - marginRight -= 3; - } - auto textCheckBox = std::make_shared(font, 10, truncatedName, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{20 - static_cast(marginRight) - 1, 1}, Vector2f{3 + marginRight, index}); - auto textureCheckBox = std::make_shared(texture, Vector2f{360, 360}, Vector2u{0, 0}, Vector2u{1, 1}, Vector2f{1 + marginRight, index}); + auto pos = 11 - (static_cast(truncatedName.size()) / 2); + auto textCheckBox = std::make_shared(font, 35, truncatedName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{static_cast(truncatedName.size()), 1}, Vector2f{pos + 2, index}); + auto textureCheckBox = std::make_shared(texture, Vector2f{360, 360}, Vector2u{0, 0}, Vector2u{1, 1}, Vector2f{pos, index}); auto checkBox = std::make_shared(textureCheckBox, textCheckBox); this->_texts.push_back(textCheckBox); this->_textures.push_back(textureCheckBox); this->_gamesCheckBoxes.push_back(checkBox); - this->_initHiddenAuthors(gameProvider.second->getManifest(), checkBox, font); this->_initHiddenScore(gameProvider.second->getManifest(), checkBox, font); + this->_initHiddenAuthors(gameProvider.second->getManifest(), checkBox, font); index += 1; count += 1; } @@ -149,19 +143,19 @@ void Menu::_initCheckBoxesGames() void Menu::_initHiddenGraphics(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font) { auto truncatName = this->_truncString(graphicsManifest.name, 23); - auto nameText = std::make_shared(font, 11, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 8}); + auto nameText = std::make_shared(font, 35, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 8}); this->_hiddenTexts[checkBox].push_back(nameText); auto truncatDesc = this->_truncString(graphicsManifest.description, 23); - auto descriptionText = std::make_shared(font, 9, truncatDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 10}); + auto descriptionText = std::make_shared(font, 30, truncatDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 10}); this->_hiddenTexts[checkBox].push_back(descriptionText); auto authors = graphicsManifest.authors; float index = 12.0; for (auto author : authors) { - auto authorNameText = std::make_shared(font, 7, this->_truncString(author.name, 23), TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, index}); - auto authorMailText = std::make_shared(font, 7, this->_truncString(author.email, 23), TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, index + 1}); - auto authorSiteText = std::make_shared(font, 7, this->_truncString(author.website, 23), TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, index + 2}); + auto authorNameText = std::make_shared(font, 25, this->_truncString(author.name, 23), TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, index}); + auto authorMailText = std::make_shared(font, 25, this->_truncString(author.email, 23), TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, index + 1}); + auto authorSiteText = std::make_shared(font, 25, this->_truncString(author.website, 23), TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, index + 2}); this->_hiddenTexts[checkBox].push_back(authorNameText); this->_hiddenTexts[checkBox].push_back(authorMailText); this->_hiddenTexts[checkBox].push_back(authorSiteText); @@ -179,17 +173,10 @@ void Menu::_initCheckBoxesGraphics() for (auto graphicsProvider : this->_graphicsProviders) { if (count > 5) break; - auto marginRight = 23 - static_cast(graphicsProvider.second->getManifest().name.size()); std::string truncatedName = graphicsProvider.second->getManifest().name.substr(0, 20); - if (marginRight < 0) { - truncatedName += "..."; - marginRight = 0; - } else { - truncatedName = graphicsProvider.second->getManifest().name; - marginRight -= 3; - } - auto textCheckBox = std::make_shared(font, 10, truncatedName, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{20 - static_cast(marginRight) - 1, 1}, Vector2f{3 + marginRight, index}); - auto textureCheckBox = std::make_shared(texture, Vector2f{360, 360}, Vector2u{0, 0}, Vector2u{1, 1}, Vector2f{1 + marginRight, index}); + auto pos = 11 - (static_cast(truncatedName.size()) / 2); + auto textCheckBox = std::make_shared(font, 35, truncatedName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{static_cast(truncatedName.size()), 1}, Vector2f{pos + 2, index}); + auto textureCheckBox = std::make_shared(texture, Vector2f{360, 360}, Vector2u{0, 0}, Vector2u{1, 1}, Vector2f{pos, index}); auto checkBox = std::make_shared(textureCheckBox, textCheckBox); this->_texts.push_back(textCheckBox); this->_textures.push_back(textureCheckBox); @@ -219,12 +206,12 @@ void Menu::_initTexts() this->_font = font; if (this->_gameProviders.empty()) { - auto noGames = std::make_shared(font, 12, "NO GAMES FOUND !", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{15, 1}, Vector2f{17, 12}); + auto noGames = std::make_shared(font, 30, "NO GAMES FOUND !", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{15, 1}, Vector2f{17, 12}); this->_texts.push_back(noGames); } else { - auto games = std::make_shared(font, 12, "Games", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{5, 1}, Vector2f{8, 7}); + auto games = std::make_shared(font, 40, "Games", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{24, 1}, Vector2f{1, 7}); this->_texts.push_back(games); - auto graphics = std::make_shared(font, 12, "Graphics", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{7, 15}); + auto graphics = std::make_shared(font, 40, "Graphics", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{24, 1}, Vector2f{1, 15}); this->_texts.push_back(graphics); } } @@ -277,7 +264,7 @@ void Menu::_handleSelectUpperCheckBox() auto index = std::distance(this->_graphicsCheckBoxes.begin(), std::find(this->_graphicsCheckBoxes.begin(), this->_graphicsCheckBoxes.end(), checkBox)); if (index == 0) { this->_gamesCheckBoxes.at(this->_gamesCheckBoxes.size() - 1)->hover(); - this->_textType = GAME; + this->_checkBoxType = GAME_CHECKBOX; } else { this->_graphicsCheckBoxes.at(index - 1)->hover(); } @@ -305,7 +292,7 @@ void Menu::_handleSelectLowerCheckBox() auto index = std::distance(this->_gamesCheckBoxes.begin(), std::find(this->_gamesCheckBoxes.begin(), this->_gamesCheckBoxes.end(), checkBox)); if (index == this->_gamesCheckBoxes.size() - 1) { this->_graphicsCheckBoxes.at(0)->hover(); - this->_textType = GRAPHICS; + this->_checkBoxType = GRAPHICS_CHECKBOX; } else { this->_gamesCheckBoxes.at(index + 1)->hover(); } @@ -345,7 +332,7 @@ void Menu::_handleKeyboardEvents(std::shared_ptr key) void Menu::_selectGame() { - if (this->_textType == GAME || this->_textType == AUTHOR) { + if (this->_checkBoxType == GAME_CHECKBOX) { for (auto checkBox : this->_gamesCheckBoxes) { if (checkBox->isHovered() && checkBox->isChecked()) this->_exitWithNewGame(); @@ -421,6 +408,7 @@ void Menu::_handleMouseMouveEvents(std::shared_ptr mouse) checkBox->unhover(); if (checkBox->isHovered(position)) { checkBox->hover(); + this->_checkBoxType = GAME_CHECKBOX; hoveredAtLeastOne = true; } } @@ -429,6 +417,7 @@ void Menu::_handleMouseMouveEvents(std::shared_ptr mouse) checkBox->unhover(); if (checkBox->isHovered(position)) { checkBox->hover(); + this->_checkBoxType = GRAPHICS_CHECKBOX; hoveredAtLeastOne = true; } } @@ -442,12 +431,15 @@ void Menu::_handleMouseButtonEvents(std::shared_ptr m return; auto position = mouse->getPosition(); auto button = mouse->getButton(); + auto move = std::dynamic_pointer_cast(mouse); if (button != events::IMouseButtonEvent::MouseButton::LEFT) return; + this->_handleMouseMouveEvents(move); for (auto checkBox : this->_gamesCheckBoxes) { - if (checkBox->isHovered(position)) + if (checkBox->isHovered(position)) { this->_selectGame(); + } } } @@ -479,11 +471,11 @@ void Menu::_handleEvents() void Menu::_renderField() { if (this->_score.player.empty()) { - auto placeholder = std::make_shared(this->_font, 6, "Guest", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{16, 1}, Vector2f{17, 23}); + auto placeholder = std::make_shared(this->_font, 30, "Guest", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{16, 1}, Vector2f{17, 23}); this->_nameField = placeholder; } else { auto truncatName = this->_truncString(this->_score.player, 17); - auto name = std::make_shared(this->_font, 8, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{16, 1}, Vector2f{17, 23}); + auto name = std::make_shared(this->_font, 35, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{16, 1}, Vector2f{17, 23}); this->_nameField = name; } if (this->_nameField) @@ -602,8 +594,9 @@ void Menu::_writeScore() } scoreFile << "Game\tPlayer\tScore" << std::endl; + auto player = this->_score.player.empty() ? "Guest" : this->_score.player; for (auto score : this->_scores) { - scoreFile << score.game << "\t" << score.player << "\t" << score.score << std::endl; + scoreFile << score.game << "\t" << player << "\t" << score.score << std::endl; } scoreFile.close(); } diff --git a/core/src/menu/Menu.hpp b/core/src/menu/Menu.hpp index 940b78a..ee6da96 100644 --- a/core/src/menu/Menu.hpp +++ b/core/src/menu/Menu.hpp @@ -56,10 +56,15 @@ class Menu { typedef enum { GAME, AUTHOR, - GRAPHICS } TextType; + typedef enum { + GAME_CHECKBOX, + GRAPHICS_CHECKBOX + } CheckBoxType; + TextType _textType; + CheckBoxType _checkBoxType; Score _score; std::vector _scores; SceneStage &_sceneStage; diff --git a/graphics/sfml/src/window/Window.cpp b/graphics/sfml/src/window/Window.cpp index 002d0a2..28a14a4 100644 --- a/graphics/sfml/src/window/Window.cpp +++ b/graphics/sfml/src/window/Window.cpp @@ -13,7 +13,7 @@ using namespace arcade::graphics::sfml::window; using namespace arcade::graphics::common::exceptions; -const Vector2u Window::tileSize = { 12, 12 }; +const Vector2u Window::tileSize = { 35, 35 }; #include Window::Window(const IWindow::WindowInitProps &props): From 5d8bf09a0b38d198a142a07b50240335e10e479a Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 5 Apr 2024 22:47:09 +0200 Subject: [PATCH 16/18] fix(core): handle respecfully no games --- core/src/menu/Menu.cpp | 44 +++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/core/src/menu/Menu.cpp b/core/src/menu/Menu.cpp index 7aab140..7a4d7e3 100644 --- a/core/src/menu/Menu.cpp +++ b/core/src/menu/Menu.cpp @@ -118,7 +118,7 @@ void Menu::_initHiddenScore(const GameManifest &gameManifest, std::shared_ptr_graphicsProvider->createTexture("assets/menu/img/space-invader.png", "assets/menu/img/space-invader.ascii"); - auto font = this->_graphicsProvider->createFont("assets/menu/fonts/arcade.ttf"); + auto font = this->_font; float index = 9.0; int count = 0; @@ -138,6 +138,10 @@ void Menu::_initCheckBoxesGames() index += 1; count += 1; } + if (this->_gamesCheckBoxes.empty()) { + auto noGames = std::make_shared(font, 35, "No games found", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{2, 11}); + this->_texts.push_back(noGames); + } } void Menu::_initHiddenGraphics(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font) @@ -166,7 +170,7 @@ void Menu::_initHiddenGraphics(const GraphicsManifest &graphicsManifest, std::sh void Menu::_initCheckBoxesGraphics() { auto texture = this->_graphicsProvider->createTexture("assets/menu/img/space-invader.png", "assets/menu/img/space-invader.ascii"); - auto font = this->_graphicsProvider->createFont("assets/menu/fonts/arcade.ttf"); + auto font = this->_font; float index = 17.0; int count = 0; @@ -193,11 +197,8 @@ void Menu::_initTextures() this->_textures.push_back(std::make_shared(backgroundTexture, Vector2f{12, 12}, Vector2u{0, 0}, Vector2u{50, 25}, Vector2f{0, 0})); auto titleTexture = this->_graphicsProvider->createTexture("assets/menu/img/title.png", "assets/menu/img/title.ascii"); this->_textures.push_back(std::make_shared(titleTexture, Vector2f{17, 17}, Vector2u{0, 0}, Vector2u{31, 5}, Vector2f{10, 1})); - - if (!this->_gameProviders.empty()) { - auto middleTexture = this->_graphicsProvider->createTexture("assets/menu/img/middle.png", "assets/menu/img/middle.ascii"); - this->_textures.push_back(std::make_shared(middleTexture, Vector2f{12, 12}, Vector2u{0, 0}, Vector2u{1, 15}, Vector2f{24, 7})); - } + auto middleTexture = this->_graphicsProvider->createTexture("assets/menu/img/middle.png", "assets/menu/img/middle.ascii"); + this->_textures.push_back(std::make_shared(middleTexture, Vector2f{12, 12}, Vector2u{0, 0}, Vector2u{1, 15}, Vector2f{24, 7})); } void Menu::_initTexts() @@ -205,15 +206,10 @@ void Menu::_initTexts() auto font = this->_graphicsProvider->createFont("assets/menu/fonts/arcade.ttf"); this->_font = font; - if (this->_gameProviders.empty()) { - auto noGames = std::make_shared(font, 30, "NO GAMES FOUND !", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{15, 1}, Vector2f{17, 12}); - this->_texts.push_back(noGames); - } else { - auto games = std::make_shared(font, 40, "Games", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{24, 1}, Vector2f{1, 7}); - this->_texts.push_back(games); - auto graphics = std::make_shared(font, 40, "Graphics", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{24, 1}, Vector2f{1, 15}); - this->_texts.push_back(graphics); - } + auto games = std::make_shared(font, 40, "Games", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{24, 1}, Vector2f{1, 7}); + this->_texts.push_back(games); + auto graphics = std::make_shared(font, 40, "Graphics", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{24, 1}, Vector2f{1, 15}); + this->_texts.push_back(graphics); } void Menu::_initWindow() @@ -263,8 +259,12 @@ void Menu::_handleSelectUpperCheckBox() checkBox->unhover(); auto index = std::distance(this->_graphicsCheckBoxes.begin(), std::find(this->_graphicsCheckBoxes.begin(), this->_graphicsCheckBoxes.end(), checkBox)); if (index == 0) { - this->_gamesCheckBoxes.at(this->_gamesCheckBoxes.size() - 1)->hover(); - this->_checkBoxType = GAME_CHECKBOX; + if (!this->_gamesCheckBoxes.empty()) { + this->_gamesCheckBoxes.at(this->_gamesCheckBoxes.size() - 1)->hover(); + this->_checkBoxType = GAME_CHECKBOX; + } else { + checkBox->hover(); + } } else { this->_graphicsCheckBoxes.at(index - 1)->hover(); } @@ -541,11 +541,19 @@ void Menu::_previousSelectedGraphics() auto index = std::distance(this->_graphicsProviders.begin(), std::find(this->_graphicsProviders.begin(), this->_graphicsProviders.end(), graphicsProvider)); auto checkBox = this->_graphicsCheckBoxes.at(index); checkBox->check(); + if (this->_gamesCheckBoxes.empty()) { + checkBox->hover(); + this->_checkBoxType = GRAPHICS_CHECKBOX; + } return; } } if (!this->_graphicsCheckBoxes.empty()) { this->_graphicsCheckBoxes.at(0)->check(); + if (this->_gamesCheckBoxes.empty()) { + _graphicsCheckBoxes.at(0)->hover(); + this->_checkBoxType = GRAPHICS_CHECKBOX; + } } else { std::cout << "Can't select a previous graphics, no graphics found" << std::endl; } From 3a4c75a195dc326015ba123c0adb698cf2a5aaae Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 5 Apr 2024 23:41:15 +0200 Subject: [PATCH 17/18] refactor(core): secure some cast and repair snake score --- core/main.cpp | 13 ++-- core/src/Core.cpp | 34 +++++----- core/src/loader/Loader.cpp | 6 +- core/src/menu/Menu.cpp | 113 ++++++++++++++++++++++++---------- core/src/menu/Menu.hpp | 67 +++++++++++++++++++- games/common/game/AGame.cpp | 1 + games/snake/src/SnakeGame.cpp | 1 + 7 files changed, 176 insertions(+), 59 deletions(-) diff --git a/core/main.cpp b/core/main.cpp index 0e74932..5a83822 100644 --- a/core/main.cpp +++ b/core/main.cpp @@ -5,6 +5,7 @@ ** main */ +#include #include "Core.hpp" #include "loader/Loader.hpp" @@ -16,16 +17,16 @@ int main(int ac, char **av) std::cerr << "Usage: ./arcade path_to_lib" << std::endl; return 84; } + try { loader.loadLibraries("./lib"); auto &games = loader.getGamesLibraries(); auto &graphics = loader.getGraphicsLibraries(); - auto it = graphics.find(av[1]); - if (it == graphics.end()) { - std::cerr << "Game library not found" << std::endl; - return 84; - } - Core core(games, graphics, av[1]); + auto libName = std::filesystem::canonical(av[1]).string(); + auto it = graphics.find(libName); + if (it == graphics.end()) + throw ArcadeError("No such graphics library: " + libName); + Core core(games, graphics, libName); core.run(); } catch (const std::exception &e) { std::cerr << e.what() << std::endl; diff --git a/core/src/Core.cpp b/core/src/Core.cpp index d34fa99..6c08ddb 100644 --- a/core/src/Core.cpp +++ b/core/src/Core.cpp @@ -19,9 +19,9 @@ Core::Core(GameProviders &gameProviders, GraphicsProviders &graphicsProviders, c this->_sceneStage = MENU; this->_gameProvider = nullptr; this->_graphicsProvider = nullptr; - for (auto &gameProvider : this->_gameProviders) { - if (gameProvider.first == graphicNameProvider) - this->_gameProvider = gameProvider.second; + for (auto &graphicsProvider : this->_graphicsProviders) { + if (graphicsProvider.first == graphicNameProvider) + this->_graphicsProvider = graphicsProvider.second; } } @@ -276,9 +276,8 @@ void Core::_preventWindowEvents(std::vector events) auto keyEvent = std::dynamic_pointer_cast(event); auto keyCode = keyEvent->getKeyCode(); auto keyType = keyEvent->getKeyType(); - if (keyType == events::IKeyEvent::CHAR && keyCode.character == 27) { + if (keyType == events::IKeyEvent::CHAR && keyCode.character == 27) this->_sceneStage = MENU; - } } } } @@ -303,8 +302,6 @@ void Core::_changeGameProvider(const unsigned char &index) return; } auto newProvider = this->_getGameProvider(index); - if (newProvider == this->_gameProvider) - return; this->_gameProvider = newProvider; this->_initGame(); this->_initWindow(); @@ -381,9 +378,10 @@ void Core::_handleMouseMove(std::shared_ptr &event, std::sh void Core::_handleWindowClose() { - if (this->_window && this->_window->isOpen()) + if (this->_window && this->_window->isOpen()) { this->_window->close(); - this->_menu.updateScore(this->_game); + this->_menu.updateScore(this->_game); + } } void Core::_handleWindowResize() @@ -513,14 +511,18 @@ void Core::_handleEvents() { auto gameEvents = this->_window->getEvents(); - this->_preventWindowEvents(gameEvents); - if (this->_sceneStage == MENU) - return; - for (auto &entity : this->_gameEntities) { - auto components = entity->getComponents(); - for (auto &component : components) { - this->_handleComponentEvents(gameEvents, component); + try { + this->_preventWindowEvents(gameEvents); + if (this->_sceneStage == MENU) + return; + for (auto &entity : this->_gameEntities) { + auto components = entity->getComponents(); + for (auto &component : components) { + this->_handleComponentEvents(gameEvents, component); + } } + } catch (std::exception &e) { + std::cerr << e.what() << std::endl; } } diff --git a/core/src/loader/Loader.cpp b/core/src/loader/Loader.cpp index b8df718..ba4e62c 100644 --- a/core/src/loader/Loader.cpp +++ b/core/src/loader/Loader.cpp @@ -27,7 +27,8 @@ void Loader::_loadGameLibrary(const std::string &filepath, std::shared_ptrloadSymbol(SHARED_STRINGIFY(SHARED_GAME_PROVIDER_GETTER_NAME)); - this->_gamesLibraries.insert({filepath, std::shared_ptr(game())}); + auto realFilePath = std::filesystem::canonical(filepath).string(); + this->_gamesLibraries.insert({realFilePath, std::shared_ptr(game())}); this->_libraries.push_back(dlLoader); } @@ -35,7 +36,8 @@ void Loader::_loadGraphicsLibrary(const std::string &filepath, std::shared_ptrloadSymbol(SHARED_STRINGIFY(SHARED_GRAPHICS_PROVIDER_GETTER_NAME)); - this->_graphicsLibraries.insert({filepath, std::shared_ptr(graphics())}); + auto realFilePath = std::filesystem::canonical(filepath).string(); + this->_graphicsLibraries.insert({realFilePath, std::shared_ptr(graphics())}); this->_libraries.push_back(dlLoader); } diff --git a/core/src/menu/Menu.cpp b/core/src/menu/Menu.cpp index 7a4d7e3..4b852a7 100644 --- a/core/src/menu/Menu.cpp +++ b/core/src/menu/Menu.cpp @@ -44,6 +44,13 @@ std::shared_ptr &Menu::_getGraphicsProvider(const unsigned ch return it->second; } +void Menu::_sortScores() +{ + std::sort(this->_scores.begin(), this->_scores.end(), [](const Score& a, const Score& b) { + return a.score > b.score; + }); +} + std::string Menu::_truncString(const std::string &str, int size) { auto strPadding = size - static_cast(str.size()); @@ -74,19 +81,23 @@ void Menu::_initHiddenAuthors(const GameManifest &gameManifest, std::shared_ptr< } } -void Menu::_initHiddenScore(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) +void Menu::_initHiddenScoreHeader(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) { auto truncatName = this->_truncString(gameManifest.name, 23); auto nameText = std::make_shared(font, 35, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 8}); this->_hiddenTexts[checkBox].push_back(nameText); - std::string truncatDesc = this->_truncString(gameManifest.description, 23); + auto truncatDesc = this->_truncString(gameManifest.description, 23); auto descriptionText = std::make_shared(font, 30, truncatDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 10}); this->_hiddenTexts[checkBox].push_back(descriptionText); +} +void Menu::_initHiddenScoreBoard(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) +{ auto scoreHI = std::make_shared(font, 30, "HI-SCORE", TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{8, 1}, Vector2f{26, 12}); this->_hiddenTexts[checkBox].push_back(scoreHI); + this->_sortScores(); auto score = 0; for (auto &scoreElem : this->_scores) { if (scoreElem.game == gameManifest.name && scoreElem.score > score) @@ -99,8 +110,11 @@ void Menu::_initHiddenScore(const GameManifest &gameManifest, std::shared_ptr_hiddenTexts[checkBox].push_back(scoreText); float index = 14; + int count = 0; for (auto &scoreElem : this->_scores) { if (scoreElem.game == gameManifest.name) { + if (count > 7) + break; auto playerName = scoreElem.player.empty() ? "Guest" : scoreElem.player; auto truncatPlayer = this->_truncString(playerName, 17); auto playerText = std::make_shared(font, 25, truncatPlayer, TextAlign::LEFT, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{17, 1}, Vector2f{26, index}); @@ -111,10 +125,27 @@ void Menu::_initHiddenScore(const GameManifest &gameManifest, std::shared_ptr_hiddenTexts[checkBox].push_back(playerText); this->_hiddenTexts[checkBox].push_back(scoreText); index += 1; + count += 1; } } } +void Menu::_initHiddenScore(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font) +{ + this->_initHiddenScoreHeader(gameManifest, checkBox, font); + this->_initHiddenScoreBoard(gameManifest, checkBox, font); +} + +void Menu::_initNoGameFound() +{ + auto font = this->_font; + + if (this->_gamesCheckBoxes.empty()) { + auto noGames = std::make_shared(font, 35, "No games found", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{2, 11}); + this->_texts.push_back(noGames); + } +} + void Menu::_initCheckBoxesGames() { auto texture = this->_graphicsProvider->createTexture("assets/menu/img/space-invader.png", "assets/menu/img/space-invader.ascii"); @@ -138,13 +169,10 @@ void Menu::_initCheckBoxesGames() index += 1; count += 1; } - if (this->_gamesCheckBoxes.empty()) { - auto noGames = std::make_shared(font, 35, "No games found", TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{22, 1}, Vector2f{2, 11}); - this->_texts.push_back(noGames); - } + this->_initNoGameFound(); } -void Menu::_initHiddenGraphics(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font) +void Menu::_initHiddenGraphicsHeader(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font) { auto truncatName = this->_truncString(graphicsManifest.name, 23); auto nameText = std::make_shared(font, 35, truncatName, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 8}); @@ -153,7 +181,10 @@ void Menu::_initHiddenGraphics(const GraphicsManifest &graphicsManifest, std::sh auto truncatDesc = this->_truncString(graphicsManifest.description, 23); auto descriptionText = std::make_shared(font, 30, truncatDesc, TextAlign::CENTER, TextVerticalAlign::MIDDLE, Color{255, 255, 255, 255}, Vector2u{23, 1}, Vector2f{25, 10}); this->_hiddenTexts[checkBox].push_back(descriptionText); +} +void Menu::_initHiddenGraphicsBoard(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font) +{ auto authors = graphicsManifest.authors; float index = 12.0; for (auto author : authors) { @@ -167,6 +198,12 @@ void Menu::_initHiddenGraphics(const GraphicsManifest &graphicsManifest, std::sh } } +void Menu::_initHiddenGraphics(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font) +{ + this->_initHiddenGraphicsHeader(graphicsManifest, checkBox, font); + this->_initHiddenGraphicsBoard(graphicsManifest, checkBox, font); +} + void Menu::_initCheckBoxesGraphics() { auto texture = this->_graphicsProvider->createTexture("assets/menu/img/space-invader.png", "assets/menu/img/space-invader.ascii"); @@ -212,6 +249,26 @@ void Menu::_initTexts() this->_texts.push_back(graphics); } +void Menu::_clearLists() +{ + this->_hiddenAuthors.clear(); + this->_hiddenTexts.clear(); + this->_texts.clear(); + this->_textures.clear(); + this->_gamesCheckBoxes.clear(); + this->_graphicsCheckBoxes.clear(); +} + +void Menu::_preventGraphicsProvider() +{ + if (this->_graphicsProvider) + return; + if (this->_graphicsProviders.empty()) + throw ArcadeError("No graphics provider found"); + this->_graphicsProvider = this->_getGraphicsProvider(0); + std::cout << "No graphics provider found, using default provider" << std::endl; +} + void Menu::_initWindow() { IWindow::WindowInitProps windowInitProps { @@ -222,18 +279,8 @@ void Menu::_initWindow() .icon = "assets/menu/img/icon.png" }; - this->_hiddenAuthors.clear(); - this->_hiddenTexts.clear(); - this->_texts.clear(); - this->_textures.clear(); - this->_gamesCheckBoxes.clear(); - this->_graphicsCheckBoxes.clear(); - if (!this->_graphicsProvider) { - if (this->_graphicsProviders.empty()) - throw ArcadeError("No graphics provider found"); - this->_graphicsProvider = this->_getGraphicsProvider(0); - std::cout << "No graphics provider found, using default provider" << std::endl; - } + this->_clearLists(); + this->_preventGraphicsProvider(); this->_initTexts(); this->_initTextures(); this->_initCheckBoxesGames(); @@ -344,7 +391,7 @@ void Menu::_selectGame() } else { for (auto checkBox : this->_graphicsCheckBoxes) { if (checkBox->isHovered() && checkBox->isChecked()) - this->_changeGraphics(); + this->_changeGraphics(checkBox); if (checkBox->isHovered()) checkBox->check(); else @@ -353,19 +400,14 @@ void Menu::_selectGame() } } -void Menu::_changeGraphics() +void Menu::_changeGraphics(std::shared_ptr checkBox) { - for (auto checkBox : this->_graphicsCheckBoxes) { - if (checkBox->isHovered()) { - auto index = std::distance(this->_graphicsCheckBoxes.begin(), std::find(this->_graphicsCheckBoxes.begin(), this->_graphicsCheckBoxes.end(), checkBox)); - auto graphicsProvider = this->_getGraphicsProvider(index); - if (graphicsProvider != this->_graphicsProvider) { - this->_graphicsProvider = graphicsProvider; - this->_window->close(); - this->_initWindow(); - } - break; - } + auto index = std::distance(this->_graphicsCheckBoxes.begin(), std::find(this->_graphicsCheckBoxes.begin(), this->_graphicsCheckBoxes.end(), checkBox)); + auto graphicsProvider = this->_getGraphicsProvider(index); + if (graphicsProvider != this->_graphicsProvider) { + this->_graphicsProvider = graphicsProvider; + this->_window->close(); + this->_initWindow(); } } @@ -517,6 +559,7 @@ void Menu::_render() void Menu::_previousSelectedGame() { + this->_checkBoxType = GAME_CHECKBOX; for (auto gameProvider : this->_gameProviders) { if (this->_gameProvider == gameProvider.second) { auto index = std::distance(this->_gameProviders.begin(), std::find(this->_gameProviders.begin(), this->_gameProviders.end(), gameProvider)); @@ -614,9 +657,11 @@ void Menu::updateScore(std::shared_ptr game) this->_score.game = game->getManifest().name; this->_score.score = game->getScore(); + std::cout << "Player Score: " << this->_score.score << std::endl; for (auto &score : this->_scores) { - auto name = this->_score.player.empty() ? "Guest" : this->_score.player; - if (score.game == this->_score.game && score.player == name) { + auto playerName = this->_score.player.empty() ? "Guest" : this->_score.player; + auto scoreName = score.player.empty() ? "Guest" : score.player; + if (score.game == this->_score.game && scoreName == playerName) { if (score.score < this->_score.score) score.score = this->_score.score; return; diff --git a/core/src/menu/Menu.hpp b/core/src/menu/Menu.hpp index ee6da96..8ff12d8 100644 --- a/core/src/menu/Menu.hpp +++ b/core/src/menu/Menu.hpp @@ -88,6 +88,18 @@ class Menu { */ void _initWindow(); + /** + * @brief Clear all lists + * + */ + void _clearLists(); + + /** + * @brief Prevent the graphics provider + * + */ + void _preventGraphicsProvider(); + /** * @brief Render the menu * @@ -161,7 +173,7 @@ class Menu { * @brief Change the text type * */ - void _changeGraphics(); + void _changeGraphics(std::shared_ptr checkBox); /** * @brief Initialize checkboxes for games @@ -194,11 +206,58 @@ class Menu { * * @param gameManifest GameManifest * @param checkBox CheckBox + * @param font IFont */ void _initHiddenScore(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font); + /** + * @brief Initialize hidden score header + * + * @param gameManifest GameManifest + * @param checkBox CheckBox + * @param font IFont + */ + void _initHiddenScoreHeader(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font); + + /** + * @brief Initialize hidden score board + * + * @param gameManifest GameManifest + * @param checkBox CheckBox + * @param font IFont + */ + void _initHiddenScoreBoard(const GameManifest &gameManifest, std::shared_ptr checkBox, std::shared_ptr font); + + /** + * @brief Initialize When No game found + * + */ + void _initNoGameFound(); + + /** + * @brief Initialize hidden graphics + * + * @param graphicsManifest GraphicsManifest + * @param checkBox CheckBox + */ void _initHiddenGraphics(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font); + /** + * @brief Initialize hidden graphics header + * + * @param graphicsManifest GraphicsManifest + * @param checkBox CheckBox + */ + void _initHiddenGraphicsHeader(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font); + + /** + * @brief Initialize hidden graphics board + * + * @param graphicsManifest GraphicsManifest + * @param checkBox CheckBox + */ + void _initHiddenGraphicsBoard(const GraphicsManifest &graphicsManifest, std::shared_ptr checkBox, std::shared_ptr font); + /** * @brief Initialize texts * @@ -226,6 +285,12 @@ class Menu { */ std::string _truncString(const std::string &str, int size); + /** + * @brief Sort the scores + * + */ + void _sortScores(); + /** * @brief Get the game provider object * diff --git a/games/common/game/AGame.cpp b/games/common/game/AGame.cpp index 8841a7e..39f99dd 100644 --- a/games/common/game/AGame.cpp +++ b/games/common/game/AGame.cpp @@ -13,6 +13,7 @@ using namespace arcade::games; common::AGame::AGame(shared::types::Vector2u size, unsigned int fps) : _size(size), _fps(fps) { this->_entities = {}; + this->_score = 0; } const shared::games::entity::EntitiesMap &common::AGame::getEntities() const { diff --git a/games/snake/src/SnakeGame.cpp b/games/snake/src/SnakeGame.cpp index b9f0b0a..248685e 100644 --- a/games/snake/src/SnakeGame.cpp +++ b/games/snake/src/SnakeGame.cpp @@ -89,6 +89,7 @@ void snake::SnakeGame::_loose() { } this->_looseGame = false; + this->_score = 0; } void snake::SnakeGame::setLooseGame(bool state) { From b1bc39dc30a0e8736da1517f8edf789b3e9456ea Mon Sep 17 00:00:00 2001 From: Yann Date: Fri, 5 Apr 2024 23:44:09 +0200 Subject: [PATCH 18/18] refactor(games): remove pacman --- assets/pacman/apple.ascii | 1 - assets/pacman/apple.png | Bin 718 -> 0 bytes assets/pacman/head.ascii | 1 - assets/pacman/head.png | Bin 1868 -> 0 bytes assets/pacman/tail.ascii | 3 - assets/pacman/tail.png | Bin 2048 -> 0 bytes assets/pacman/wall.ascii | 1 - assets/pacman/wall.png | Bin 237 -> 0 bytes games/CMakeLists.txt | 1 - games/pacman/CMakeLists.txt | 24 ---- games/pacman/export.cpp | 22 ---- games/pacman/src/PacmanGame.cpp | 105 ------------------ games/pacman/src/PacmanGame.hpp | 70 ------------ games/pacman/src/PacmanGameProvider.cpp | 19 ---- games/pacman/src/PacmanGameProvider.hpp | 35 ------ .../pacman/src/entities/apple/AppleEntity.cpp | 65 ----------- .../pacman/src/entities/apple/AppleEntity.hpp | 52 --------- .../entities/background/BackgroundEntity.cpp | 43 ------- .../entities/background/BackgroundEntity.hpp | 35 ------ .../pacman/src/entities/pacman/HeadEntity.cpp | 89 --------------- .../pacman/src/entities/pacman/HeadEntity.hpp | 66 ----------- games/pacman/src/entities/pacman/Pacman.cpp | 75 ------------- games/pacman/src/entities/pacman/Pacman.hpp | 67 ----------- .../pacman/src/entities/pacman/TailEntity.cpp | 56 ---------- .../pacman/src/entities/pacman/TailEntity.hpp | 51 --------- .../components/HeadKeyboardComponent.cpp | 54 --------- .../components/HeadKeyboardComponent.hpp | 45 -------- games/pacman/src/entities/wall/WallEntity.cpp | 56 ---------- games/pacman/src/entities/wall/WallEntity.hpp | 40 ------- 29 files changed, 1076 deletions(-) delete mode 100644 assets/pacman/apple.ascii delete mode 100644 assets/pacman/apple.png delete mode 100644 assets/pacman/head.ascii delete mode 100644 assets/pacman/head.png delete mode 100644 assets/pacman/tail.ascii delete mode 100644 assets/pacman/tail.png delete mode 100644 assets/pacman/wall.ascii delete mode 100644 assets/pacman/wall.png delete mode 100644 games/pacman/CMakeLists.txt delete mode 100644 games/pacman/export.cpp delete mode 100644 games/pacman/src/PacmanGame.cpp delete mode 100644 games/pacman/src/PacmanGame.hpp delete mode 100644 games/pacman/src/PacmanGameProvider.cpp delete mode 100644 games/pacman/src/PacmanGameProvider.hpp delete mode 100644 games/pacman/src/entities/apple/AppleEntity.cpp delete mode 100644 games/pacman/src/entities/apple/AppleEntity.hpp delete mode 100644 games/pacman/src/entities/background/BackgroundEntity.cpp delete mode 100644 games/pacman/src/entities/background/BackgroundEntity.hpp delete mode 100644 games/pacman/src/entities/pacman/HeadEntity.cpp delete mode 100644 games/pacman/src/entities/pacman/HeadEntity.hpp delete mode 100644 games/pacman/src/entities/pacman/Pacman.cpp delete mode 100644 games/pacman/src/entities/pacman/Pacman.hpp delete mode 100644 games/pacman/src/entities/pacman/TailEntity.cpp delete mode 100644 games/pacman/src/entities/pacman/TailEntity.hpp delete mode 100644 games/pacman/src/entities/pacman/components/HeadKeyboardComponent.cpp delete mode 100644 games/pacman/src/entities/pacman/components/HeadKeyboardComponent.hpp delete mode 100644 games/pacman/src/entities/wall/WallEntity.cpp delete mode 100644 games/pacman/src/entities/wall/WallEntity.hpp diff --git a/assets/pacman/apple.ascii b/assets/pacman/apple.ascii deleted file mode 100644 index 60a89ed..0000000 --- a/assets/pacman/apple.ascii +++ /dev/null @@ -1 +0,0 @@ -O \ No newline at end of file diff --git a/assets/pacman/apple.png b/assets/pacman/apple.png deleted file mode 100644 index 1bb1a638577716032def9fd93d851cff035e3994..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 718 zcmV;<0x|uGP)JN z6G0Tm-`iLfL9-|x#nn>9lNG&q%6c%QC+lBe`X2=JSRsEx1@AUDFVfx&y%?`vG$4q- z=t6rb?P0forGiH zfF)*YuFr=TF^ccA)vMF}ad*j^bia76F3$z9g@}1_gg#MqLBdBwpMW@uT6e7pba-+~ zPowv*Z$SCY^?-`)uE$qcMD=cz+V0N4_6=^Imb8Z0&f)HQc z{~Rvr#u*7r*Bt!-#cdseDCSzpYcfy`GAc9a15v0rNjb}_MC)MY-ZEH%UA&`mQR|?r zb6}AYiiT!>HCYk12cfSDo2t-zR^Ik1Q>zgA$n4N(iMK&?WWg&3SBB+X`_L|I-XMgrwka{pF` zLcxa4J&AFdNt;WYfkH6vsB_i9G-)Do*xMcD5huxAsAcjv`O6~jgF`L(y*%P1xqsF5 zk~FijpG#Y&qq>r=taGxIn5?%GLACLZ7;zTa1LF(Kax@MzC;$Ke07*qoM6N<$g0C_< AjsO4v diff --git a/assets/pacman/head.ascii b/assets/pacman/head.ascii deleted file mode 100644 index 71c4a23..0000000 --- a/assets/pacman/head.ascii +++ /dev/null @@ -1 +0,0 @@ -@@@@ \ No newline at end of file diff --git a/assets/pacman/head.png b/assets/pacman/head.png deleted file mode 100644 index f369b2a2f9686b3eea791b5e79ea3bdd2c0cddf9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1868 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 -#include "PacmanGame.hpp" -#include "entities/wall/WallEntity.hpp" -#include "entities/background/BackgroundEntity.hpp" -#include "entities/apple/AppleEntity.hpp" -#include "common/components/TextureComponent.hpp" -#include "entities/pacman/components/HeadKeyboardComponent.hpp" - -using namespace arcade::games; - -const shared::games::GameManifest pacman::PacmanGame::manifest = { - .name = "pacman", - .description = "Pacman original game", - .version = "1.0.0", - .authors = { - { - .name = "TekMath", - .email = "matheo.coquet@epitech.eu", - .website = "https://github.com/tekmath" - }, - { - .name = "Yann Masson", - .email = "flavienchenu@epitech.eu", - .website = "https://github.com/flavien-chenu" - } - } -}; - -pacman::PacmanGame::PacmanGame() : common::AGame(Vector2u(20, 20), 60) { - this->_pacman = std::make_unique(4); - this->_registerEntity(this->_pacman->head); - - for (auto &tail: this->_pacman->getTails()) { - this->_registerEntity(tail); - } - - this->_registerEntity(std::make_unique(this->getSize())); - this->_registerEntity(std::make_unique(this->getSize())); - - this->_apple = std::make_unique(this->getSize()); - this->_registerEntity(this->_apple); - - this->_clock = std::chrono::milliseconds(0); - this->_looseGame = false; - this->speedTime = 100; - this->speedBoost = 0; -} - -const shared::games::GameManifest &pacman::PacmanGame::getManifest() const noexcept { - return PacmanGame::manifest; -} - -void pacman::PacmanGame::compute(shared::games::DeltaTime dt) { - unsigned int speed = this->speedTime; - this->_clock += dt; - - if (this->_looseGame) { - return this->_loose(); - } - if (this->speedBoost > 0) { - speed = 0; - this->speedBoost -= 1; - } - if (this->_clock > std::chrono::milliseconds(speed) + this->_pacman->lastMove) { - this->_pacman->lastMove = this->_clock; - this->_pacman->forward(); - } -} - -void pacman::PacmanGame::_loose() { - this->_clock = std::chrono::milliseconds(0); - this->_pacman->lastMove = std::chrono::milliseconds(900); - - this->_entities.erase(std::remove_if(this->_entities.begin(), this->_entities.end(), [](const shared::games::entity::EntityPtr& entity) { - auto tail = std::dynamic_pointer_cast(entity); - return !(tail == nullptr); - }), this->_entities.end()); - - this->_pacman->reset(); - for (auto &tail: this->_pacman->getTails()) { - this->_registerEntity(tail); - } - - this->_looseGame = false; -} - -void pacman::PacmanGame::setLooseGame(bool state) { - this->_looseGame = state; -} - -void pacman::PacmanGame::addNewPoint() { - std::shared_ptr newTail = this->_pacman->addTail(); - - this->_registerEntity(newTail); - this->_apple->generateApple(); - this->speedTime -= 2; - this->_score += 10; -} diff --git a/games/pacman/src/PacmanGame.hpp b/games/pacman/src/PacmanGame.hpp deleted file mode 100644 index 940051b..0000000 --- a/games/pacman/src/PacmanGame.hpp +++ /dev/null @@ -1,70 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** arcade -** File description: -** PacmanGame.hpp -*/ - -#pragma once - -#include "common/game/AGame.hpp" -#include "games/pacman/src/entities/pacman/Pacman.hpp" -#include "entities/apple/AppleEntity.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; - - /** - * @brief Set loose game state - * - * @param state If the game is loose or not - */ - void setLooseGame(bool state); - - /** - * @brief Add new point to player and re-generate an apple - */ - void addNewPoint(); - - unsigned int speedTime; - - unsigned int speedBoost; - -protected: - /** - * @brief Execute the process of the end of the game when the player _loose - */ - void _loose(); - - std::unique_ptr _pacman; - std::shared_ptr _apple; - shared::games::DeltaTime _clock; - bool _looseGame; -}; diff --git a/games/pacman/src/PacmanGameProvider.cpp b/games/pacman/src/PacmanGameProvider.cpp deleted file mode 100644 index 963aaf3..0000000 --- a/games/pacman/src/PacmanGameProvider.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** arcade -** File description: -** PacmanGameProvider.cpp -*/ - -#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 deleted file mode 100644 index a15f5b5..0000000 --- a/games/pacman/src/PacmanGameProvider.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** arcade -** File description: -** PacmanGameProvider.hpp -*/ - -#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/apple/AppleEntity.cpp b/games/pacman/src/entities/apple/AppleEntity.cpp deleted file mode 100644 index 1407030..0000000 --- a/games/pacman/src/entities/apple/AppleEntity.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** AppleEntity.cpp -** File description: -** AppleEntity class -*/ - -#include -#include "AppleEntity.hpp" -#include "common/components/CollidableComponent.hpp" -#include "common/components/TextureComponent.hpp" -#include "../pacman/HeadEntity.hpp" -#include "../pacman/TailEntity.hpp" -#include "../../PacmanGame.hpp" - -using namespace arcade::games::pacman; -using namespace arcade::games::common::components; - -arcade::games::pacman::AppleEntity::AppleEntity(shared::types::Vector2u size): _mapSize(size) { - this->_create(); - this->generateApple(); -} - -void AppleEntity::generateApple() { - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution dis(1, this->_mapSize.x - 2); - Vector2i randomPosition = Vector2i(dis(gen), dis(gen)); - - for (auto &component: this->_components) { - auto posCmp = std::dynamic_pointer_cast(component); - if (posCmp == nullptr) continue; - - posCmp->getPosition().x = randomPosition.x; - posCmp->getPosition().y = randomPosition.y; - } -} - -void AppleEntity::_create() { - shared::games::components::TextureProps textureProps = { - .sources = { - .ascii = "assets/pacman/apple.ascii", - .bin = "assets/pacman/apple.png", - .binTileSize = Vector2f(40, 40) - }, - .origin = Vector2u(0, 0) - }; - std::shared_ptr collision = std::make_shared(*this, this->_onCollide); - std::shared_ptr texture = std::make_shared(*this, Vector2u(1, 1), 9, - textureProps); - - this->_components.push_back(collision); - this->_components.push_back(texture); -} - -void arcade::games::pacman::AppleEntity::_onCollide(std::shared_ptr ctx, - std::shared_ptr target) { - auto game = std::dynamic_pointer_cast(ctx); - - if (!game) - return; - if (dynamic_cast(&target->getEntity()) || dynamic_cast(&target->getEntity())) { - game->addNewPoint(); - } -} diff --git a/games/pacman/src/entities/apple/AppleEntity.hpp b/games/pacman/src/entities/apple/AppleEntity.hpp deleted file mode 100644 index 79ba676..0000000 --- a/games/pacman/src/entities/apple/AppleEntity.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** AppleEntity.hpp -** File description: -** AppleEntity class -*/ - -#pragma once - -#include "common/entity/AEntity.hpp" -#include "shared/types/Vector.hpp" -#include "shared/games/components/ICollidableComponent.hpp" - -namespace arcade::games::pacman { - class AppleEntity; -} - -class arcade::games::pacman::AppleEntity : public common::AEntity { -public: - ~AppleEntity() override = default; - - /** - * @brief Create the apple entity - * @param size Size of the map - */ - explicit AppleEntity(shared::types::Vector2u - size); - - /** - * @brief Update the position of the apple on the map - * (As a new apple reward for the player) - */ - void generateApple(); - -protected: - /** - * @brief Create the apple components - */ - void _create(); - - /** - * @brief Represent the function that will be executed - * when the apple will collide with an other collidable component - * @param ctx Context of the game - * @param target Target component - */ - static void _onCollide(std::shared_ptr ctx, - std::shared_ptr target); - - - shared::types::Vector2u _mapSize; -}; diff --git a/games/pacman/src/entities/background/BackgroundEntity.cpp b/games/pacman/src/entities/background/BackgroundEntity.cpp deleted file mode 100644 index faab65e..0000000 --- a/games/pacman/src/entities/background/BackgroundEntity.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** BackgroundEntity.cpp -** File description: -** BackgroundEntity class -*/ - -#include "BackgroundEntity.hpp" -#include "common/components/TextureComponent.hpp" - -using namespace arcade::games::pacman; -using namespace arcade::games::common::components; - -arcade::games::pacman::BackgroundEntity::BackgroundEntity(shared::types::Vector2u size) { - unsigned int textureOriginX = 1; - unsigned int textureOriginY = 1; - - for (std::size_t x = 1; x < size.x - 1; x++) { - for (std::size_t y = 1; y < size.y - 1; y++) { - this->_addColor(Vector2i(x, y), Vector2u(textureOriginY, 0)); - textureOriginY = textureOriginY == 1 ? 2 : 1; - } - textureOriginX = textureOriginX == 1 ? 2 : 1; - textureOriginY = textureOriginX; - } -} - -void arcade::games::pacman::BackgroundEntity::_addColor(shared::types::Vector2i position, shared::types::Vector2u origin) { - shared::games::components::TextureProps textureProps = { - .sources = { - .ascii = "assets/pacman/wall.ascii", - .bin = "assets/pacman/wall.png", - .binTileSize = Vector2f(40, 40) - }, - .origin = origin - }; - std::shared_ptr texture = std::make_shared(*this, Vector2u(1, 1), 2, - textureProps); - - texture->getPosition().x = position.x; - texture->getPosition().y = position.y; - this->_components.push_back(texture); -} diff --git a/games/pacman/src/entities/background/BackgroundEntity.hpp b/games/pacman/src/entities/background/BackgroundEntity.hpp deleted file mode 100644 index 3402541..0000000 --- a/games/pacman/src/entities/background/BackgroundEntity.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** WallEntity.hpp -** File description: -** WallEntity class -*/ - -#pragma once - -#include -#include "common/entity/AEntity.hpp" -#include "shared/types/Vector.hpp" - -namespace arcade::games::pacman { - class BackgroundEntity; -} - -class arcade::games::pacman::BackgroundEntity : public common::AEntity { -public: - ~BackgroundEntity() override = default; - - /** - * @brief Create a background to the game - * @param size Size of the game - */ - explicit BackgroundEntity(shared::types::Vector2u size); - -protected: - /** - * @brief Add a color to the background (create a texture composent) - * @param position Position of the wall - * @param origin Origin of the texture - */ - void _addColor(shared::types::Vector2i position, shared::types::Vector2u origin); -}; diff --git a/games/pacman/src/entities/pacman/HeadEntity.cpp b/games/pacman/src/entities/pacman/HeadEntity.cpp deleted file mode 100644 index 93c5a13..0000000 --- a/games/pacman/src/entities/pacman/HeadEntity.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** HeadEntity.cpp -** File description: -** HeadEntity class -*/ - -#include "PacmanGame.hpp" -#include "HeadEntity.hpp" -#include "../apple/AppleEntity.hpp" -#include "../wall/WallEntity.hpp" -#include "components/HeadKeyboardComponent.hpp" - -using namespace arcade::games::common::components; -using namespace shared::games::components; - -arcade::games::pacman::HeadEntity::HeadEntity() : _textureProps( - arcade::games::pacman::HeadEntity::_defaultTextureProps()), - direction(1, 0), - position(6, 10) { - std::shared_ptr collide = std::make_shared(*this, HeadEntity::_onCollide); - std::shared_ptr texture = std::make_shared(*this, Vector2u(1, 1), 10, - this->_textureProps); - std::shared_ptr keyboard = std::make_shared( - *this); - - this->_components.push_back(collide); - this->_components.push_back(texture); - this->_components.push_back(keyboard); - this->reset(); -} - -shared::games::components::TextureProps arcade::games::pacman::HeadEntity::_defaultTextureProps() { - return { - .sources = { - .ascii = "assets/pacman/head.ascii", - .bin = "assets/pacman/head.png", - .binTileSize = Vector2f(40, 40) - }, - .origin = Vector2u(3, 0) - }; -} - -void arcade::games::pacman::HeadEntity::forward() { - this->position.x += this->direction.x; - this->position.y += this->direction.y; - - for (auto &component: this->_components) { - auto posCmp = std::dynamic_pointer_cast(component); - if (posCmp == nullptr) continue; - - posCmp->getPosition().x += this->direction.x; - posCmp->getPosition().y += this->direction.y; - - auto textureCmp = std::dynamic_pointer_cast(component); - if (textureCmp == nullptr) continue; - - textureCmp->getTextureProps().origin = Vector2u(0, 0); - if (this->direction.y == 0) - textureCmp->getTextureProps().origin.x = 2; - if (this->direction.x > 0) - textureCmp->getTextureProps().origin.x += 1; - if (this->direction.y > 0) - textureCmp->getTextureProps().origin.x += 1; - } -} - -void arcade::games::pacman::HeadEntity::_onCollide(std::shared_ptr ctx, - std::shared_ptr target) { - auto game = std::dynamic_pointer_cast(ctx); - - if (!game) - return; - if (dynamic_cast(&target->getEntity()) || dynamic_cast(&target->getEntity())) { - game->setLooseGame(true); - } -} - -void arcade::games::pacman::HeadEntity::reset() { - this->direction = Vector2i(1, 0); - this->position = Vector2i(6, 10); - for (auto &component: this->_components) { - std::shared_ptr 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/pacman/HeadEntity.hpp b/games/pacman/src/entities/pacman/HeadEntity.hpp deleted file mode 100644 index c2b9688..0000000 --- a/games/pacman/src/entities/pacman/HeadEntity.hpp +++ /dev/null @@ -1,66 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** HeadEntity.hpp -** File description: -** HeadEntity class -*/ - -#pragma once - -#include "common/entity/AEntity.hpp" -#include "common/components/CollidableComponent.hpp" -#include "common/components/TextureComponent.hpp" - -namespace arcade::games::pacman { - class PacmanGame; - - class HeadEntity; -} - -class arcade::games::pacman::HeadEntity : public common::AEntity { -public: - ~HeadEntity() override = default; - - /** - * @brief Create the head of a pacman - */ - explicit HeadEntity(); - - /** - * @brief Update the position of the head of the pacman - */ - void forward(); - - /** - * @brief Direction of the pacman head - */ - Vector2i direction; - - /** - * @brief Position of the pacman head - */ - Vector2i position; - - /** - * @brief Set the head at default position - */ - void reset(); - -protected: - /** - * @brief Get default texture props - * @return Texture props - */ - static shared::games::components::TextureProps _defaultTextureProps(); - - /** - * @brief Represent the function that will be executed - * when the pacman will collide with an other collidable component - * @param ctx Context of the game - * @param target Target component - */ - static void _onCollide(std::shared_ptr ctx, - std::shared_ptr target); - - shared::games::components::TextureProps _textureProps; -}; diff --git a/games/pacman/src/entities/pacman/Pacman.cpp b/games/pacman/src/entities/pacman/Pacman.cpp deleted file mode 100644 index 317ea30..0000000 --- a/games/pacman/src/entities/pacman/Pacman.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** arcade -** File description: -** pacman.cpp -*/ - -#include "Pacman.hpp" -#include "TailEntity.hpp" -#include "HeadEntity.hpp" - -using namespace shared::games::entity; -using namespace arcade::games::pacman; - -Pacman::Pacman(unsigned int tails) { - this->lastMove = std::chrono::milliseconds(900); - this->head = std::make_shared(); - this->_baseTails = tails; - - this->reset(); -} - -Pacman::~Pacman() = default; - -std::vector> &Pacman::getTails() { - return this->_tails; -} - -std::shared_ptr Pacman::addTail() { - std::shared_ptr newTail = std::make_shared(); - - this->_tails.push_back(newTail); - return newTail; -} - -void Pacman::forward() { - Vector2i oldPosition = this->head->position; - Vector2i tempOldPosition = oldPosition; - int at = -1; - - this->head->forward(); - for (auto &tail: this->_tails) { - at += 1; - tempOldPosition = tail->getPosition(); - tail->setPosition(oldPosition); - oldPosition = tempOldPosition; - - Vector2i old = at > 0 ? this->_tails.at(at - 1)->getPosition() : this->head->position; - if (tail == this->_tails.back()) { - if (tail->getPosition().y < old.y) - tail->setTextureOrigin(Vector2u(0, 1)); - if (tail->getPosition().y > old.y) - tail->setTextureOrigin(Vector2u(1, 1)); - if (tail->getPosition().x < old.x) - tail->setTextureOrigin(Vector2u(2, 1)); - if (tail->getPosition().x > old.x) - tail->setTextureOrigin(Vector2u(3, 1)); - continue; - } - if (tail->getPosition().y == old.y) - tail->setTextureOrigin(Vector2u(1, 0)); - else - tail->setTextureOrigin(Vector2u(0, 0)); - } -} - -void Pacman::reset() { - this->head->reset(); - this->_tails.clear(); - - for (size_t i = 0; i < this->_baseTails; i++) { - this->addTail(); - this->forward(); - } -} diff --git a/games/pacman/src/entities/pacman/Pacman.hpp b/games/pacman/src/entities/pacman/Pacman.hpp deleted file mode 100644 index 05af76e..0000000 --- a/games/pacman/src/entities/pacman/Pacman.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** arcade -** File description: -** pacman.hpp -*/ - -#pragma once - -#include -#include -#include - -#include "common/game/AGame.hpp" -#include "shared/games/IEntity.hpp" -#include "HeadEntity.hpp" -#include "TailEntity.hpp" - -namespace arcade::games::pacman { - class Pacman; -} - -class arcade::games::pacman::Pacman { -public: - explicit Pacman(unsigned int tails); - ~Pacman(); - - /** - * @brief Head of the pacman - * - */ - std::shared_ptr head; - - /** - * @brief Add a tail to the pacman body - * - * @return The entity to the new tail - */ - std::shared_ptr addTail(); - - /** - * Get tails of the pacman - * - * @return Vector of tails - */ - std::vector> &getTails(); - - /** - * @brief Reset the pacman - */ - void reset(); - - /** - * @brief Update the position of the pacman - */ - void forward(); - - shared::games::DeltaTime lastMove; -protected: - /** - * @brief Entities that compose the pacman - * - */ - std::vector> _tails; - - unsigned int _baseTails; -}; diff --git a/games/pacman/src/entities/pacman/TailEntity.cpp b/games/pacman/src/entities/pacman/TailEntity.cpp deleted file mode 100644 index f6c43fa..0000000 --- a/games/pacman/src/entities/pacman/TailEntity.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** TailEntity.cpp -** File description: -** TailEntity class -*/ - -#include "TailEntity.hpp" - -using namespace arcade::games::common::components; -using namespace shared::games::components; - -arcade::games::pacman::TailEntity::TailEntity() : _textureProps( - arcade::games::pacman::TailEntity::_defaultTextureProps()), _position(0, 0) { - std::shared_ptr collide = std::make_shared(*this, nullptr); - std::shared_ptr texture = std::make_shared(*this, Vector2u(1, 1), 10, - this->_textureProps); - this->_components.push_back(collide); - this->_components.push_back(texture); -} - -shared::games::components::TextureProps arcade::games::pacman::TailEntity::_defaultTextureProps() { - return { - .sources = { - .ascii = "assets/pacman/tail.ascii", - .bin = "assets/pacman/tail.png", - .binTileSize = Vector2f(40, 40) - }, - .origin = Vector2u(0, 0) - }; -} - -void arcade::games::pacman::TailEntity::setPosition(Vector2i position) { - this->_position = position; - - for (auto &component: this->_components) { - auto posCmp = std::dynamic_pointer_cast(component); - if (posCmp == nullptr) continue; - - posCmp->getPosition().x = position.x; - posCmp->getPosition().y = position.y; - } -} - -void arcade::games::pacman::TailEntity::setTextureOrigin(shared::types::Vector2u origin) { - for (auto &component: this->_components) { - auto txCmp = std::dynamic_pointer_cast(component); - if (txCmp == nullptr) continue; - - txCmp->getTextureProps().origin = origin; - } -} - -Vector2i arcade::games::pacman::TailEntity::getPosition() { - return this->_position; -} diff --git a/games/pacman/src/entities/pacman/TailEntity.hpp b/games/pacman/src/entities/pacman/TailEntity.hpp deleted file mode 100644 index e7d60e8..0000000 --- a/games/pacman/src/entities/pacman/TailEntity.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** TailEntity.hpp -** File description: -** TailEntity class -*/ - -#pragma once - -#include "common/entity/AEntity.hpp" -#include "common/components/CollidableComponent.hpp" -#include "common/components/TextureComponent.hpp" - -namespace arcade::games::pacman { - class TailEntity; -} - -class arcade::games::pacman::TailEntity : public common::AEntity { -public: - ~TailEntity() override = default; - - explicit TailEntity(); - - /** - * @brief Set position of the tail - * @param position - */ - void setPosition(Vector2i position); - - /** - * @brief Set texture origin for direction of the tail - * @param origin - */ - void setTextureOrigin(Vector2u origin); - - /** - * @brief Get position of the tail - * @return Vector of the position - */ - Vector2i getPosition(); - -protected: - /** - * @brief Get default texture props - * @return Texture props - */ - static shared::games::components::TextureProps _defaultTextureProps(); - - shared::games::components::TextureProps _textureProps; - Vector2i _position; -}; diff --git a/games/pacman/src/entities/pacman/components/HeadKeyboardComponent.cpp b/games/pacman/src/entities/pacman/components/HeadKeyboardComponent.cpp deleted file mode 100644 index f5afa50..0000000 --- a/games/pacman/src/entities/pacman/components/HeadKeyboardComponent.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** KeyboardComponent.cpp -** File description: -** HeadKeyboardComponent class -*/ - -#include "HeadKeyboardComponent.hpp" -#include "../../../PacmanGame.hpp" - -using namespace arcade::games::pacman::components; -using namespace shared::games::components; - -HeadKeyboardComponent::HeadKeyboardComponent(HeadEntity &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.y != 1) { - this->_parent.direction = Vector2i(0, -1); - } - if (keyData.code.arrow == DOWN && this->_parent.direction.y != -1) { - this->_parent.direction = Vector2i(0, 1); - } - if (keyData.code.arrow == LEFT && this->_parent.direction.x != 1) { - this->_parent.direction = Vector2i(-1, 0); - } - if (keyData.code.arrow == RIGHT && this->_parent.direction.x != -1) { - this->_parent.direction = Vector2i(1, 0); - } - } - if (keyData.type == CHAR) { - if (keyData.code.character == 'z' && this->_parent.direction.y != 1) { - this->_parent.direction = Vector2i(0, -1); - } - if (keyData.code.character == 's' && this->_parent.direction.y != -1) { - this->_parent.direction = Vector2i(0, 1); - } - if (keyData.code.character == 'q' && this->_parent.direction.x != 1) { - this->_parent.direction = Vector2i(-1, 0); - } - if (keyData.code.character == 'd' && this->_parent.direction.x != -1) { - this->_parent.direction = Vector2i(1, 0); - } - } - if (keyData.type == CHAR && keyData.code.character == ' ') { - auto game = std::dynamic_pointer_cast(ctx); - - game->speedBoost = 3; - } -} - -void HeadKeyboardComponent::onKeyRelease(std::shared_ptr ctx, - shared::games::components::IKeyboardComponent::KeyData keyData) {} diff --git a/games/pacman/src/entities/pacman/components/HeadKeyboardComponent.hpp b/games/pacman/src/entities/pacman/components/HeadKeyboardComponent.hpp deleted file mode 100644 index dd92c9f..0000000 --- a/games/pacman/src/entities/pacman/components/HeadKeyboardComponent.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** HeadKeyboardComponent.hpp -** File description: -** HeadKeyboardComponent class -*/ - -#pragma once - -#include "shared/games/components/IKeyboardComponent.hpp" -#include "common/components/AComponent.hpp" -#include "../HeadEntity.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(HeadEntity &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: - HeadEntity &_parent; -}; diff --git a/games/pacman/src/entities/wall/WallEntity.cpp b/games/pacman/src/entities/wall/WallEntity.cpp deleted file mode 100644 index 0c4bbad..0000000 --- a/games/pacman/src/entities/wall/WallEntity.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** WallEntity.cpp -** File description: -** WallEntity class -*/ - -#include "WallEntity.hpp" -#include "common/components/CollidableComponent.hpp" -#include "common/components/TextureComponent.hpp" - -using namespace arcade::games::pacman; -using namespace arcade::games::common::components; - -WallEntity::WallEntity(shared::types::Vector2u size) { - if (size.x < 3 || size.y < 3) - throw WallException("Invalid size of map"); - - for (std::size_t y = 0; y < size.y; y++) { - this->_createWall(Vector2i(0, y)); - } - for (std::size_t x = 1; x < size.x - 1; x++) { - this->_createWall(Vector2i(x, 0)); - this->_createWall(Vector2i(x, size.y - 1)); - } - for (std::size_t y = 0; y < size.y; y++) { - this->_createWall(Vector2i(size.x - 1, y)); - } -} - -void WallEntity::_createWall(shared::types::Vector2i position) { - shared::games::components::TextureProps textureProps = { - .sources = { - .ascii = "assets/pacman/wall.ascii", - .bin = "assets/pacman/wall.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); -} - -WallEntity::WallException::WallException(const std::string &message) : _message(message) {} - -const char *WallEntity::WallException::what() const noexcept { - return this->_message.c_str(); -} diff --git a/games/pacman/src/entities/wall/WallEntity.hpp b/games/pacman/src/entities/wall/WallEntity.hpp deleted file mode 100644 index 693cde6..0000000 --- a/games/pacman/src/entities/wall/WallEntity.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/* -** EPITECH PROJECT, 2024 -** WallEntity.hpp -** File description: -** WallEntity class -*/ - -#pragma once - -#include -#include "common/entity/AEntity.hpp" -#include "shared/types/Vector.hpp" - -namespace arcade::games::pacman { - class WallEntity; -} - -class arcade::games::pacman::WallEntity : public common::AEntity { -public: - ~WallEntity() override = default; - - explicit WallEntity(shared::types::Vector2u size); - - class WallException : public std::exception { - public: - WallException(const std::string &message); - - const char *what() const noexcept override; - - private: - const std::string &_message; - }; - -protected: - /** - * @brief Create a wall (part of) (Component creation) - * @param position Position of the wall - */ - void _createWall(shared::types::Vector2i position); -};