From f3a5647e5b06047b371ec025b83b16dc420a38ea Mon Sep 17 00:00:00 2001 From: ScriptSorcerer20 Date: Sat, 4 Jul 2026 23:50:07 +0200 Subject: [PATCH] To much gap between last commit Im now working next on shoorting for turret Added new sand map and new cannon tower images aswell as function to play animations, showing range, placing turrets on allowed tiles for towers Buy and cancel button to buy towers --- assets/images/entities/enemies/enemy.png | Bin 0 -> 214 bytes .../entities/towers/cannon/red_cannon.png | Bin 0 -> 219 bytes .../images/entities/towers/cannon/shoot/0.png | Bin 0 -> 226 bytes .../images/entities/towers/cannon/shoot/1.png | Bin 0 -> 247 bytes .../images/entities/towers/cannon/shoot/2.png | Bin 0 -> 232 bytes .../images/entities/towers/cannon/shoot/3.png | Bin 0 -> 218 bytes .../images/entities/towers/cannon/shoot/4.png | Bin 0 -> 220 bytes .../images/entities/towers/cannon/shoot/5.png | Bin 0 -> 247 bytes .../images/entities/towers/cannon/shoot/6.png | Bin 0 -> 237 bytes .../images/entities/towers/cannon/shoot/7.png | Bin 0 -> 202 bytes .../images/entities/towers/cannon/shoot/8.png | Bin 0 -> 222 bytes assets/images/tiles/desert/0.png | Bin 0 -> 99 bytes assets/images/tiles/desert/1.png | Bin 0 -> 170 bytes assets/images/tiles/desert/10.png | Bin 0 -> 160 bytes assets/images/tiles/desert/11.png | Bin 0 -> 160 bytes assets/images/tiles/desert/12.png | Bin 0 -> 225 bytes assets/images/tiles/desert/13.png | Bin 0 -> 231 bytes assets/images/tiles/desert/14.png | Bin 0 -> 228 bytes assets/images/tiles/desert/15.png | Bin 0 -> 236 bytes assets/images/tiles/desert/16.png | Bin 0 -> 99 bytes assets/images/tiles/desert/17.png | Bin 0 -> 165 bytes assets/images/tiles/desert/18.png | Bin 0 -> 169 bytes assets/images/tiles/desert/2.png | Bin 0 -> 242 bytes assets/images/tiles/desert/3.png | Bin 0 -> 168 bytes assets/images/tiles/desert/4.png | Bin 0 -> 243 bytes assets/images/tiles/desert/5.png | Bin 0 -> 155 bytes assets/images/tiles/desert/6.png | Bin 0 -> 167 bytes assets/images/tiles/desert/7.png | Bin 0 -> 142 bytes assets/images/tiles/desert/8.png | Bin 0 -> 159 bytes assets/images/tiles/desert/9.png | Bin 0 -> 152 bytes assets/maps/desert.json | 1 + editor.py | 5 +- game/camera.py | 15 ++- game/enemy.py | 21 +++- game/game.py | 13 +- game/screens/game_play.py | 113 +++++++++++++++++- game/screens/main_menu.py | 1 - game/tilemap.py | 13 ++ game/tower.py | 62 ++++++++++ game/util.py | 28 +++++ 40 files changed, 248 insertions(+), 24 deletions(-) create mode 100644 assets/images/entities/enemies/enemy.png create mode 100644 assets/images/entities/towers/cannon/red_cannon.png create mode 100644 assets/images/entities/towers/cannon/shoot/0.png create mode 100644 assets/images/entities/towers/cannon/shoot/1.png create mode 100644 assets/images/entities/towers/cannon/shoot/2.png create mode 100644 assets/images/entities/towers/cannon/shoot/3.png create mode 100644 assets/images/entities/towers/cannon/shoot/4.png create mode 100644 assets/images/entities/towers/cannon/shoot/5.png create mode 100644 assets/images/entities/towers/cannon/shoot/6.png create mode 100644 assets/images/entities/towers/cannon/shoot/7.png create mode 100644 assets/images/entities/towers/cannon/shoot/8.png create mode 100644 assets/images/tiles/desert/0.png create mode 100644 assets/images/tiles/desert/1.png create mode 100644 assets/images/tiles/desert/10.png create mode 100644 assets/images/tiles/desert/11.png create mode 100644 assets/images/tiles/desert/12.png create mode 100644 assets/images/tiles/desert/13.png create mode 100644 assets/images/tiles/desert/14.png create mode 100644 assets/images/tiles/desert/15.png create mode 100644 assets/images/tiles/desert/16.png create mode 100644 assets/images/tiles/desert/17.png create mode 100644 assets/images/tiles/desert/18.png create mode 100644 assets/images/tiles/desert/2.png create mode 100644 assets/images/tiles/desert/3.png create mode 100644 assets/images/tiles/desert/4.png create mode 100644 assets/images/tiles/desert/5.png create mode 100644 assets/images/tiles/desert/6.png create mode 100644 assets/images/tiles/desert/7.png create mode 100644 assets/images/tiles/desert/8.png create mode 100644 assets/images/tiles/desert/9.png create mode 100644 assets/maps/desert.json create mode 100644 game/tower.py diff --git a/assets/images/entities/enemies/enemy.png b/assets/images/entities/enemies/enemy.png new file mode 100644 index 0000000000000000000000000000000000000000..888b03f52c925413c3ece49af2736032fccec854 GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|CV09yhFJ6_ zrz9l&IPbuiu*k(Ylqcb!+K+c1bl8BP?Rxon0}$xYnhmCFVy+)vaHGE4M*PF8^NBY; zgiLw(UENru(Cv#u%S}FJr)`-$An=|0s>C_DCy5-E<$U|a6VADr3#18HEyz>YXKllM zm~}_avRT|6d@hT46Anz~+aT#yt3QE@&CZyS!RLkED`o!G=|HzJc)I$ztaD0e0svM~ BNC5x< literal 0 HcmV?d00001 diff --git a/assets/images/entities/towers/cannon/red_cannon.png b/assets/images/entities/towers/cannon/red_cannon.png new file mode 100644 index 0000000000000000000000000000000000000000..c5ef0fbbaa7d8c9cfa759325fe1d64f0b91e77f2 GIT binary patch literal 219 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|rh2+KhFJ6_ zrz9l&IN!j0hsQrH0SE%(Eybq`v8lxfW%u-K*wks(5Yce8!PL!-XVf_>{&Df)$9 zIL7LHhv5rD3u6pp=WW(!-xX#sBph7%bBU1S*@)N$(ue)Gr13E4eX}%*iTgD1;itEs zCAcbP0l+XkK-SFJ5M=_2i*b0CXBSy{Px(H_G&>oxLwE{kp{ zJSbq!V9Sum5bp4((NRp=Tg6yelF{r5}E)$PhboH literal 0 HcmV?d00001 diff --git a/assets/images/entities/towers/cannon/shoot/2.png b/assets/images/entities/towers/cannon/shoot/2.png new file mode 100644 index 0000000000000000000000000000000000000000..08f55e469fe755c75a9b046ab7e53a3c22c5b7e0 GIT binary patch literal 232 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|7J0fjhFJ6_ zrz9l&IN!jmp*h0<1nyK9uuT_YQ;QMm>FJ5M=_2i*b0CXBSy{Px(H_G&>oxLwE{kp{ zJSbq!V9Sum5bp4(!T!-dBcRXn6?MKt$Q2ib4YbuZkRoNhQv9!CyE&i=Q2XB|8@^C zN_08LeWLELSg%2Y%-o(EM#9@(I9>0!&LDB(%&DXVAedp7D^(b$z|O!hMPIo#EzwX4 P=t2fhS3j3^P6Px#u}MThR5*>Ll06E-KoCaX1ntBtgj9Amf!xDmm;=SrSl9|_?5xBqY#VT`5;nUt z*`Nap%Pim9Z+-;u{1JuqFt}zl#K&iFO>z%&;SsBZ*ui#xSARDFA~Lt>^;T^xaaGo{ z-0R(|kfe#47@#Wa#8m>Y#7mF~kP}-Fa}NNnCzl19fajy2zwNRBbqWB7<0oej;ynm! x)5bVPI8Jquv~k74MZg&6wguqQb?Zv_CBDo^K=HfM5+48n002ovPDHLkV1gcmWj_D_ literal 0 HcmV?d00001 diff --git a/assets/images/entities/towers/cannon/shoot/6.png b/assets/images/entities/towers/cannon/shoot/6.png new file mode 100644 index 0000000000000000000000000000000000000000..e1e9ba0fcf1853755b8726effaafe2b966692d20 GIT binary patch literal 237 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|mV3H5hFJ8T zon**$$U(sMKFix9+ASevW{r0aC(mF$dO6|-SLT~FN3?UK3)YI=d9wapS)GKKopt>` zp8E{vc_zPpCc^OgZRjVv(8;eCg-_LFXGjzC|M*FIbx3jWcERrzeL+i3WwK?wDtqX~ zHRaKHmZ0D4E39iu3+#3nvCrReU+dWEXUiMTFdoSJf6D5jQfH#OsEUhH>Xgugkm4YP l2RFVm%xP1sZw=bR=<8s0aJBKJML;Jrc)I$ztaD0e0suwJUr_)6 literal 0 HcmV?d00001 diff --git a/assets/images/entities/towers/cannon/shoot/7.png b/assets/images/entities/towers/cannon/shoot/7.png new file mode 100644 index 0000000000000000000000000000000000000000..b1f1bbcfbf4890f2b98bf7d67dbd8376366c61c9 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|T0C7GLo9l) zPV(k$Fc5ILpR}ZbrAsrQk!wN|XI5kXq@t#lWzkg+56t;>)90R_8${hZ_dHIX9?>}l^N~NraBx_%VJ@;{qV!T$UFH? zclf4%b<1HDy37ADwAnlMKC?mZVzWtRCoXc%-Yrv+!Y)`3bPt24tDnm{r-UW|#(7J0 literal 0 HcmV?d00001 diff --git a/assets/images/entities/towers/cannon/shoot/8.png b/assets/images/entities/towers/cannon/shoot/8.png new file mode 100644 index 0000000000000000000000000000000000000000..4def5bd3edc2061a0b4277109b8a9056183b2121 GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|W_Y?dhFJ7o zoxEGH*+9VMzTvxOe@+Kskw*tY7HTP!NSY)HTN^DC66}<0;d^qR(R|Xgyz*~l?^rfy zXl#;d`2Kw1)(IJ`f}HynvnC0O2nc@K67|0_YNcM?;|J$i|1ijIQ3z#k)|B+AeDz?_ zL}}xBlbZSBzGs_AI{b+)DE?*X^I4c7d;9Xu!VeO@*KX2!P>>zX@M~SS{KIISptbTg ULDouFfo^2*boFyt=akR{0KI%s>;M1& literal 0 HcmV?d00001 diff --git a/assets/images/tiles/desert/0.png b/assets/images/tiles/desert/0.png new file mode 100644 index 0000000000000000000000000000000000000000..c6abb51257107faeae39a1ab92800e1606be3310 GIT binary patch literal 99 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|WIbIRLo9le v_v}^qY0u2s&?$6wFKwako17ay1hRLJ1z>gTe~DWM4fVJsTn literal 0 HcmV?d00001 diff --git a/assets/images/tiles/desert/1.png b/assets/images/tiles/desert/1.png new file mode 100644 index 0000000000000000000000000000000000000000..17889a082f599594ecf96092719de039034f5719 GIT binary patch literal 170 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|QaoK8Lo9le z_v}^qY0u2s&?$6wF`IxvL-6^z8q5(JIB&)8K6{|xtr;^A9Cp+Vy%fW+dFJb5@rz=b z5)XX$ww9Ctf_<3=i$4@Hu8Ff)vGmk|mCyYGjKjni>~6_n?qEH9fPvwKgZQz(6-(@Z P_Az+6`njxgN@xNA5f3`s literal 0 HcmV?d00001 diff --git a/assets/images/tiles/desert/10.png b/assets/images/tiles/desert/10.png new file mode 100644 index 0000000000000000000000000000000000000000..376608b0436bb4b60e8dd09e814beac0c42b9e9b GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|qC8z3Lo9le z_v}^qY0u2s&?$5_#IS+&*n=y@?h}91WvU0V8QAUI(zU|iK&ryUIEQk@lWY%|R3sbD zihk*LD+!;F!%&sOQ{%PdPQ&}@WkPdvBtNh!ZERbxnwjC;CaKixulM8wZDH_q^>bP0 Hl+XkK5Rf;n literal 0 HcmV?d00001 diff --git a/assets/images/tiles/desert/11.png b/assets/images/tiles/desert/11.png new file mode 100644 index 0000000000000000000000000000000000000000..e05f6fff209bbf0c82d2d648630ceeedc05fe974 GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|qC8z3Lo9le z_v}^qY0nG<%ja1$Yd-kBbS@7F_`G0RlHq395Yv#vuyLKkH@%~J35wy$XGDE&uy`_F z;XRU=z@WKuVwT5k$le;`rVR?OTqENG0SnrF5*2c!hhgaDnHNKn2DEa@Fay(nW+!5HpeL+vmZ33eX4-h0V z^-D?s!Myru2|wyG)w`ISHXb?zGH2?Wg9jR>2u)<%)%c>#h_51#h2bEd`jbD5hnE7K O$>8bg=d#Wzp$PzU9Z`$` literal 0 HcmV?d00001 diff --git a/assets/images/tiles/desert/13.png b/assets/images/tiles/desert/13.png new file mode 100644 index 0000000000000000000000000000000000000000..8207dd2e8ca01d3aa4641e45f068d907b26677a5 GIT binary patch literal 231 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|7J9lkhFJ6_ z@7b&J)1H~Np;PE=h+zY3>;v9@wy;*E_&fnK5cBZa?CTq&moDwRD!?QDfZ1I>vCZ6* z?M}@PNoSsHg?CmTJ2ISC%5(DoL7rGqgy`zipC6e!JUPwF#-{7LW>&L*uG%?PplJp& zwO`~_4FVdQ&MBb@04h^ZsQ>@~ literal 0 HcmV?d00001 diff --git a/assets/images/tiles/desert/14.png b/assets/images/tiles/desert/14.png new file mode 100644 index 0000000000000000000000000000000000000000..687f30649db4ab9addc7d524d63428aad5892344 GIT binary patch literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|=6Sj}hFJ6_ z@7b&J)1Da!md~?h)_m}L>0BNV@OiRRh5w2ai71*@upQmoxI2*S^Za z{N!9mmhPxytht{5Kkk~zkg)UT2V>P=hKC#8v29p!`g2g4!`1255vp}7YZDT7t2$g@ zm=mY4>czUJA5|#`o`I7mUbp_oWAHjBXPyL z*4rmvG(3HF_`HauLy5vWtB)N<%ms{MrIm4uM0Q1f1bKwTJjNt37oUjf*3CAZ{_FNf5pxK2qvtV*$4!!GQJvm g4$lt6I01dLMoEuh2HQ<5pobP0l+XkKSF;+3 literal 0 HcmV?d00001 diff --git a/assets/images/tiles/desert/17.png b/assets/images/tiles/desert/17.png new file mode 100644 index 0000000000000000000000000000000000000000..8cd09f5ddd5130920dee4e2661001074f25685ef GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|;yqm)Lo9le z_v}^qY0oV8;lU$eo{c_hUly1N+nwbB0F(U2mZaGLu>8w0~T4TWjbxm9?9Rxx5Xl${N$8a*_)IHepma(6H?7zc|s@5m|; Q0$Ru5>FVdQ&MBb@0NZCZWdHyG literal 0 HcmV?d00001 diff --git a/assets/images/tiles/desert/2.png b/assets/images/tiles/desert/2.png new file mode 100644 index 0000000000000000000000000000000000000000..3b8259643748e150e1f5cbda61e605186e5ef6aa GIT binary patch literal 242 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|)_A%&hFJ6_ z@7b&J)1F!E!-Ge{Ifn`+tTdh52m*rB8F_%<^0RvhAW-r3p?>oW2IDYOpGj5I3i_7J zQ)M=qFL9v7S9zBrr`{h4srcF--3AQO3fELEcokR@5}md&vc!J)bE)tY&jB&E4GqZ( zY66|CDwT|uhJrjUPH_q^m~t4Ri_)4bMem+G@rSkA?okOV_ok$zMSOQfb$*Cc&-{=e f+Mb%q1_TV9$rj1BQ+bvG-Ob?X>gTe~DWM4f9RN|? literal 0 HcmV?d00001 diff --git a/assets/images/tiles/desert/3.png b/assets/images/tiles/desert/3.png new file mode 100644 index 0000000000000000000000000000000000000000..5a285a6e0040419c0b19ed717dc2dafff6e46a3a GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|l001;Lo9le zLuS^$w`XQ;*m&XMEG6a{akW3X!w;_Jub2F=GV#z-PPQW~Gd}Ka*r064>$r_!HDgPT z>P^-kItfZg%_hY<`0z}8%DO1lq33&nl*5Ui2HY91S-W@?%&H_c&z@s=l`rqLPqt$@ P&^887S3j3^P6;hZ_g~^vwzyj240O9rxQfe6M#UcWXr#P-$z&5_wyt%o#BZ*DP>`5Yybogr?xWr z*_N{bv4|bdh6k6XJUDcI!`n0BJk1wwvcxv5;gmjL@BpZ<<;;^g4T+09e literal 0 HcmV?d00001 diff --git a/assets/images/tiles/desert/5.png b/assets/images/tiles/desert/5.png new file mode 100644 index 0000000000000000000000000000000000000000..a115c976046ce095289833f02cfbf91b1aab34b8 GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~q!3HGX7W?Z1DaPU;cPEB*=VV?2Iia2|jv*Qo zllSaZ`Dwp=o;5QN9RBWYEt!xbF<&5|rYQ4jebcH95*(X5S|iS$m^Fb>Sd%S*c`;j$ zl!GX9gv5kP7W;ZybR~@qfZ$%-B%hMBLu?Fn;u8C3H^}`1TEO7x>gTe~DWM4fvu7_R literal 0 HcmV?d00001 diff --git a/assets/images/tiles/desert/6.png b/assets/images/tiles/desert/6.png new file mode 100644 index 0000000000000000000000000000000000000000..b24ae330fdde9e52be1ba1143cf1aaf58010016a GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|5A0Q0{1Tb${}6IV&f8rbdJ^2%QDRl%;N&IMjJvrd{Z+}xca*}%hg zjG^mrLy~wv3d5$)o@NZO#-3~mm(Lsk0;hFuYuE&Wdag1QnJ6+d%;Qw}{6|i88_+Ta MPgg&ebxsLQ086Dew*UYD literal 0 HcmV?d00001 diff --git a/assets/images/tiles/desert/7.png b/assets/images/tiles/desert/7.png new file mode 100644 index 0000000000000000000000000000000000000000..a8265b96cb3dcb52627fb68d5878349192c9eadc GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|JUm?-Lo9le z_v}^qY0oTD@M@>A0QbK5TPF{IfXfy>omqiA3P;OQwx;Z4knE9SFm0G3v7n3F;1c5| lhS->fs|-OghG&A57|INV7-xOT{0=me!PC{xWt~$(696twEj9oE literal 0 HcmV?d00001 diff --git a/assets/images/tiles/desert/8.png b/assets/images/tiles/desert/8.png new file mode 100644 index 0000000000000000000000000000000000000000..b188b4c7f86709c8a9663ec8292b0b4ab120816b GIT binary patch literal 159 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|B0XIkLo9le z_v}^qY0u2s&?$752MBapL<(N*T>N2w{4LKL3?;rVicYj`Sl}(hJmIQgqOb~UfJ{dL z^9APie|ienMX!`H9%Y*#Jax-??i~y|2Tm3-7UeK9lr9r(|F3Fh1hj;~)78&qol`;+ E08gnieE= len(self.waypoints): return tile_size = self.game.tilemap.tile_size - target = pg.Vector2( + self.target = pg.Vector2( tile_to_pixel( self.waypoints[self.target_index], tile_size, @@ -36,16 +41,22 @@ class Enemy(pg.sprite.Group): ) ) - direction = target - self.pos + direction = self.target - self.pos distance = direction.length() if distance <= self.speed: - self.pos = target + self.pos = self.target self.target_index += 1 else: direction = direction.normalize() self.pos += direction * self.speed + def rotate(self): + dist = self.target - self.pos + + self.angle = math.degrees(math.atan2(-dist[1], dist[0])) + self.image = pg.transform.rotate(self.game.assets['enemy'].copy(), self.angle) + self.rect = self.image.get_rect() self.rect.center = self.pos def render(self, surf, camera): diff --git a/game/game.py b/game/game.py index 24a07da..dade825 100644 --- a/game/game.py +++ b/game/game.py @@ -23,18 +23,15 @@ class Game: "assets/theme/theme.json" ) self.tilemap = Tilemap(self) - self.map = 'test' - self.path = 'assets/maps/' + str(self.map) + '.json' - try: - self.tilemap.load(self.path) - except FileNotFoundError: - print('File not Found') - print(self.tilemap.waypoints) self.assets={ "base": load_images('/tiles/test'), "jungle": load_images('/tiles/jungle'), - "enemy": load_image('/entities/enemies/sand_monster.png') + "desert": load_images('/tiles/desert'), + "enemy": load_image('/entities/enemies/enemy.png'), + "cannon": load_image('/entities/towers/cannon/shoot/0.png'), + "red_cannon": load_image('/entities/towers/cannon/red_cannon.png'), + "cannon/shoot": Animation(load_images('/entities/towers/cannon/shoot'), 10, False) } self.screens = { diff --git a/game/screens/game_play.py b/game/screens/game_play.py index f40085c..a4162d5 100644 --- a/game/screens/game_play.py +++ b/game/screens/game_play.py @@ -1,6 +1,7 @@ from game.screens.base_screen import BaseScreen from game.enemy import Enemy from game.camera import Camera +from game.tower import Tower, TowerGroup from game.util import * import pygame as pg import pygame_gui as pgi @@ -15,19 +16,99 @@ class GamePlay(BaseScreen): # self.map_surface = pg.surface.Surface((self.game_surface.get_width()/self.tile_multiplicator,self.game_surface.get_height()/self.tile_multiplicator)) self.camera = Camera() + self.center = (self.game_surface.get_width() /2, self.game_surface.get_height() /2) self.movment = [False, False, False, False] + self.selected = None + self.notunselect = True - self.map = 'test' + self.map = 'desert' self.path = 'assets/maps/' + str(self.map) + '.json' - self.enemy = Enemy(self.game, 0.5, 100) - try: self.game.tilemap.load(self.path) except FileNotFoundError: print('File not Found') + self.enemy_group = pg.sprite.Group() + self.tower_group = TowerGroup() + + self.enemy = Enemy(self.game, 0.5, 100) + + self.buy_button = pgi.elements.UIButton( + relative_rect=pg.Rect( + self.width - 200, + self.height -250, + 150, + 50 + ), + + text="Buy Tower", + manager=self.game.ui_manager + ) + self.cancel_button = pgi.elements.UIButton( + relative_rect=pg.Rect( + self.width - 200, + self.height -175, + 150, + 50 + ), + + text="Cancel", + manager=self.game.ui_manager + ) + self.buy_button.hide() + self.cancel_button.hide() + self.bought = False + self.elements = [ + self.buy_button, + self.cancel_button + ] + def process_event(self, event): + #calculate tile position from mouse position + self.mpos = pg.mouse.get_pos() + game_rect = self.game_surface.get_rect(topleft=(0, self.height / 6)) + + if game_rect.collidepoint(self.mpos): + local_mpos = ( + self.mpos[0] - game_rect.x, + self.mpos[1] - game_rect.y + ) + + world_pos = self.camera.screen_to_world(local_mpos) + self.tile_pos_decimal = pixel_to_tile(world_pos, self.game.tilemap.tile_size) + self.tile_pos = (int(self.tile_pos_decimal[0]), int(self.tile_pos_decimal[1])) + else: + self.tile_pos = None + + if event.type == pgi.UI_BUTTON_PRESSED: + if event.ui_element == self.buy_button: + self.bought = True + # self.tower = Tower(self.game, self.mpos, self.tile_pos, 'cannon') + if event.ui_element == self.cancel_button: + self.bought = False + + self.tile_pos = (int(self.tile_pos_decimal[0]), int(self.tile_pos_decimal[1])) + if event.type == pg.MOUSEBUTTONDOWN: + if self.tile_pos is not None: + if event.button == 1: + self.selected = self.select_turret(self.tile_pos) + self.clear_selection() + if self.selected is not None: + print(f'selected: {self.selected}') + self.selected.selected = True + print(f'{self.selected}') + if self.bought: + if self.game.tilemap.placeable(self.tile_pos): + if not any(tower.tile_pos == self.tile_pos for tower in self.tower_group): + tower = Tower(self.game, self.mpos, self.tile_pos, 'cannon', 40) + self.tower_group.add(tower) + self.bought = False + if event.button == 3: + for tower in self.tower_group: + if tower.tile_pos == self.tile_pos: + tower.kill() + if event.type == pg.KEYDOWN: if event.key == pg.K_a: self.movment[0] = True @@ -39,9 +120,9 @@ class GamePlay(BaseScreen): self.movment[3] = True if event.key == pg.K_q: - self.camera.change_zoom(-0.25) + self.camera.zoom_offset(self.center, -0.25) if event.key == pg.K_e: - self.camera.change_zoom(0.25) + self.camera.zoom_offset(self.center ,0.25) if event.type == pg.KEYUP: if event.key == pg.K_a: self.movment[0] = False @@ -54,6 +135,7 @@ class GamePlay(BaseScreen): def update(self, dt): self.enemy.update() + self.tower_group.update("sigma") self.camera.move((self.movment[1] - self.movment[0]) * 2, (self.movment[3] - self.movment[2]) * 2) @@ -64,7 +146,26 @@ class GamePlay(BaseScreen): self.game.tilemap.render_game(self.game_surface, self.camera) self.enemy.render(self.game_surface, self.camera) + self.tower_group.render(self.game_surface, self.camera) + + if self.bought: + if self.game.tilemap.placeable(self.tile_pos): + self.game_surface.blit(pg.transform.scale2x(self.game.assets["cannon"]), (self.mpos[0] - (self.game.tilemap.tile_size //2), self.mpos[1] - (self.game.tilemap.tile_size //2 + self.height/6))) + else: + self.game_surface.blit(pg.transform.scale2x(self.game.assets["red_cannon"]), (self.mpos[0] - (self.game.tilemap.tile_size //2), self.mpos[1] - (self.game.tilemap.tile_size //2 + self.height/6))) # self.game_surface.blit(pg.transform.scale(self.map_surface, self.game_surface.get_size())) - + surface.blit(self.game_surface, (0, self.height/6)) + + # if self.bought: + # self.game_surface.blit(pg.transform.scale2x(self.game.assets["cannon"]), (self.mpos[0] - (self.game.tilemap.tile_size //2), self.mpos[1] - (self.game.tilemap.tile_size //2))) + + def select_turret(self, tile_pos): + for tower in self.tower_group: + if (tile_pos[0], tile_pos[1]) == (tower.tile_pos[0], tower.tile_pos[1]): + return tower + + def clear_selection(self): + for tower in self.tower_group: + tower.selected = False \ No newline at end of file diff --git a/game/screens/main_menu.py b/game/screens/main_menu.py index 2831a04..ca36441 100644 --- a/game/screens/main_menu.py +++ b/game/screens/main_menu.py @@ -70,7 +70,6 @@ class MainMenu(BaseScreen): if event.type == pgi.UI_BUTTON_PRESSED: if event.ui_element == self.play_button: - # Zum Gameplay wechseln self.game.change_screen("game") diff --git a/game/tilemap.py b/game/tilemap.py index 59e510b..e1bd591 100644 --- a/game/tilemap.py +++ b/game/tilemap.py @@ -13,6 +13,8 @@ class Tilemap: self.offgrid_tiles = [] self.waypoints=[] + self.tower_placeable = [{"type": "desert", "variant": 0}] + def save(self, path): f = open(path, 'w') json.dump({'tilemap': self.tilemap, 'tile_size': self.tile_size, 'waypoints': self.waypoints}, f) @@ -27,6 +29,17 @@ class Tilemap: self.tile_size = map_data['tile_size'] self.waypoints = map_data['waypoints'] + def placeable(self, tile_pos): + str_tile_pos = f'{tile_pos[0]};{tile_pos[1]}' + if str_tile_pos not in self.tilemap: + return False + + tile = self.tilemap[str_tile_pos] + for ti in self.tower_placeable: + if tile['type'] == ti['type'] and tile['variant'] == ti['variant']: + return True + return False + def render(self, surf, offset=(0, 0)): for x in range(offset[0] // self.tile_size, (offset[0] + surf.get_width()) // self.tile_size + 1): for y in range(offset[1] // self.tile_size, (offset[1] + surf.get_height()) // self.tile_size + 1): diff --git a/game/tower.py b/game/tower.py new file mode 100644 index 0000000..3683740 --- /dev/null +++ b/game/tower.py @@ -0,0 +1,62 @@ +import pygame as pg +from game.util import * + +class Tower(pg.sprite.Sprite): + def __init__(self, game, pos, tile_pos, type, range, level=1): + super().__init__() + self.game = game + self.type = type + self.image = self.game.assets[type] + self.rect = self.image.get_rect() + self.rect.center = pos + + self.range = range + self.selected = False + + self.pos = pos + self.tile_pos = tile_pos + self.level = level + self.action = "" + self.set_action('shoot') + + def update(self, enemies): + self.animation.update() + + def set_action(self, action): + if action != self.action: + self.action = action + self.animation = self.game.assets[self.type + '/' + self.action].copy() + + def render(self, surf, camera): + screen_pos = camera.world_to_screen(pg.Vector2( + tile_to_pixel(self.tile_pos, self.game.tilemap.tile_size, True) + )) + + anim_img = self.animation.img() + scaled_image = pg.transform.scale( + anim_img, + ( + int(anim_img.get_width() * camera.zoom), + int(anim_img.get_height() * camera.zoom) + ) + ) + + rect = scaled_image.get_rect(center=screen_pos) + + if self.selected: + scaled_range = int(self.range * camera.zoom) + range_surf = pg.Surface((scaled_range * 2, scaled_range * 2), pg.SRCALPHA) + pg.draw.circle(range_surf, (200, 200, 200, 100), (scaled_range, scaled_range), scaled_range) + range_rect = range_surf.get_rect(center=screen_pos) + surf.blit(range_surf, range_rect) + + surf.blit(scaled_image, rect) + +class TowerGroup(pg.sprite.Group): + def render(self, surf, camera): + for tower in self.sprites(): + tower.render(surf, camera) + + def update(self, enemies): + for tower in self.sprites(): + tower.update(enemies) \ No newline at end of file diff --git a/game/util.py b/game/util.py index 73ce868..3c750f8 100644 --- a/game/util.py +++ b/game/util.py @@ -26,3 +26,31 @@ def tile_to_pixel(waypoint, tile_size, center=False): waypoint[0] * tile_size, waypoint[1] * tile_size ) + +def pixel_to_tile(waypoint, tile_size): + return ( + waypoint[0] / tile_size, + waypoint[1] / tile_size + ) + +class Animation: + def __init__(self, images, img_dur=5, loop=True): + self.images = images + self.loop = loop + self.img_duration = img_dur + self.done = False + self.frame = 0 + + def copy(self): + return Animation(self.images, self.img_duration, self.loop) + + def update(self): + if self.loop: + self.frame = (self.frame + 1) % (self.img_duration * len(self.images)) + else: + self.frame = min(self.frame + 1, self.img_duration * len(self.images)) + if self.frame >= self.img_duration * len(self.images) - 1: + self.done = True + + def img(self): + return self.images[int(self.frame / self.img_duration) - 1] \ No newline at end of file