From c3c21a223618946206d9589a50f766b70c9d4f7b Mon Sep 17 00:00:00 2001 From: Martin Prokoph Date: Sat, 1 Mar 2025 20:42:13 +0100 Subject: [PATCH] feat: add textures --- CMakeLists.txt | 16 +++ src/adventura.cpp | 2 +- src/appcontext.hpp | 27 ++++ src/assets/textures/box.png | Bin 0 -> 509 bytes src/assets/textures/ladder.png | Bin 0 -> 304 bytes src/assets/textures/platform.png | Bin 0 -> 233 bytes src/assets/textures/player_falling.png | Bin 0 -> 184 bytes src/assets/textures/player_idle.png | Bin 0 -> 178 bytes src/assets/textures/sand.png | Bin 0 -> 635 bytes src/assets/textures/spike.png | Bin 0 -> 482 bytes src/assets/textures/wall.png | Bin 0 -> 285 bytes src/assets/textures/water.png | Bin 0 -> 227 bytes src/assets/textures_base/box.pxo | Bin 0 -> 800 bytes src/assets/textures_base/ladder.pxo | Bin 0 -> 692 bytes src/assets/textures_base/platform.pxo | Bin 0 -> 667 bytes src/assets/textures_base/player_falling.pxo | Bin 0 -> 649 bytes src/assets/textures_base/player_idle.pxo | Bin 0 -> 651 bytes src/assets/textures_base/sand.pxo | Bin 0 -> 848 bytes src/assets/textures_base/spike.pxo | Bin 0 -> 761 bytes src/assets/textures_base/wall.pxo | Bin 0 -> 679 bytes src/assets/textures_base/water.pxo | Bin 0 -> 664 bytes src/camera.hpp | 3 + src/main.cpp | 68 +++------- src/output.hpp | 28 ++++- src/renderer.cpp | 131 ++++++++++++++++++++ worlds/4.txt | 2 +- worlds/5.txt | 2 +- 27 files changed, 221 insertions(+), 58 deletions(-) create mode 100644 src/appcontext.hpp create mode 100644 src/assets/textures/box.png create mode 100644 src/assets/textures/ladder.png create mode 100755 src/assets/textures/platform.png create mode 100644 src/assets/textures/player_falling.png create mode 100644 src/assets/textures/player_idle.png create mode 100644 src/assets/textures/sand.png create mode 100644 src/assets/textures/spike.png create mode 100644 src/assets/textures/wall.png create mode 100644 src/assets/textures/water.png create mode 100644 src/assets/textures_base/box.pxo create mode 100644 src/assets/textures_base/ladder.pxo create mode 100644 src/assets/textures_base/platform.pxo create mode 100644 src/assets/textures_base/player_falling.pxo create mode 100644 src/assets/textures_base/player_idle.pxo create mode 100644 src/assets/textures_base/sand.pxo create mode 100644 src/assets/textures_base/spike.pxo create mode 100644 src/assets/textures_base/wall.pxo create mode 100644 src/assets/textures_base/water.pxo create mode 100644 src/camera.hpp create mode 100644 src/renderer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ccc7b3e..ca20ba0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -151,12 +151,28 @@ else() DEPENDS "${filename}" ) endmacro() + macro(copy_dir filename) + if (ANDROID) + # MOBILE_ASSETS_DIR is set in the gradle file via the cmake command line and points to the Android Studio Assets folder. + # when we copy assets there, the Android build pipeline knows to add them to the apk. + set(outname "${MOBILE_ASSETS_DIR}/${filename}") + else() + # for platforms that do not have a good packaging format, all we can do is copy the assets to the process working directory. + set(outname "${CMAKE_BINARY_DIR}/$/${filename}") + endif() + add_custom_command(POST_BUILD + TARGET "${EXECUTABLE_NAME}" + COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_LIST_DIR}/src/${filename}" "${outname}" + DEPENDS "${filename}" + ) + endmacro() copy_helper("assets/Inter-VariableFont.ttf") copy_helper("assets/MartianMono-VariableFont.ttf") copy_helper("assets/sunset_on_the_beach.ogg") copy_helper("assets/success.ogg") copy_helper("assets/failure.ogg") copy_helper("assets/gs_tiger.svg") + copy_dir("assets/textures/") endif() # set some extra configs for each platform diff --git a/src/adventura.cpp b/src/adventura.cpp index be07f14..893f99f 100644 --- a/src/adventura.cpp +++ b/src/adventura.cpp @@ -59,7 +59,7 @@ bool startWorld(string worldFile) { world.loadFromFile(worldFile); Player player = Player(world.getStartPos(), world); - render(world, player.mapToWorldspace()); + renderWorld(world); inputLoop(player, world, testMode, worldIndex); diff --git a/src/appcontext.hpp b/src/appcontext.hpp new file mode 100644 index 0000000..a5fad70 --- /dev/null +++ b/src/appcontext.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "player.hpp" +#include "world.hpp" +#include "camera.hpp" + +struct AppContext { + SDL_Window* window; + SDL_Renderer* renderer; + SDL_Texture* messageTex, *imageTex; + SDL_FRect messageDest; + SDL_AudioDeviceID audioDevice; + Mix_Music* music; + SDL_AppResult app_quit = SDL_APP_CONTINUE; + Player* player; + World* world; + TTF_Font* font; + std::filesystem::path basePath; + Pos camera; +}; \ No newline at end of file diff --git a/src/assets/textures/box.png b/src/assets/textures/box.png new file mode 100644 index 0000000000000000000000000000000000000000..6d28df382f17323e96071ce9ba019c7e0c56838e GIT binary patch literal 509 zcmVPx$w@E}nR5*==lTD7=KoCZs{{(Gg6NZUx76>WI4YJ9RvddYrnMDj-v-bd+G4pyMsK>DCCt`*Z|l~+c6S?G!m?eEqR`4 zkqT41+}F(GDI*~mcn-FjElE=5@s#DhW_KvHNHy9WO0rV&dG?Vf!=>G{9hH={myR$9 zSWJSR6VG+X^NiQ^2H&xI;->9z6*$jzXfGW}k^&i7De10jYT0n=ZY(ANNs?+u3Z!kW z$86#|7MtqK{&zEjJ1X-0KEkKxu(uuM(9}FI zIMy{;DM=$iIC&-n%>*(%%18)y?eX5Al9CWO)-|hQ%RHWH+KP!cEO}jT@P?(%^|r7( z+zS?ypeI&Lp2iW2^NCflr9GeUUAqr)Rc!UDOkgHtwVma@*8h5hSlIZk&2d}kWF=+q zxXwU2_DSE~1JA*N`#GzbFp_5c>)e0*Tw8wt&QtI9PV5^y00000NkvXXu0mjfmd5J2 literal 0 HcmV?d00001 diff --git a/src/assets/textures/ladder.png b/src/assets/textures/ladder.png new file mode 100644 index 0000000000000000000000000000000000000000..f6398dbc02c1ae72e7db779d3ad0cff244f2a042 GIT binary patch literal 304 zcmV-00nh%4P)Px#>PbXFR5*>DQ?U)gFc7>zloS*cq@#d}K~m5$6H3Vdv>AjQG5}Q2APP4rA|;lQ zDI6z$>thgCS=Rr(@BSR2N3q{&dp=%n5f~KtR%eR@q8n>suJDwvb=|$m-7=k{jT4AQ z0&z0jj|57>vR`WrU`7aDt;S{r(o6{)_Og2N5*(Qpbd1OT3#bRZj7bkd1X&6oH8LI{ z4{WVZAi7aTS>0I=&WD{AjfB7`m5x!8>l@&&ki5V}C2SS;1Fb7ivE~au|J#b|V zV>o?2L}S*>zo2i<(trO#-~2TPlUq>Im>9?b_ZL1r;CSN#KDem>0000_W?T((Ec)L}L*=5%?A>j$Hl#^4Nci)%jv9D{}ur|9| zmwV5?>#dg0-n$Pbf09uHQ>A;0dy{dr>mdKI;Vst0NlY@(*OVf literal 0 HcmV?d00001 diff --git a/src/assets/textures/player_falling.png b/src/assets/textures/player_falling.png new file mode 100644 index 0000000000000000000000000000000000000000..95d067a79d947de00ede1b1286a2e4d1d4d764fd GIT binary patch literal 184 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|iacE$Lo9l? z26+lK7;td+y?^w7{~>Q#O*2ioGfSCy6HNtNTvBeI=_%ZP@C-XcyHL^h6YuLqj~tlJ zVt#*9SG**mUcX7X$5o;|x%>j7=n7qfdn>P4*Phm0leZ`@(MV+C g-@ST;qH8R~!xnaHF8{OY0?>8_Pgg&ebxsLQ05_6D#{d8T literal 0 HcmV?d00001 diff --git a/src/assets/textures/player_idle.png b/src/assets/textures/player_idle.png new file mode 100644 index 0000000000000000000000000000000000000000..429e55b5e97f8231c4d33e41596968754d4d3345 GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|ay(reLo9mt zPCU(fz<|T~?TX@!|HHn#T4bT%sx`giL$$=Ah_q$DR9+U{PWsNy@cN2|QqcYXoN8&U zJB0#gTarQgd+*a*SwnerIXfK1OtDnm{r-UW|fG0)+jEP)Px%HAzH4R5*=gl3h>JP#DL5paZ&%ET!6Y9+-8$0G13%)H`qRO1bhI_?7%H-VvhS zVL}K~0+OsFC3SS#b;!E9HV!Xp4-B8Hb8`OA^ZZ}V#P-K`7hJ2rKStF|0Oqs-T|W;% zRVX-a1b{9qI_^G`SwjW}WHUhXs6#UJ0C3!hs!-$|NC&Lemq~^m&E|+flul2E9zn0q ztZLy0BLGfM+c<7SKPuqbTj>B@SbW~GS$gu8q7t(7K%ud-Nq)A*9bt0*%fl#_(1nFz zRM3TmTAIWUMg+Y+6W2W$gk4JN0)um#+;o{_=ux@*5~ukI^U(`B?!Lt8!b&A1LyxLZ z$W0X}sS6}=h^VcTn<_9@e#%+5#lw|XocB`gw~Q6(+a!=~y0HX65{K}|qp`C|5{Ddq z{Q!X5+NRa~0v7|$x-C@Ayi6e(di*>+B8fwSULU=>&f4?WGv3fqyKSNeSN??@={V0;@t{uW`WD%4B9zvl^3-JveUkA8@h0APx$oJmAMR5*>@kUvi2KorJ*HXeBf3GU(D|Bc??4Uew8HvS(fp2dmG!bST2`lq_QkoJUvlW6-k<69UmUnu9Ub! zpo;>j6m?l*IS#8RVzb>w7X>=cP3;Q7a~$JJiQVx$be>~74z3Waq6l3S)Mbe)<(p6l zI-bXK93z!7W>*O8Jj>W@xB2mI?06o)2cs?uLj&+TvC|YC&tnxuW>LT!E}-+=^#2_9 Y6*z(JPx#*GWV{R5*?8lRXZDFbstsh#e_wBp)D?56IS?q33At!o&e0v0BOr=+HWPNy`oD zC1CvX*?A1NWjT{7dOLDP6sacw?AwMpg!&EuQy<)0F{{sW2q5;O#wb#&F*1+P zW3z8!G*9NMVY8@kr)PhV@%)V~tQU~7gN(V{xuY-?oV$@&Ap3wh^ jeqQQ;7sWbYnka%7gDv0@;%bzu00000NkvXXu0mjfgAjHd literal 0 HcmV?d00001 diff --git a/src/assets/textures/water.png b/src/assets/textures/water.png new file mode 100644 index 0000000000000000000000000000000000000000..86e3f3e4bdf895081688ed391d1ce504ca401846 GIT binary patch literal 227 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRt!3HF+tk*dLq!^2X+?^QKos)S9mYg)PM99aSdpCZ91n{ zuYFxxlK6%Nw>wU&#WYyyH8e(lpSRFsm8NH+sQa|#Hez=+e_wdy_vYQ|k`h3$WXf5| z4V{M>eC8F2zo^=hyu>Dmp)|R1cKD2cdI^u7iKaCqvazwXmFwpnRK34)ZF@Atm5pbs)Fchgo-MC-pa1j4|F-Bf{^NG@i(4;!f9S&4^*))+#On3p ztcb~3Yu+0;ZLH3he#60~@s>l<#IJ|_XVptT<8=WO+I^cQx7dvSN?v}Lw0iXBp#WFLym&A z{=x@-D;-zP)IRQH%5mC<*LmOF-0!mm3X4wpFRooRU$P?0BP?{uj>F&TdJl*P6&?Pw z;acX}V0G)-pmUpMzWiJ}?fp@~jj?+Rt4_SE$_i0s})Hf#Cr>p<@-K}Sm-uM6e{Qs{CH{=I+GXhf` u?z9LBEnw1w0(i)6Y#_x7H?P@%r!_wH zlj+*7E#I1c+a3*ZZIh5PRS6W5$h=xUpZSabZP97`$L;19x8CA^=)$<_eKMno6 zQ`Ig;-A``G`hL&shH%J&K(9{$4zF)iKUklx*uT@sxk|IDOT$nprx8uobyWY+}M!T=2EP1hZiDlB_sl}&C79B5WTjeU- z(Y#&P^kd$(vooJKSMzUAs=b=>VsVO|v%OL?$J#Ti-%dTWQ2ns_tpeG}(UW?#H2By< zzc8mZe0TNpU7{<`ee{Hmv1!lKvh8>CosPVDGGFa?h&}g*D?;nDJXXl<{%zW{Yr+HR zY3*D6vgcOadpWrvZ05{;cf_C0lNH>3Rr+)Ev)7%TS0qAq@c+_YBKi8JzyIO=e@%}H zoakXP>SeaTBZWH*wzTI&=F3qM1EHzP15;7%VP4*-)36u?sp ix;Avr!Za{2WC3;K@p^zaD;r2L6A(54X*r;47#INGKnrUC literal 0 HcmV?d00001 diff --git a/src/assets/textures_base/platform.pxo b/src/assets/textures_base/platform.pxo new file mode 100644 index 0000000000000000000000000000000000000000..7106b6db177140fd266ff3c9d5faa1d8ef917ebd GIT binary patch literal 667 zcmWIWW@Zs#VBp|jC=E@FN)B3J>%z#u(8$EVz{$YCkdj!EsFziopO-uFZeFtiPiuVY zC)2fETfQ~@wmll+%Eq%*YLW&gPt@1D&l&z+E)&&OKW;a_xb@Qahc1j=?~~a~tX?n9 zikO_W=DmT_#_IiMHv~lm1UWRx*y2Y*r3#Gu96Axow&THImk*7B(8^Z~0i7JdOw zBx6Ko&vJWNKlxzkd&5npo4;gvCEYHr^CC9oZObfEmfo~9Tl>mj&cciU z_DL^%okRD`&MjT`YvJDZ=!5&bjJ{0dp1x3is>77D&so(=3tpT&G080G_(@$)Ha?w) z3p(~KXZc`v;-kl{Q=0;K4;cj?o{(RD`>&ddk6)$9t>wRFHZE^V332VR&Ut^EqefBH z`V4=z?b@$bPWsqurr$jC<)_{0?~gieth+a(&N$bOz6VQu(SSR`=={15kqcQh~zKL|_mzurM%41F6j1#Prm7P=M>F6(#1T z7V8`8=Ok997R4LBo#@EdV8FprTakaK`h)D(UafYu$0G3yR9H^s?RHqa^|M6s$GzX( zefnpg-kdG@^2l=bFKK>f@>6@uwcf1>zoYR?x&LqE{29+p&(C^ywz}}$-f-LfiSzD$ z{=vUu@855kyBPw!8G#XwI~jnS2}~7G08bR?+R(iO)4;%x4b+Xtg8|;GY#_xUeqQdxyLrt9JgxDm zpG?rcIKgl>dNl7JY^?GPvVh@ zIOHf;>o0uZwbF6rOzq=NrW~hzc%ApzzvF4Wu%26Vp@UK_RZ6R+N~V zTC8uVpOaXbS`=@XoN$2e-(p6YQw6V7-Fha}SzB9M`1aK$y>(_`A|u86o~nyue*U4+k8@@1xSu}@y1Q9*(s zyXzNQU&ec_GW|=|PHD}Wpi`VB@#$^e?)xnrPh(a|zZL#_=0LEsQs~4-e7CEm8}*kg zIs9kCxy-r2>a*-L({G-6`MGx5`&Pk?u{#T^F08aQT_wca{(Iqmhgr$C-(PzEDBr*9 zMe`pO@4N{f%u;;IU$)Av>)Re5fD+VeetdWx2n=Ed76t}sAeEV$n4TIB3UK|jqQu

