From 9cfee49590526bf675c169d79d72c9dc85bcfd7e Mon Sep 17 00:00:00 2001 From: brxxh <11dac2t@huhn-online.de> Date: Fri, 30 May 2025 17:27:11 +0200 Subject: [PATCH 01/10] Add tappyplane; Fix design problems TappyPlane is the new QuickWings using the Kenney assets --- examples/CMakeLists.txt | 2 +- examples/quickwings/CMakeLists.txt | 23 - examples/quickwings/assets/background-day.png | Bin 10361 -> 0 bytes examples/quickwings/assets/base.png | Bin 1963 -> 0 bytes examples/quickwings/assets/gameover.png | Bin 758 -> 0 bytes examples/quickwings/assets/message.png | Bin 1602 -> 0 bytes examples/quickwings/assets/pipe-green.png | Bin 2527 -> 0 bytes .../quickwings/assets/yellowbird-downflap.png | Bin 426 -> 0 bytes .../quickwings/assets/yellowbird-midflap.png | Bin 425 -> 0 bytes .../quickwings/assets/yellowbird-upflap.png | Bin 427 -> 0 bytes examples/quickwings/quickwings.cpp | 546 ------------------ examples/tappyplane/CMakeLists.txt | 18 + .../assets}/Font/kenvector_future.ttf | Bin .../assets}/Font/kenvector_future_thin.ttf | Bin .../assets}/PNG/Letters/letterA.png | Bin .../assets}/PNG/Letters/letterB.png | Bin .../assets}/PNG/Letters/letterC.png | Bin .../assets}/PNG/Letters/letterD.png | Bin .../assets}/PNG/Letters/letterE.png | Bin .../assets}/PNG/Letters/letterF.png | Bin .../assets}/PNG/Letters/letterG.png | Bin .../assets}/PNG/Letters/letterH.png | Bin .../assets}/PNG/Letters/letterI.png | Bin .../assets}/PNG/Letters/letterJ.png | Bin .../assets}/PNG/Letters/letterK.png | Bin .../assets}/PNG/Letters/letterL.png | Bin .../assets}/PNG/Letters/letterM.png | Bin .../assets}/PNG/Letters/letterN.png | Bin .../assets}/PNG/Letters/letterO.png | Bin .../assets}/PNG/Letters/letterP.png | Bin .../assets}/PNG/Letters/letterQ.png | Bin .../assets}/PNG/Letters/letterR.png | Bin .../assets}/PNG/Letters/letterS.png | Bin .../assets}/PNG/Letters/letterT.png | Bin .../assets}/PNG/Letters/letterU.png | Bin .../assets}/PNG/Letters/letterV.png | Bin .../assets}/PNG/Letters/letterW.png | Bin .../assets}/PNG/Letters/letterX.png | Bin .../assets}/PNG/Letters/letterY.png | Bin .../assets}/PNG/Letters/letterZ.png | Bin .../assets}/PNG/Numbers/number0.png | Bin .../assets}/PNG/Numbers/number1.png | Bin .../assets}/PNG/Numbers/number2.png | Bin .../assets}/PNG/Numbers/number3.png | Bin .../assets}/PNG/Numbers/number4.png | Bin .../assets}/PNG/Numbers/number5.png | Bin .../assets}/PNG/Numbers/number6.png | Bin .../assets}/PNG/Numbers/number7.png | Bin .../assets}/PNG/Numbers/number8.png | Bin .../assets}/PNG/Numbers/number9.png | Bin .../assets}/PNG/Planes/planeBlue1.png | Bin .../assets}/PNG/Planes/planeBlue2.png | Bin .../assets}/PNG/Planes/planeBlue3.png | Bin .../assets}/PNG/Planes/planeGreen1.png | Bin .../assets}/PNG/Planes/planeGreen2.png | Bin .../assets}/PNG/Planes/planeGreen3.png | Bin .../assets}/PNG/Planes/planeRed1.png | Bin .../assets}/PNG/Planes/planeRed2.png | Bin .../assets}/PNG/Planes/planeRed3.png | Bin .../assets}/PNG/Planes/planeYellow1.png | Bin .../assets}/PNG/Planes/planeYellow2.png | Bin .../assets}/PNG/Planes/planeYellow3.png | Bin .../assets}/PNG/UI/UIbg.png | Bin .../assets}/PNG/UI/buttonLarge.png | Bin .../assets}/PNG/UI/buttonSmall.png | Bin .../assets}/PNG/UI/medalBronze.png | Bin .../assets}/PNG/UI/medalGold.png | Bin .../assets}/PNG/UI/medalSilver.png | Bin .../assets}/PNG/UI/tap.png | Bin .../assets}/PNG/UI/tapLeft.png | Bin .../assets}/PNG/UI/tapRight.png | Bin .../assets}/PNG/UI/tapTick.png | Bin .../assets}/PNG/UI/textGameOver.png | Bin .../assets}/PNG/UI/textGetReady.png | Bin .../assets}/PNG/background.png | Bin .../assets}/PNG/groundDirt.png | Bin .../assets}/PNG/groundGrass.png | Bin .../assets}/PNG/groundIce.png | Bin .../assets}/PNG/groundRock.png | Bin .../assets}/PNG/groundSnow.png | Bin .../assets}/PNG/puffLarge.png | Bin .../assets}/PNG/puffSmall.png | Bin .../assets}/PNG/rock.png | Bin .../assets}/PNG/rockDown.png | Bin .../assets}/PNG/rockGrass.png | Bin .../assets}/PNG/rockGrassDown.png | Bin .../assets}/PNG/rockIce.png | Bin .../assets}/PNG/rockIceDown.png | Bin .../assets}/PNG/rockSnow.png | Bin .../assets}/PNG/rockSnowDown.png | Bin .../assets}/PNG/starBronze.png | Bin .../assets}/PNG/starGold.png | Bin .../assets}/PNG/starSilver.png | Bin .../assets}/Spritesheet/planes.png | Bin .../assets}/Spritesheet/planes.xml | 0 .../assets}/Spritesheet/sheet.png | Bin .../assets}/Spritesheet/sheet.xml | 0 .../assets}/Vector/vector.svg | 0 .../assets}/Vector/vector.swf | Bin .../assets}/license.txt | 0 .../assets}/preview.png | Bin .../assets}/sample.png | Bin 81791 -> 81792 bytes examples/tappyplane/tappyplane.cpp | 456 +++++++++++++++ 103 files changed, 475 insertions(+), 570 deletions(-) delete mode 100644 examples/quickwings/CMakeLists.txt delete mode 100644 examples/quickwings/assets/background-day.png delete mode 100644 examples/quickwings/assets/base.png delete mode 100644 examples/quickwings/assets/gameover.png delete mode 100644 examples/quickwings/assets/message.png delete mode 100644 examples/quickwings/assets/pipe-green.png delete mode 100644 examples/quickwings/assets/yellowbird-downflap.png delete mode 100644 examples/quickwings/assets/yellowbird-midflap.png delete mode 100644 examples/quickwings/assets/yellowbird-upflap.png delete mode 100644 examples/quickwings/quickwings.cpp create mode 100644 examples/tappyplane/CMakeLists.txt rename examples/{quickwings/assets/tappybird => tappyplane/assets}/Font/kenvector_future.ttf (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/Font/kenvector_future_thin.ttf (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterA.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterB.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterC.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterD.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterE.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterF.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterG.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterH.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterI.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterJ.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterK.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterL.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterM.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterN.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterO.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterP.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterQ.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterR.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterS.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterT.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterU.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterV.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterW.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterX.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterY.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Letters/letterZ.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Numbers/number0.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Numbers/number1.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Numbers/number2.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Numbers/number3.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Numbers/number4.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Numbers/number5.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Numbers/number6.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Numbers/number7.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Numbers/number8.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Numbers/number9.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Planes/planeBlue1.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Planes/planeBlue2.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Planes/planeBlue3.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Planes/planeGreen1.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Planes/planeGreen2.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Planes/planeGreen3.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Planes/planeRed1.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Planes/planeRed2.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Planes/planeRed3.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Planes/planeYellow1.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Planes/planeYellow2.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/Planes/planeYellow3.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/UI/UIbg.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/UI/buttonLarge.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/UI/buttonSmall.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/UI/medalBronze.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/UI/medalGold.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/UI/medalSilver.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/UI/tap.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/UI/tapLeft.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/UI/tapRight.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/UI/tapTick.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/UI/textGameOver.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/UI/textGetReady.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/background.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/groundDirt.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/groundGrass.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/groundIce.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/groundRock.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/groundSnow.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/puffLarge.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/puffSmall.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/rock.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/rockDown.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/rockGrass.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/rockGrassDown.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/rockIce.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/rockIceDown.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/rockSnow.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/rockSnowDown.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/starBronze.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/starGold.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/PNG/starSilver.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/Spritesheet/planes.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/Spritesheet/planes.xml (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/Spritesheet/sheet.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/Spritesheet/sheet.xml (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/Vector/vector.svg (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/Vector/vector.swf (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/license.txt (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/preview.png (100%) rename examples/{quickwings/assets/tappybird => tappyplane/assets}/sample.png (99%) create mode 100644 examples/tappyplane/tappyplane.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 9d4c49a..713b59e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,3 +1,3 @@ add_subdirectory(simple) add_subdirectory(pong) -add_subdirectory(quickwings) \ No newline at end of file +add_subdirectory(tappyplane) diff --git a/examples/quickwings/CMakeLists.txt b/examples/quickwings/CMakeLists.txt deleted file mode 100644 index 5ac3667..0000000 --- a/examples/quickwings/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -set(quickwings_srcs quickwings.cpp) -set(quickwings_assets - assets/background-day.png - assets/base.png - assets/pipe-green.png - assets/yellowbird-downflap.png - assets/yellowbird-midflap.png - assets/yellowbird-upflap.png - ) - -set_source_files_properties(${quickwings_assets} PROPERTIES HEADER_FILE_ONLY TRUE) - -add_executable(quickwings ${quickwings_srcs} ${quickwings_assets}) - -target_link_libraries(quickwings paradiso_core) - -# -# copy files to bin/../assets folder -# -add_custom_command(TARGET quickwings POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_CURRENT_SOURCE_DIR}/assets/ - $/assets) diff --git a/examples/quickwings/assets/background-day.png b/examples/quickwings/assets/background-day.png deleted file mode 100644 index f9ed139c84f87b86b0ea31e47c729fde44f8b70d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10361 zcmeHtXIB$i&~88w1S#qPJyHcZAcz&E6O<-RR18ShqYxq>V(5?rY;+>h1Oq{O3qh*1 z1QkSS37|j-Axevs5E3AiB;<1Ly+7go_WEIe*n6#6d#{;ip8d?MNw{&{N&x+`kV1XrzUt5wwKv9qR$M#hi?6mwtim^Y7F+2h}DKShl7XrBND z?%c-m8N3#iq%6OyrDV%@vU*6&Bx? z1HBL=-EVc_b`j+2>3CJ!>+KzdS;bXqmsDHT9P&Y#9EK64pLmzpaY`}-iQ^xCwiB>5 z!Qv6jsCc8k32czDSs4gJPz~^F9MDoWkmL1Cf7c8kAS5U>zwgU~YeLed zcQs4}Rivd&mF;4L{<0)=iYo8z_y5`d@y8!L{KL2JNuJG$TwwG%Z8zBbLM=jaT@TDBu8sKW_Q6U8b4&h#orvkg36;mNyDetYH4DVR zQ~aUa=GWkFQXi8%1+*U+j<3;pqO2fk=CHcG3?brd(4h7mwY7J;CgG|`QoWGZn7bTKNCB(1^$kE-|` zlKfD`fq2-8h78fQz38EJG5_*ta;ys1yUZhFV}#B}^dOJ-`e{M%hUx{Er< zMBH=1ef8@uPuHcpZWice2Q_XAT&TX|dQ=BT*oTb|&Z?r+-SQo>{Rd>8m(Sy3ak%r* z+;`4b4cxNOYEk1e4<@#X1aqAdLq(O(L1Ra;(JKr07V{}!9}KcKfWlNI&4PXWnp^zn z*B8O_E(5W_muNR3uy0q8AEcbx!-*~lH?*#|$GjnL@SG=;2MtJ})g1S}yA3)K{%ua= zraZ)|&)X#zb}v|G>>`fkB3@7i16!MY_ER7>;o)*^qtk@;!^2R}Rg4+dtWF!#D7jD& zbb;>fF$I(%Hl$e@3Q50dF^%d*9y73A{iRDvD`JD^Ym`_fYza<3_cg*Ne@zvYdio-D z#w_%XpX7tlC0id*4tQdRk z-`>n8%SR4rb$jMMJC4P);yiul-eAmfK`5Pp9~Ci9b7f+!n0jPfG>}CTRgUS56?RpM z*wOm@j35Gob+Nj3;y)`~$u+sSbP+eG$lVwVFzz^cxDPf~oq*@qq#eH9Lb8UeeP1x~#%Zkdsr~Qm7*U`)49Y z;Uj|;iXkZ9n#&j(OMD$TphhA=b5dSY;5{* z^?m^btlqzV(t034N9vK*rbJCK4Dv=v5Hoq8_xJJR0X=a((O^T2+YP=}er||;T1}}* zWv_Z>ISDwid#W`L0ejYLxJa*3IJyqZGi_z{^Mh_pKNs_D9m{swgTs}dpO>OgTxPA74eUf{D=)=qbbd2!h@jOj8=TNtail=dAmpsRVR9$)kltme zDWuX&CWR1k`e98`ZGJ&8xUH1)p+5?Lpzz!vGh$)ALYjPM9Mlk0sn)No|6&M9xc9>fZ6#7;fw&aR1G*H&E^ zdiw)T-Q#ne8D^NM@?+oFxH3VO+1pWZ7_CI%=s+U}nO%^$!vEz^fxJA0eE98+y{~Y(Z83{@sXg zhpp-cZM%Ec$ycdT2P8O2%^uOD)^$l&PeEfSKkYrcQ5~^5&dKan!`}XfK*LSA{Vr|~ zERQL*d#+;!h$V?Pgh-8XPZRn_KZZ|_hFMijkFNxG2>$Jby?BgrF<^_+ooPW`VqzDF z?1zI^9OgESuG`@2rcy7;9pBrFbh+=}T z9jl6G8Gc+~pxalA?iqqS*LI>jEEpx@Gw>O7!_>zp2d}mgukcEfa&bk87Y^(ffnDFW z+zFpot_bURmzMr5DBAB?z+0eIJ9?{7(pJHW&1fX4TB_!vm?HGtIhZ4=SxO zQpZ9|=zh6h zU^Di6tG3eoQCNT^?L3xf3AG%pW$b&%yMgmuUu10=aX>K23uFDb>*l%}xXllzuaK+mx_@7p&DF?UA8bD!N*D`e-ABOdkDP=-+idP)*b0dDV-D|8$!G0dJrMhF%2 z*e$hLz)Hc~32$WEO@>TB*_Y2=lG9yQm?B+MAOrd2lhfMb}QE0+`(?u>XljS+wJ9jEFuh81{Kn~%(UG<&O ztZ^H90trg3VT3ln#480$4b~?A^|k?=KKU+7TrmoN^}oyxMjHKJg1h+t2`(Y( zszbH>sJxA1MQ|;03-TFzCIzt_933;mi350+{N5ZI_lT5>??eLap#3{7*y2%0*}y=`dx`I1HB0#f17v2+FB_=s5o+K0Wp$5>bL0w{Z@RFKSDGce zD9o#sjexu>fp-ZbJ13NAl~k&gTtv4P1}9ZqwHn4_SOJ?SAm@nAm{fG09KFFtk&LEe z2CHy)D@7YRA}8(1_h;5&liV5ssON#H#qmqN$eqXv96oizGo_y2wy%A0J{uA7RqvG4 zU2RLp3^-mh43e0Ro9>#Kw{bP`nHmVQC&~cW;oRviBTI(dfeH4WD$!Wk*@Z7g$oHj) z`A&$IDeRG?djUo1j^rW-H1C{6uTD>GaE=xZZvCf^|L$Pcqr7pJn7Pc;z{RV5(84Q?NF8 zN+UctguC{(iPEYb+#Hx`9(Gr&$`D7XN`e!7fln5zU0SU+x*ENr(3ihoGVQ=AK*A_~ zWbw)$7G%W$ekHXkvJ6YtA<#xa3#8qZgZ^z{+>J@5>R=PYfncoD!+wrV`S63uu<-j} z*jYPbyz6J6r6C3K6iG>s?MX;|V-FUQ$==}&NPvY3=Wwc=>ha(B6?_l zVb72WjVvCkaJz3~t2?3l#q@Sdh`zi%>i3Zh6Mc7A9eh9-?kB;}n5?K-P#Sg&Xa$H} z6r{g}JIwWD(c6a6ErFZABA)!nM{ML{@DWJ}g4385K;g;`{N(oR8v5@hN3}w2;7FYq zjfdo;_+L}cQSy!9+fyySX2@fsFe5p>_ECQ>ztxWr1wT3R;i#(S zqh7z(Iw=J=aGpmFfd1Z|MEaBu_UC*~uL63{L?+bDNDTAd%+in*x9r0jzt!J}(z73vFO7~jR+g>zITEjWB_*)$gWbrw^g3k5* zxpMYF|0=9R%9n9}!uO%?bF$@R(T2P3nTKVF<9(lw?3KATv7;h5meu`q8AkN1Zrlu> zJ}ni8bfDIY{jxv0?52VX5A@#J%G*F}Ci_68wERrUeq|r<-js!WWN6q(d7O z>eYvd2y`Sn=`$i!adw{14-ERDB}@2T#9JloPEm98+vb;f4&3!sW)3IRt8lYA)%o0x znZ(m0$12z91RwG^`svr4YJ8 zqMqGeVv@(G0W(egh>uE_;)+@tvEjne^!Dy&^TVF28*XFmDiNV0+%wyx;=xf}S&t&)!J zj&O}}N7J+M4lPQ=@uiP@aS@gF?O?PiDOSY{QkzxB81DS-UqyqZ(Ja#0gXqA1m+t!Z z#mu-t`1XBVYWbYi8)3p%DBKCMWMRm{&7^rLn3zN`EyyrJEq~DpC4sgbXZBVykOtF! zk2Ls;0}%}H#~!!aYC(bAn535Gr!quMU%Mf`Tfv9sz#sRF2ogqRZV8p zXx@xiu2f;s;b`ZVUbsM+E`ALe73)brcd*#MpdjT+dH*G=AeO_f3u1(}A9Ssuc z6>V17R=jcua|a1A;{kiM?R(RuiZXuqo5gJ7iwj@bEL2{mYfgQ=SZ>ictG|@+il;-X z-E7Tn0Pf0E6@^@6zg56KmxW1Q?Rz3iA#Z|2|v$M}Hw8?za_NGN~ zlxx|iLTrdNo3=DX7|tCGb18ka{W5qZvLua>?|hOrTFruRNVpZ_rDpoRe7BJ_$EB?5 zCzBg3Z-)-`?$$tn%gs`|Bfb9yAc3JU!|b#6?o(hy*2K1PCn#qp%?oeU~2c+ zfs^A2^!nQ#bw^%yX4WEUBun!aGO)v8LvWViIB;*VdUezobXOL~Y6e&Dd%X|&|8%;$ z9Nx)V>jsT`ZMP^Ec4911DQEp}lYk|2@7hhzt)>-=VY)Xkc^}f`t4DgXy;fW{s*9>&G{Ak(-yMwl-L{o-QT&r49JeM>92; zv$xIw!yw$KPHqxt#NEcrnaT0Ogm(`&C~4u8uv@K%Eu<|CbAfUl-&fqyF#I6E9FPZM5Hcsko{A)2(0T zs4a2yfIzC%N39x2|4i4fZ0?cx`PBKN+~u0l7MZCsvA!=`?4Ua$86B|^i2y+>bzLMRmqz76{8BNG(BGWG~;H7`Dogmw#s^^32E3q2s|Zvaq41_ zf%v=J4XWqCuHzUL9;@p-2 z$^PWP(4|-3iv9jwXQa9({iXz^aDRso%=OAzjwqZTc8^b$uTRyF^UW z2ALQDbb~W4k0GNgb#$6vQ^D7uDjoy$aFK17n48|-`@%+0uL&T?8B1~|c6MC?VxThH zHu6Eqq$M5gE>B76Y-a3kp`1MvAnn0yEi#(xZ$5#0nJ5+Ja1#L7U-I89fQlDb4O^6$ zKEx*B|IuU{)eJ8^8171l)#*tf#6BE6=jL#^ezU?x+370OZm*l`8{2U-rTyQkf9Auv zVU^0mY3=9o@|1$Cz!>hbb!d~d)p+zu@u7Y>AN8F1b(hNlfmx*br~iZi&qtv#A~rJL zO|;OZ^f8}`r?wfS`ZRZMVKpKcWsFc#z9k z=Y7+pWt!m}9Mu+sx?F01n*nB2A14YY%G~Io9cT6Hx+W` zyH_q2?P+BFd>A^9MW~#Zx}C5US{hjXeTASAe@ktaw=KxhNk~IWj6@#G8+~X*F6A-z z*R$2HFAEzogKllZa2I=#0C|naA+>`HYXY z7ylc0$PzpPHO)06y1e3EocIndIo?zU;n_|_PXtv42D)NvH)ZYH@;I=ehxD;(u3rEe z<YPw?a?9Ag43pgnsP&e0z#SxUd3pB z9M%>T%@Dq3>aFUk9Al~`aQKGWomLA#Y#rc0xxcx%kaYP;Q^86h+vdF*P*zzWGsQO+ zAebq1%{24wf~zYp&jX`hNgJt<;$S diff --git a/examples/quickwings/assets/base.png b/examples/quickwings/assets/base.png deleted file mode 100644 index 26fa39129aa33fe2b906d9b77751651fee1a2272..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1963 zcmeAS@N?(olHy`uVBq!ia0y~yVEh4O7jUov$xnNd>VN`yna<7unaRlv3>p(lC)#=+ z4iIUZALhETtBKE5#wesPBT(c>;OhrLORjL$>E`A{E$mdxocKs;J$1i)nn?v$}b`YemTRxlJ2O0S* zx2*m*aWO(Zg09NG6GcCXba-r4*}T8j*?wPU*wMwOZ!c?6?$fdS*ygJ1b-gFV`Ad&Y zrI*(C`<1(nohVpZ9W63T&i4IQ{#n}}u6|QFzkS~KQWjqRg1oDLR!_QoWA}@vv&3$- z_wicnU6J`x*5Y={gS~T$g6xBubM_}5IL*1`yz_O_EqY;_R?RD}VLw^=(=~jyk%O;PHSfSq=|b^!PEybFoTr4H+OtG!Y2&-LKR@Rz`846h&v&_g^Mtp* zkK6li=f`daMkW>x0S`_aucd-*5Y7+X4S)YVo-Dm5Rl%VFC}hZJ{^N$jQAIFkJJW6c z__#Tx&Gp~D{ERFzzrSzZ*Wb1OtinJKhO9c6SiA??9b1IHFq97|K(FrE zDEFVwZ12-{*(KZ6xHY!_O0)YnGyD9vV&C-54-cn{toZw9*TMeFUwuFhWKm*L&;PLR z<~siw{PP1Bd^=lzX4{vX|I$jW#+KXA%oPU1d@ekSg$rBHM{|>aG{>2+vNRV>8dG~tu;U$kht9L#Pw>zzOS#!Q; z($A^qH=Qmyl|Ct=?&;FyCqj5=tbWPD3CqYnvZRLI=x4)+NE!!tyP_#A90m|hq zVFJl9G@f-kc$*0v4FVzo9}X_;f&_!e9$AnyBav~=QQY`6?zK#qG8~eHcB(ehe3dtTp zz6=aistgPb%?u1b{{!il3=E|P3=FRl7#OT(0Cnb1ia+WGRBI666XN>+KTrui5MtpD zL_lSK7I-{KkT{)kY#vZKPf3tpFwlA?HfDB44p#0zv)_qt0E#mvdAqwXbg;^L06Clm z9+AZi4BWyX%*Zfnjs#GUy~NYkmHja@4+E3%^IxhvfO@8Rx;Tb-9KSmKVD4c99@ni- z6IhviFD!5n&tUW5pQ+GrG24IE0*Ai6X|3ym)-4d-(xeqFXn{4@1l2{lx8d|iC} zkYKRyDWm<|FFuJ}t9rC^!>{QK4!%0C_*=p+*QX@Q8NAMrYM7qS=$9^Qwf?+pTIsI| zCGtVCjI$QCr5u>jz3JY^c_IhCZ`zXJ&A6fT0E68$WkKP!K@C=i3qLkKP;jW-pxkV6 zz?bQSrNym=jgA5V*M2e{xG(ZRiXrZawnOAgF@|`zH@~7B{=7TI{HpTWi=PdjLO+T# z4oU-o9h?Opt8>ukAa*&$cI$lNeYxFSSTa(s+Mk@;w!X`6s)5n8c(H zn*t+EwZt`|BqgyV)hf9t6-Y4{85mmX8W`&u8ip8JSQ!{u8Cq%^m{}PZJk+v0jG`eo aKP5A*61Rp4<&E_~4Gf;HelF{r5}E*LS`Uf< diff --git a/examples/quickwings/assets/message.png b/examples/quickwings/assets/message.png deleted file mode 100644 index 9243ab58b2910ae63393eb28ac5867237826d7e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1602 zcmZ{kdpOg39LIldIW|ifigMOTTMu)YOPX;kovjgbzqjPBo3RiTT`cC3OLY=0TXb=Y zmBic&vucSriOh8gtz-$C)XuLz&mZUeJm2T_d4Im2_xE}K@qNCT?ye*lL=OT00L;me z;0clo018lLC9o>A@?e5cj&dM70KmgM=vs&hsJDeVdXfR)G!g*L(*Zyx2RR1-2^awQ z7z_ZoLIBtlbL9|kA2_?i-Nl;-QZ5Ilel2e-X?1lKl>S5hK)K`K;GpMjqTCSnWz$Ym z@K`zC)71+Mpw0Jr1l|WIggTQ53UWo0F;J+*ItIi602KafD*!icZU&pG@lIr-sz^y4 zP=wE{BEj^^%T5Fb@1%F1N66Hh7%d>!v!o_uAmJMNo1$^yoJv9 z&8+QAN{w_yCR4T3J^s6vxOB+tc1jB+pUik+ROrlGR)1gAr}jdlH1ID!()zr71gJpf4^jw zX7D}I?w^tkxt~WQdo)tH@Gatcoq5;-y;-{pA^gdsX`I(<@6o6&g^C2%^v5OoJJWa1 zlkWgy#u7vFW05U2p-_GMrC!3MO@JPo5~y6Gb26D;kj#@vSJ$sZ|5#Y}E6{)-;+v%6 z;EW(knzEdgRGGtQ4?wuN?)PoUnW!`$F1gSEovhBwi%E+eLS=M*DL>FqN$m0HQo}SC zNmz5ClTD?>&mLPFn4>LH?vg2#PWk5ITNlav@^!3aEqP!PFQEo)J)SELSEkjhl&ppG z5D8L)vFcl5?oRs*afmSMfh+gth?#zkAXO?-w_oV+PVagxKAfXb%OiMyP*;JyD3*rd zsBbF%Tv|^@qk|7GS&PZsMb8b43-pa$Si%rKbF>Oe4N4D4-lJCAFvuG=o=43VYuRUn zA!dB?%FY?5Dd`H?gr`dEvxb+dXx~gJQxjM5`zWe&6H3lc#(nH{(YXQx2&}w~keLx| z;rnFLJ%U~Xo4PDm^v4e+$Y|I?hrCeEF-cms!^IKjlv#|r3JtsYA@BWOZ`)U}Kw?sB zIHt`fs+%ahwTVb?c~RfwI~58gaa+SD$Mo|Gi)KS1uBahxWajI=*fPRdOBIuo zzad+0m=GkVZ1Xuwk}cEv;{qdOgnyged0ojJd$lrFV!E|QwN68k>EPM~`;*l|6W(I^ zbU0_Udtvq2tG9w#QbK7`irpd3TfxA%x#h-UR1p3khuNL>sy=Novll<1*{+=5b&Qp> zIDNz=`=x7xF2&^xb;i*-a?RLc`@o4|NRU7tiW-#`=b}uAqoR~D zECC;Gf~2SBK)DEC=oO@XU!L`KH0OIO?&or*fS-L0{-713C{+!MVI!u@&M4_?Q$<*a zbcV5NFz&!$94yk(B5C@aj&9?7+;)N^qIgU__c)7=-R}81aMC(I#`hz6WlN()eI8rY z?65zO)Phn$(1C)do!2Q##mM{e>n$uZI-eRR>TG-xmyEcv#gEZ0;>F7J-=S!C*=8f1 z)7N?COlx~tj5|amS1=f^lqGUn=fO`A8Bg?&4-bitz=fTN00CHF%xz3CmL}%r-sV^w s#sX(ipfF?Y@85{o%=IVJaEDwkZF za z9fAYu#^16N$nDmDlZKNBkx0H{fq`sN`Hay2ikofQB?Y63uf0s!pnfw%www-EsF z#T@`pxd3oDF!M%-8EBM?yMo8;?d{>unYT^`ch7|nEX9njB}{K8efpj{y^}Puo-iPY zX&Cl@`qs0UR(e;FWL2TDt zc*8KUnCqO&wx@vkg+@U+XZ;wbJyO7Y&HkmBuKDoRso)}xQ(zA0gYW=-Xj-G|l-8-B z#$kVY_2sU4a_eMJ5eIaz3(7s~mw|9kfzNCw&FmzNu2BXAu{r-bn?@8~2+A>--cIhC zBU8#u19J_WXqwatOjeWaBc5yBAc4ydo!F#t_@VWKgi@X>vk`auA&S62xF%`SSeUFv zT>TJXVl%OCDTXr>TH4{lY_bi@GbAz)k2+lXmZIy12vim(EDz-d=2u`!c`kKBMD9%J z?L5##kIF*#FGbf65yKv$n2lgXm+?*7_y$;x#O0IRlED(_i4B@-vUXOZZJ!{9$k3}B zBtGhJ&1%BYD$xCcXl4_RT7f2JAnFH+oEcJShbwo6bS+*TY>K7EE3kKf2+7Xc9x$FC z@%@*0UN%Pq$>J(lkn9V>I)(zk0q(y;Br8!;4EIZiOARdzm}I5YsaIaocC52;$qijI_dY+>uPFN zS5s2X__5jV@>O8x!f%Cy5dQkM!(uHgNF6@q_L8))(#M7DtE%et4Mq9+p1NU1zFr9^ zspj8jM-I=i!vwn<9Med4R8-&uKw6uB=8WZj`Xm^Se_ST=U0zjz8@$W8mwsM3TsZM6 zbwxPY9CtJYrWmm@!{?Z%$66SQLq?5a0~&vg_`1HZwDdOZM^kUUwDg6zi@$7rq`mPe zhDyF(P*%Zo-)N~DRlaw<>h zfzzt0sLABOw#LOUNej6`UZ(;? zLzLgs8@JtOs13u*zk+^v-{&CXrp>f=ew-%?&zTguBb0`Vp6Qkyq+)EP@L%H&AvwocYc)5()sd|MNv8?16Tm3JXwXS`Ga8^}YS+T{haZPy#lL5eUp?rBYp=U4!que5CRy9$jN+p@CF{!POl` z@(A+3iSf!nCmhNZe)S2~uv0M`z%T%$s?|w|2UP zpM0kwfURtA!oq75S9GY$6*bO9y2@;Bbrm*b$SUAj#?>1rMSs{3*~N2Sm-in9D(&dp zkMHLdhq&w$mi2d6M?YHj88CZuELD3qH|MoFzoUk-bF4Te;3-y@AX?&I7fwx?)l$=R zZt37NbV?@ZUI!f=Eo7a-j!Pzg{;l3$f!EGD zW<^Hz`e52x$#ieP*2wUnzH+x_&+z>8*@bB?^mXN@?RIhX>b`s~oKzE;&)_qEIA5To~k)_UG zg(BNua0kqB#&bx>6YUN5RJ)|Oa-iOjj=i-wzpjwT8#7jIbYN_Ykc<}r7_T{j~Jn*qbMU_s_drxf##oOAm92yYtWPwdU-0o;} z_4gEk%~SJg)wW2;qU;i{{g%#uC#^BBUk-(NdHix{5M6yl>H^mVHa=v%_t=U~OeZdf z6VqMyjbzQ(EXyugwpKzU{xmw(ELVL}q*;z6>3Ll=Op}oKqx@vs&*SfdQ?Wv?E${=? zBw-v#-X0_$lvjuk2mlhHXQ+!fqpPQf*E@$oAW?dTClLlH1cDDY0k@DU)Otn z{rdG|yYcmBXZ~0)JZRAQ|NsAjlBe20X~vQuzhDN3XE)M7oFs2|7ml`jQ>%a+&H|6f zVg?3oVGw3ym^DWND9B#o>Fdh=n3;!xN%;9M)g3^gEKe855Q)pZ7Xx_@DDbdch_c|` z+Rz#`qc!rtzdq>=sjVsBUE?z}5|%k^4ByAJ!`ka$T!g!ToEOuzDa{u&IhFo(WoYXz zDx9oRkXI(;$Etnt%hpG8VzmpM7VpkfwA$Ns>~Px5;^<#p`}Q%EMVg;vcHSliv{kjl zHKHUXu_Vlzw{7+P2v7+D!wY8#kY85lg&vOJ8UAvZrIGp!Q0 Uh6&}3^*{{_p00i_>zopr0M`A6wg3PC diff --git a/examples/quickwings/assets/yellowbird-midflap.png b/examples/quickwings/assets/yellowbird-midflap.png deleted file mode 100644 index 2ca3c2d034b2332726bb6157591ee3319900c2fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 425 zcmeAS@N?(olHy`uVBq!ia0vp^N0k@DU)Otn z{rdG|yYcmBXZ~0)JZRAQ|NsAjlBe20X~vQuzhDN3XE)M7oFs2|7ml`jQ>%a+&H|6f zVg?3oVGw3ym^DWND9B#o>Fdh=n3;!xN%;9M)g3^gOivfb5Q)pJ7ccT2P~cz*2-_hV zaZog3q4tiZ*WX=k-CFeW?_KXB9ZGT)DW}32LR~d)aPO9UxKJfwxlGFf6@%Z?=Pl^{ zvG%BD+$I544c4p8tvx5#F1#mwQfZCt4!*T6202kV(`MNHKjQ6|w8gBn>)PVeKuc9i zTq8@t-i!lHI diff --git a/examples/quickwings/assets/yellowbird-upflap.png b/examples/quickwings/assets/yellowbird-upflap.png deleted file mode 100644 index 2f693da65360f492a3b364b2231c4419d9c782af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 427 zcmeAS@N?(olHy`uVBq!ia0vp^N0k@DU)Otn z{rdG|yYcmBXZ~0)JZRAQ|NsAjlBe20X~vQuzhDN3XE)M7oFs2|7ml`jQ>%a+&H|6f zVg?3oVGw3ym^DWND9B#o>Fdh=n3;!xN%;9M)g3^gY)==*5Q)pZ7b67^DDbdch=}0c z*w7lWf>q~8UGW7c%d}nbAJ~jk1Y89cDsE;t(-Tx6cDq}mWY$sdu9K+~ws_3@r^r9I zCHG+9?$S+MuIzlKO>=(;hl+0XPf?aSSe>cdvL$iD>MaNR?LSVG4zn=ZxrY0iGSFJp z64!{5l*E!$tK_0oAjM#0U}&jpV61Cs7-DE)Wng4wXsK;rW@TXTP|NZ#iiX_$l+3hB W+!`j7H`W6+FnGH9xvX -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -// TODO remove all hard coded 'magic' values! - -// TODO - remove global variables -const int frame_rate = 60; -bool game_over = false; -float risky_pos_x; -float risky_pos_max_x; -float risky_pos_bottom_y; -float risky_pos_top_y; -float risky_pos_bottom_max_y; -float risky_pos_top_max_y; - -struct Background { - paradiso::Sprite backgroundLeft; - paradiso::Sprite backgroundRight; - paradiso::Sprite grassLeft; - paradiso::Sprite grassRight; - - paradiso::Sprite* scrolling[2] = {&backgroundLeft, &backgroundRight}; - - paradiso::Renderer renderer{}; - - // TODO no constructors in rule of zero - Background() { - auto backgroundImage = - paradiso::BitmapIO::get().load("background-day.png"); - backgroundLeft = paradiso::Sprite{ - .bitmap = backgroundImage, - .pivot = {paradiso::Vector2::make(0.0f, 0.16f)}, - .scale = {paradiso::Vector2::make(1.01f, 1.3f)}}; - backgroundRight = paradiso::Sprite{ - .bitmap = backgroundImage, - .pivot = {paradiso::Vector2::make(2.018f, 0.16f)}, - .scale = {paradiso::Vector2::make(1.01f, 1.3f)}}; - - auto grassImage = paradiso::BitmapIO::get().load("base.png"); - grassLeft = paradiso::Sprite{ - .bitmap = grassImage, - .pivot = {paradiso::Vector2::make(0.0f, -1.0f)}, - .scale = {paradiso::Vector2::make(1.0f, 0.33333f)}}; - grassRight = paradiso::Sprite{ - .bitmap = grassImage, - .pivot = {paradiso::Vector2::make(2.0f, -1.0f)}, - .scale = {paradiso::Vector2::make(1.0f, 0.33333f)}}; - } - - void draw(const paradiso::Shader& shader) { - for (auto sprite : scrolling) { - if (game_over == false) { - if (sprite->pivot.x() <= -2.0f) { - sprite->pivot.x() += 4.0f; - } - sprite->pivot.x() -= 0.002f; - } - shader.set_uniform("pivot", sprite->pivot); - shader.set_uniform("scale", sprite->scale); - shader.set_uniform("rotation", sprite->rotation); - renderer.draw(*sprite, shader); - } - } -}; - -struct Pipe { - paradiso::Sprite pipe_top{}; - paradiso::Sprite pipe_bottom{}; - - paradiso::Renderer renderer1{}; - paradiso::Renderer renderer2{}; - - bool paused = false; - - int pipe_spawn_rand_int = rand() % 80 + 15; - float pipe_spawn_rand = float(pipe_spawn_rand_int) / 100; - - bool pos_reset = false; - - // TODO no constructors in rule of zero - - Pipe() { - auto pipe_image = paradiso::BitmapIO::get().load("pipe-green.png"); - - pipe_top = paradiso::Sprite{ - .bitmap = pipe_image, - .pivot = {paradiso::Vector2::make(1.4f, - pipe_spawn_rand + 1.0f)}, - .scale = {paradiso::Vector2::make( - ((500.0f - (500.0f - 52.0f)) / 500.0f) * 2.25f, - ((700.0f - (700.0f - 320.0f)) / 700.0f) * 2.25f)}, - .rotation = 3.1415926f}; - pipe_bottom = paradiso::Sprite{ - .bitmap = pipe_image, - .pivot = {paradiso::Vector2::make(1.4f, - pipe_spawn_rand - 1.5f)}, - .scale = {paradiso::Vector2::make( - ((500.0f - (500.0f - 52.0f)) / 500.0f) * 2.25f, - ((700.0f - (700.0f - 320.0f)) / 700.0f) * 2.25f)}}; - - paused = true; - } - - void update() { - - // TODO improve state handling - - if (game_over == true) { - paused = true; - } - - if (paused == true) { - return; - } else { - pipe_spawn_rand_int = rand() % 80 + 15; - pipe_spawn_rand = float(pipe_spawn_rand_int) / 100; - - pipe_top.pivot.x() -= 0.02f; - pipe_bottom.pivot.x() -= 0.02f; - - risky_pos_x = pipe_top.pivot.x(); - risky_pos_max_x = pipe_top.pivot.x() + - ((500.0f - (500.0f - 52.0f)) / 500.0f) * 2.25f; - - risky_pos_top_y = pipe_top.pivot.y(); - risky_pos_top_max_y = pipe_top.pivot.y() + 10.0f; - - risky_pos_bottom_y = pipe_bottom.pivot.y(); - risky_pos_bottom_max_y = pipe_bottom.pivot.y() - 10.0f; - - if (pipe_top.pivot.x() <= -1.4f || pipe_bottom.pivot.x() <= -1.4f) { - pos_reset = true; - - if (pos_reset == true) { - pipe_top.pivot.y() = pipe_spawn_rand + 1.0f; - pipe_bottom.pivot.y() = pipe_spawn_rand - 1.5; - - pos_reset = false; - } - - pipe_top.pivot.x() = 1.4f; - pipe_bottom.pivot.x() = 1.4f; - } - } - } - - void draw(const paradiso::Shader& shader) { - shader.set_uniform("pivot", pipe_bottom.pivot); - shader.set_uniform("scale", pipe_bottom.scale); - renderer1.draw(pipe_bottom, shader); - - shader.set_uniform("pivot", pipe_top.pivot); - shader.set_uniform("scale", pipe_top.scale); - shader.set_uniform("rotation", pipe_top.rotation); - renderer1.draw(pipe_top, shader); - } -}; - -struct Grass { - paradiso::Sprite grassLeft; - paradiso::Sprite grassRight; - paradiso::Sprite* scrolling[2] = {&grassLeft, &grassRight}; - - paradiso::Renderer renderer1{}; - paradiso::Renderer renderer2{}; - - // TODO no constructors in rule of zero - Grass() { - auto grassImage = paradiso::BitmapIO::get().load("base.png"); - grassLeft = paradiso::Sprite{ - .bitmap = grassImage, - .pivot = {paradiso::Vector2::make(0.0f, -0.9f)}, - .scale = {paradiso::Vector2::make( - ((500.0f - (500.0f - 504.0f)) / 500.0f) * 2.25f, - ((700.0f - (700.0f - 112.0f)) / 700.0f) * 2.25f)}}; - grassRight = paradiso::Sprite{ - .bitmap = grassImage, - .pivot = {paradiso::Vector2::make(1.002f, -0.9f)}, - .scale = {paradiso::Vector2::make( - ((500.0f - (500.0f - 504.0f)) / 500.0f) * 2.25f, - ((700.0f - (700.0f - 112.0f)) / 700.0f) * 2.25f)}}; - } - - void draw(const paradiso::Shader& shader) { - if (game_over == false) { - grassLeft.pivot.x() -= 0.02f; - grassRight.pivot.x() -= 0.02f; - - if (grassRight.pivot.x() <= 0.0f) { - grassLeft.pivot.x() = 1.002f; - } - if (grassRight.pivot.x() <= -1.002f) { - grassRight.pivot.x() = 1.002f; - } - } - - shader.set_uniform("pivot", grassLeft.pivot); - shader.set_uniform("scale", grassLeft.scale); - shader.set_uniform("rotation", grassLeft.rotation); - - shader.set_uniform("pivot", grassRight.pivot); - shader.set_uniform("scale", grassRight.scale); - shader.set_uniform("rotation", grassRight.rotation); - - renderer1.draw(grassLeft, shader); - renderer2.draw(grassRight, shader); - } -}; - -struct QuickWings { - paradiso::Renderer renderer1{}; - paradiso::Renderer renderer2{}; - paradiso::Renderer renderer3{}; - - std::array birds; - unsigned int flap = 0; - unsigned int flapSpeed = 15; // How many ticks per flap - unsigned int flapCounter = 0; // How many ticks since last flap - - float velocity = 0.0f; - const float max_velocity = 0.02f; - - const float gravity = -0.002f; - const float move_up_velocity = 0.02f; - - bool move_up = false; - bool paused = true; - - const float max_pos = 0.95f; - const float min_pos = -0.5f; - - float pos = 0.34f; - - float rotation = 0.0f; - - int collision_counter = 0; - - // TODO no constructors in rule of zero - QuickWings() { - float scaleh = 0.08f; - float scalew = 0.158f; - - birds = { - paradiso::Sprite{ - .bitmap = - paradiso::BitmapIO::get().load("yellowbird-downflap.png"), - .pivot = {paradiso::Vector2::make(0.0f, 0.0f)}, - .scale = {paradiso::Vector2::make(scalew, scaleh)}}, - paradiso::Sprite{ - .bitmap = - paradiso::BitmapIO::get().load("yellowbird-midflap.png"), - .pivot = {paradiso::Vector2::make(0.0f, 0.0f)}, - .scale = {paradiso::Vector2::make(scalew, scaleh)}}, - paradiso::Sprite{ - .bitmap = - paradiso::BitmapIO::get().load("yellowbird-upflap.png"), - .pivot = {paradiso::Vector2::make(0.0f, 0.0f)}, - .scale = {paradiso::Vector2::make(scalew, scaleh)}}}; - } - - void draw(const paradiso::Shader& shader) { - // Update flap state - if (flapCounter < flapSpeed) { - flapCounter++; - } else { - flapCounter = 0; - flap = (flap + 1) % birds.size(); - } - - auto bird = birds[flap]; - bird.pivot.y() = pos; - bird.rotation = rotation; - shader.set_uniform("pivot", bird.pivot); - shader.set_uniform("scale", bird.scale); - shader.set_uniform("rotation", bird.rotation); - - switch (flap) { - case 0: - renderer1.draw(bird, shader); - break; - case 1: - renderer2.draw(bird, shader); - break; - case 2: - renderer3.draw(bird, shader); - break; - } - } - - void update() { - - if (game_over == true) { - paused = true; - } - - // Stop game - if (paused) { - return; - } else { - // Apply gravity - velocity += gravity; - - if (move_up) - velocity += move_up_velocity - gravity; - - // Cap velocity - if (velocity > max_velocity) - velocity = max_velocity; - if (velocity < -max_velocity) - velocity = -max_velocity; - - // Cap position - pos += velocity; - if (pos < min_pos) { - pos = min_pos; - velocity = 0.0f; - game_over = true; - } - if (pos > max_pos) { - pos = max_pos; - velocity = 0.0f; - game_over = true; - } - - // Update rotation - rotation = velocity * 10.0f; - } - - float final_risky_pos_top_y = risky_pos_top_y - 1.06f; - float final_risky_pos_bottom_y = risky_pos_bottom_y + 1.06f; - - if (risky_pos_x - 0.3f <= 0.0f && risky_pos_max_x >= 0.0f) { - if (pos >= final_risky_pos_top_y && pos <= risky_pos_top_max_y) { - game_over = true; - } - if (pos <= final_risky_pos_bottom_y && - pos >= risky_pos_bottom_max_y) { - if (collision_counter == 0) { - collision_counter++; - } else { - collision_counter = 2; - } - - if (collision_counter == 2) { - game_over = true; - } - } - } - } - - // keyboard handler - void on_keyboard(const paradiso::Window::KeyboardInputStack& input) { - if (input.size()) { - paused = false; - - if (paused == false) { - bool pressed_up = - input.top().key == ' ' || input.top().key == 'W'; - - if (input.top().action == 1 && pressed_up) { - move_up = true; - } else if (input.top().action == 0 && pressed_up) { - move_up = false; - } - } else { - return; - } - } - } -}; - -struct Message { - paradiso::Sprite messageSprite; - paradiso::Renderer renderer{}; - bool start = false; - float pos = 100.0f; - - Message() { - auto messageImage = paradiso::BitmapIO::get().load("message.png"); - messageSprite = paradiso::Sprite{ - .bitmap = messageImage, - .pivot = {paradiso::Vector2::make(0.0f, 0.0f)}, - .scale = {paradiso::Vector2::make(0.8f, 0.8f)}}; - }; - - void draw(const paradiso::Shader& shader) { - shader.set_uniform("pivot", messageSprite.pivot); - shader.set_uniform("scale", messageSprite.scale); - renderer.draw(messageSprite, shader); - } - - void update() { - if (start == true) { - messageSprite.pivot.y() = pos; - } - } - - void on_keyboard(const paradiso::Window::KeyboardInputStack& input) { - if (input.size()) { - start = true; - } - } -}; - -struct GameOverMessage { - paradiso::Sprite messageSprite; - paradiso::Renderer renderer{}; - - GameOverMessage() { - auto messageImage = paradiso::BitmapIO::get().load("gameover.png"); - messageSprite = paradiso::Sprite{ - .bitmap = messageImage, - .pivot = {paradiso::Vector2::make(0.0f, 0.4f)}, - .scale = {paradiso::Vector2::make( - ((500.0f - (500.0f - 192.0f)) / 500.0f) * 2.25f, - ((700.0f - (700.0f - 42.0f)) / 700.0f) * 2.25f)}}; - }; - - void draw(const paradiso::Shader& shader) { - shader.set_uniform("pivot", messageSprite.pivot); - shader.set_uniform("scale", messageSprite.scale); - renderer.draw(messageSprite, shader); - } -}; - -auto main() -> int { - std::srand(std::time(nullptr)); - - // Ausgabefenster ... sieht aus als wäre es auf dem Stack - auto window = paradiso::Window(); - - auto size = paradiso::Size{.width = 500, .height = 700}; - - /* - window.set_resizecallback([](auto& w) -> void { - w.set_size(paradiso::Size{.width = 405, .height = 720}); - }); - -*/ - window - .set_size(size) // ... Grösse - .set_position(paradiso::Point{.x = 1920 / 2 - 500 / 2, - .y = 1080 / 2 - 700 / 2}) // ... Position - .set_title("PardiSO.FlappyBird") // ... Titel - .set_visible(true); // ... und jetzt anzeigen! - - // der Fenster Kontext - auto ctx = paradiso::Context{}; - - // ein Shader (Schattierungsprogramm) - auto shader = paradiso::Shader{}; - - // wir nutzen einen vorgefertigten shader - shader.load_preset(paradiso::Shader::Preset::Sprite); - - // ein viewport stellt die Sicht der Kamera dar, d.h. bei quadratischen - // Pixeln sollte hier auch eine dementsprechende Grösse eingestellt - // werden - ctx.set_viewport(paradiso::Rectangle{ - .position = paradiso::Point{.x = 0, .y = 0}, .size = size}); - - // nothing beats a classic look - ctx.set_clearcolor(paradiso::RGBA::from_rgb(0x00, 0x00, 0x00)); - - // Asset loader bekommt den Pfad - - paradiso::BitmapIO::get().set_path("assets"); - - // Load - auto background = Background{}; - auto grass = Grass{}; - auto quickwingsapp = QuickWings{}; - auto pipe = Pipe{}; - auto message = Message{}; - auto gameover = GameOverMessage{}; - - // timer - - // das update führt den hier mitgegebnen Ausdruck innerhalb der internen - // Updates des Fensters auf. Es wird hier auch explizit ein bool gefordert - // damit das update auch zu jederzeit unterbrochen werden kann - while (window.update([&](paradiso::Window& w) -> bool { - ctx.set_viewport(paradiso::Rectangle{ - .position = paradiso::Point{.x = 0, .y = 0}, .size = size}); - - ctx.clear(); - auto t1 = std::chrono::high_resolution_clock::now(); - - // Keyboard and state change + update - if (quickwingsapp.paused == false) { - pipe.paused = false; - } - - pipe.update(); - - quickwingsapp.on_keyboard(w.keyboard_input()); - quickwingsapp.update(); - - message.on_keyboard(w.keyboard_input()); - message.update(); - - // Draw - background.draw(shader); - pipe.draw(shader); - grass.draw(shader); - message.draw(shader); - - if (game_over == true) { - gameover.draw(shader); - } - - quickwingsapp.draw(shader); - - // wait for frame rate - auto t2 = std::chrono::high_resolution_clock::now(); - auto duration = - std::chrono::duration_cast(t2 - t1); - auto wait = std::chrono::microseconds(1000000 / frame_rate) - duration; - std::this_thread::sleep_for(wait); - - // Quit - return !(w.keyboard_input().size() && - w.keyboard_input().top().key == 'Q'); - })) { - }; - - return 0; -} diff --git a/examples/tappyplane/CMakeLists.txt b/examples/tappyplane/CMakeLists.txt new file mode 100644 index 0000000..7d4f40a --- /dev/null +++ b/examples/tappyplane/CMakeLists.txt @@ -0,0 +1,18 @@ +set(tappyplane_srcs tappyplane.cpp) +set(tappyplane_assets + assets/PNG/background.png + ) + +set_source_files_properties(${tappyplane_assets} PROPERTIES HEADER_FILE_ONLY TRUE) + +add_executable(tappyplane ${tappyplane_srcs} ${tappyplane_assets}) + +target_link_libraries(tappyplane paradiso_core) + +# +# copy files to bin/../assets folder +# +add_custom_command(TARGET tappyplane POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_CURRENT_SOURCE_DIR}/assets/ + $/assets) diff --git a/examples/quickwings/assets/tappybird/Font/kenvector_future.ttf b/examples/tappyplane/assets/Font/kenvector_future.ttf similarity index 100% rename from examples/quickwings/assets/tappybird/Font/kenvector_future.ttf rename to examples/tappyplane/assets/Font/kenvector_future.ttf diff --git a/examples/quickwings/assets/tappybird/Font/kenvector_future_thin.ttf b/examples/tappyplane/assets/Font/kenvector_future_thin.ttf similarity index 100% rename from examples/quickwings/assets/tappybird/Font/kenvector_future_thin.ttf rename to examples/tappyplane/assets/Font/kenvector_future_thin.ttf diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterA.png b/examples/tappyplane/assets/PNG/Letters/letterA.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterA.png rename to examples/tappyplane/assets/PNG/Letters/letterA.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterB.png b/examples/tappyplane/assets/PNG/Letters/letterB.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterB.png rename to examples/tappyplane/assets/PNG/Letters/letterB.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterC.png b/examples/tappyplane/assets/PNG/Letters/letterC.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterC.png rename to examples/tappyplane/assets/PNG/Letters/letterC.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterD.png b/examples/tappyplane/assets/PNG/Letters/letterD.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterD.png rename to examples/tappyplane/assets/PNG/Letters/letterD.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterE.png b/examples/tappyplane/assets/PNG/Letters/letterE.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterE.png rename to examples/tappyplane/assets/PNG/Letters/letterE.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterF.png b/examples/tappyplane/assets/PNG/Letters/letterF.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterF.png rename to examples/tappyplane/assets/PNG/Letters/letterF.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterG.png b/examples/tappyplane/assets/PNG/Letters/letterG.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterG.png rename to examples/tappyplane/assets/PNG/Letters/letterG.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterH.png b/examples/tappyplane/assets/PNG/Letters/letterH.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterH.png rename to examples/tappyplane/assets/PNG/Letters/letterH.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterI.png b/examples/tappyplane/assets/PNG/Letters/letterI.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterI.png rename to examples/tappyplane/assets/PNG/Letters/letterI.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterJ.png b/examples/tappyplane/assets/PNG/Letters/letterJ.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterJ.png rename to examples/tappyplane/assets/PNG/Letters/letterJ.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterK.png b/examples/tappyplane/assets/PNG/Letters/letterK.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterK.png rename to examples/tappyplane/assets/PNG/Letters/letterK.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterL.png b/examples/tappyplane/assets/PNG/Letters/letterL.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterL.png rename to examples/tappyplane/assets/PNG/Letters/letterL.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterM.png b/examples/tappyplane/assets/PNG/Letters/letterM.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterM.png rename to examples/tappyplane/assets/PNG/Letters/letterM.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterN.png b/examples/tappyplane/assets/PNG/Letters/letterN.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterN.png rename to examples/tappyplane/assets/PNG/Letters/letterN.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterO.png b/examples/tappyplane/assets/PNG/Letters/letterO.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterO.png rename to examples/tappyplane/assets/PNG/Letters/letterO.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterP.png b/examples/tappyplane/assets/PNG/Letters/letterP.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterP.png rename to examples/tappyplane/assets/PNG/Letters/letterP.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterQ.png b/examples/tappyplane/assets/PNG/Letters/letterQ.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterQ.png rename to examples/tappyplane/assets/PNG/Letters/letterQ.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterR.png b/examples/tappyplane/assets/PNG/Letters/letterR.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterR.png rename to examples/tappyplane/assets/PNG/Letters/letterR.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterS.png b/examples/tappyplane/assets/PNG/Letters/letterS.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterS.png rename to examples/tappyplane/assets/PNG/Letters/letterS.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterT.png b/examples/tappyplane/assets/PNG/Letters/letterT.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterT.png rename to examples/tappyplane/assets/PNG/Letters/letterT.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterU.png b/examples/tappyplane/assets/PNG/Letters/letterU.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterU.png rename to examples/tappyplane/assets/PNG/Letters/letterU.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterV.png b/examples/tappyplane/assets/PNG/Letters/letterV.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterV.png rename to examples/tappyplane/assets/PNG/Letters/letterV.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterW.png b/examples/tappyplane/assets/PNG/Letters/letterW.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterW.png rename to examples/tappyplane/assets/PNG/Letters/letterW.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterX.png b/examples/tappyplane/assets/PNG/Letters/letterX.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterX.png rename to examples/tappyplane/assets/PNG/Letters/letterX.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterY.png b/examples/tappyplane/assets/PNG/Letters/letterY.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterY.png rename to examples/tappyplane/assets/PNG/Letters/letterY.png diff --git a/examples/quickwings/assets/tappybird/PNG/Letters/letterZ.png b/examples/tappyplane/assets/PNG/Letters/letterZ.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Letters/letterZ.png rename to examples/tappyplane/assets/PNG/Letters/letterZ.png diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number0.png b/examples/tappyplane/assets/PNG/Numbers/number0.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Numbers/number0.png rename to examples/tappyplane/assets/PNG/Numbers/number0.png diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number1.png b/examples/tappyplane/assets/PNG/Numbers/number1.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Numbers/number1.png rename to examples/tappyplane/assets/PNG/Numbers/number1.png diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number2.png b/examples/tappyplane/assets/PNG/Numbers/number2.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Numbers/number2.png rename to examples/tappyplane/assets/PNG/Numbers/number2.png diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number3.png b/examples/tappyplane/assets/PNG/Numbers/number3.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Numbers/number3.png rename to examples/tappyplane/assets/PNG/Numbers/number3.png diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number4.png b/examples/tappyplane/assets/PNG/Numbers/number4.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Numbers/number4.png rename to examples/tappyplane/assets/PNG/Numbers/number4.png diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number5.png b/examples/tappyplane/assets/PNG/Numbers/number5.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Numbers/number5.png rename to examples/tappyplane/assets/PNG/Numbers/number5.png diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number6.png b/examples/tappyplane/assets/PNG/Numbers/number6.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Numbers/number6.png rename to examples/tappyplane/assets/PNG/Numbers/number6.png diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number7.png b/examples/tappyplane/assets/PNG/Numbers/number7.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Numbers/number7.png rename to examples/tappyplane/assets/PNG/Numbers/number7.png diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number8.png b/examples/tappyplane/assets/PNG/Numbers/number8.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Numbers/number8.png rename to examples/tappyplane/assets/PNG/Numbers/number8.png diff --git a/examples/quickwings/assets/tappybird/PNG/Numbers/number9.png b/examples/tappyplane/assets/PNG/Numbers/number9.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Numbers/number9.png rename to examples/tappyplane/assets/PNG/Numbers/number9.png diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeBlue1.png b/examples/tappyplane/assets/PNG/Planes/planeBlue1.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Planes/planeBlue1.png rename to examples/tappyplane/assets/PNG/Planes/planeBlue1.png diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeBlue2.png b/examples/tappyplane/assets/PNG/Planes/planeBlue2.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Planes/planeBlue2.png rename to examples/tappyplane/assets/PNG/Planes/planeBlue2.png diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeBlue3.png b/examples/tappyplane/assets/PNG/Planes/planeBlue3.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Planes/planeBlue3.png rename to examples/tappyplane/assets/PNG/Planes/planeBlue3.png diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeGreen1.png b/examples/tappyplane/assets/PNG/Planes/planeGreen1.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Planes/planeGreen1.png rename to examples/tappyplane/assets/PNG/Planes/planeGreen1.png diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeGreen2.png b/examples/tappyplane/assets/PNG/Planes/planeGreen2.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Planes/planeGreen2.png rename to examples/tappyplane/assets/PNG/Planes/planeGreen2.png diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeGreen3.png b/examples/tappyplane/assets/PNG/Planes/planeGreen3.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Planes/planeGreen3.png rename to examples/tappyplane/assets/PNG/Planes/planeGreen3.png diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeRed1.png b/examples/tappyplane/assets/PNG/Planes/planeRed1.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Planes/planeRed1.png rename to examples/tappyplane/assets/PNG/Planes/planeRed1.png diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeRed2.png b/examples/tappyplane/assets/PNG/Planes/planeRed2.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Planes/planeRed2.png rename to examples/tappyplane/assets/PNG/Planes/planeRed2.png diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeRed3.png b/examples/tappyplane/assets/PNG/Planes/planeRed3.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Planes/planeRed3.png rename to examples/tappyplane/assets/PNG/Planes/planeRed3.png diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeYellow1.png b/examples/tappyplane/assets/PNG/Planes/planeYellow1.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Planes/planeYellow1.png rename to examples/tappyplane/assets/PNG/Planes/planeYellow1.png diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeYellow2.png b/examples/tappyplane/assets/PNG/Planes/planeYellow2.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Planes/planeYellow2.png rename to examples/tappyplane/assets/PNG/Planes/planeYellow2.png diff --git a/examples/quickwings/assets/tappybird/PNG/Planes/planeYellow3.png b/examples/tappyplane/assets/PNG/Planes/planeYellow3.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/Planes/planeYellow3.png rename to examples/tappyplane/assets/PNG/Planes/planeYellow3.png diff --git a/examples/quickwings/assets/tappybird/PNG/UI/UIbg.png b/examples/tappyplane/assets/PNG/UI/UIbg.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/UI/UIbg.png rename to examples/tappyplane/assets/PNG/UI/UIbg.png diff --git a/examples/quickwings/assets/tappybird/PNG/UI/buttonLarge.png b/examples/tappyplane/assets/PNG/UI/buttonLarge.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/UI/buttonLarge.png rename to examples/tappyplane/assets/PNG/UI/buttonLarge.png diff --git a/examples/quickwings/assets/tappybird/PNG/UI/buttonSmall.png b/examples/tappyplane/assets/PNG/UI/buttonSmall.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/UI/buttonSmall.png rename to examples/tappyplane/assets/PNG/UI/buttonSmall.png diff --git a/examples/quickwings/assets/tappybird/PNG/UI/medalBronze.png b/examples/tappyplane/assets/PNG/UI/medalBronze.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/UI/medalBronze.png rename to examples/tappyplane/assets/PNG/UI/medalBronze.png diff --git a/examples/quickwings/assets/tappybird/PNG/UI/medalGold.png b/examples/tappyplane/assets/PNG/UI/medalGold.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/UI/medalGold.png rename to examples/tappyplane/assets/PNG/UI/medalGold.png diff --git a/examples/quickwings/assets/tappybird/PNG/UI/medalSilver.png b/examples/tappyplane/assets/PNG/UI/medalSilver.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/UI/medalSilver.png rename to examples/tappyplane/assets/PNG/UI/medalSilver.png diff --git a/examples/quickwings/assets/tappybird/PNG/UI/tap.png b/examples/tappyplane/assets/PNG/UI/tap.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/UI/tap.png rename to examples/tappyplane/assets/PNG/UI/tap.png diff --git a/examples/quickwings/assets/tappybird/PNG/UI/tapLeft.png b/examples/tappyplane/assets/PNG/UI/tapLeft.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/UI/tapLeft.png rename to examples/tappyplane/assets/PNG/UI/tapLeft.png diff --git a/examples/quickwings/assets/tappybird/PNG/UI/tapRight.png b/examples/tappyplane/assets/PNG/UI/tapRight.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/UI/tapRight.png rename to examples/tappyplane/assets/PNG/UI/tapRight.png diff --git a/examples/quickwings/assets/tappybird/PNG/UI/tapTick.png b/examples/tappyplane/assets/PNG/UI/tapTick.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/UI/tapTick.png rename to examples/tappyplane/assets/PNG/UI/tapTick.png diff --git a/examples/quickwings/assets/tappybird/PNG/UI/textGameOver.png b/examples/tappyplane/assets/PNG/UI/textGameOver.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/UI/textGameOver.png rename to examples/tappyplane/assets/PNG/UI/textGameOver.png diff --git a/examples/quickwings/assets/tappybird/PNG/UI/textGetReady.png b/examples/tappyplane/assets/PNG/UI/textGetReady.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/UI/textGetReady.png rename to examples/tappyplane/assets/PNG/UI/textGetReady.png diff --git a/examples/quickwings/assets/tappybird/PNG/background.png b/examples/tappyplane/assets/PNG/background.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/background.png rename to examples/tappyplane/assets/PNG/background.png diff --git a/examples/quickwings/assets/tappybird/PNG/groundDirt.png b/examples/tappyplane/assets/PNG/groundDirt.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/groundDirt.png rename to examples/tappyplane/assets/PNG/groundDirt.png diff --git a/examples/quickwings/assets/tappybird/PNG/groundGrass.png b/examples/tappyplane/assets/PNG/groundGrass.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/groundGrass.png rename to examples/tappyplane/assets/PNG/groundGrass.png diff --git a/examples/quickwings/assets/tappybird/PNG/groundIce.png b/examples/tappyplane/assets/PNG/groundIce.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/groundIce.png rename to examples/tappyplane/assets/PNG/groundIce.png diff --git a/examples/quickwings/assets/tappybird/PNG/groundRock.png b/examples/tappyplane/assets/PNG/groundRock.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/groundRock.png rename to examples/tappyplane/assets/PNG/groundRock.png diff --git a/examples/quickwings/assets/tappybird/PNG/groundSnow.png b/examples/tappyplane/assets/PNG/groundSnow.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/groundSnow.png rename to examples/tappyplane/assets/PNG/groundSnow.png diff --git a/examples/quickwings/assets/tappybird/PNG/puffLarge.png b/examples/tappyplane/assets/PNG/puffLarge.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/puffLarge.png rename to examples/tappyplane/assets/PNG/puffLarge.png diff --git a/examples/quickwings/assets/tappybird/PNG/puffSmall.png b/examples/tappyplane/assets/PNG/puffSmall.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/puffSmall.png rename to examples/tappyplane/assets/PNG/puffSmall.png diff --git a/examples/quickwings/assets/tappybird/PNG/rock.png b/examples/tappyplane/assets/PNG/rock.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/rock.png rename to examples/tappyplane/assets/PNG/rock.png diff --git a/examples/quickwings/assets/tappybird/PNG/rockDown.png b/examples/tappyplane/assets/PNG/rockDown.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/rockDown.png rename to examples/tappyplane/assets/PNG/rockDown.png diff --git a/examples/quickwings/assets/tappybird/PNG/rockGrass.png b/examples/tappyplane/assets/PNG/rockGrass.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/rockGrass.png rename to examples/tappyplane/assets/PNG/rockGrass.png diff --git a/examples/quickwings/assets/tappybird/PNG/rockGrassDown.png b/examples/tappyplane/assets/PNG/rockGrassDown.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/rockGrassDown.png rename to examples/tappyplane/assets/PNG/rockGrassDown.png diff --git a/examples/quickwings/assets/tappybird/PNG/rockIce.png b/examples/tappyplane/assets/PNG/rockIce.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/rockIce.png rename to examples/tappyplane/assets/PNG/rockIce.png diff --git a/examples/quickwings/assets/tappybird/PNG/rockIceDown.png b/examples/tappyplane/assets/PNG/rockIceDown.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/rockIceDown.png rename to examples/tappyplane/assets/PNG/rockIceDown.png diff --git a/examples/quickwings/assets/tappybird/PNG/rockSnow.png b/examples/tappyplane/assets/PNG/rockSnow.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/rockSnow.png rename to examples/tappyplane/assets/PNG/rockSnow.png diff --git a/examples/quickwings/assets/tappybird/PNG/rockSnowDown.png b/examples/tappyplane/assets/PNG/rockSnowDown.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/rockSnowDown.png rename to examples/tappyplane/assets/PNG/rockSnowDown.png diff --git a/examples/quickwings/assets/tappybird/PNG/starBronze.png b/examples/tappyplane/assets/PNG/starBronze.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/starBronze.png rename to examples/tappyplane/assets/PNG/starBronze.png diff --git a/examples/quickwings/assets/tappybird/PNG/starGold.png b/examples/tappyplane/assets/PNG/starGold.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/starGold.png rename to examples/tappyplane/assets/PNG/starGold.png diff --git a/examples/quickwings/assets/tappybird/PNG/starSilver.png b/examples/tappyplane/assets/PNG/starSilver.png similarity index 100% rename from examples/quickwings/assets/tappybird/PNG/starSilver.png rename to examples/tappyplane/assets/PNG/starSilver.png diff --git a/examples/quickwings/assets/tappybird/Spritesheet/planes.png b/examples/tappyplane/assets/Spritesheet/planes.png similarity index 100% rename from examples/quickwings/assets/tappybird/Spritesheet/planes.png rename to examples/tappyplane/assets/Spritesheet/planes.png diff --git a/examples/quickwings/assets/tappybird/Spritesheet/planes.xml b/examples/tappyplane/assets/Spritesheet/planes.xml similarity index 100% rename from examples/quickwings/assets/tappybird/Spritesheet/planes.xml rename to examples/tappyplane/assets/Spritesheet/planes.xml diff --git a/examples/quickwings/assets/tappybird/Spritesheet/sheet.png b/examples/tappyplane/assets/Spritesheet/sheet.png similarity index 100% rename from examples/quickwings/assets/tappybird/Spritesheet/sheet.png rename to examples/tappyplane/assets/Spritesheet/sheet.png diff --git a/examples/quickwings/assets/tappybird/Spritesheet/sheet.xml b/examples/tappyplane/assets/Spritesheet/sheet.xml similarity index 100% rename from examples/quickwings/assets/tappybird/Spritesheet/sheet.xml rename to examples/tappyplane/assets/Spritesheet/sheet.xml diff --git a/examples/quickwings/assets/tappybird/Vector/vector.svg b/examples/tappyplane/assets/Vector/vector.svg similarity index 100% rename from examples/quickwings/assets/tappybird/Vector/vector.svg rename to examples/tappyplane/assets/Vector/vector.svg diff --git a/examples/quickwings/assets/tappybird/Vector/vector.swf b/examples/tappyplane/assets/Vector/vector.swf similarity index 100% rename from examples/quickwings/assets/tappybird/Vector/vector.swf rename to examples/tappyplane/assets/Vector/vector.swf diff --git a/examples/quickwings/assets/tappybird/license.txt b/examples/tappyplane/assets/license.txt similarity index 100% rename from examples/quickwings/assets/tappybird/license.txt rename to examples/tappyplane/assets/license.txt diff --git a/examples/quickwings/assets/tappybird/preview.png b/examples/tappyplane/assets/preview.png similarity index 100% rename from examples/quickwings/assets/tappybird/preview.png rename to examples/tappyplane/assets/preview.png diff --git a/examples/quickwings/assets/tappybird/sample.png b/examples/tappyplane/assets/sample.png similarity index 99% rename from examples/quickwings/assets/tappybird/sample.png rename to examples/tappyplane/assets/sample.png index efccaf41be84dda2d60704f099885b4532ec89b6..55328036a4be96591ded081c18b6f214af3869bf 100644 GIT binary patch delta 13 UcmezWkEP*1OT!k%dV5AL05Povg8%>k delta 11 ScmZqp&+`8tOT!k%dV2sRHwAbA diff --git a/examples/tappyplane/tappyplane.cpp b/examples/tappyplane/tappyplane.cpp new file mode 100644 index 0000000..cda1265 --- /dev/null +++ b/examples/tappyplane/tappyplane.cpp @@ -0,0 +1,456 @@ +/** + * paradiso - Paradigmen der Softwareentwicklung + * + * (c) Copyright 2023-2025 Hartmut Seichter and Contributors + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +static const unsigned int FRAME_RATE = 60; +static const unsigned int WINDOW_WIDTH = 800; +static const unsigned int WINDOW_HEIGHT = 480; +static const unsigned int WINDOW_SCALE = 2; + +// x,y+h --- x+w,y+h +// | | +// | | +// | | +// x,y ----- x+w,y +struct AABB { + paradiso::Vector2 position{}; + paradiso::Vector2 size{}; + + bool is_colliding_with(const AABB& other) { + return position.x() < other.position.x() + other.size.x() && + position.x() + size.x() > other.position.x() && + position.y() < other.position.y() + other.size.y() && + position.y() + size.y() > other.position.y(); + } +}; + +struct Background { + static constexpr float SCROLLING_SPEED = 0.003f; + + std::array sprites; + paradiso::Renderer renderer{}; + + paradiso::Bitmap image = + paradiso::BitmapIO::get().load("PNG/background.png"); + + void init() { + sprites = {paradiso::Sprite{ + .bitmap = image, + .pivot = {paradiso::Vector2::make(0.0f, 0.0f)}, + .scale = {paradiso::Vector2::make(1.0f, 1.0f)}}, + paradiso::Sprite{ + .bitmap = image, + .pivot = {paradiso::Vector2::make(2.0f, 0.0f)}, + .scale = {paradiso::Vector2::make(1.0f, 1.0f)}}}; + } + + void update() { + for (auto& sprite : sprites) { + sprite.pivot.x() -= SCROLLING_SPEED; + if (sprite.pivot.x() <= -2.0f) { + sprite.pivot.x() += 4.0f; + } + } + } + + void draw(const paradiso::Shader& shader) { + for (const auto& sprite : sprites) { + shader.set_uniform("pivot", sprite.pivot); + shader.set_uniform("scale", sprite.scale); + shader.set_uniform("rotation", sprite.rotation); + renderer.draw(sprite, shader); + } + } +}; + +struct Ground { + static constexpr float SCROLLING_SPEED = 0.009f; + + std::array sprites; + paradiso::Renderer renderer{}; + + // Maybe put this into 'init()' because we might use the other textures + // like snow, ice, ... and then we can parameterize this. + paradiso::Bitmap image = + paradiso::BitmapIO::get().load("PNG/groundGrass.png"); + + AABB aabb{}; + + void init() { + // The image's height is 71 px. + float scale_y = 71.0f / (float)WINDOW_HEIGHT; + + float pivot_y = -1.0f + scale_y; + + sprites = { + paradiso::Sprite{ + .bitmap = image, + .pivot = {paradiso::Vector2::make(0.0f, pivot_y)}, + .scale = {paradiso::Vector2::make(1.0f, scale_y)}}, + paradiso::Sprite{ + .bitmap = image, + .pivot = {paradiso::Vector2::make(2.0f, pivot_y)}, + .scale = {paradiso::Vector2::make(1.0f, scale_y)}}}; + + // We'll make the height half the height of the texture. + // (If you want 1:1 size, you need to double the scale of the sprite.) + aabb = AABB{ + .position = {paradiso::Vector2::make(-1.0f, -1.0f)}, + .size = {paradiso::Vector2::make(2.0f, scale_y)} + }; + } + + void update() { + for (auto& sprite : sprites) { + sprite.pivot.x() -= SCROLLING_SPEED; + if (sprite.pivot.x() <= -2.0f) { + sprite.pivot.x() += 4.0f; + } + } + } + + void draw(const paradiso::Shader& shader) { + for (const auto& sprite : sprites) { + shader.set_uniform("pivot", sprite.pivot); + shader.set_uniform("scale", sprite.scale); + shader.set_uniform("rotation", sprite.rotation); + renderer.draw(sprite, shader); + } + } +}; + +struct Rocks { + static constexpr float SCROLLING_SPEED = 0.006f; + static constexpr float GAP_SIZE = 1.6f; + + paradiso::Sprite top_sprite; + paradiso::Sprite bottom_sprite; + + paradiso::Renderer top_renderer{}; + paradiso::Renderer bottom_renderer{}; + + // Maybe put this into 'init()' because we might use the other textures + // like snow, ice, ... and then we can parameterize this. + paradiso::Bitmap top_image = + paradiso::BitmapIO::get().load("PNG/rockGrassDown.png"); + paradiso::Bitmap bottom_image = + paradiso::BitmapIO::get().load("PNG/rockGrass.png"); + + AABB top_aabb; + AABB bottom_aabb; + + void init(float x) { + // The image's size is 108x239 px. + float scale_x = 108.0f / (float)WINDOW_WIDTH; + float scale_y = 239.0f / (float)WINDOW_HEIGHT; + auto scale = paradiso::Vector2{ + paradiso::Vector2::make(scale_x, scale_y)}; + + float top_position_y = + 1.0f - scale_y + ((float)(std::rand() % 60) / 100) + 0.04f; + float bottom_position_y = top_position_y - GAP_SIZE; + + top_sprite = paradiso::Sprite{ + .bitmap = top_image, + .pivot = {paradiso::Vector2::make(x, top_position_y)}, + .scale = scale}; + + bottom_sprite = paradiso::Sprite{ + .bitmap = bottom_image, + .pivot = {paradiso::Vector2::make(x, bottom_position_y)}, + .scale = scale}; + + // We'll make the width half the width of the texture. + // (If you want 1:1 size, you need to double the scale of the sprite.) + auto size = paradiso::Vector2{ + paradiso::Vector2::make(scale_x, scale_y * 2)}; + + auto top_position = + paradiso::Vector2{paradiso::Vector2::make( + top_sprite.pivot.x() - size.x() / 2, + top_sprite.pivot.y() - size.y() / 2)}; + + auto bottom_position = + paradiso::Vector2{paradiso::Vector2::make( + bottom_sprite.pivot.x() - size.x() / 2, + bottom_sprite.pivot.y() - size.y() / 2)}; + + top_aabb = AABB{top_position, size}; + bottom_aabb = AABB{bottom_position, size}; + } + + void update() { + top_sprite.pivot.x() -= SCROLLING_SPEED; + bottom_sprite.pivot.x() -= SCROLLING_SPEED; + + // +----------+ + // | | + // | # #-------- the x it is. + // | \ | + // +----\-----+ + // \ + // *------- the x we need. + + // @Efficiency: We could just scroll it with the sprite. + top_aabb.position.x() = top_sprite.pivot.x() - top_aabb.size.x() / 2; + bottom_aabb.position.x() = + bottom_sprite.pivot.x() - bottom_aabb.size.x() / 2; + + if (top_sprite.pivot.x() <= -1.2f) { + // Reset. + init(1.2f); + return; + } + } + + void draw(const paradiso::Shader& shader) { + shader.set_uniform("pivot", top_sprite.pivot); + shader.set_uniform("scale", top_sprite.scale); + shader.set_uniform("rotation", top_sprite.rotation); + top_renderer.draw(top_sprite, shader); + + shader.set_uniform("pivot", bottom_sprite.pivot); + shader.set_uniform("scale", bottom_sprite.scale); + shader.set_uniform("rotation", bottom_sprite.rotation); + bottom_renderer.draw(bottom_sprite, shader); + } +}; + +struct Plane { + static const unsigned int SPRITE_COUNT = 3; + static constexpr float GRAVITY = -0.001f; + static constexpr float JUMP_VELOCITY = 0.03f; + static constexpr float MAX_VELOCITY = 0.03f; + + std::array sprites; + std::array renderers; + + unsigned int anim_interval = 10; + unsigned int anim_counter = 0; + + // The direction where 'current_sprite' should go because the animation + // shouldn't loop. + int anim_direction = 1; + + unsigned int current_sprite = 0; + + float position_y = 0.5f; + float rotation = 0.0f; + + float velocity_y = 0.0f; + + AABB aabb; + + void init() { + // The image's size is 88x73 px. + float scale_x = 88.0f / (float)WINDOW_WIDTH; + float scale_y = 73.0f / (float)WINDOW_HEIGHT; + + auto pivot = paradiso::Vector2{ + paradiso::Vector2::make(0.0f, position_y)}; + auto scale = paradiso::Vector2{ + paradiso::Vector2::make(scale_x, scale_y)}; + + sprites = { + paradiso::Sprite{.bitmap = paradiso::BitmapIO::get().load( + "PNG/Planes/planeRed1.png"), + .pivot = pivot, + .scale = scale}, + paradiso::Sprite{.bitmap = paradiso::BitmapIO::get().load( + "PNG/Planes/planeRed2.png"), + .pivot = pivot, + .scale = scale}, + paradiso::Sprite{.bitmap = paradiso::BitmapIO::get().load( + "PNG/Planes/planeRed3.png"), + .pivot = pivot, + .scale = scale}, + }; + + // We'll make the size half the size of the texture. + // (If you want 1:1 size, you need to double the scale of the sprite.) + auto size = paradiso::Vector2{ + paradiso::Vector2::make(scale_x, scale_y)}; + + // Center it. + auto position = paradiso::Vector2{paradiso::Vector2::make( + pivot.x() - size.x() / 2, pivot.y() - size.y() / 2)}; + + aabb = AABB{position, size}; + } + + void update(const paradiso::Window::KeyboardInputStack& input) { + if (anim_counter < anim_interval) { + anim_counter++; + } else { + anim_counter = 0; + + current_sprite += anim_direction; + if (current_sprite == SPRITE_COUNT - 1) { + anim_direction = -1; + } else if (current_sprite == 0) { + anim_direction = 1; + } + } + + if (input.size() && input.top().key == ' ' && input.top().action == 1) { + velocity_y += JUMP_VELOCITY; + } else { + velocity_y += GRAVITY; + } + + velocity_y = std::clamp(velocity_y, -MAX_VELOCITY, MAX_VELOCITY); + position_y += velocity_y; + + // +---------+ + // | | + // | #------- the y it is. + // | | + // +----#----+ + // \ + // *----- the y we need. + + // @Efficiency: We could just add the velocity. + aabb.position.y() = position_y - aabb.size.y() / 2; + + rotation = velocity_y * 500.0f; + } + + void draw(const paradiso::Shader& shader) { + auto sprite = sprites[current_sprite]; + sprite.rotation = rotation * (std::numbers::pi / 180.0f); + sprite.pivot.y() = position_y; + + shader.set_uniform("pivot", sprite.pivot); + shader.set_uniform("scale", sprite.scale); + shader.set_uniform("rotation", sprite.rotation); + renderers[current_sprite].draw(sprite, shader); + } +}; + +auto main() -> int { + std::srand(std::time(nullptr)); + + auto canvas_size = paradiso::Size{.width = WINDOW_WIDTH * WINDOW_SCALE, + .height = WINDOW_HEIGHT * WINDOW_SCALE}; + + // Unser Fenster, auf das wir rendern. + auto window = paradiso::Window(); + window + .set_size(canvas_size) // ... Größe + .set_position(paradiso::Point{.x = 200, .y = 200}) // ... Position + .set_title("ParadiSO.TappyPlane") // ... Titel + .set_visible(true); // ... und jetzt anzeigen! + + // Der Fenster Context. + auto context = paradiso::Context{}; + + // Ein Shader (Schattierungsprogramm). + auto shader = paradiso::Shader{}; + + // Wir nutzen einen vorgefertigten Shader, der speziell für Sprites ist. + shader.load_preset(paradiso::Shader::Preset::Sprite); + + // Ein Viewport stellt die Sicht der Kamera dar, d.h. bei quadratischen + // Pixeln sollte hier auch eine dementsprechende Größe eingestellt + // werden. + context.set_viewport(paradiso::Rectangle{ + .position = paradiso::Point{.x = 0, .y = 0}, .size = canvas_size}); + + // Conflower blue + context.set_clearcolor(paradiso::RGBA::from_rgb(0x64, 0x95, 0xED)); + + // Der Asset Loader bekommt den Pfad. + paradiso::BitmapIO::get().set_path("assets"); + + // Wir initialisieren unsere Sachen. + auto background = Background{}; + background.init(); + + auto ground = Ground{}; + ground.init(); + + auto rocks1 = Rocks{}; + rocks1.init(1.2f); + + auto rocks2 = Rocks{}; + rocks2.init(2.4f); + + auto plane = Plane{}; + plane.init(); + + auto top_aabb = + AABB{.position = {paradiso::Vector2::make(-1.0f, 1.0f)}, + .size = {paradiso::Vector2::make(2.0f, 0.5f)}}; + + while (window.update([&](paradiso::Window& window) -> bool { + background.update(); + ground.update(); + + rocks1.update(); + rocks2.update(); + + plane.update(window.keyboard_input()); + + if (plane.aabb.is_colliding_with(rocks1.top_aabb) || + plane.aabb.is_colliding_with(rocks1.bottom_aabb) || + plane.aabb.is_colliding_with(rocks2.top_aabb) || + plane.aabb.is_colliding_with(rocks2.bottom_aabb) || + plane.aabb.is_colliding_with(top_aabb) || + plane.aabb.is_colliding_with(ground.aabb)) { + + std::cout << "COLLIDING" << std::endl; + } + + auto t1 = std::chrono::high_resolution_clock::now(); + + context.set_viewport(paradiso::Rectangle{ + .position = paradiso::Point{.x = 0, .y = 0}, .size = canvas_size}); + context.clear(); + + background.draw(shader); + + plane.draw(shader); + + rocks1.draw(shader); + rocks2.draw(shader); + + ground.draw(shader); + + // Einen kurzen Moment warten, um auf 60 FPS zu kommen. + auto t2 = std::chrono::high_resolution_clock::now(); + auto duration = + std::chrono::duration_cast(t2 - t1); + auto wait = std::chrono::microseconds(1000000 / FRAME_RATE) - duration; + std::this_thread::sleep_for(wait); + + if (window.keyboard_input().size() && + window.keyboard_input().top().key == 'Q') { + // Update-Loop beenden. + return false; + } + + return true; + })) { + }; + + return 0; +} From 2d7277efeca8f054f07c06b6dff2527d0621a22b Mon Sep 17 00:00:00 2001 From: brxxh <11dac2t@huhn-online.de> Date: Fri, 30 May 2025 19:57:30 +0200 Subject: [PATCH 02/10] Add game state and some UI --- examples/tappyplane/tappyplane.cpp | 299 +++++++++++++++++++++++------ 1 file changed, 236 insertions(+), 63 deletions(-) diff --git a/examples/tappyplane/tappyplane.cpp b/examples/tappyplane/tappyplane.cpp index cda1265..4575f67 100644 --- a/examples/tappyplane/tappyplane.cpp +++ b/examples/tappyplane/tappyplane.cpp @@ -25,6 +25,7 @@ static const unsigned int FRAME_RATE = 60; static const unsigned int WINDOW_WIDTH = 800; static const unsigned int WINDOW_HEIGHT = 480; static const unsigned int WINDOW_SCALE = 2; +static const char ACTION_KEY = ' '; // x,y+h --- x+w,y+h // | | @@ -97,7 +98,7 @@ struct Ground { void init() { // The image's height is 71 px. - float scale_y = 71.0f / (float)WINDOW_HEIGHT; + float scale_y = 71.0f / WINDOW_HEIGHT; float pivot_y = -1.0f + scale_y; @@ -113,10 +114,8 @@ struct Ground { // We'll make the height half the height of the texture. // (If you want 1:1 size, you need to double the scale of the sprite.) - aabb = AABB{ - .position = {paradiso::Vector2::make(-1.0f, -1.0f)}, - .size = {paradiso::Vector2::make(2.0f, scale_y)} - }; + aabb = AABB{.position = {paradiso::Vector2::make(-1.0f, -1.0f)}, + .size = {paradiso::Vector2::make(2.0f, scale_y)}}; } void update() { @@ -160,13 +159,13 @@ struct Rocks { void init(float x) { // The image's size is 108x239 px. - float scale_x = 108.0f / (float)WINDOW_WIDTH; - float scale_y = 239.0f / (float)WINDOW_HEIGHT; + float scale_x = 108.0f / WINDOW_WIDTH; + float scale_y = 239.0f / WINDOW_HEIGHT; auto scale = paradiso::Vector2{ paradiso::Vector2::make(scale_x, scale_y)}; float top_position_y = - 1.0f - scale_y + ((float)(std::rand() % 60) / 100) + 0.04f; + 1.0f - scale_y + (std::rand() % 60) / 100.0f + 0.04f; float bottom_position_y = top_position_y - GAP_SIZE; top_sprite = paradiso::Sprite{ @@ -179,10 +178,10 @@ struct Rocks { .pivot = {paradiso::Vector2::make(x, bottom_position_y)}, .scale = scale}; - // We'll make the width half the width of the texture. + // We'll make the width a quarter the width of the texture. // (If you want 1:1 size, you need to double the scale of the sprite.) auto size = paradiso::Vector2{ - paradiso::Vector2::make(scale_x, scale_y * 2)}; + paradiso::Vector2::make(scale_x / 2, scale_y * 2)}; auto top_position = paradiso::Vector2{paradiso::Vector2::make( @@ -204,11 +203,13 @@ struct Rocks { // +----------+ // | | + // | | // | # #-------- the x it is. // | \ | - // +----\-----+ - // \ - // *------- the x we need. + // | \ | + // +-----\----+ + // \ + // *------ the x we need. // @Efficiency: We could just scroll it with the sprite. top_aabb.position.x() = top_sprite.pivot.x() - top_aabb.size.x() / 2; @@ -236,15 +237,20 @@ struct Rocks { }; struct Plane { - static const unsigned int SPRITE_COUNT = 3; static constexpr float GRAVITY = -0.001f; static constexpr float JUMP_VELOCITY = 0.03f; static constexpr float MAX_VELOCITY = 0.03f; - std::array sprites; - std::array renderers; + static constexpr float INIT_POSITION_Y = 0.0f; + static constexpr float INIT_VELOCITY_Y = 0.0f; + static constexpr float INIT_ROTATION = 0.0f; + + static const unsigned int ANIM_INTERVAL = 10; + + // Animation sprites + std::array sprites; + std::array renderers; - unsigned int anim_interval = 10; unsigned int anim_counter = 0; // The direction where 'current_sprite' should go because the animation @@ -253,17 +259,16 @@ struct Plane { unsigned int current_sprite = 0; - float position_y = 0.5f; - float rotation = 0.0f; - - float velocity_y = 0.0f; + float position_y = INIT_POSITION_Y; + float velocity_y = INIT_VELOCITY_Y; + float rotation = INIT_ROTATION; AABB aabb; void init() { // The image's size is 88x73 px. - float scale_x = 88.0f / (float)WINDOW_WIDTH; - float scale_y = 73.0f / (float)WINDOW_HEIGHT; + float scale_x = 88.0f / WINDOW_WIDTH; + float scale_y = 73.0f / WINDOW_HEIGHT; auto pivot = paradiso::Vector2{ paradiso::Vector2::make(0.0f, position_y)}; @@ -285,6 +290,11 @@ struct Plane { .scale = scale}, }; + // For reseting. + position_y = INIT_POSITION_Y; + velocity_y = INIT_VELOCITY_Y; + rotation = INIT_ROTATION; + // We'll make the size half the size of the texture. // (If you want 1:1 size, you need to double the scale of the sprite.) auto size = paradiso::Vector2{ @@ -298,20 +308,21 @@ struct Plane { } void update(const paradiso::Window::KeyboardInputStack& input) { - if (anim_counter < anim_interval) { + if (anim_counter < ANIM_INTERVAL) { anim_counter++; } else { anim_counter = 0; current_sprite += anim_direction; - if (current_sprite == SPRITE_COUNT - 1) { + if (current_sprite >= sprites.size() - 1) { anim_direction = -1; } else if (current_sprite == 0) { anim_direction = 1; } } - if (input.size() && input.top().key == ' ' && input.top().action == 1) { + if (input.size() && input.top().key == ACTION_KEY && + input.top().action == 1) { velocity_y += JUMP_VELOCITY; } else { velocity_y += GRAVITY; @@ -320,13 +331,17 @@ struct Plane { velocity_y = std::clamp(velocity_y, -MAX_VELOCITY, MAX_VELOCITY); position_y += velocity_y; - // +---------+ - // | | - // | #------- the y it is. - // | | - // +----#----+ - // \ - // *----- the y we need. + // +-------------+ + // | | + // | | + // | | + // | #--------- the y it is. + // | | + // | # | + // | \ | + // +--------\----+ + // \ + // *--- the y we need. // @Efficiency: We could just add the velocity. aabb.position.y() = position_y - aabb.size.y() / 2; @@ -346,6 +361,125 @@ struct Plane { } }; +struct StartText { + static const unsigned int TAP_ANIM_INTERVAL = 40; + + // textGetReady.png, tapLeft.png, tapRight.png + std::array base_sprites; + std::array base_renderers; + + // tap.png, tapTick.png + std::array tap_sprites; + std::array tap_renderers; + + unsigned int tap_anim_counter = 0; + unsigned int current_tap_sprite = 0; + + void init() { + base_sprites = { + // textGetReady.png + paradiso::Sprite{ + .bitmap = + paradiso::BitmapIO::get().load("PNG/UI/textGetReady.png"), + .pivot = {paradiso::Vector2::make(0.0f, 0.5f)}, + // The image's size is 400x73 px. + .scale = {paradiso::Vector2::make( + 400.0f / WINDOW_WIDTH, 73.0f / WINDOW_HEIGHT)}}, + // tapLeft.png + paradiso::Sprite{ + .bitmap = paradiso::BitmapIO::get().load("PNG/UI/tapLeft.png"), + .pivot = {paradiso::Vector2::make(0.5f, 0.0f)}, + // The image's size is 85x42 px. + .scale = {paradiso::Vector2::make( + 85.0f / WINDOW_WIDTH, 42.0f / WINDOW_HEIGHT)}}, + // tapRight.png + paradiso::Sprite{ + .bitmap = paradiso::BitmapIO::get().load("PNG/UI/tapRight.png"), + .pivot = {paradiso::Vector2::make(-0.5f, 0.0f)}, + // The image's size is 85x42 px. + .scale = {paradiso::Vector2::make( + 85.0f / WINDOW_WIDTH, 42.0f / WINDOW_HEIGHT)}}, + }; + + tap_sprites = { + // tap.png + paradiso::Sprite{ + .bitmap = paradiso::BitmapIO::get().load("PNG/UI/tap.png"), + .pivot = {paradiso::Vector2::make(0.0f, -0.5f)}, + // The image's size is 59x59 px. + .scale = {paradiso::Vector2::make( + 59.0f / WINDOW_WIDTH, 59.0f / WINDOW_HEIGHT)}}, + // tapTick.png + paradiso::Sprite{ + .bitmap = paradiso::BitmapIO::get().load("PNG/UI/tapTick.png"), + .pivot = {paradiso::Vector2::make(0.0f, -0.5f)}, + // The image's size is 59x59 px. + .scale = {paradiso::Vector2::make( + 59.0f / WINDOW_WIDTH, 59.0f / WINDOW_HEIGHT)}}, + }; + } + + void update() { + if (tap_anim_counter < TAP_ANIM_INTERVAL) { + tap_anim_counter++; + } else { + tap_anim_counter = 0; + current_tap_sprite = (current_tap_sprite + 1) % tap_sprites.size(); + } + } + + void draw(const paradiso::Shader& shader) { + for (unsigned int i = 0; i < base_sprites.size(); i++) { + auto sprite = base_sprites[i]; + auto& renderer = base_renderers[i]; + + shader.set_uniform("pivot", sprite.pivot); + shader.set_uniform("scale", sprite.scale); + shader.set_uniform("rotation", sprite.rotation); + renderer.draw(sprite, shader); + } + + auto tap_sprite = tap_sprites[current_tap_sprite]; + auto& tap_renderer = tap_renderers[current_tap_sprite]; + + shader.set_uniform("pivot", tap_sprite.pivot); + shader.set_uniform("scale", tap_sprite.scale); + shader.set_uniform("rotation", tap_sprite.rotation); + tap_renderer.draw(tap_sprite, shader); + } +}; + +struct GameOverText { + paradiso::Sprite sprite; + paradiso::Renderer renderer{}; + + paradiso::Bitmap image = + paradiso::BitmapIO::get().load("PNG/UI/textGameOver.png"); + + void init() { + // The image's size is 412x78 px. + float scale_x = 412.0f / WINDOW_WIDTH; + float scale_y = 78.0f / WINDOW_HEIGHT; + + sprite = {.bitmap = image, + .pivot = {paradiso::Vector2::make(0.0f, 0.0f)}, + .scale = {paradiso::Vector2::make(scale_x, scale_y)}}; + } + + void update() { + // @ToDo: Make the sprite slide down. + } + + void draw(const paradiso::Shader& shader) { + shader.set_uniform("pivot", sprite.pivot); + shader.set_uniform("scale", sprite.scale); + shader.set_uniform("rotation", sprite.rotation); + renderer.draw(sprite, shader); + } +}; + +enum class GameState { Start, Playing, GameOver }; + auto main() -> int { std::srand(std::time(nullptr)); @@ -382,45 +516,82 @@ auto main() -> int { paradiso::BitmapIO::get().set_path("assets"); // Wir initialisieren unsere Sachen. + auto game_state = GameState::Start; + auto background = Background{}; - background.init(); - auto ground = Ground{}; - ground.init(); - auto rocks1 = Rocks{}; - rocks1.init(1.2f); - auto rocks2 = Rocks{}; - rocks2.init(2.4f); - auto plane = Plane{}; + auto start_text = StartText{}; + auto game_over_text = GameOverText{}; + + background.init(); + ground.init(); + rocks1.init(1.2f); + rocks2.init(2.4f); plane.init(); + start_text.init(); + game_over_text.init(); auto top_aabb = AABB{.position = {paradiso::Vector2::make(-1.0f, 1.0f)}, .size = {paradiso::Vector2::make(2.0f, 0.5f)}}; while (window.update([&](paradiso::Window& window) -> bool { - background.update(); - ground.update(); + auto t1 = std::chrono::high_resolution_clock::now(); - rocks1.update(); - rocks2.update(); - - plane.update(window.keyboard_input()); - - if (plane.aabb.is_colliding_with(rocks1.top_aabb) || - plane.aabb.is_colliding_with(rocks1.bottom_aabb) || - plane.aabb.is_colliding_with(rocks2.top_aabb) || - plane.aabb.is_colliding_with(rocks2.bottom_aabb) || - plane.aabb.is_colliding_with(top_aabb) || - plane.aabb.is_colliding_with(ground.aabb)) { - - std::cout << "COLLIDING" << std::endl; + if (window.keyboard_input().size() && + window.keyboard_input().top().key == 'Q') { + // Update-Loop beenden. + return false; } - auto t1 = std::chrono::high_resolution_clock::now(); + if (game_state == GameState::Start) { + if (window.keyboard_input().size() && + window.keyboard_input().top().key == ACTION_KEY && + window.keyboard_input().top().action == 1) { + game_state = GameState::Playing; + + // Make the plane jump for the first time. + // @ToDo: The plane jumps too high because there was no gravity + // before. + plane.update(window.keyboard_input()); + } + + background.update(); + ground.update(); + start_text.update(); + } else if (game_state == GameState::Playing) { + background.update(); + ground.update(); + + rocks1.update(); + rocks2.update(); + + plane.update(window.keyboard_input()); + + if (plane.aabb.is_colliding_with(rocks1.top_aabb) || + plane.aabb.is_colliding_with(rocks1.bottom_aabb) || + plane.aabb.is_colliding_with(rocks2.top_aabb) || + plane.aabb.is_colliding_with(rocks2.bottom_aabb) || + plane.aabb.is_colliding_with(top_aabb) || + plane.aabb.is_colliding_with(ground.aabb)) { + game_state = GameState::GameOver; + } + } else if (game_state == GameState::GameOver) { + if (window.keyboard_input().size() && + window.keyboard_input().top().key == ACTION_KEY) { + + // Reset everything. + background.init(); + ground.init(); + rocks1.init(1.2f); + rocks2.init(2.4f); + plane.init(); + game_state = GameState::Start; + } + } context.set_viewport(paradiso::Rectangle{ .position = paradiso::Point{.x = 0, .y = 0}, .size = canvas_size}); @@ -435,6 +606,14 @@ auto main() -> int { ground.draw(shader); + // Kinda dumb that we check the game state here the second time but I + // like to seperate 'update' from 'draw'. + if (game_state == GameState::Start) { + start_text.draw(shader); + } else if (game_state == GameState::GameOver) { + game_over_text.draw(shader); + } + // Einen kurzen Moment warten, um auf 60 FPS zu kommen. auto t2 = std::chrono::high_resolution_clock::now(); auto duration = @@ -442,12 +621,6 @@ auto main() -> int { auto wait = std::chrono::microseconds(1000000 / FRAME_RATE) - duration; std::this_thread::sleep_for(wait); - if (window.keyboard_input().size() && - window.keyboard_input().top().key == 'Q') { - // Update-Loop beenden. - return false; - } - return true; })) { }; From b412c992ee4fefe9e38e9e8f3a6c0960558b9dff Mon Sep 17 00:00:00 2001 From: brxxh <11dac2t@huhn-online.de> Date: Fri, 30 May 2025 20:10:19 +0200 Subject: [PATCH 03/10] Make the game go faster after some time --- examples/tappyplane/tappyplane.cpp | 51 ++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/examples/tappyplane/tappyplane.cpp b/examples/tappyplane/tappyplane.cpp index 4575f67..6e90794 100644 --- a/examples/tappyplane/tappyplane.cpp +++ b/examples/tappyplane/tappyplane.cpp @@ -22,11 +22,15 @@ #include static const unsigned int FRAME_RATE = 60; + static const unsigned int WINDOW_WIDTH = 800; static const unsigned int WINDOW_HEIGHT = 480; static const unsigned int WINDOW_SCALE = 2; + static const char ACTION_KEY = ' '; +static constexpr float SCROLLING_SPEED_INC_FACTOR = 1.0002f; + // x,y+h --- x+w,y+h // | | // | | @@ -45,7 +49,9 @@ struct AABB { }; struct Background { - static constexpr float SCROLLING_SPEED = 0.003f; + static constexpr float INIT_SCROLLING_SPEED = 0.003f; + + float scrolling_speed = INIT_SCROLLING_SPEED; std::array sprites; paradiso::Renderer renderer{}; @@ -54,6 +60,9 @@ struct Background { paradiso::BitmapIO::get().load("PNG/background.png"); void init() { + // For resetting. + scrolling_speed = INIT_SCROLLING_SPEED; + sprites = {paradiso::Sprite{ .bitmap = image, .pivot = {paradiso::Vector2::make(0.0f, 0.0f)}, @@ -66,7 +75,7 @@ struct Background { void update() { for (auto& sprite : sprites) { - sprite.pivot.x() -= SCROLLING_SPEED; + sprite.pivot.x() -= scrolling_speed; if (sprite.pivot.x() <= -2.0f) { sprite.pivot.x() += 4.0f; } @@ -84,7 +93,9 @@ struct Background { }; struct Ground { - static constexpr float SCROLLING_SPEED = 0.009f; + static constexpr float INIT_SCROLLING_SPEED = 0.009f; + + float scrolling_speed = INIT_SCROLLING_SPEED; std::array sprites; paradiso::Renderer renderer{}; @@ -97,6 +108,9 @@ struct Ground { AABB aabb{}; void init() { + // For resetting. + scrolling_speed = INIT_SCROLLING_SPEED; + // The image's height is 71 px. float scale_y = 71.0f / WINDOW_HEIGHT; @@ -120,7 +134,7 @@ struct Ground { void update() { for (auto& sprite : sprites) { - sprite.pivot.x() -= SCROLLING_SPEED; + sprite.pivot.x() -= scrolling_speed; if (sprite.pivot.x() <= -2.0f) { sprite.pivot.x() += 4.0f; } @@ -138,9 +152,11 @@ struct Ground { }; struct Rocks { - static constexpr float SCROLLING_SPEED = 0.006f; + static constexpr float INIT_SCROLLING_SPEED = 0.006f; static constexpr float GAP_SIZE = 1.6f; + float scrolling_speed = INIT_SCROLLING_SPEED; + paradiso::Sprite top_sprite; paradiso::Sprite bottom_sprite; @@ -157,7 +173,11 @@ struct Rocks { AABB top_aabb; AABB bottom_aabb; - void init(float x) { + void init(float x, bool reset_scrolling_speed = false) { + if (reset_scrolling_speed) { + scrolling_speed = INIT_SCROLLING_SPEED; + } + // The image's size is 108x239 px. float scale_x = 108.0f / WINDOW_WIDTH; float scale_y = 239.0f / WINDOW_HEIGHT; @@ -198,8 +218,8 @@ struct Rocks { } void update() { - top_sprite.pivot.x() -= SCROLLING_SPEED; - bottom_sprite.pivot.x() -= SCROLLING_SPEED; + top_sprite.pivot.x() -= scrolling_speed; + bottom_sprite.pivot.x() -= scrolling_speed; // +----------+ // | | @@ -290,7 +310,7 @@ struct Plane { .scale = scale}, }; - // For reseting. + // For resetting. position_y = INIT_POSITION_Y; velocity_y = INIT_VELOCITY_Y; rotation = INIT_ROTATION; @@ -528,8 +548,8 @@ auto main() -> int { background.init(); ground.init(); - rocks1.init(1.2f); - rocks2.init(2.4f); + rocks1.init(1.2f, true); // We don't need to set this to true, + rocks2.init(2.4f, true); // but why not? plane.init(); start_text.init(); game_over_text.init(); @@ -571,6 +591,11 @@ auto main() -> int { plane.update(window.keyboard_input()); + background.scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; + ground.scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; + rocks1.scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; + rocks2.scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; + if (plane.aabb.is_colliding_with(rocks1.top_aabb) || plane.aabb.is_colliding_with(rocks1.bottom_aabb) || plane.aabb.is_colliding_with(rocks2.top_aabb) || @@ -586,8 +611,8 @@ auto main() -> int { // Reset everything. background.init(); ground.init(); - rocks1.init(1.2f); - rocks2.init(2.4f); + rocks1.init(1.2f, true); + rocks2.init(2.4f, true); plane.init(); game_state = GameState::Start; } From ccd0697ab3f41d6cb2e9623d993bdf90f1a1276f Mon Sep 17 00:00:00 2001 From: brxxh <11dac2t@huhn-online.de> Date: Sat, 31 May 2025 00:02:16 +0200 Subject: [PATCH 04/10] Some architectural changes --- examples/tappyplane/tappyplane.cpp | 553 ++++++++++++++++------------- 1 file changed, 316 insertions(+), 237 deletions(-) diff --git a/examples/tappyplane/tappyplane.cpp b/examples/tappyplane/tappyplane.cpp index 6e90794..4d4a5cc 100644 --- a/examples/tappyplane/tappyplane.cpp +++ b/examples/tappyplane/tappyplane.cpp @@ -17,9 +17,15 @@ #include #include +#include #include +#include +#include -#include +namespace TappyPlane { + +using SpriteName = std::tuple; +using SpriteMap = std::unordered_map; static const unsigned int FRAME_RATE = 60; @@ -56,23 +62,24 @@ struct Background { std::array sprites; paradiso::Renderer renderer{}; - paradiso::Bitmap image = - paradiso::BitmapIO::get().load("PNG/background.png"); - - void init() { - // For resetting. - scrolling_speed = INIT_SCROLLING_SPEED; - + void init(SpriteMap& sprite_map) { sprites = {paradiso::Sprite{ - .bitmap = image, + .bitmap = sprite_map["background"], .pivot = {paradiso::Vector2::make(0.0f, 0.0f)}, .scale = {paradiso::Vector2::make(1.0f, 1.0f)}}, paradiso::Sprite{ - .bitmap = image, + .bitmap = sprite_map["background"], .pivot = {paradiso::Vector2::make(2.0f, 0.0f)}, .scale = {paradiso::Vector2::make(1.0f, 1.0f)}}}; } + void reset() { + scrolling_speed = INIT_SCROLLING_SPEED; + + sprites[0].pivot.x() = 0.0f; + sprites[1].pivot.x() = 2.0f; + } + void update() { for (auto& sprite : sprites) { sprite.pivot.x() -= scrolling_speed; @@ -100,17 +107,9 @@ struct Ground { std::array sprites; paradiso::Renderer renderer{}; - // Maybe put this into 'init()' because we might use the other textures - // like snow, ice, ... and then we can parameterize this. - paradiso::Bitmap image = - paradiso::BitmapIO::get().load("PNG/groundGrass.png"); - AABB aabb{}; - void init() { - // For resetting. - scrolling_speed = INIT_SCROLLING_SPEED; - + void init(SpriteMap& sprite_map) { // The image's height is 71 px. float scale_y = 71.0f / WINDOW_HEIGHT; @@ -118,11 +117,11 @@ struct Ground { sprites = { paradiso::Sprite{ - .bitmap = image, + .bitmap = sprite_map["ground"], .pivot = {paradiso::Vector2::make(0.0f, pivot_y)}, .scale = {paradiso::Vector2::make(1.0f, scale_y)}}, paradiso::Sprite{ - .bitmap = image, + .bitmap = sprite_map["ground"], .pivot = {paradiso::Vector2::make(2.0f, pivot_y)}, .scale = {paradiso::Vector2::make(1.0f, scale_y)}}}; @@ -132,6 +131,13 @@ struct Ground { .size = {paradiso::Vector2::make(2.0f, scale_y)}}; } + void reset() { + scrolling_speed = INIT_SCROLLING_SPEED; + + sprites[0].pivot.x() = 0.0f; + sprites[1].pivot.x() = 2.0f; + } + void update() { for (auto& sprite : sprites) { sprite.pivot.x() -= scrolling_speed; @@ -153,7 +159,14 @@ struct Ground { struct Rocks { static constexpr float INIT_SCROLLING_SPEED = 0.006f; - static constexpr float GAP_SIZE = 1.6f; + static constexpr float GAP_SIZE = 1.5f; + + // The image's size is 108x239 px. + static constexpr float INIT_SCALE_X = 108.0f / WINDOW_WIDTH; + static constexpr float INIT_SCALE_Y = 239.0f / WINDOW_HEIGHT; + + static constexpr paradiso::Vector2 INIT_SCALE{ + paradiso::Vector2::make(INIT_SCALE_X, INIT_SCALE_Y)}; float scrolling_speed = INIT_SCROLLING_SPEED; @@ -163,45 +176,20 @@ struct Rocks { paradiso::Renderer top_renderer{}; paradiso::Renderer bottom_renderer{}; - // Maybe put this into 'init()' because we might use the other textures - // like snow, ice, ... and then we can parameterize this. - paradiso::Bitmap top_image = - paradiso::BitmapIO::get().load("PNG/rockGrassDown.png"); - paradiso::Bitmap bottom_image = - paradiso::BitmapIO::get().load("PNG/rockGrass.png"); - AABB top_aabb; AABB bottom_aabb; - void init(float x, bool reset_scrolling_speed = false) { - if (reset_scrolling_speed) { - scrolling_speed = INIT_SCROLLING_SPEED; - } + float init_pivot_x = 0.0f; - // The image's size is 108x239 px. - float scale_x = 108.0f / WINDOW_WIDTH; - float scale_y = 239.0f / WINDOW_HEIGHT; - auto scale = paradiso::Vector2{ - paradiso::Vector2::make(scale_x, scale_y)}; - - float top_position_y = - 1.0f - scale_y + (std::rand() % 60) / 100.0f + 0.04f; - float bottom_position_y = top_position_y - GAP_SIZE; - - top_sprite = paradiso::Sprite{ - .bitmap = top_image, - .pivot = {paradiso::Vector2::make(x, top_position_y)}, - .scale = scale}; - - bottom_sprite = paradiso::Sprite{ - .bitmap = bottom_image, - .pivot = {paradiso::Vector2::make(x, bottom_position_y)}, - .scale = scale}; + auto get_random_top_position_y() -> float { + return 1.0f - INIT_SCALE_Y + (std::rand() % 50) / 100.0f + 0.01f; + } + void init_aabbs() { // We'll make the width a quarter the width of the texture. // (If you want 1:1 size, you need to double the scale of the sprite.) auto size = paradiso::Vector2{ - paradiso::Vector2::make(scale_x / 2, scale_y * 2)}; + paradiso::Vector2::make(INIT_SCALE_X / 2, INIT_SCALE_Y * 2)}; auto top_position = paradiso::Vector2{paradiso::Vector2::make( @@ -217,6 +205,52 @@ struct Rocks { bottom_aabb = AABB{bottom_position, size}; } + void init(SpriteMap& sprite_map, float pivot_x) { + init_pivot_x = pivot_x; + + float top_position_y = get_random_top_position_y(); + float bottom_position_y = top_position_y - GAP_SIZE; + + top_sprite = paradiso::Sprite{.bitmap = sprite_map["rocks.top"], + .pivot = {paradiso::Vector2::make( + init_pivot_x, top_position_y)}, + .scale = INIT_SCALE}; + + bottom_sprite = + paradiso::Sprite{.bitmap = sprite_map["rocks.bottom"], + .pivot = {paradiso::Vector2::make( + init_pivot_x, bottom_position_y)}, + .scale = INIT_SCALE}; + + init_aabbs(); + } + + void reset() { + scrolling_speed = INIT_SCROLLING_SPEED; + + float top_position_y = get_random_top_position_y(); + float bottom_position_y = top_position_y - GAP_SIZE; + + top_sprite.pivot = paradiso::Vector2{ + paradiso::Vector2::make(init_pivot_x, top_position_y)}; + bottom_sprite.pivot = paradiso::Vector2{ + paradiso::Vector2::make(init_pivot_x, bottom_position_y)}; + + init_aabbs(); + } + + void jump_back() { + float top_position_y = get_random_top_position_y(); + float bottom_position_y = top_position_y - GAP_SIZE; + + top_sprite.pivot = paradiso::Vector2{ + paradiso::Vector2::make(1.2f, top_position_y)}; + bottom_sprite.pivot = paradiso::Vector2{ + paradiso::Vector2::make(1.2f, bottom_position_y)}; + + init_aabbs(); + } + void update() { top_sprite.pivot.x() -= scrolling_speed; bottom_sprite.pivot.x() -= scrolling_speed; @@ -231,14 +265,14 @@ struct Rocks { // \ // *------ the x we need. - // @Efficiency: We could just scroll it with the sprite. + // @Efficiency: We could just scroll the AABBs with the sprites. top_aabb.position.x() = top_sprite.pivot.x() - top_aabb.size.x() / 2; bottom_aabb.position.x() = bottom_sprite.pivot.x() - bottom_aabb.size.x() / 2; if (top_sprite.pivot.x() <= -1.2f) { // Reset. - init(1.2f); + jump_back(); return; } } @@ -267,6 +301,16 @@ struct Plane { static const unsigned int ANIM_INTERVAL = 10; + // The image's size is 88x73 px. + static constexpr float INIT_SCALE_X = 88.0f / WINDOW_WIDTH; + static constexpr float INIT_SCALE_Y = 73.0f / WINDOW_HEIGHT; + + static constexpr paradiso::Vector2 INIT_SCALE{ + paradiso::Vector2::make(INIT_SCALE_X, INIT_SCALE_Y)}; + + static constexpr paradiso::Vector2 INIT_PIVOT{ + paradiso::Vector2::make(0.0f, INIT_POSITION_Y)}; + // Animation sprites std::array sprites; std::array renderers; @@ -285,46 +329,45 @@ struct Plane { AABB aabb; - void init() { - // The image's size is 88x73 px. - float scale_x = 88.0f / WINDOW_WIDTH; - float scale_y = 73.0f / WINDOW_HEIGHT; + void init_aabb() { + // We'll make the size half the size of the texture. + // (If you want 1:1 size, you need to double the scale of the sprite.) + // We could use INIT_SCALE here, but we'll keep this for clarity. + auto size = paradiso::Vector2{ + paradiso::Vector2::make(INIT_SCALE_X, INIT_SCALE_Y)}; - auto pivot = paradiso::Vector2{ - paradiso::Vector2::make(0.0f, position_y)}; - auto scale = paradiso::Vector2{ - paradiso::Vector2::make(scale_x, scale_y)}; + // Center it. + auto position = paradiso::Vector2{paradiso::Vector2::make( + INIT_PIVOT.x() - size.x() / 2, INIT_PIVOT.y() - size.y() / 2)}; - sprites = { - paradiso::Sprite{.bitmap = paradiso::BitmapIO::get().load( - "PNG/Planes/planeRed1.png"), - .pivot = pivot, - .scale = scale}, - paradiso::Sprite{.bitmap = paradiso::BitmapIO::get().load( - "PNG/Planes/planeRed2.png"), - .pivot = pivot, - .scale = scale}, - paradiso::Sprite{.bitmap = paradiso::BitmapIO::get().load( - "PNG/Planes/planeRed3.png"), - .pivot = pivot, - .scale = scale}, - }; + aabb = AABB{position, size}; + } + + void init(SpriteMap& sprite_map) { + sprites = {paradiso::Sprite{.bitmap = sprite_map["plane.1"], + .pivot = INIT_PIVOT, + .scale = INIT_SCALE}, + paradiso::Sprite{.bitmap = sprite_map["plane.2"], + .pivot = INIT_PIVOT, + .scale = INIT_SCALE}, + paradiso::Sprite{.bitmap = sprite_map["plane.3"], + .pivot = INIT_PIVOT, + .scale = INIT_SCALE}}; + + init_aabb(); + } + + void reset() { + for (auto& sprite : sprites) { + sprite.pivot = INIT_PIVOT; + sprite.scale = INIT_SCALE; + } - // For resetting. position_y = INIT_POSITION_Y; velocity_y = INIT_VELOCITY_Y; rotation = INIT_ROTATION; - // We'll make the size half the size of the texture. - // (If you want 1:1 size, you need to double the scale of the sprite.) - auto size = paradiso::Vector2{ - paradiso::Vector2::make(scale_x, scale_y)}; - - // Center it. - auto position = paradiso::Vector2{paradiso::Vector2::make( - pivot.x() - size.x() / 2, pivot.y() - size.y() / 2)}; - - aabb = AABB{position, size}; + init_aabb(); } void update(const paradiso::Window::KeyboardInputStack& input) { @@ -363,7 +406,7 @@ struct Plane { // \ // *--- the y we need. - // @Efficiency: We could just add the velocity. + // @Efficiency: We could just add the velocity to the AABB's y position. aabb.position.y() = position_y - aabb.size.y() / 2; rotation = velocity_y * 500.0f; @@ -381,7 +424,7 @@ struct Plane { } }; -struct StartText { +struct StartUI { static const unsigned int TAP_ANIM_INTERVAL = 40; // textGetReady.png, tapLeft.png, tapRight.png @@ -395,43 +438,37 @@ struct StartText { unsigned int tap_anim_counter = 0; unsigned int current_tap_sprite = 0; - void init() { + void init(SpriteMap& sprite_map) { base_sprites = { - // textGetReady.png paradiso::Sprite{ - .bitmap = - paradiso::BitmapIO::get().load("PNG/UI/textGetReady.png"), + .bitmap = sprite_map["start_ui.text"], .pivot = {paradiso::Vector2::make(0.0f, 0.5f)}, // The image's size is 400x73 px. .scale = {paradiso::Vector2::make( 400.0f / WINDOW_WIDTH, 73.0f / WINDOW_HEIGHT)}}, - // tapLeft.png paradiso::Sprite{ - .bitmap = paradiso::BitmapIO::get().load("PNG/UI/tapLeft.png"), - .pivot = {paradiso::Vector2::make(0.5f, 0.0f)}, + .bitmap = sprite_map["tap_sign.left"], + .pivot = {paradiso::Vector2::make(-0.5f, 0.0f)}, // The image's size is 85x42 px. .scale = {paradiso::Vector2::make( 85.0f / WINDOW_WIDTH, 42.0f / WINDOW_HEIGHT)}}, - // tapRight.png paradiso::Sprite{ - .bitmap = paradiso::BitmapIO::get().load("PNG/UI/tapRight.png"), - .pivot = {paradiso::Vector2::make(-0.5f, 0.0f)}, + .bitmap = sprite_map["tap_sign.right"], + .pivot = {paradiso::Vector2::make(0.5f, 0.0f)}, // The image's size is 85x42 px. .scale = {paradiso::Vector2::make( 85.0f / WINDOW_WIDTH, 42.0f / WINDOW_HEIGHT)}}, }; tap_sprites = { - // tap.png paradiso::Sprite{ - .bitmap = paradiso::BitmapIO::get().load("PNG/UI/tap.png"), + .bitmap = sprite_map["tap.normal"], .pivot = {paradiso::Vector2::make(0.0f, -0.5f)}, // The image's size is 59x59 px. .scale = {paradiso::Vector2::make( 59.0f / WINDOW_WIDTH, 59.0f / WINDOW_HEIGHT)}}, - // tapTick.png paradiso::Sprite{ - .bitmap = paradiso::BitmapIO::get().load("PNG/UI/tapTick.png"), + .bitmap = sprite_map["tap.tick"], .pivot = {paradiso::Vector2::make(0.0f, -0.5f)}, // The image's size is 59x59 px. .scale = {paradiso::Vector2::make( @@ -469,19 +506,16 @@ struct StartText { } }; -struct GameOverText { +struct GameOverUI { paradiso::Sprite sprite; paradiso::Renderer renderer{}; - paradiso::Bitmap image = - paradiso::BitmapIO::get().load("PNG/UI/textGameOver.png"); - - void init() { + void init(SpriteMap& sprite_map) { // The image's size is 412x78 px. float scale_x = 412.0f / WINDOW_WIDTH; float scale_y = 78.0f / WINDOW_HEIGHT; - sprite = {.bitmap = image, + sprite = {.bitmap = sprite_map["game_over_ui.text"], .pivot = {paradiso::Vector2::make(0.0f, 0.0f)}, .scale = {paradiso::Vector2::make(scale_x, scale_y)}}; } @@ -500,155 +534,200 @@ struct GameOverText { enum class GameState { Start, Playing, GameOver }; -auto main() -> int { - std::srand(std::time(nullptr)); +struct App { + SpriteMap sprites; - auto canvas_size = paradiso::Size{.width = WINDOW_WIDTH * WINDOW_SCALE, - .height = WINDOW_HEIGHT * WINDOW_SCALE}; + static auto create() -> App { + auto app = App{}; - // Unser Fenster, auf das wir rendern. - auto window = paradiso::Window(); - window - .set_size(canvas_size) // ... Größe - .set_position(paradiso::Point{.x = 200, .y = 200}) // ... Position - .set_title("ParadiSO.TappyPlane") // ... Titel - .set_visible(true); // ... und jetzt anzeigen! + paradiso::BitmapIO::get().set_path( + paradiso::get_executable_path().parent_path().string() + "/assets"); - // Der Fenster Context. - auto context = paradiso::Context{}; + auto assets = std::array{ + SpriteName{"background", "PNG/background.png"}, + SpriteName{"ground", "PNG/groundGrass.png"}, + SpriteName{"rocks.top", "PNG/rockGrassDown.png"}, + SpriteName{"rocks.bottom", "PNG/rockGrass.png"}, + SpriteName{"plane.1", "PNG/Planes/planeRed1.png"}, + SpriteName{"plane.2", "PNG/Planes/planeRed2.png"}, + SpriteName{"plane.3", "PNG/Planes/planeRed3.png"}, + SpriteName{"tap_sign.left", "PNG/UI/tapRight.png"}, + SpriteName{"tap_sign.right", "PNG/UI/tapLeft.png"}, + SpriteName{"tap.normal", "PNG/UI/tap.png"}, + SpriteName{"tap.tick", "PNG/UI/tapTick.png"}, + SpriteName{"start_ui.text", "PNG/UI/textGetReady.png"}, + SpriteName{"game_over_ui.text", "PNG/UI/textGameOver.png"}, + }; - // Ein Shader (Schattierungsprogramm). - auto shader = paradiso::Shader{}; + for (const auto& [name, filename] : assets) { + std::print("{} : {} -> ", name, filename); - // Wir nutzen einen vorgefertigten Shader, der speziell für Sprites ist. - shader.load_preset(paradiso::Shader::Preset::Sprite); - - // Ein Viewport stellt die Sicht der Kamera dar, d.h. bei quadratischen - // Pixeln sollte hier auch eine dementsprechende Größe eingestellt - // werden. - context.set_viewport(paradiso::Rectangle{ - .position = paradiso::Point{.x = 0, .y = 0}, .size = canvas_size}); - - // Conflower blue - context.set_clearcolor(paradiso::RGBA::from_rgb(0x64, 0x95, 0xED)); - - // Der Asset Loader bekommt den Pfad. - paradiso::BitmapIO::get().set_path("assets"); - - // Wir initialisieren unsere Sachen. - auto game_state = GameState::Start; - - auto background = Background{}; - auto ground = Ground{}; - auto rocks1 = Rocks{}; - auto rocks2 = Rocks{}; - auto plane = Plane{}; - auto start_text = StartText{}; - auto game_over_text = GameOverText{}; - - background.init(); - ground.init(); - rocks1.init(1.2f, true); // We don't need to set this to true, - rocks2.init(2.4f, true); // but why not? - plane.init(); - start_text.init(); - game_over_text.init(); - - auto top_aabb = - AABB{.position = {paradiso::Vector2::make(-1.0f, 1.0f)}, - .size = {paradiso::Vector2::make(2.0f, 0.5f)}}; - - while (window.update([&](paradiso::Window& window) -> bool { - auto t1 = std::chrono::high_resolution_clock::now(); - - if (window.keyboard_input().size() && - window.keyboard_input().top().key == 'Q') { - // Update-Loop beenden. - return false; + auto bitmap = paradiso::BitmapIO::get().load(filename); + app.sprites[name] = bitmap; } - if (game_state == GameState::Start) { - if (window.keyboard_input().size() && - window.keyboard_input().top().key == ACTION_KEY && - window.keyboard_input().top().action == 1) { - game_state = GameState::Playing; + return app; + } - // Make the plane jump for the first time. - // @ToDo: The plane jumps too high because there was no gravity - // before. - plane.update(window.keyboard_input()); - } + void run() { + auto canvas_size = + paradiso::Size{.width = WINDOW_WIDTH * WINDOW_SCALE, + .height = WINDOW_HEIGHT * WINDOW_SCALE}; - background.update(); - ground.update(); - start_text.update(); - } else if (game_state == GameState::Playing) { - background.update(); - ground.update(); + // Unser Fenster, auf das wir rendern. + auto window = paradiso::Window(); + window + .set_size(canvas_size) // ... Größe + .set_position(paradiso::Point{.x = 200, .y = 200}) // ... Position + .set_title("ParadiSO.TappyPlane") // ... Titel + .set_visible(true); // ... und jetzt anzeigen! - rocks1.update(); - rocks2.update(); + // Der Fenster Context. + auto context = paradiso::Context{}; - plane.update(window.keyboard_input()); + // Ein Shader (Schattierungsprogramm). + auto shader = paradiso::Shader{}; - background.scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; - ground.scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; - rocks1.scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; - rocks2.scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; - - if (plane.aabb.is_colliding_with(rocks1.top_aabb) || - plane.aabb.is_colliding_with(rocks1.bottom_aabb) || - plane.aabb.is_colliding_with(rocks2.top_aabb) || - plane.aabb.is_colliding_with(rocks2.bottom_aabb) || - plane.aabb.is_colliding_with(top_aabb) || - plane.aabb.is_colliding_with(ground.aabb)) { - game_state = GameState::GameOver; - } - } else if (game_state == GameState::GameOver) { - if (window.keyboard_input().size() && - window.keyboard_input().top().key == ACTION_KEY) { - - // Reset everything. - background.init(); - ground.init(); - rocks1.init(1.2f, true); - rocks2.init(2.4f, true); - plane.init(); - game_state = GameState::Start; - } - } + // Wir nutzen einen vorgefertigten Shader, der speziell für Sprites ist. + shader.load_preset(paradiso::Shader::Preset::Sprite); + // Ein Viewport stellt die Sicht der Kamera dar, d.h. bei quadratischen + // Pixeln sollte hier auch eine dementsprechende Größe eingestellt + // werden. context.set_viewport(paradiso::Rectangle{ .position = paradiso::Point{.x = 0, .y = 0}, .size = canvas_size}); - context.clear(); - background.draw(shader); + // Conflower blue + context.set_clearcolor(paradiso::RGBA::from_rgb(0x64, 0x95, 0xED)); - plane.draw(shader); + // Der Asset Loader bekommt den Pfad. + paradiso::BitmapIO::get().set_path("assets"); - rocks1.draw(shader); - rocks2.draw(shader); + // Wir initialisieren unsere Sachen. + auto game_state = GameState::Start; - ground.draw(shader); + auto background = Background{}; + auto ground = Ground{}; + auto rocks1 = Rocks{}; + auto rocks2 = Rocks{}; + auto plane = Plane{}; + auto start_ui = StartUI{}; + auto game_over_ui = GameOverUI{}; - // Kinda dumb that we check the game state here the second time but I - // like to seperate 'update' from 'draw'. - if (game_state == GameState::Start) { - start_text.draw(shader); - } else if (game_state == GameState::GameOver) { - game_over_text.draw(shader); - } + background.init(sprites); + ground.init(sprites); + rocks1.init(sprites, 1.2f); // We don't need to set this to true, + rocks2.init(sprites, 2.4f); // but why not? + plane.init(sprites); + start_ui.init(sprites); + game_over_ui.init(sprites); - // Einen kurzen Moment warten, um auf 60 FPS zu kommen. - auto t2 = std::chrono::high_resolution_clock::now(); - auto duration = - std::chrono::duration_cast(t2 - t1); - auto wait = std::chrono::microseconds(1000000 / FRAME_RATE) - duration; - std::this_thread::sleep_for(wait); + auto top_aabb = + AABB{.position = {paradiso::Vector2::make(-1.0f, 1.0f)}, + .size = {paradiso::Vector2::make(2.0f, 0.5f)}}; - return true; - })) { - }; + while (window.update([&](paradiso::Window& window) -> bool { + auto t1 = std::chrono::high_resolution_clock::now(); + if (window.keyboard_input().size() && + window.keyboard_input().top().key == 'Q') { + // Update-Loop beenden. + return false; + } + + if (game_state == GameState::Start) { + if (window.keyboard_input().size() && + window.keyboard_input().top().key == ACTION_KEY && + window.keyboard_input().top().action == 1) { + game_state = GameState::Playing; + + // Make the plane jump for the first time. + // @ToDo: The plane jumps too high because there was no + // gravity before. + plane.update(window.keyboard_input()); + } + + background.update(); + ground.update(); + start_ui.update(); + } else if (game_state == GameState::Playing) { + background.update(); + ground.update(); + + rocks1.update(); + rocks2.update(); + + plane.update(window.keyboard_input()); + + // @ToDo: Should we really do this here? + background.scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; + ground.scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; + rocks1.scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; + rocks2.scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; + + if (plane.aabb.is_colliding_with(rocks1.top_aabb) || + plane.aabb.is_colliding_with(rocks1.bottom_aabb) || + plane.aabb.is_colliding_with(rocks2.top_aabb) || + plane.aabb.is_colliding_with(rocks2.bottom_aabb) || + plane.aabb.is_colliding_with(top_aabb) || + plane.aabb.is_colliding_with(ground.aabb)) { + game_state = GameState::GameOver; + } + } else if (game_state == GameState::GameOver) { + if (window.keyboard_input().size() && + window.keyboard_input().top().key == ACTION_KEY) { + + // Reset everything. + background.reset(); + ground.reset(); + rocks1.reset(); + rocks2.reset(); + plane.reset(); + game_state = GameState::Start; + } + } + + context.set_viewport( + paradiso::Rectangle{.position = paradiso::Point{.x = 0, .y = 0}, + .size = canvas_size}); + context.clear(); + + background.draw(shader); + + plane.draw(shader); + + rocks1.draw(shader); + rocks2.draw(shader); + + ground.draw(shader); + + // Kinda dumb that we check the game state here the second time but + // I like to seperate 'update' from 'draw'. + if (game_state == GameState::Start) { + start_ui.draw(shader); + } else if (game_state == GameState::GameOver) { + game_over_ui.draw(shader); + } + + // Einen kurzen Moment warten, um auf 60 FPS zu kommen. + auto t2 = std::chrono::high_resolution_clock::now(); + auto duration = + std::chrono::duration_cast(t2 - t1); + auto wait = + std::chrono::microseconds(1000000 / FRAME_RATE) - duration; + std::this_thread::sleep_for(wait); + + return true; + })) { + }; + } +}; + +} // namespace TappyPlane + +auto main() -> int { + std::srand(std::time(nullptr)); + auto app = TappyPlane::App::create(); + app.run(); return 0; } From c82dcc9081156775079ebb4becae86d9ae3dd356 Mon Sep 17 00:00:00 2001 From: brxxh <11dac2t@huhn-online.de> Date: Sat, 31 May 2025 00:06:06 +0200 Subject: [PATCH 05/10] Update the scrolling speed in each update function --- examples/tappyplane/tappyplane.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/examples/tappyplane/tappyplane.cpp b/examples/tappyplane/tappyplane.cpp index 4d4a5cc..45b4ac5 100644 --- a/examples/tappyplane/tappyplane.cpp +++ b/examples/tappyplane/tappyplane.cpp @@ -81,6 +81,8 @@ struct Background { } void update() { + scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; + for (auto& sprite : sprites) { sprite.pivot.x() -= scrolling_speed; if (sprite.pivot.x() <= -2.0f) { @@ -139,6 +141,8 @@ struct Ground { } void update() { + scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; + for (auto& sprite : sprites) { sprite.pivot.x() -= scrolling_speed; if (sprite.pivot.x() <= -2.0f) { @@ -252,6 +256,8 @@ struct Rocks { } void update() { + scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; + top_sprite.pivot.x() -= scrolling_speed; bottom_sprite.pivot.x() -= scrolling_speed; @@ -653,18 +659,11 @@ struct App { } else if (game_state == GameState::Playing) { background.update(); ground.update(); - rocks1.update(); rocks2.update(); plane.update(window.keyboard_input()); - // @ToDo: Should we really do this here? - background.scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; - ground.scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; - rocks1.scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; - rocks2.scrolling_speed *= SCROLLING_SPEED_INC_FACTOR; - if (plane.aabb.is_colliding_with(rocks1.top_aabb) || plane.aabb.is_colliding_with(rocks1.bottom_aabb) || plane.aabb.is_colliding_with(rocks2.top_aabb) || @@ -693,12 +692,9 @@ struct App { context.clear(); background.draw(shader); - plane.draw(shader); - rocks1.draw(shader); rocks2.draw(shader); - ground.draw(shader); // Kinda dumb that we check the game state here the second time but From 64311c8a4df908075fd3ffd94b25bd1275e7b626 Mon Sep 17 00:00:00 2001 From: brxxh <11dac2t@huhn-online.de> Date: Sat, 31 May 2025 00:08:01 +0200 Subject: [PATCH 06/10] Update the plane animtion on the start --- examples/tappyplane/tappyplane.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/tappyplane/tappyplane.cpp b/examples/tappyplane/tappyplane.cpp index 45b4ac5..f1e2a8e 100644 --- a/examples/tappyplane/tappyplane.cpp +++ b/examples/tappyplane/tappyplane.cpp @@ -376,7 +376,7 @@ struct Plane { init_aabb(); } - void update(const paradiso::Window::KeyboardInputStack& input) { + void update_animation() { if (anim_counter < ANIM_INTERVAL) { anim_counter++; } else { @@ -389,6 +389,10 @@ struct Plane { anim_direction = 1; } } + } + + void update(const paradiso::Window::KeyboardInputStack& input) { + update_animation(); if (input.size() && input.top().key == ACTION_KEY && input.top().action == 1) { @@ -654,6 +658,7 @@ struct App { } background.update(); + plane.update_animation(); // Only the animation. ground.update(); start_ui.update(); } else if (game_state == GameState::Playing) { From 9cd2979eceae60037acb7435ab55f6ff4936f5e0 Mon Sep 17 00:00:00 2001 From: brxxh <11dac2t@huhn-online.de> Date: Sat, 31 May 2025 00:13:35 +0200 Subject: [PATCH 07/10] Remove a redundant comment --- examples/tappyplane/tappyplane.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/tappyplane/tappyplane.cpp b/examples/tappyplane/tappyplane.cpp index f1e2a8e..949f576 100644 --- a/examples/tappyplane/tappyplane.cpp +++ b/examples/tappyplane/tappyplane.cpp @@ -626,8 +626,8 @@ struct App { background.init(sprites); ground.init(sprites); - rocks1.init(sprites, 1.2f); // We don't need to set this to true, - rocks2.init(sprites, 2.4f); // but why not? + rocks1.init(sprites, 1.2f); + rocks2.init(sprites, 2.4f); plane.init(sprites); start_ui.init(sprites); game_over_ui.init(sprites); From c46779d92cb0d8d7d99b73c280aa1eef3c5d5a11 Mon Sep 17 00:00:00 2001 From: brxxh <11dac2t@huhn-online.de> Date: Sat, 31 May 2025 00:14:57 +0200 Subject: [PATCH 08/10] Don't set the BitmapIO path again --- examples/tappyplane/tappyplane.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/tappyplane/tappyplane.cpp b/examples/tappyplane/tappyplane.cpp index 949f576..e60bf83 100644 --- a/examples/tappyplane/tappyplane.cpp +++ b/examples/tappyplane/tappyplane.cpp @@ -610,9 +610,6 @@ struct App { // Conflower blue context.set_clearcolor(paradiso::RGBA::from_rgb(0x64, 0x95, 0xED)); - // Der Asset Loader bekommt den Pfad. - paradiso::BitmapIO::get().set_path("assets"); - // Wir initialisieren unsere Sachen. auto game_state = GameState::Start; From 80a0919c3f6b37c472229ffad3d6bf6618df73a6 Mon Sep 17 00:00:00 2001 From: brxxh <11dac2t@huhn-online.de> Date: Sat, 31 May 2025 20:22:54 +0200 Subject: [PATCH 09/10] Add different world and plane types --- examples/tappyplane/tappyplane.cpp | 126 ++++++++++++++++++++++------- 1 file changed, 97 insertions(+), 29 deletions(-) diff --git a/examples/tappyplane/tappyplane.cpp b/examples/tappyplane/tappyplane.cpp index e60bf83..ae786bc 100644 --- a/examples/tappyplane/tappyplane.cpp +++ b/examples/tappyplane/tappyplane.cpp @@ -166,11 +166,11 @@ struct Rocks { static constexpr float GAP_SIZE = 1.5f; // The image's size is 108x239 px. - static constexpr float INIT_SCALE_X = 108.0f / WINDOW_WIDTH; - static constexpr float INIT_SCALE_Y = 239.0f / WINDOW_HEIGHT; + static constexpr float SCALE_X = 108.0f / WINDOW_WIDTH; + static constexpr float SCALE_Y = 239.0f / WINDOW_HEIGHT; - static constexpr paradiso::Vector2 INIT_SCALE{ - paradiso::Vector2::make(INIT_SCALE_X, INIT_SCALE_Y)}; + static constexpr paradiso::Vector2 SCALE{ + paradiso::Vector2::make(SCALE_X, SCALE_Y)}; float scrolling_speed = INIT_SCROLLING_SPEED; @@ -186,14 +186,14 @@ struct Rocks { float init_pivot_x = 0.0f; auto get_random_top_position_y() -> float { - return 1.0f - INIT_SCALE_Y + (std::rand() % 50) / 100.0f + 0.01f; + return 1.0f - SCALE_Y + (std::rand() % 50) / 100.0f + 0.01f; } void init_aabbs() { // We'll make the width a quarter the width of the texture. // (If you want 1:1 size, you need to double the scale of the sprite.) auto size = paradiso::Vector2{ - paradiso::Vector2::make(INIT_SCALE_X / 2, INIT_SCALE_Y * 2)}; + paradiso::Vector2::make(SCALE_X / 2, SCALE_Y * 2)}; auto top_position = paradiso::Vector2{paradiso::Vector2::make( @@ -218,13 +218,13 @@ struct Rocks { top_sprite = paradiso::Sprite{.bitmap = sprite_map["rocks.top"], .pivot = {paradiso::Vector2::make( init_pivot_x, top_position_y)}, - .scale = INIT_SCALE}; + .scale = SCALE}; bottom_sprite = paradiso::Sprite{.bitmap = sprite_map["rocks.bottom"], .pivot = {paradiso::Vector2::make( init_pivot_x, bottom_position_y)}, - .scale = INIT_SCALE}; + .scale = SCALE}; init_aabbs(); } @@ -305,17 +305,17 @@ struct Plane { static constexpr float INIT_VELOCITY_Y = 0.0f; static constexpr float INIT_ROTATION = 0.0f; + static constexpr paradiso::Vector2 INIT_PIVOT{ + paradiso::Vector2::make(0.0f, INIT_POSITION_Y)}; + static const unsigned int ANIM_INTERVAL = 10; // The image's size is 88x73 px. - static constexpr float INIT_SCALE_X = 88.0f / WINDOW_WIDTH; - static constexpr float INIT_SCALE_Y = 73.0f / WINDOW_HEIGHT; + static constexpr float SCALE_X = 88.0f / WINDOW_WIDTH; + static constexpr float SCALE_Y = 73.0f / WINDOW_HEIGHT; - static constexpr paradiso::Vector2 INIT_SCALE{ - paradiso::Vector2::make(INIT_SCALE_X, INIT_SCALE_Y)}; - - static constexpr paradiso::Vector2 INIT_PIVOT{ - paradiso::Vector2::make(0.0f, INIT_POSITION_Y)}; + static constexpr paradiso::Vector2 SCALE{ + paradiso::Vector2::make(SCALE_X, SCALE_Y)}; // Animation sprites std::array sprites; @@ -338,9 +338,10 @@ struct Plane { void init_aabb() { // We'll make the size half the size of the texture. // (If you want 1:1 size, you need to double the scale of the sprite.) - // We could use INIT_SCALE here, but we'll keep this for clarity. + // We could use 'SCALE' here, but we'll keep this for clarity. + // (Although, now we no longer need 'SCALE' as a constant in this entire struct.) auto size = paradiso::Vector2{ - paradiso::Vector2::make(INIT_SCALE_X, INIT_SCALE_Y)}; + paradiso::Vector2::make(SCALE_X, SCALE_Y)}; // Center it. auto position = paradiso::Vector2{paradiso::Vector2::make( @@ -352,13 +353,13 @@ struct Plane { void init(SpriteMap& sprite_map) { sprites = {paradiso::Sprite{.bitmap = sprite_map["plane.1"], .pivot = INIT_PIVOT, - .scale = INIT_SCALE}, + .scale = SCALE}, paradiso::Sprite{.bitmap = sprite_map["plane.2"], .pivot = INIT_PIVOT, - .scale = INIT_SCALE}, + .scale = SCALE}, paradiso::Sprite{.bitmap = sprite_map["plane.3"], .pivot = INIT_PIVOT, - .scale = INIT_SCALE}}; + .scale = SCALE}}; init_aabb(); } @@ -366,7 +367,6 @@ struct Plane { void reset() { for (auto& sprite : sprites) { sprite.pivot = INIT_PIVOT; - sprite.scale = INIT_SCALE; } position_y = INIT_POSITION_Y; @@ -547,20 +547,84 @@ enum class GameState { Start, Playing, GameOver }; struct App { SpriteMap sprites; - static auto create() -> App { + enum class WorldType { Dirt, Grass, Ice, Rock, Snow }; + enum class PlaneType { Blue, Green, Red, Yellow }; + + static auto create(WorldType world_type = WorldType::Grass, PlaneType plane_type = PlaneType::Red) -> App { auto app = App{}; paradiso::BitmapIO::get().set_path( paradiso::get_executable_path().parent_path().string() + "/assets"); + // Yes, I'm lazy, how did you know? + const char *ground_filename = nullptr; + const char *rocks_top_filename = nullptr; + const char *rocks_bottom_filename = nullptr; + switch (world_type) { + case WorldType::Dirt: + ground_filename = "PNG/groundDirt.png"; + rocks_top_filename = "PNG/rockDown.png"; + rocks_bottom_filename = "PNG/rock.png"; + break; + case WorldType::Ice: + ground_filename = "PNG/groundIce.png"; + rocks_top_filename = "PNG/rockIceDown.png"; + rocks_bottom_filename = "PNG/rockIce.png"; + break; + case WorldType::Rock: + ground_filename = "PNG/groundRock.png"; + rocks_top_filename = "PNG/rockDown.png"; + rocks_bottom_filename = "PNG/rock.png"; + break; + case WorldType::Snow: + ground_filename = "PNG/groundSnow.png"; + rocks_top_filename = "PNG/rockSnowDown.png"; + rocks_bottom_filename = "PNG/rockSnow.png"; + break; + default: + case WorldType::Grass: + ground_filename = "PNG/groundGrass.png"; + rocks_top_filename = "PNG/rockGrassDown.png"; + rocks_bottom_filename = "PNG/rockGrass.png"; + break; + } + + // Yes, I'm lazy, how did you know? + const char *plane_1_filename = nullptr; + const char *plane_2_filename = nullptr; + const char *plane_3_filename = nullptr; + switch (plane_type) { + case PlaneType::Blue: + plane_1_filename = "PNG/Planes/planeBlue1.png"; + plane_2_filename = "PNG/Planes/planeBlue2.png"; + plane_3_filename = "PNG/Planes/planeBlue3.png"; + break; + case PlaneType::Green: + plane_1_filename = "PNG/Planes/planeGreen1.png"; + plane_2_filename = "PNG/Planes/planeGreen2.png"; + plane_3_filename = "PNG/Planes/planeGreen3.png"; + break; + case PlaneType::Yellow: + plane_1_filename = "PNG/Planes/planeYellow1.png"; + plane_2_filename = "PNG/Planes/planeYellow2.png"; + plane_3_filename = "PNG/Planes/planeYellow3.png"; + break; + default: + case PlaneType::Red: + plane_1_filename = "PNG/Planes/planeRed1.png"; + plane_2_filename = "PNG/Planes/planeRed2.png"; + plane_3_filename = "PNG/Planes/planeRed3.png"; + break; + } + auto assets = std::array{ SpriteName{"background", "PNG/background.png"}, - SpriteName{"ground", "PNG/groundGrass.png"}, - SpriteName{"rocks.top", "PNG/rockGrassDown.png"}, - SpriteName{"rocks.bottom", "PNG/rockGrass.png"}, - SpriteName{"plane.1", "PNG/Planes/planeRed1.png"}, - SpriteName{"plane.2", "PNG/Planes/planeRed2.png"}, - SpriteName{"plane.3", "PNG/Planes/planeRed3.png"}, + SpriteName{"ground", ground_filename}, + SpriteName{"rocks.top", rocks_top_filename}, + SpriteName{"rocks.bottom", rocks_bottom_filename}, + SpriteName{"plane.1", plane_1_filename}, + SpriteName{"plane.2", plane_2_filename}, + SpriteName{"plane.3", plane_3_filename}, SpriteName{"tap_sign.left", "PNG/UI/tapRight.png"}, SpriteName{"tap_sign.right", "PNG/UI/tapLeft.png"}, SpriteName{"tap.normal", "PNG/UI/tap.png"}, @@ -725,7 +789,11 @@ struct App { auto main() -> int { std::srand(std::time(nullptr)); - auto app = TappyPlane::App::create(); + + auto world_type = TappyPlane::App::WorldType::Grass; + auto plane_type = TappyPlane::App::PlaneType::Red; + + auto app = TappyPlane::App::create(world_type, plane_type); app.run(); return 0; } From b6805f71644793e582bcfa9d0058fc68772ec666 Mon Sep 17 00:00:00 2001 From: brxxh <11dac2t@huhn-online.de> Date: Sat, 31 May 2025 23:01:17 +0200 Subject: [PATCH 10/10] Format the code using clang-format --- examples/tappyplane/tappyplane.cpp | 112 +++++++++++++++-------------- 1 file changed, 57 insertions(+), 55 deletions(-) diff --git a/examples/tappyplane/tappyplane.cpp b/examples/tappyplane/tappyplane.cpp index ae786bc..95bab15 100644 --- a/examples/tappyplane/tappyplane.cpp +++ b/examples/tappyplane/tappyplane.cpp @@ -339,7 +339,8 @@ struct Plane { // We'll make the size half the size of the texture. // (If you want 1:1 size, you need to double the scale of the sprite.) // We could use 'SCALE' here, but we'll keep this for clarity. - // (Although, now we no longer need 'SCALE' as a constant in this entire struct.) + // (Although, now we no longer need 'SCALE' as a constant in this entire + // struct.) auto size = paradiso::Vector2{ paradiso::Vector2::make(SCALE_X, SCALE_Y)}; @@ -550,71 +551,72 @@ struct App { enum class WorldType { Dirt, Grass, Ice, Rock, Snow }; enum class PlaneType { Blue, Green, Red, Yellow }; - static auto create(WorldType world_type = WorldType::Grass, PlaneType plane_type = PlaneType::Red) -> App { + static auto create(WorldType world_type = WorldType::Grass, + PlaneType plane_type = PlaneType::Red) -> App { auto app = App{}; paradiso::BitmapIO::get().set_path( paradiso::get_executable_path().parent_path().string() + "/assets"); // Yes, I'm lazy, how did you know? - const char *ground_filename = nullptr; - const char *rocks_top_filename = nullptr; - const char *rocks_bottom_filename = nullptr; + const char* ground_filename = nullptr; + const char* rocks_top_filename = nullptr; + const char* rocks_bottom_filename = nullptr; switch (world_type) { - case WorldType::Dirt: - ground_filename = "PNG/groundDirt.png"; - rocks_top_filename = "PNG/rockDown.png"; - rocks_bottom_filename = "PNG/rock.png"; - break; - case WorldType::Ice: - ground_filename = "PNG/groundIce.png"; - rocks_top_filename = "PNG/rockIceDown.png"; - rocks_bottom_filename = "PNG/rockIce.png"; - break; - case WorldType::Rock: - ground_filename = "PNG/groundRock.png"; - rocks_top_filename = "PNG/rockDown.png"; - rocks_bottom_filename = "PNG/rock.png"; - break; - case WorldType::Snow: - ground_filename = "PNG/groundSnow.png"; - rocks_top_filename = "PNG/rockSnowDown.png"; - rocks_bottom_filename = "PNG/rockSnow.png"; - break; - default: - case WorldType::Grass: - ground_filename = "PNG/groundGrass.png"; - rocks_top_filename = "PNG/rockGrassDown.png"; - rocks_bottom_filename = "PNG/rockGrass.png"; - break; + case WorldType::Dirt: + ground_filename = "PNG/groundDirt.png"; + rocks_top_filename = "PNG/rockDown.png"; + rocks_bottom_filename = "PNG/rock.png"; + break; + case WorldType::Ice: + ground_filename = "PNG/groundIce.png"; + rocks_top_filename = "PNG/rockIceDown.png"; + rocks_bottom_filename = "PNG/rockIce.png"; + break; + case WorldType::Rock: + ground_filename = "PNG/groundRock.png"; + rocks_top_filename = "PNG/rockDown.png"; + rocks_bottom_filename = "PNG/rock.png"; + break; + case WorldType::Snow: + ground_filename = "PNG/groundSnow.png"; + rocks_top_filename = "PNG/rockSnowDown.png"; + rocks_bottom_filename = "PNG/rockSnow.png"; + break; + default: + case WorldType::Grass: + ground_filename = "PNG/groundGrass.png"; + rocks_top_filename = "PNG/rockGrassDown.png"; + rocks_bottom_filename = "PNG/rockGrass.png"; + break; } // Yes, I'm lazy, how did you know? - const char *plane_1_filename = nullptr; - const char *plane_2_filename = nullptr; - const char *plane_3_filename = nullptr; + const char* plane_1_filename = nullptr; + const char* plane_2_filename = nullptr; + const char* plane_3_filename = nullptr; switch (plane_type) { - case PlaneType::Blue: - plane_1_filename = "PNG/Planes/planeBlue1.png"; - plane_2_filename = "PNG/Planes/planeBlue2.png"; - plane_3_filename = "PNG/Planes/planeBlue3.png"; - break; - case PlaneType::Green: - plane_1_filename = "PNG/Planes/planeGreen1.png"; - plane_2_filename = "PNG/Planes/planeGreen2.png"; - plane_3_filename = "PNG/Planes/planeGreen3.png"; - break; - case PlaneType::Yellow: - plane_1_filename = "PNG/Planes/planeYellow1.png"; - plane_2_filename = "PNG/Planes/planeYellow2.png"; - plane_3_filename = "PNG/Planes/planeYellow3.png"; - break; - default: - case PlaneType::Red: - plane_1_filename = "PNG/Planes/planeRed1.png"; - plane_2_filename = "PNG/Planes/planeRed2.png"; - plane_3_filename = "PNG/Planes/planeRed3.png"; - break; + case PlaneType::Blue: + plane_1_filename = "PNG/Planes/planeBlue1.png"; + plane_2_filename = "PNG/Planes/planeBlue2.png"; + plane_3_filename = "PNG/Planes/planeBlue3.png"; + break; + case PlaneType::Green: + plane_1_filename = "PNG/Planes/planeGreen1.png"; + plane_2_filename = "PNG/Planes/planeGreen2.png"; + plane_3_filename = "PNG/Planes/planeGreen3.png"; + break; + case PlaneType::Yellow: + plane_1_filename = "PNG/Planes/planeYellow1.png"; + plane_2_filename = "PNG/Planes/planeYellow2.png"; + plane_3_filename = "PNG/Planes/planeYellow3.png"; + break; + default: + case PlaneType::Red: + plane_1_filename = "PNG/Planes/planeRed1.png"; + plane_2_filename = "PNG/Planes/planeRed2.png"; + plane_3_filename = "PNG/Planes/planeRed3.png"; + break; } auto assets = std::array{