From 13fbc3fe3d562e493841f076d087f2cb54a59589 Mon Sep 17 00:00:00 2001 From: Rene Kievits Date: Thu, 17 Oct 2024 23:05:52 +0200 Subject: [PATCH] Started fixing positioning and scaling making it more accurate to the original --- README.md | 1 - assets/sprites/scoreboard.png | Bin 11038 -> 10650 bytes assets/sprites/title.png | Bin 9290 -> 4874 bytes assets/sprites/title_bg.png | Bin 12133 -> 4889 bytes src/Game.cpp | 12 +- src/Game.hpp | 2 + src/GameBoard.cpp | 6 +- src/GameBoard.hpp | 4 +- src/Renderer.cpp | 277 ++++++++++++++++++++++------------ src/Renderer.hpp | 15 +- src/Sound.cpp | 25 ++- src/Sound.hpp | 10 +- src/main.cpp | 4 +- 13 files changed, 215 insertions(+), 141 deletions(-) diff --git a/README.md b/README.md index af31828..df45864 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ ## TODO -- Game Over screen - Add Gamemodes - Gamemode selection screen - Save score diff --git a/assets/sprites/scoreboard.png b/assets/sprites/scoreboard.png index 9c250db7623c9ec09929219cf6e7f13741885cf4..84f2e5a69a3fe82fca1f76a49fa31a97c913f9a8 100644 GIT binary patch literal 10650 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 AG5`Po literal 11038 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 YU)q{hzZZdjmH+?%07*qoM6N<$g8G_RB>(^b diff --git a/assets/sprites/title.png b/assets/sprites/title.png index e7f0bd1851fb20c26aff1d0a9b5fcfe597454e8d..406aeeab6d1eec6ae7269c9b4e7e21d5dcafd89a 100644 GIT binary patch literal 4874 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 CAleK7 literal 9290 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 diff --git a/assets/sprites/title_bg.png b/assets/sprites/title_bg.png index 750f9e4e328ca58ca25081704f81fae5bdcdfd71..d7a1a182a85fdecff4add3ac9a2d798101cd8428 100644 GIT binary patch literal 4889 zcmeHLdsGuw8c#q4Q^g{Ps90h+RD&j&Ox}?QN&*B8B47p7*2&BSM#;lukbrtrEQl7m zQWeo6VnI<6S#0oyi}+SlKwXj6Zc&!*cBO@Cwb+8Vcf!-tp0meuw*L{%&Hd)y-}k%U z{oU_=Fl>zo4;jmt%%IU|W7VO`NYHNw4RUq>->an<9dr$Nj9RBw`_Y`i13=P8(5PVw zNAI&CU^~zqX^x=J0Bt<5DGb#n(?{C-EMQORvv&e}MjwV+iBET+jRk!^XfUwdL4Oo9 zVoUE@)xf4c&i0>BU{TEdeTZ5U!GyVdh%1l+e+U-J`H-A1Ve(~iAuNaZ08K9(jEG{2 zQ&uknEa^m0P=q=th-oq#bwnagqgnIU=O{ui1$t&QpA0)_%WRr^d0Nl}r>eu5XxThh zzmMY%EOy#4|8=1{=(CoV8K*tGx?_*YPfOdLJo0l+3t-l{gm2?Uwj`?$sIrp1I)D1M zv-+F$PA@-Sd}yy?bm0A2K0Cq~XS$ERyH4foD7@yHlXs+kt9Ek1Kil4$Q{8+eB{%sW z`+dG}Uoh(Bh?Wue#(rYmY}MVnE9-CziH(iStlv6)%vt7Bp9lEvX6bIPUw*!IIOp~) zw~(#rkrQt&zg3$N=CARJiq3xaO167K-O~K~EB94)-1x|on=td{vJz36yGO+cR|o9x zi{?)7XtAv-&b!`_a`#fe4=+{b8?8q-=Ad-Z;q6`lFTK0l%VP8Qk~=P{3p=lz3<%!z zh}*ET>6gw5{i*PcH3HMYr0&Z1p)Pf5QPGu8H}>cswVW-wv9{(r7wCEM{EXI6dR&jz z)f!M_taaRcDlp;pk4w9}O2!4|rtYeyySQws7>}2)Jy%s;WqjRe>*{pe9%()yZ(DF0 zB%zgvjv-?-3*@L#&qXk!7Ux>^ChEj!{sC4Kg08|zrWTJU3<_39)p-_^z!a<{A`PT5 z1>p%qXsQ{HN)3-jQ&*ufj1@44;ct}#0zFP5OshW8V3AuDEIY3p*wiqO#k51nRSH%N zNTeX68D|Q)LN3HnS&20;YYv0yZ^m@;NM&#z1$a`h5=hb{=kb!0lex(PuF)LN>Ihob1^P~sNUOqfW*Xkb#Dh}M`yDp)Kq&+Ly+Z_;Q6=na-W z6@VT*D`MjDxe!mU=MD9+kg7F+q%WX9^sq#ym~dVsZZRgAQCzhKH;_I@zN$3W}dLuS!#=f1QfdKab-Z#+w zd$)rDN~4i0jc5`To?5A3QR~YwBT8U$y9r4J7|a*SIAWau;s~`el%v%`0*+XUp|Dh< zlL#gF5Gu97LLvqfr>FoqmjFB%rWJ`$ftDlC3ZxvN1VTAdLJg}2*qNUBSUl&jzlXF3qho)SfI62VW>RVXx1a( zI0-!xkMm51c>4q;xO{GeTET+3(BMc!B0}nbgMzhyFeF(AC!z^G9z`OQntTZ?<4eUd zSO5!zQYn8B^Z{y@Ur|2|BjL@b0FEn*|nEn6{jy#mGfb~=CL%laD z3SZs()ccr7*sl_kX}=V51nu2|1zCgl9v0y0ok9~3Lp% zM+`waj*u_Yau5iWa%2JljOxTP2`-V^RTyBm7(@W# zSDpBnIVL0aYFfybw&LRFIkVVoPKvNL3d=xRS=y!-p^;~fpSp4C^}@@iy$`w<6&8N) z?j7l=O(>g$E|02Z-^{e-Tk2#rjqF1y1?&fz&%W;5$8Y47?x@T)XZ!ME#8*SvvnTnm z$3%UIkYTg3k(YPw+YWu+#k<+E`$F}#F=*Di7d_Fk`*Bmy)Lk!bZ*f_a&WFWp-$3)w5TX?7%V8E_cqVs6IY>as9&9q@R06-5i(AU%ou&6n^Hf zPdDnEZ5Kta@+z0IHm20Ic9hq(6J>2rypPnR?Hs@U!_~i)5UG1lHYTNu9)CHZVG>v1 z*LEjiYC+7!5YkxeSMg4nqgc7m74n*%^{S!#0v?>38CW{2Jmc)5ussj+Ha@;5KlYSW zij68U)%i-^Uy)#A{7tfC&xBf|!2>yxTF-V~+E#2P3ABeRcWiUf$MmUzE)s&5&eF zDay#&U$?%M(P`e`vted&YtfO(`OtqRc2w)9001%w1^@s6+hNdU001BWNklGoCsuS%StqNv+~Jdm!aY7qkesUQIn?4Vl&5U~?}7m!ej-Qyc$%(ZtY zsZSO0@i}X+$DCu1`B-ajAN}obf4@GyzB;@)IXWEcf7e%6hwH=9L2nQG<#5pdPxQ-` zem^?WcY1TJpZdrD9nntL@aFjX`tauH`f#Gp{ZpS^U0olpPp;LLc50>{>hN%+ey-GB zz4@!d@$unEzhCJSUG4VAy8eyk;31B)`vI@%fZ-M&y zOwd3AL{>7$12MW-=s;Fi2Hu!Jg^C&hhLq)R{61^E*7(;3K-${)n32Xh(Hx|21NcO! zv{^B>k;VActgg?e7_VCCb7L;r)V0yE?c2tW0s(44Y8}#7+PlSxfCJ+7*-1eLu+i(W z7V0@L4RwCZngk_NRL_^pcu;@59B5DVm1=vaAADu3?e}j2B^wG7q8@ln-c5B;Yp!wb@kyIMM{nN;VSa4e%o91rZFwXjNPF<#lN; zX$C;EG{Xya_q-$y&BH)9h_ZIud6sJ-o7qDRHk$A-S| zKKkgtZIBqlwG5T%8y;R`abPLdQ_?YpZX;qmUE@BP$E+_}fK;L;Q%u&4u&`Ff`TIv7 z#i$Dk7G%63KwPth99m}4$2Rk_gd6fbET!J0Y#Cj7ZmFY1=Dd~%U{NwQI)xXR}|M8#yc@PfDV(3zR zOQ%a^xMPNHIAZhQch;=2?bpogy2eYZa5B3ZAi&03)Dzh_G`F*}r#5liWL#rdWLYiN zWc~ArqaR;Li#k)Q1$H7<0q$Nf6SVavMp}f|j7bp_h80hoJP>mrz@!oF z&MwUGoAwUA%AA3G;w+=83k1Y`UIAP12$3<$9KZ+Q5a`=g0tY|_xj7k%5WNoUN^Iij z!y!bKW0wr;)CKb%_A~pIcMO6UT`V>Kkc7;y6BZ^!=7PpY099j=Bsj6soUZW_h#IrC z_GfO|6|EoOBC6` zOCm9FSg=XkF47xLbDL1?z-FeKm3NH^?D;BQ0%5fLVtaO-eK4 zcM^XD=M0%DK!IprRSD3rGopa4vT|%RQk8dXP+1*X3h^$sce7NLh?}$wl1<}U0hW`5 z1d$H)qSP>R2Ca~Bf&4xI;W{ygVs|r9`Ml9hCT4Sr#(f=eqZ5Eqa>j@Y_fRBvl{5xL zY?{Qcp1?-HBqJA3N0WBY?{*o7k`Qu&tth*=MAV7`%C%Z-v?YxuX}H{1um5FF@ZGa# z20foW{pN{fF;xn)er4Xo@j2x|ma25AalKd~w$?x^UDe3&00%9;-=I(z!9P0%4i zvpO%R zy-74yslots5z8+F&8Q#i&^nvvI1wrv#BMtWTqR?74zx*stjiW)K)Nhr#V6eHSX1gK z);xcMCyd0;UH*Nz|KZ)k+1F34!w>G>Ih>t;6TrO1QYoPUsz?;lAW4iQ{n>=#H5v>x z<+fA+0zA0N3{*YDuxxlw&(5bJ<4Y26m07a%#ze`s=#8ut)^gm&M*`ko-hFR0>Z|f! z+$Zk<;;@@F-8vDIGq+$_01}|M+Xk)%Yba^r9Wz(VYa3^|G`ed}?CDlP9es>o#Z-<7 z>957qnKA6o7>;ilKI~J8xV2r+f*^w9cicE{%U-4-ec@Doq*0ibeK)e-3@7@OMm*tY zIWCZrQUJ9tJ2|deLGzAD$2Sj^jqKIW-Mb%1-$#ch-vGY2TQe)&d#;tzWWh`3eAn_4 zGWM@z=QRkkS>j}SArdFPvn)4lT88HWARpnROsT2C7>HMnUl^cuLA_5{6RWoM$vyq$ z&jMe?UR_Q3tTK-~{r>y!9lX-ia>yzpR6_tkgFu_Q-+DGEfe(Vrns(<%Q@4wi68Eg~ z!H`=$+CX4IH`5AJ*tqnc{b@3Jn~*UVM~Hj#O!;C*(iVrPAWUtl?Ybm(l7i0BNeI2R z6p?%%#Zh(wU1dv`ZCK3sh^f17GF#%doHmlk$ay8~pr6cl=7o1d+IR2WH`s8!26~om zSyM6^#+Y4{(aFBg)D{6PiC@6$s@sgaE5OJ5;9V5L)m0yze|w&|6Vcd;0>BjIsE%QA z%t^v%;A!G37T$eN;4AyQz0xYn%UNqV{P66D#bnIV1yip%)*n(xtmzEO=HWLfN>@rJ zvfMWgHkKaFY|D&6lUEK3l7~Lk`MeI1&2ACis z0fgg2O(~#Fy1*K*Ez3IEkrj2p@$5B(*!AArY3$C*|5!yVW_*CVE4bd1E`EIWy_Ii6 zFQHnrTvo#vjQ~IpclJ~zn6b|OblxSS3OE|c3%JM*0)F;`rFK$$|r8EAkMA&g1= z8wL;G%X%hj-M363I~E@`WW(QXfv@;DxbOFghYY4#c@6+1drOAcy~ivg9%i3aV{9mE zm}i%L2Y_6VT@2SA?PiGwcNwBH!?)8YR?#UL9|mPKZ*$@85YkeRw><;=6^FSdnx4WS zxo}d7eOYzZH@+wRj(31G^5RefY;yPBU3nFx-Jd+!y z%tLn#Is9g}jwT*U&>BBEjN>v;f%Hd+FGX651x{C!st=`^NQ{#o;ZRZrd$d*4+A~_uXtbjB&o(WBztvvp3 zjOk{2JyW2(?L#EtU@WUhLS?b^(cEY##>;g^YVd6QH#TA=(gi;OA@n{_+=CaOZ*t zWmU@5^0&e?;HwMiaVdmjCpiA8GSBfYVi4@dt6E0H;*uRxeYZsXoe#QpK3PlZfZ-pl zz=hSIXUe>GHXO)wHxgN`-G*hIZW(~qq_7h zxSjYemC%ME!yd~>3FD;N?*7|-o8%KRc+r{zr;WDK6h;vP;xNMRuYNoHQ%T`{x#Dwy z@D0fsV6n#-W@Xwb^O*B&w=F}vEYepKJCI*i;s?Sv6cude?3?2;K68C>3f=+CS`LCM+whs|qUwCu&ZPvqa}t}8 zdc*aIefQ6QmH=C;vqEXfc3c)< zWjCnIsK?5Nwf*)M32uxLU}S>Sj*`{X6358gC1ygaoo}Fm4Z?x{|k{$kB zp}};#Z3l~nA(=n!K35@=aExo5g9RTK%GP2)*T6kXbuH3kQdC|$59!{!L99~+_bp5a zXtFZNv8A22L}>N2b~#M0{>?L5gHKbzJdOn_AIRUm?nG|})Oc!^IxpdcX3NFCES+=C z@UFJsa;P=^=}drQTbGMy!zzc)g6ri)CeF6`l~K3dt#Uw((q08y%jotIK4*Y&p&z?o z$km8+(3gc-L*X9Vu|G__1ns0GlK71P|K0cgTyfBWwYR<0*5Cv9(2=`J0eKE5?Qn|N z>0JNCNqU!{^v|WvL=D93B4l9&n<-}{{{~97({Qt?>lKTs+OMUeT(le{#=&nc-{W$i zlKUq3Wnao!!p+jMi@}H8E+ZIqffGwhF=uValQaP~%d1R6Ol+o!;docZbxJ-b398>O z&;q&$+{JrzY5inAyk<(gzwg5czaJia^5Agm^w#0U<;CIiM~@EL6$^OHmi#|E-cx3e zlgXgLSJRR*;Hrqvh$|G>KnWk_<4n%Su}r0gDxH_{SPTkin6Y@N*^%9vSKMtXPYgC3 zAZFn|icL{^YG*KMjc)VHjx8oeOi>RAv=-8V$tI!n#4{_WYmA;4WtL!YuB=|YyAQ9% zKLfBtY$?E^wSaFGp?v>DT`=v{d78B>(|9#W8*8t7cO6WIxxTOR7brD+g44Joe&s*M z|MAhDZrPSajl0e4bH#>#es{gc@vcwI%-X12_%p_eSGptc{r2j2`{{=te|ore>*nFb z#igb4=<%1@mQziz>|x_{DGF_{v$P#($a3uDJ>T#ZI%BM!sX{dRH7AdPhq&y%;rnyB zU}QHLi~B*IlkTVk+87AL&z6xa60>UqTm));brv<|WWe;3`kbpu zRni=0wP=kd#E-j(r3O3sZ1=%i3G_&`&YWM@oZ*DCnf>+XeP>ye9SdXUR;_q(um`tQQvd~`;`TUbmD^P zD82D7;CuD^D}Vg(!9#)X)L&mdzdW4YK0UnD&o3T}2?fH9 zmg)l^lT8aNc&R!`?)JUG$dy4|sRXMv6Hh}qm8#0I#l zYC1K$vLDhkDz!?V<9RGK-CI7&tn#)R>n^KZmAjCN_xNK{h)r zi!*`W>|JgBJ zyW_|yw~i)$bq>(bWf3`Rm@7R5}w?Zi; zG~Y2&vBWTULIKCN4Z_!!k!2g{TK22v$QyUo6HJ%uU(#C*T~^4gy~{PYthbT}3J zp{SRa&)x6o&6}Fz$>H+ixxx0OK==*!iI{CiAYsz1XlD}p@CBA!vccLIl@KQ3%-jWO zGXg*7I*>Z76jw7<_+6&Av-Ev!bW68zt5ZWn0thQX*tqkpqBXW15cHm^SPBbct=4Xq zvB0d)ycS9?#AR+ZaX7kX7idrrLbCfOd+sj8Hl2|W zb4)BayDkYvH!gQSD8@lhr#dV#S~Tgg<3b^xIU4md1Mk^#;>U&h`O2tg9MjHj%qS^q zZ}K2(@y$oSzV^<{g9jh`s+;c!e2(>x4liE*k_0i$UuhPhDM5XH6GlwP*8ob4<3gk(J~EjZGSr6(~NJ%>Hk-r#82pv^S0 z-^b*l*kfmZwN|?k`l!NzTO(;#2~fCsFGw?4+3I`PU?=Vj*K){!91uEjE>f!>GG(gx zi+CEdFpT5SwbezZW4kRQ)fw!w$<@mHsr)vZ?@f%XSN;jpyT{o|p}ZrRm@Q|%$cwd( zky`>yBh)3gSB`Ywl9!2vn&bw8>=OgeL}T~Fe7}-#XpVNf)$0w#dlZ*1E-u!RPX$0k zcJboUbGf14amk;5`PJd+**6_$CaH;W3LcF$Sj;*jKgxX^g)=J?n(=YBrJTX9a6%$_ zdVVg3MQJQ3r(Qzkm|Ri1b1}(pKx>3{m7688>ZT3#;*4m^L6P)P3-os>}5BR45 z?mmoY5|RoVci&Xn)3cG;>^%Z;EAx&k?dP~sgf-^bkim+gq%>9kIDTE3e{GQCbF-iT z+@+9|MJ9HLX9#;CoK=Z(;JqowbxD9}1E={Y)mpN|=4cjQn`z+$6v@2Yym5Nx<_gbr zRnBn2p*!DD<0lV4&AfE^?Hgh`Ok3AJfBvHLg#mAQ^?0sJvES{}+lS{bFYIj|fBER} zwGxw5z?l@G7>1M(D7Rhq2!2*?uk^tOZ1o)-&YtMR^~fp=6=Oi_PsM;E0~dpN%|Xur zRT{$rQ)GlZFfE`%Nq z=N=i?NcG#?2*pRVH^ijWiKZ;^cIx|xy@whV_ympCI-B|?(iYDFX_Bs}jEk&Ljr0D! zJ94{WzE3~}XK-57tlJXb6H~!63t3gjGOSlTJ`{EX zG-$#}T+Aq^a+2*%Rv5zUkuV#@jO%i(k|exK61!4;z-lX1e{(deya7YqyZ^!Aw_ho> z9Lw!KC_0Y?rW;{b3h`?H;_^kLsQ;f56OO@XFEvq{xh>toluF%xo%|Y z7Kvj%V_M^FRN5rcmHc5}IulYS+2sFaj3b`W)L;abU}`{NxSu5K#1X z##?P>{aj?d4fFVC5{=w-lGo^VfH_RLkZR@8FpQTQ&F4biK((zj$8%-KwQ-qoJZBW& zdBu&#a1!(b2*aZ@TZ1e&f^@U_qcym%fS;DzsprVUa;SmEiPxxRE_LhKK|oh2plA4u z-Mpv<+YN$#Z#RsgLX`UH1PGlQkXO39?f&7l_IFv&!-t)gt&VLL-@t(n!_je1ho{i4KV#cNZ@m|}wE1KcYG&6XVoSLreCK9-0< zu&B6WPkQA$+u7PF3kE2YXsi`Z;%?A%Um-gOMcTfslzLw0YktdV4j;roW(CaJuB*(p zf`Be|l|QSQ&|zwH?nEgfha~*gZ5lIT0L+on4gl{%pj`a*y~5~u=r!x}eI-V4$}PYD z{#vD$2i=5;J_(^tZ{DyRCgG>}JYEN*1ArdAaV65dpdPq0yj!N8Hizf`vUk4Ik!v?^}9^(MjWgv9JDXeSFTf;t8q zciN(KZqYNbtE*Ue4uuRTW7APyv>exg1V|JDu{>?EU$gXr_`+J9f>W;OneKx^x zxoSUKe!6bkXWyWU^0IHbUFU=V*3!bF)D9SvHRGB;hx&$QAYuT?-Y(g2PrkUsFt;Jh zl39IAN_+W`u=##nNv9q&S8fZkpp%g@M`FgE7qb~KH^B!r5Ng#fs=Lm*aQG& z&IyZS&^GkrWWB#>n@u`=_#itSeyRQGjoS`_#${is&gc5%)LJ!#n=ZjbvN?Pb-P3k? zA9X-&kQebF3CYv1vuB*(l5SfOY0!O7F)953#Eqb~x%mb%-xaqi_FYt&J{$K09A%VY z!`PU<;}%BlIRG_Tz*@Pd)*}wSuCbfm2MbxGl~@K{Thd+)cvxZ)!=!+nBk^UV7?DTX zLB)^_?D=Ncnq_1+WM1Z;vRHzN=JPFPr=}PqGOzmic3taAZeWroXBb#)CG7uJ?ThYH z|C>2kLd^zQz*WmG&$T@UbGe?cz5rXIMFmP2T2F>B^$+xPgMW$r_~?Q6cmoFCSFO)Z zZ)=MU;|7HK>XO=DHxw*;eRku`>$RrfGUn)~B4OIdu&0M}vA5x-E&-i|ll!Ug& ztt58;P;+CA=ZgI%<2JF_OSLNStxv-=QJ4}43m>8Tv0POeR@E%~Oxw0D`2awcav^X&e)PH7%_a^R@KfK7-0yyP-xZ9nwUZK}h;igy=I0o2TwCh1 zd%`XZo9X5I{o(x#71x^%2L!eT$2kG>dSpd2rG%39C1ETZ-;UBc)dVm4|H_Jumu%I! zW{E{%fpzs5PxWr{EwfOw za@3VW(U?8P?m>5A=(DWr+mYCdRvR-!G7TyI`Qi3Ex4hq-#HwIzxUdpDb$L&_4Zi_E zb^FO@+VNRVs3}pSxra8j1g38*^rvc+g#~r=( z+5o;ud9{l#dZcG(CmIa6Fg%#2uL9$(Ac^AH>|_RPnGGlkA6 z6&2i@m6CBLNZ<z-obvH| zTb}+&Y1KO5FhDkjRl6g8b6n~REiQkEV0=dji4Jnq%1U~HXWsYu1~sQGJKtHQ`_^yi!zah0uoSaz=`L46nu!f^~h}qgybwY z+mw^X8! z@z^^hhCWsKWL}tIYJg*8=(W$rmLP6u+ie_H(iRn;RkE>+Y9wY!y>R7^9zT|Q)!lS- z6S3NJWdShY9d}2ZXjHB5sahap7|?sc!@`X@_{R4N@Afc~4P-4222o-%()FYO$}iNt ziVb_znS4mp6LEafN_^1T$bk2AQTJ_^>uSn|D<~&5s~zsB)sL$i#1#NJaU51Qo;{x! z2W+|Rt~6t;fQr}bFS}3T9hpJnGK-r2<_v4N4y5RCi6f_1bs9d3KINCttJ`d6nMHiIBo1A%^Ngd#vx=%x#o>RF?l)AcYN4zl+HE+Z9ok zbi(}`H_AeDd#q193xuC22FwG%F$(6!4p)xb$ML0rZ@22#GUfcHL2k;$&J!Jw%;nE< z!L)Q8P@T9AsE3-LaaeWfB*_OS&zZpcVn6;2#KX@%K0Nw7ZP(J5j&!x_fSpXlo4QwP z+jgZUW2~-0Sx&Xadbv$80ef#r0SJ(dU1{JJ)fE`XbEk-Gz6G#h?^1~4sO-2du((W6 z7df)Cdt08P57uNI*=-2JR@7c-wu|_D5iTB`nXZCL0t1J2p8jWLl`?_Hf^7?rB`Ze1q?4oz$_l^hW8`(#zS!($BtvPA{mcstEt zYufMra`MA-4Fjf25ldHrX7(L5={-THy&A;@h%x} zw^gcZon*9c)?h!Nac(L0yC96v%k0M~XSKtfJK@y2X+t1#@4gNr=rjx`v2Tc}Uy8Ab z7teK|b#B>>N7TQRVSFEKOA0_fe+y0x*49D^rJ~7`lmtY@C%$K)RBwxO2`B9Vz_R=n za`Wc~P&Bk2U+i;wK&3=9wC3jz*X?el2jgae8Z#Co2c!ELJq%(ZPb%5P+=BE9t!}~r4^=n;i?)^2nVruqkjVl|95c56f z^fT+v*S>Zb_Gf{M)%bY6*2C*7m0rF+lRIq*j3O~0%z*|BK|3?A*_XaPeENy*J=W)Z z&*`VH1l+F$+?07O^!Yw*EEDfU0Fa^P`6&`8&kJRn9xUvrl>jA=OtRYJ- zSSB3jmWT^bLnsniOE>GeeBRWjmK4|0D8bg3a!xW+D}>lfZzv1-j~tGxO>k<)%il)9 z9p&0;JRLi>%hJ|XAxdoK+t$&Rw-+pU0`xD)cbA)us~-B6`Qx^675JiSX{Mw)mi zqr?Rh$|!DAk(xijilw4hCu*8340Gc~j$GZn`=O@OU7exbvTD{feq+1|Gj9CuJR-); z*mGJjPlwIDzJ8*<=5rxHI)u<2bnFe^(mL;bpnH%1#jecp;nR;F6v(>yNo{Z5zO5VI z***E(wZj}B!3Fm(B~3gwdzS2hI*2!^)I|6tLEG|73skd6t6++0(0>==?U``Tx@Jsn zU27lcF&7{Uf`qnsk10h=l7Uo-%Q!XNiFw}Jt%*~c3XwGcA=V_Jpe*AF?Y0yL*y1FwLK8-Z|dJ|Hk5L7i_}r+W6YvSOVL1R($X=l}To!S(VA6X3g~bZ~5$^MzN+S|1%g`uj)z ziK40FalA@TQuDI7hxvt=6GFJHIF~t46MX&KE0?1l>P#Y2=LRU;JgXqP<{lK*#14v{ z$PuG`>o^uW2F%oV_w%!LK)(kVyM0fuI&I?5FdwXwOlbRCIB{f)Gj`&Q3!RfKIaM<; z==9m^^uvEu6H9Di8$o0*wl0`l!#T&C8{t~WkiFEDb;7fwf|i#+yWM2br1hH*oM27m zezHPJJGd%polU@oJwqGnUW}xBDkkJ34kR1B)S=8jgt^W*8T$Fpy8Fzshs?JC!K>dD z+~;qFz_rYbBPlayMusic(MusicName::MAIN_THEME); - lastUpdateTime = SDL_GetTicks( ); while (!gameState.gameover && !gameBoard->isCollision( )) { if (gameState.quit) return; @@ -57,7 +56,6 @@ void Game::run( ) { gameState.gameover = true; sound->PauseMusic( ); sound->PlaySound(SoundName::GAME_OVER); - while (gameState.gameover) { if (gameState.quit) return; SDL_SetRenderDrawColor(renderer.get( ), 248, 248, 248, 255); @@ -124,10 +122,7 @@ void Game::inputHandler( ) { Mix_VolumeMusic(Mix_GetMusicVolume(bgm.get( )) - 8); break; case SDLK_m: - if (true) - sound->ResumeMusic( ); - else - sound->PauseMusic( ); + sound->IsMusicPlaying( ) ? sound->PauseMusic( ) : sound->ResumeMusic( ); break; default: break; @@ -154,11 +149,8 @@ void Game::handleWindowResize( ) { int windowWidth, windowHeight; SDL_GetWindowSize(window.get( ), &windowWidth, &windowHeight); - gameRenderer->setBlockSize(windowHeight / gameBoard->getHeight( )); + //gameRenderer->setScale(windowHeight / gameBoard->getHeight( )); - int offsetX = (windowWidth - gameBoard->getWidth( ) * gameRenderer->getBlockSize( )) / 2; - int offsetY = (windowHeight - gameBoard->getHeight( ) * gameRenderer->getBlockSize( )) / 2; - gameRenderer->setOffset(offsetX, offsetY); gameRenderer->setWindowSize(windowWidth, windowHeight); } diff --git a/src/Game.hpp b/src/Game.hpp index 64c5cbd..5d956ab 100644 --- a/src/Game.hpp +++ b/src/Game.hpp @@ -34,6 +34,8 @@ private: struct GameState { bool gameover = false; + bool singlePlayer = false; + bool multiPlayer = false; bool startSequence = false; bool quit = false; } gameState; diff --git a/src/GameBoard.cpp b/src/GameBoard.cpp index e2deb7d..ed10c10 100644 --- a/src/GameBoard.cpp +++ b/src/GameBoard.cpp @@ -2,8 +2,8 @@ #include GameBoard::GameBoard( ) - : lockedTetrominos(20, vector(10, 0)), - lockedColors(20, std::vector(10, { 0, 0, 0, 255 })), score(0), level(0), lines(0), collision(false), + : lockedTetrominos(18, vector(10, 0)), + lockedColors(18, std::vector(10, { 0, 0, 0, 255 })), score(0), level(0), lines(0), collision(false), sound(make_unique( )) { spawnNewTetromino( ); } @@ -162,7 +162,7 @@ void GameBoard::spawnNewTetromino( ) { } currentTetromino = move(nextTetromino); - currentTetromino->move(width / 2 - 1, 0); + currentTetromino->move(4, 0); // Generate next tetromino random_device dev; diff --git a/src/GameBoard.hpp b/src/GameBoard.hpp index 4aa66f2..7c8fa9b 100644 --- a/src/GameBoard.hpp +++ b/src/GameBoard.hpp @@ -22,7 +22,7 @@ private: shared_ptr currentTetromino; shared_ptr nextTetromino; const int width = 10; - const int height = 20; + const int height = 18; bool collision; int score; int level; @@ -36,7 +36,7 @@ public: bool tryMoveCurrentTetromino(int dx, int dy); bool tryRotateCurrentTetromino( ); bool isValidPosition(const vector>& shape, int x, int y) const; - bool moveToBottom( ); + void moveToBottom( ); const bool isCollision( ) const; const int getScore( ) const; diff --git a/src/Renderer.cpp b/src/Renderer.cpp index 57c1fb7..bebbd0c 100644 --- a/src/Renderer.cpp +++ b/src/Renderer.cpp @@ -1,7 +1,8 @@ #include "Renderer.hpp" #include +#include -Renderer::Renderer(shared_ptr renderer, int w, int h) : renderer(renderer), blockSize(30), windowHeight(h), windowWidth(w) { +Renderer::Renderer(shared_ptr renderer, int w, int h) : renderer(renderer), windowHeight(h), windowWidth(w) { textures[TetrisAssets::SINGLE] = "assets/sprites/single.png"; textures[TetrisAssets::BORDER] = "assets/sprites/border.png"; textures[TetrisAssets::J] = "assets/sprites/J.png"; @@ -20,33 +21,80 @@ Renderer::Renderer(shared_ptr renderer, int w, int h) : renderer(r } void Renderer::renderBoard(const shared_ptr gameBoard) { + drawScoreboard(gameBoard->getScore( ), gameBoard->getLevel( ), gameBoard->getLines( )); drawWall(gameBoard->getWidth( ), gameBoard->getHeight( )); drawLockedBlocks(gameBoard); drawTetromino(gameBoard->getCurrentTetromino( )); - drawScoreboard(gameBoard->getScore( ), gameBoard->getLevel( ), gameBoard->getLines( )); } void Renderer::drawScoreboard(int score, int level, int lines) { - // 6 Because the gameBoard is 10 blocks, half that is 5 + 1 for the wall = 6 - SDL_Rect blackRect = { 0, 0, (windowWidth / 2) - (blockSize * 6) - blockSize / 8, windowHeight }; + SDL_Rect blackRect = { 0, 0, 7 * scale, windowHeight }; SDL_SetRenderDrawColor(renderer.get( ), 0, 0, 0, 255); SDL_RenderFillRect(renderer.get( ), &blackRect); - + SDL_Color col{ 255,255,255 }; auto surf = unique_ptr(IMG_Load("assets/sprites/scoreboard.png"), SDL_FreeSurface); - renderTexture("assets/sprites/scoreboard.png", windowWidth - surf->w * static_cast(windowHeight) / surf->h, 0, surf->w * static_cast(windowHeight) / surf->h, windowHeight); + scoreBoardDimensions = renderTexture( + "assets/sprites/scoreboard.png", + windowWidth, + 0, + surf->w * scale, + surf->h * scale, + col, + 1.0f, + HAlign::RIGHT + ); - renderText(fmt::format("{0}", score), windowWidth - 30, 97, 32, SDL_Color{ 0,0,0 }, HAlign::RIGHT); - renderText(fmt::format("{0}", level), windowWidth - 92, 230, 32, SDL_Color{ 0,0,0 }); - renderText(fmt::format("{0}", lines), windowWidth - 92, 330, 32, SDL_Color{ 0,0,0 }); + renderText( + fmt::format("{0}", score), + windowWidth - (7 * scale), + 23 * scale, + 8 * scale, + SDL_Color{ 0,0,0 }, + HAlign::RIGHT, + VAlign::TOP + ); + renderText( + fmt::format("{0}", level), + windowWidth - (15 * scale), + 55 * scale, + 8 * scale, + SDL_Color{ 0,0,0 }, + HAlign::RIGHT, + VAlign::TOP + ); + renderText( + fmt::format("{0}", lines), + windowWidth - (15 * scale), + 79 * scale, + 8 * scale, + SDL_Color{ 0,0,0 }, + HAlign::RIGHT, + VAlign::TOP + ); } void Renderer::drawWall(const int w, const int h) { - int innerBorderThickness = blockSize / 4; + SDL_Color color{ 165, 42, 42 }, gapColor{ 0,0,0 }; + SDL_SetRenderDrawColor(renderer.get( ), color.r, color.g, color.b, 255); - for (int y = 0; y < (h + (innerBorderThickness * h)); ++y) { - SDL_Color color{ 165, 42, 42 }; - renderTexture(textures[TetrisAssets::BORDER], offsetX - blockSize, (offsetY + y * blockSize) - (innerBorderThickness * y + 1), blockSize, blockSize, color); - renderTexture(textures[TetrisAssets::BORDER], offsetX + w * blockSize, (offsetY + y * blockSize) - (innerBorderThickness * y + 1), blockSize, blockSize, color); + for (int y = 0; y <= windowHeight; y += ((gridSize - 2) * scale)) { + leftBorder = renderTexture( + textures[TetrisAssets::BORDER], + gridSize * scale, + y, + gridSize * scale, + (gridSize * scale), + color + ); + int t = ceil(static_cast(scoreBoardDimensions->w) / scale / gridSize); + rightBorder = renderTexture( + textures[TetrisAssets::BORDER], + windowWidth - (ceil(static_cast(scoreBoardDimensions->w) / scale / gridSize) + 1) * 8 * scale, + y, + gridSize * scale, + gridSize * scale, + color + ); } } @@ -61,10 +109,10 @@ void Renderer::drawLockedBlocks(const shared_ptr gameBoard) { SDL_Color color = lockedColors[row][col]; renderTexture( textures[shapeToAsset(static_cast(blockType - 1))], - offsetX + col * blockSize, - offsetY + row * blockSize, - blockSize, - blockSize, + (col + 2) * gridSize * scale, + row * gridSize * scale, + gridSize * scale, + gridSize * scale, color); } } @@ -83,60 +131,60 @@ void Renderer::drawTetromino(const shared_ptr tetromino) { for (int i = 0; i < 4; ++i) { renderTexture( textures[TetrisAssets::I_MIDR], - offsetX + (x + i) * blockSize, - offsetY + y * blockSize, - blockSize, - blockSize, + (2 + x + i) * gridSize * scale, + y * gridSize * scale, + gridSize * scale, + gridSize * scale, tetromino->getColor( ) ); } renderTexture( textures[TetrisAssets::I_ENDR], - offsetX + (x + 0) * blockSize, - offsetY + y * blockSize, - blockSize, - blockSize, + (2 + x) * gridSize * scale, + y * gridSize * scale, + gridSize * scale, + gridSize * scale, tetromino->getColor( ) ); renderTexture( textures[TetrisAssets::I_STARTR], - offsetX + (x + 3) * blockSize, - offsetY + y * blockSize, - blockSize, - blockSize, + (2 + x + 3) * gridSize * scale, + y * gridSize * scale, + gridSize * scale, + gridSize * scale, tetromino->getColor( ) ); } else { renderTexture( textures[TetrisAssets::I_END], - offsetX + x * blockSize, - offsetY + y * blockSize, - blockSize, - blockSize, + (2 + x) * gridSize * scale, + y * gridSize * scale, + gridSize * scale, + gridSize * scale, tetromino->getColor( ) ); renderTexture( textures[TetrisAssets::I_MID], - offsetX + x * blockSize, - offsetY + (y + 1) * blockSize, - blockSize, - blockSize, + (2 + x) * gridSize * scale, + (y + 1) * gridSize * scale, + gridSize * scale, + gridSize * scale, tetromino->getColor( ) ); renderTexture( textures[TetrisAssets::I_MID], - offsetX + x * blockSize, - offsetY + (y + 2) * blockSize, - blockSize, - blockSize, + (2 + x) * gridSize * scale, + (y + 2) * gridSize * scale, + gridSize * scale, + gridSize * scale, tetromino->getColor( ) ); renderTexture( textures[TetrisAssets::I_START], - offsetX + x * blockSize, - offsetY + (y + 3) * blockSize, - blockSize, - blockSize, + (2 + x) * gridSize * scale, + (y + 3) * gridSize * scale, + gridSize * scale, + gridSize * scale, tetromino->getColor( ) ); } @@ -147,10 +195,10 @@ void Renderer::drawTetromino(const shared_ptr tetromino) { if (shape[row][col] != 0) { renderTexture( textures[shapeToAsset(tetromino->getShapeEnumn( ))], - offsetX + (x + col) * blockSize, - offsetY + (y + row) * blockSize, - blockSize, - blockSize, + ((x + col) * gridSize * scale) + leftBorder->x + leftBorder->w, + (y + row) * gridSize * scale, + gridSize * scale, + gridSize * scale, tetromino->getColor( ) ); } @@ -194,43 +242,76 @@ const TetrisAssets Renderer::shapeToAsset(const TetrominoShape shape) const { } void Renderer::renderStartScreen( ) { - SDL_SetRenderDrawColor(renderer.get( ), 248, 248, 248, 255); + SDL_SetRenderDrawColor(renderer.get( ), 0, 0, 0, 255); SDL_RenderClear(renderer.get( )); - int borderThickness = 20; - SDL_Rect borderRect = { - borderThickness, - borderThickness, - windowWidth - 2 * borderThickness, - windowHeight - 2 * borderThickness - }; - SDL_SetRenderDrawColor(renderer.get( ), 0, 0, 0, 255); - SDL_RenderDrawRect(renderer.get( ), &borderRect); + auto title = unique_ptr(IMG_Load("assets/sprites/title.png"), SDL_FreeSurface); - int titleWidth = static_cast(windowWidth * 0.8f); - int titleHeight = static_cast(titleWidth * 0.315f); + int titlePaddingX = 3, titlePaddingY = 8; - renderTexture( + TextureDimensions* titleDimensions = renderTexture( "assets/sprites/title.png", - (windowWidth / 2) - (titleWidth / 2), - static_cast(windowHeight * 0.160f), - titleWidth, - titleHeight + titlePaddingX * scale, + titlePaddingY * scale, + title->w * scale, + title->h * scale ); auto titleBg = unique_ptr(IMG_Load("assets/sprites/title_bg.png"), SDL_FreeSurface); - int titleBgWidth = static_cast(windowWidth * 0.8f); - int titleBgHeight = static_cast(titleBgWidth * (static_cast(titleBg->h) / titleBg->w)); + SDL_Color col = { 255,255,255 }; - renderTexture( + TextureDimensions* titleBgDimensions = renderTexture( "assets/sprites/title_bg.png", - (windowWidth / 2) - (titleBgWidth / 2), - static_cast(windowHeight * 0.5f), - titleBgWidth, - titleBgHeight + windowWidth / 2, + titleDimensions->y + titleDimensions->h, + titleBg->w * scale, + titleBg->h * scale, + col, + 1.0f, + HAlign::CENTER + ); + + SDL_SetRenderDrawColor(renderer.get( ), 248, 248, 248, 255); + + int titleBgBottomPadding = 6; + int y = titleBgDimensions->y + titleBgDimensions->h + titleBgBottomPadding * scale; + + SDL_Rect rect{ + 0, + y, + windowWidth, + windowHeight - y, + }; + + SDL_RenderFillRect(renderer.get( ), &rect); + + TextDimensions player1TextDimendions = renderText( + "1player", + windowWidth / 4, + y + (1 * scale), + 8 * scale, + SDL_Color{ 0, 0, 0 }, + HAlign::CENTER + ); + + renderText( + "2player", + windowWidth * 3 / 4, + y + (1 * scale), + 8 * scale, + SDL_Color{ 0, 0, 0 }, + HAlign::CENTER + ); + + renderText( + "©1989 ®", + windowWidth / 2, + windowHeight - (14 * scale), + 8 * scale, + SDL_Color{ 0, 0, 0 }, + HAlign::CENTER ); - renderText("press G to start", (windowWidth / 2), windowHeight - 70, 16, SDL_Color{ 0, 0, 0 }, HAlign::CENTER); SDL_RenderPresent(renderer.get( )); } @@ -268,29 +349,29 @@ void Renderer::renderTetrominoPreview(const shared_ptr nextTetromino) for (int i = 0; i < 4; ++i) { renderTexture( textures[TetrisAssets::I_MIDR], - (windowWidth - 155) + (x + i) * blockSize, - (windowHeight - 120) + y * blockSize, - blockSize, - blockSize, + (windowWidth - 155) + (x + i) * gridSize * scale, + (windowHeight - 120) + y * gridSize * scale, + gridSize * scale, + gridSize * scale, nextTetromino->getColor( ) ); } renderTexture( textures[TetrisAssets::I_ENDR], - (windowWidth - 155) + x * blockSize, - (windowHeight - 120) + y * blockSize, - blockSize, - blockSize, + (windowWidth - 155) + x * gridSize * scale, + (windowHeight - 120) + y * gridSize * scale, + gridSize * scale, + gridSize * scale, nextTetromino->getColor( ) ); renderTexture( textures[TetrisAssets::I_STARTR], - (windowWidth - 155) + (x + 3) * blockSize, - (windowHeight - 120) + y * blockSize, - blockSize, - blockSize, + (windowWidth - 155) + (x + 3) * gridSize * scale, + (windowHeight - 120) + y * gridSize * scale, + gridSize * scale, + gridSize * scale, nextTetromino->getColor( ) ); @@ -300,10 +381,10 @@ void Renderer::renderTetrominoPreview(const shared_ptr nextTetromino) if (nextTetromino->getShape( )[row][col] != 0) { renderTexture( textures[shapeToAsset(nextTetromino->getShapeEnumn( ))], - (windowWidth - 140) + col * blockSize, - (windowHeight - 130) + row * blockSize, - blockSize, - blockSize, + (windowWidth - 140) + col * gridSize * scale, + (windowHeight - 130) + row * gridSize * scale, + gridSize * scale, + gridSize * scale, nextTetromino->getColor( ) ); } @@ -312,7 +393,7 @@ void Renderer::renderTetrominoPreview(const shared_ptr nextTetromino) } } -const Renderer::TextDimensions Renderer::renderText(const string& text, int x, int y, int fontSize, SDL_Color color, HAlign hAlign, VAlign vAlign) { +Renderer::TextDimensions Renderer::renderText(const string& text, int x, int y, int fontSize, SDL_Color color, HAlign hAlign, VAlign vAlign) { auto font = unique_ptr(TTF_OpenFont("assets/font/tetris-gb.ttf", fontSize), TTF_CloseFont); if (!font) { SDL_Log("Failed to create font: %s", TTF_GetError( )); return{ 0,0,0,0 }; } @@ -342,15 +423,15 @@ const Renderer::TextDimensions Renderer::renderText(const string& text, int x, i return TextDimensions{ x, y, width, height }; } -const Renderer::TextureDimensions Renderer::renderTexture( +Renderer::TextureDimensions* Renderer::renderTexture( const string& texturePath, int x, int y, int width, int height, SDL_Color color, float scale, HAlign textHAlign, VAlign textVAlign) { auto surface = unique_ptr (IMG_Load(texturePath.c_str( )), SDL_FreeSurface); - if (!surface) { SDL_Log("Failed to load surface from %s: %s", texturePath, SDL_GetError( ));return{ 0,0,0,0 }; } + if (!surface) { SDL_Log("Failed to load surface from %s: %s", texturePath, SDL_GetError( ));return nullptr; } auto texture = unique_ptr(SDL_CreateTextureFromSurface(renderer.get( ), surface.get( )), SDL_DestroyTexture); - if (!texture) { SDL_Log("Failed to create texture from surface: %s", SDL_GetError( )); return{ 0,0,0,0 }; } + if (!texture) { SDL_Log("Failed to create texture from surface: %s", SDL_GetError( )); return nullptr; } SDL_SetTextureBlendMode(texture.get( ), SDL_BLENDMODE_BLEND); SDL_SetTextureColorMod(texture.get( ), color.r, color.g, color.b); @@ -372,12 +453,12 @@ const Renderer::TextureDimensions Renderer::renderTexture( SDL_Rect rect{ x,y,textureWidth,textureHeight }; SDL_RenderCopy(renderer.get( ), texture.get( ), nullptr, &rect); - return { x,y,textureWidth, textureHeight }; + return new TextureDimensions{ x,y,textureWidth, textureHeight }; } -const int Renderer::getBlockSize( ) const { return blockSize; } +const int Renderer::getScale( ) const { return scale; } -void Renderer::setBlockSize(int newBlockSize) { blockSize = newBlockSize; } +void Renderer::setScale(int newScale) { scale = newScale; } void Renderer::setOffset(int newX, int newY) { offsetX = newX; diff --git a/src/Renderer.hpp b/src/Renderer.hpp index ebfe0e8..557833c 100644 --- a/src/Renderer.hpp +++ b/src/Renderer.hpp @@ -37,13 +37,11 @@ private: void drawTetromino(const shared_ptr tetromino); void drawScoreboard(int score, int level, int lines); - const bool loadTexture(const string& filePath, const TetrisAssets shape); - const TetrisAssets shapeToAsset(const TetrominoShape shape) const; const shared_ptr renderer; - int blockSize; + int scale = 5, gridSize = 8; int offsetX, offsetY; int windowHeight = 0, windowWidth = 0; @@ -71,6 +69,9 @@ private: const SDL_Color color; }; + TextureDimensions* scoreBoardDimensions; + TextureDimensions* leftBorder, * rightBorder; + public: Renderer(shared_ptr renderer, int w, int h); @@ -78,18 +79,18 @@ public: void renderStartScreen( ); void renderGameOver(shared_ptr gameBoard); - const TextDimensions renderText( + TextDimensions renderText( const string& text, int x, int y, int fontSize, SDL_Color color, HAlign textHAlign = HAlign::LEFT, VAlign textVAlign = VAlign::TOP ); - const TextureDimensions renderTexture( + TextureDimensions* renderTexture( const string& texturePath, int x, int y, int width = 0, int height = 0, SDL_Color color = { 255,255,255 }, float scale = 1.0f, HAlign textHAlign = HAlign::LEFT, VAlign textVAlign = VAlign::TOP ); void renderTetrominoPreview(const shared_ptr nextTetromino); - const int getBlockSize( ) const; - void setBlockSize(int newBlockSize); + const int getScale( ) const; + void setScale(int newBlockSize); void setOffset(int newX, int newY); const int getOffsetX( ) const; const int getOffsetY( ) const; diff --git a/src/Sound.cpp b/src/Sound.cpp index 68980a8..f369810 100644 --- a/src/Sound.cpp +++ b/src/Sound.cpp @@ -1,5 +1,8 @@ #include "Sound.hpp" +unique_ptr>> Sound::cachedSounds = nullptr; +unique_ptr>> Sound::cachedMusic = nullptr; + Sound::Sound( ) { if (!cachedSounds) { cachedSounds = make_unique>>( ); @@ -80,30 +83,26 @@ bool Sound::PlayMusic(MusicName musicName, int loop) { return true; } -bool Sound::PauseMusic( ) { +void Sound::PauseMusic( ) { if (Mix_PlayingMusic( ) != 0) Mix_PauseMusic( ); } -bool Sound::ResumeMusic( ) { - if (Mix_PausedMusic( ) == 0) +void Sound::ResumeMusic( ) { + if (Mix_PausedMusic( )) Mix_ResumeMusic( ); } -bool Sound::IncreaseVolume( ) { +void Sound::IncreaseVolume( ) { int currentVolume = Mix_Volume(-1, -1); - if (currentVolume < MIX_MAX_VOLUME) { + if (currentVolume < MIX_MAX_VOLUME) Mix_Volume(-1, currentVolume + 2); - return true; - } - return false; } -bool Sound::DecreaseVolume( ) { +void Sound::DecreaseVolume( ) { int currentVolume = Mix_Volume(-1, -1); - if (currentVolume > 0) { + if (currentVolume > 0) Mix_Volume(-1, currentVolume - 2); - return true; - } - return false; } + +bool Sound::IsMusicPlaying( ) { return Mix_PlayingMusic( ) && !Mix_PausedMusic( ); } diff --git a/src/Sound.hpp b/src/Sound.hpp index 02cb8fa..151ec73 100644 --- a/src/Sound.hpp +++ b/src/Sound.hpp @@ -38,9 +38,9 @@ public: bool PlaySound(SoundName soundName, int loop = 0); bool PlayMusic(MusicName musicName, int loop = -1); - bool PauseMusic( ); - bool ResumeMusic( ); - bool IncreaseVolume( ); - bool DecreaseVolume( ); - + void PauseMusic( ); + void ResumeMusic( ); + void IncreaseVolume( ); + void DecreaseVolume( ); + bool IsMusicPlaying( ); }; diff --git a/src/main.cpp b/src/main.cpp index 8515f9e..49ab592 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -30,8 +30,8 @@ int main( ) { return 1; } - Game game; - if (!game.init("Tetris", 810, 600)) { + Game game; // 810:600 + if (!game.init("Tetris", 800, 720)) { SDL_Log("Failed to init game"); SDL_Quit( ); return 1;