1$WZP>kW@) zEI47jL(9yx*XX}q_v?GfDcNZ+Z<=)Gp8q;6AX#bu89mdPQKj3KS*9$#X=%3hl|jsc zi~#mYFMORt@0{7T%j1b}HShMO+9@e7bj9_Y?`JUu&N{pK?aV_9)s@|EdCE?Xp2Q;) zamZ1y)?fI*Yo+7LncBylOgT>b@H+3af78EPps?ta|Ki#e?^NMu+wFn2 z=FY^rsMlMrt(-j9PBZ=HnJ+&LPxn9SxUue@#olKnwx+9unA>wN#4DbS=&!4i`1f|b z<}Zgh-8%{%%u;;MU$)i-*WRsX2tWzzSBCE@M1f(=z{0>F4Wu%26Vp@UK_RZ6R+N~V zTC8uVpOaXbS`=?s8?>>D$&u&peQg%&o5#G?`+>wbfnAOV3Ak>M@znUAuNI{ zJL@BAFSex1tmiQHjElRcGPz&c^_@=d>9YHESKrp%GksfkgE#I&&(k|wbdsBCF||KHm?a)x!d*Ni%X1UqwAmdpR^4N4#uC2KALt@Fy~+7_PU~bH3=%uzohM5 zbw$hm+~4y7kJijgUr-y!ep%+-{nruaE*C0RO<XZ z!0%k&`_T76s@?kA?^)Q^oJkhBIq&D$xb@F3*BQ)J%znC`xyGZ}{N490_P>n({GV{y zZjH1>#P+{}e;(T$ztC4It{D4fs=uOAtkXSQ7@}FKQDLU-MnT4p4Rx( zPo`_TwtQ>)ZF@Atm5pbs)Fcf~o~W;Pp9j3?-=?i2-&bq*oNMX(!<|eb_mA^rlw5Pa zx>Iv(`6?=C&x&DeP5!raGBOoSUGNN7dIA@nl zb9YkkWsS@Eo3_2Pb=#IUEzZ|7r+VG>8Y%Tp-)}Be3toNhnu+@w6YJy4LS@^GMR;F1 z2<^#S(Y5+!So$jYTh%*QU$0himfu+*`74mqCDUyEws5ZYc|CJ7luPH_u|0X9QB_9d z;`b>G_rxvbJfkheRyjtbWl4N`o45OZOUFq~``&LW>(U;qRE!Lr_=xZJSE)w*B~RLZ zCazq*be`4Cm+DV-X3w;{pZ+sWM)3Ag>C4f}Uat(CDq*pv`5)Kip098G{SWW|tLiF$ zVzsq7$EAk0!yVc7|j`V0&&&fMvp{_LK{b+6w7^Jj5{E=``O zWPPswzS_x6|Nl90e2f$M7+yAOnTO4x(n`6bRqy$$7aV2&77{AW|LXo39_4-6w<~LB zJr11q`b@^rZq@R0Yvo>izfl}}{Ix+&MCGeD*S-h7cbfD6b?Lb^8Ar4(P2Y9ySYgfm z0*_thBG{*YB>(D_%5r>Yq&oE9YDMp0-l$tM|^mdsE-aTsvI# z{_E0jECJq(z~qEGk%2-1nC74Wp5)NAp@$eu0|P@AP&c0N3-D%T11V+#!UiCn40H_x F0|0+7I`sem literal 0 HcmV?d00001 diff --git a/src/assets/textures_base/wall.pxo b/src/assets/textures_base/wall.pxo new file mode 100644 index 0000000000000000000000000000000000000000..b95dd5fef28df302f65ae47dfba47ef02905b716 GIT binary patch literal 679 zcmWIWW@Zs#VBp|jI5{OTDyeq$KPN^8hFT^D22KVBhLpsTM7^xy{Jh+Wck`MJcv|CA zKbfxW+VZXGx9w3AS2mulQj;_|r)+t(`+UHQ{%zVi@_n^-&$*VqKRl61Axqx7x(jCaa2)+Qt+6zs&?n%D zWQ@q{S#C3HCoe61Z@9^H^OvkyN47n$@?CB?asPQe)0t7F+m=}-EWK%Iw)U05oCO&H z?2~TzI)}!b-DVZ|_rkryx&iU3lD|&0p1u(2tKhY{a_in8i!Uip9Hdt!7kyV@W}j9N z;Bx;m%ZGg@K6>0bwK0JAkWujA3Hjx>|Ejsnne*v##{5_5Z1bchg^Fsv+Yq~6@Q0IE z-VFI^R=TCHQkMIliZnB>-FN=eUJIpd-R6G!ma+c5tBxEHL!VSH`#{CRElzrDNc zCWM#g2`pjcZGZg5sXxSidwc*&KtGQ7GAkb#zzi%54AMXLMrZI6byvhnnaP14{LiTZl?`G?E$x#1CZGQVriiE>^4DO`DCe?RAigkJ7N z)4E)8W4akX-OY|p_MUK9lG)N@!M2>cpRX6%`|Wh{%+ibEib!-gv3@&C&(WYZ!A~ZQ z-4k{#YHYt>k$u&Y=h6$$Dl^xOFH^Q23$~avJ6*i1L^Ue-;*<>`m!eimUtILRagW>6 z&f@E)Qxi>Re`;T~`2w*s zPYTpI`DeliBG8f&0eu0(cfV=>N5PyWYSrr~ls% zgFm<97nRJLGvi_7&Z;Yy=07sNyI3}Ve*j8=uYI=3AOaZB4lE1|(m*;hH!(dm9u(~Q zX+?>-sm1z+`Zjk9t&xuoaz z_xg6$F$8!s0%IF@8UVVA0hlD90G=YywW0e2rh$Q>5U3lEzXH5j*+7b!fUp5X16{+w F008bB|Lgz& literal 0 HcmV?d00001 diff --git a/src/camera.hpp b/src/camera.hpp new file mode 100644 index 0000000..0f154df --- /dev/null +++ b/src/camera.hpp @@ -0,0 +1,3 @@ +struct Pos { + float x, y; +}; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index ebefc7c..f118e7d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,11 +7,15 @@ #include #include #include +#include #include "adventura.cpp" #include "events.hpp" +#include "renderer.cpp" +#include "appcontext.hpp" using std::pair; +using std::map; constexpr uint32_t windowStartWidth = 1200; constexpr uint32_t windowStartHeight = 800; @@ -20,20 +24,7 @@ void loadWorld(void* appstate, string worldFile); void resetWorld(void* appstate); void loadNextWorld(void* appstate); void playSound(void* appstate, string soundFile); - -struct AppContext { - SDL_Window* window; - SDL_Renderer* renderer; - SDL_Texture* messageTex, *imageTex; - SDL_FRect messageDest; - SDL_AudioDeviceID audioDevice; - Mix_Music* music; - SDL_AppResult app_quit = SDL_APP_CONTINUE; - Player* player; - World* world; - TTF_Font* font; - std::filesystem::path basePath; -}; +void setScale(void* appstate); SDL_AppResult SDL_Fail(){ SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Error %s", SDL_GetError()); @@ -160,11 +151,11 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { loadNextWorld(*appstate); SDL_SetRenderVSync(renderer, -1); // enable vysnc + + setScale(*appstate); SDL_Log("Application started successfully!"); - //start(argc, argv); - return SDL_APP_CONTINUE; } @@ -191,6 +182,10 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event* event) { playSound(appstate, "assets/failure.ogg"); resetWorld(appstate); } + + if (event->type == SDL_EVENT_WINDOW_RESIZED) { + setScale(appstate); + } if (event->type == SDL_EVENT_QUIT) { app->app_quit = SDL_APP_SUCCESS; @@ -198,7 +193,7 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event* event) { return SDL_APP_CONTINUE; } -vector, SDL_Texture*>> textureCache; + SDL_AppResult SDL_AppIterate(void *appstate) { auto* app = (AppContext*)appstate; @@ -210,44 +205,16 @@ SDL_AppResult SDL_AppIterate(void *appstate) { auto blue = (std::sin(time) * 2 + 1) / 2.0 * 255; SDL_SetRenderDrawBlendMode(app->renderer, SDL_BLENDMODE_ADD); SDL_SetRenderDrawColor(app->renderer, red, green, blue, 1); - SDL_SetRenderDrawColor(app->renderer, 0, 0, 0, 20); + SDL_SetRenderDrawColor(app->renderer, 20, 20, 20, 20); SDL_RenderClear(app->renderer); + setCameraPos(appstate); + // Renderer uses the painter's algorithm to make the text appear above the image, we must render the image first. //SDL_RenderTexture(app->renderer, app->imageTex, NULL, NULL); - vector> worldState = render(*(app->world), (*app->player).mapToWorldspace()); - for (int i = 0; i < worldState.size(); i++) { - vector line = worldState.at(i); - SDL_Texture* messageTex; - if (i < textureCache.size() && textureCache.at(i).first == line) { - messageTex = textureCache.at(i).second; - } - else { - if (i < textureCache.size()) { - SDL_DestroyTexture(textureCache.at(i).second); - } - SDL_Surface* surfaceMessage = TTF_RenderText_Solid(app->font, line.data(), line.size(), { 255,255,255 }); - - // make a texture from the surface - messageTex = SDL_CreateTextureFromSurface(app->renderer, surfaceMessage); - - SDL_DestroySurface(surfaceMessage); - while (textureCache.size() <= i) { - textureCache.push_back({{}, nullptr}); - } - textureCache.at(i) = {line, messageTex}; - } - auto messageTexProps = SDL_GetTextureProperties(messageTex); - SDL_FRect text_rect{ - .x = 0, - .y = float(i * SDL_GetNumberProperty(messageTexProps, SDL_PROP_TEXTURE_HEIGHT_NUMBER, 0)*2), - .w = float(SDL_GetNumberProperty(messageTexProps, SDL_PROP_TEXTURE_WIDTH_NUMBER, 0))*2, - .h = float(SDL_GetNumberProperty(messageTexProps, SDL_PROP_TEXTURE_HEIGHT_NUMBER, 0))*2 - }; - - SDL_RenderTexture(app->renderer, messageTex, NULL, &text_rect); - } + renderWorld(appstate); + renderPlayer(appstate); //SDL_RenderTexture(app->renderer, app->messageTex, NULL, &app->messageDest); SDL_RenderPresent(app->renderer); @@ -302,6 +269,7 @@ void loadNextWorld(void* appstate) { int index = std::find(worldFiles.begin(), worldFiles.end(), currentWorld) - worldFiles.begin(); if (index + 1 < worldFiles.size()) { loadWorld(appstate, worldFiles.at(index + 1)); + enteredNextWorld = true; } else { resetWorld(appstate); diff --git a/src/output.hpp b/src/output.hpp index 949c4f4..c68f367 100644 --- a/src/output.hpp +++ b/src/output.hpp @@ -9,6 +9,28 @@ static void jumpBackOneLine() { } +/** + * Renders the current state of the game world and player onto the console. + * It prints the world's blocks with their respective colors and encodings (characters). + * + * @param world Reference to the World object representing the current world. + */ +static vector> renderWorld(World &world) { + vector> canvas = world.getFieldState(); + vector> out; + + for (unsigned int y = 0; y <= world.getMaxY(); y++) { + vector line; + for (unsigned int x = 0; x <= world.getMaxX(); x++) { + if (canvas.size() > y && canvas.at(y).size() > x) { + line.push_back(canvas.at(y).at(x).getEncoding()); + } + else line.push_back(' '); + } + out.push_back(line); + } + return out; +} /** * Renders the current state of the game world and player onto the console. * It prints the world's blocks with their respective colors and encodings (characters). @@ -17,7 +39,7 @@ static void jumpBackOneLine() { * @param world Reference to the World object representing the current world. * @param playerTexture Reference to the current Player texture. */ -static vector> render(World &world, vector> playerTexture) { +static vector> renderPlayer(World &world, vector> playerTexture) { vector> canvas = world.getFieldState(); vector> out; @@ -29,10 +51,6 @@ static vector> render(World &world, vector> playerText line.push_back(playerTexture.at(y).at(x)); //cout << Color::BRIGHT_YELLOW << playerTexture.at(y).at(x); } - else if (canvas.size() > y && canvas.at(y).size() > x) { - line.push_back(canvas.at(y).at(x).getEncoding()); - //cout << canvas.at(y).at(x).getColor() << canvas.at(y).at(x).getEncoding(); - } else line.push_back(' '); } out.push_back(line); diff --git a/src/renderer.cpp b/src/renderer.cpp new file mode 100644 index 0000000..e3d18b8 --- /dev/null +++ b/src/renderer.cpp @@ -0,0 +1,131 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "appcontext.hpp" + +using std::pair; +using std::map; + +float scale = 0; +void setScale(void* appstate) { + auto* app = (AppContext*)appstate; + int width, height, bbwidth, bbheight; + SDL_GetWindowSize(app->window, &width, &height); + SDL_GetWindowSizeInPixels(app->window, &bbwidth, &bbheight); + scale = float(width) / 500; + SDL_Log("Scale: %f", scale); +} + +map> textureCache; +void renderWorld(void* appstate) { + auto* app = (AppContext*)appstate; + + vector> worldState = renderWorld(*(app->world)); + for (int y = 0; y < worldState.size(); y++) { + vector line = worldState.at(y); + for (int x = 0; x < line.size(); x++) { + char blockChar = line.at(x); + SDL_Texture* messageTex; + if (textureCache.contains(blockChar)) { + messageTex = textureCache.at(blockChar).first; + } + else { + SDL_Surface* surface; + Block block = (*app->world).getBlockRegistry().getByEncoding(blockChar); + string texturePath = (app->basePath / "assets/textures/").string() + block.getId().path_ + ".png"; + bool isText = true; + if (std::filesystem::exists(texturePath)) { + isText = false; + // load the SVG + surface = IMG_Load(texturePath.c_str()); + } + else { + std::string_view block_str = string(1, blockChar); + surface = TTF_RenderText_Solid(app->font, block_str.data(), block_str.size(), { 255,255,255 }); + } + // make a texture from the surface + messageTex = SDL_CreateTextureFromSurface(app->renderer, surface); + SDL_SetTextureScaleMode(messageTex, SDL_ScaleMode::SDL_SCALEMODE_NEAREST); + + SDL_DestroySurface(surface); + textureCache.insert({blockChar, {messageTex, isText}}); + } + auto messageTexProps = SDL_GetTextureProperties(messageTex); + SDL_FRect text_rect{ + .x = float(x * 16 * scale)+3 + app->camera.x, + .y = float(y * 16 * scale) + app->camera.y, + .w = float(10 * scale), + .h = float(16 * scale) + }; + SDL_FRect texture_rect{ + .x = float(x * 16 * scale) + app->camera.x, + .y = float(y * 16 * scale) + app->camera.y, + .w = float(16 * scale), + .h = float(16 * scale) + }; + bool isText = textureCache.at(blockChar).second; + + SDL_RenderTexture(app->renderer, messageTex, NULL, isText ? &text_rect : &texture_rect); + } + } +} +map playerTextureCache; +void renderPlayer(void* appstate) { + auto* app = (AppContext*)appstate; + BlockPos playerPos = (*app->player).getPos(); + + string state = "idle"; + if ((*app->player).isFreeFalling()) state = "falling"; + if (!(*app->player).isAlive()) state = "dead"; + SDL_Texture* messageTex; + if (playerTextureCache.contains(state)) { + messageTex = playerTextureCache.at(state); + } + else { + SDL_Surface* surface; + string texturePath = (app->basePath / "assets/textures/").string() + "player_"+ state + ".png"; + if (std::filesystem::exists(texturePath)) { + // load the SVG + surface = IMG_Load(texturePath.c_str()); + } + // make a texture from the surface + messageTex = SDL_CreateTextureFromSurface(app->renderer, surface); + SDL_SetTextureScaleMode(messageTex, SDL_ScaleMode::SDL_SCALEMODE_NEAREST); + + SDL_DestroySurface(surface); + playerTextureCache.insert({state, messageTex}); + } + auto messageTexProps = SDL_GetTextureProperties(messageTex); + SDL_FRect text_rect{ + .x = float((playerPos.getX()-0.5) * 16 * scale) + app->camera.x, + .y = float(playerPos.getY() * 16 * scale) + app->camera.y, + .w = float(32 * scale), + .h = float(32 * scale) + }; + + SDL_RenderTexture(app->renderer, messageTex, NULL, &text_rect); +} + +bool enteredNextWorld = false; +auto smoothStartTime = 0; +int targetCameraX = 0; +void setCameraPos(void* appstate) { + auto* app = (AppContext*)appstate; + auto time = SDL_GetTicks() / 100000.f; + + int lastCameraX = app->camera.x; + targetCameraX = -(std::max(0, app->player->getPos().getX() - 5)) * 16 * scale; + if (!enteredNextWorld) { + if (lastCameraX != app->camera.x) smoothStartTime = time; + app->camera.x = lastCameraX + (targetCameraX - lastCameraX) * std::min(1.0f, (time - smoothStartTime) * 0.25f); + } + else { + app->camera.x = targetCameraX; + enteredNextWorld = false; + } +} \ No newline at end of file diff --git a/worlds/4.txt b/worlds/4.txt index 6735422..ee8ac62 100644 --- a/worlds/4.txt +++ b/worlds/4.txt @@ -3,7 +3,7 @@ Welt 4: In der Klemme S - --- + -0- 0 0 x x 0 ------------- diff --git a/worlds/5.txt b/worlds/5.txt index 66c9a6b..a4f34a1 100644 --- a/worlds/5.txt +++ b/worlds/5.txt @@ -4,7 +4,7 @@ Welt 5: Die Beachparty 0***************0 0 0 x -------^^^^^^^^^^^^^^^^^^^------------ - H ---------------- + H -0-------------- H H H 0 H S H 0 H