From 54e2b8dcc275ac77efce220719d2b68d3d8328f7 Mon Sep 17 00:00:00 2001 From: Loxnebot Date: Tue, 24 Feb 2026 23:18:24 +0200 Subject: [PATCH] deleted useless images, updated useful ones, new hud --- images/GoblinWorker/spritePics/19.png | Bin 516 -> 0 bytes images/GoblinWorker/spritePics/21.png | Bin 567 -> 0 bytes images/GoblinWorker/spritePics/22.png | Bin 561 -> 0 bytes images/GoblinWorker/spritePics/23.png | Bin 639 -> 0 bytes images/GoblinWorker/spritePics/24.png | Bin 583 -> 0 bytes images/GoblinWorker/spritePics/25.png | Bin 570 -> 0 bytes images/GoblinWorker/spritePics/26.png | Bin 462 -> 0 bytes images/GoblinWorker/spritePics/27.png | Bin 516 -> 0 bytes images/GoblinWorker/spritePics/29.png | Bin 492 -> 0 bytes images/GoblinWorker/spritePics/30.png | Bin 217 -> 0 bytes images/GoblinWorker/spritePics/32.png | Bin 454 -> 0 bytes .../spritePics/{07.png => Jump.png} | Bin .../spritePics/{36.png => death1.png} | Bin .../spritePics/{35.png => death2.png} | Bin .../spritePics/{34.png => death3.png} | Bin .../spritePics/{28.png => death4.png} | Bin .../spritePics/{33.png => hurt1.png} | Bin .../spritePics/{31.png => hurt2.png} | Bin .../spritePics/{16.png => walkleft.png} | Bin .../spritePics/{08.png => walkright.png} | Bin images/walk.png | Bin 754 -> 0 bytes main.py | 173 ++++++++++++------ 22 files changed, 117 insertions(+), 56 deletions(-) delete mode 100644 images/GoblinWorker/spritePics/19.png delete mode 100644 images/GoblinWorker/spritePics/21.png delete mode 100644 images/GoblinWorker/spritePics/22.png delete mode 100644 images/GoblinWorker/spritePics/23.png delete mode 100644 images/GoblinWorker/spritePics/24.png delete mode 100644 images/GoblinWorker/spritePics/25.png delete mode 100644 images/GoblinWorker/spritePics/26.png delete mode 100644 images/GoblinWorker/spritePics/27.png delete mode 100644 images/GoblinWorker/spritePics/29.png delete mode 100644 images/GoblinWorker/spritePics/30.png delete mode 100644 images/GoblinWorker/spritePics/32.png rename images/GoblinWorker/spritePics/{07.png => Jump.png} (100%) rename images/GoblinWorker/spritePics/{36.png => death1.png} (100%) rename images/GoblinWorker/spritePics/{35.png => death2.png} (100%) rename images/GoblinWorker/spritePics/{34.png => death3.png} (100%) rename images/GoblinWorker/spritePics/{28.png => death4.png} (100%) rename images/GoblinWorker/spritePics/{33.png => hurt1.png} (100%) rename images/GoblinWorker/spritePics/{31.png => hurt2.png} (100%) rename images/GoblinWorker/spritePics/{16.png => walkleft.png} (100%) rename images/GoblinWorker/spritePics/{08.png => walkright.png} (100%) delete mode 100644 images/walk.png diff --git a/images/GoblinWorker/spritePics/19.png b/images/GoblinWorker/spritePics/19.png deleted file mode 100644 index afe0dc19874db8bf4b72f723ebf614917086e5c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 516 zcmV+f0{i`mP)h6?1=M13fr5_q9n3$ zkCo}}{NsZ%*558q`B7P1E|_6{z{mihqPx}yTN#7O&_JgNc`8CcsF$Q6Cy)?_kKRQg*LpDeEWk09$tbLzk21!IgR09CKO7ZY4(XhGz0000j6HX-s!4OnvX3ckVgooBQ6&k$?JSE$Z(M#WV5S|ISK;AQCB*Oi+_f<}G3X zf^Mc4yE=`(w|8y#lluX>5oqZ*upT$em z7;K9Fv?NE-=(8vYfC?U;+vg=38G9FC2rx*QTU`-7?cUz2NjEg)nsssIQ&i?9nxDxx zje1Fykw?g?5@HuG(do@eAXTPAF84=;f6mI|(tPS_MI3Q;XEN?WP8(E~PRKiQPf4t3 zzY#HTe4$Hob|uH2CXf*$V-PWL65bC&U|-Q5BceDH9bt(hgzBOb0R|2A<=Hl53Xf7Z z=q0wI`kFTGf2BKoEfei8X1_UDV!lGYL}ZHDbS}N&3yHK;2{I$%cs(rq5mW1|u?2;-a$H+^m&wf~DOn0m_bU9?Wp!rHw~% zA%~nbx_c+Ec`gAf(oyCq)FiFJ0{Ms?7$~9_h&9h+qm~}>R>X}9 z!+}E3JqC_#zXcTTefGWq009606(TET00006NklIVP- diff --git a/images/GoblinWorker/spritePics/22.png b/images/GoblinWorker/spritePics/22.png deleted file mode 100644 index 78147841db30a0bf937f7b2d96facfb142516f5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 561 zcmV-10?z%3P)z6u{q-k^}i$l5MZj`jdkj&L#`XoNaPkWFDUH~YERYmTEKW{760@%%ZBc!& zA^ug8{ES8)MWMM;SC=jB!O|8Djl2rb$W_fOFWH7WJI`hd36uGychLi;Et;LmrPkof z2qI)u33HdUMaNf10avC?&Uc4}lQZ(AY1|*Jh$}8{jmKSxfflLE7xIqWTQXO))`(~} zI@h5wI}!u-Z7?wz=*bb9vE(MaAB4a`6b?s@5i$9Rwy?xiSXpo+Kr^jFrtnv4oI2)K zR9n@;IwhUqOBri@GC7UGBJ&k;GsSE;kM8i9M4BoDnGtcluBM3ivWdY}0R+@nhe{YM zud#CJZ!fg$uapTOCaES=$Y3xcGfO;F7MqzC1i%(ISlGT0V100P#~=%9_el^$&KTXk z5m-N!fEDSj&L{gMcVm$}3r&FnxPEAm=3t(@#rA~1heYZDvBt?EmwhW@;X-4D=AipD z9NBycD6D_l`vd?0|NqY4ddL6(00v1!K~w_(sR$#bkOxd(00000NkvXXu0mjfc1rfN diff --git a/images/GoblinWorker/spritePics/23.png b/images/GoblinWorker/spritePics/23.png deleted file mode 100644 index 894e6c18b54217600c6bf72df0b035b2c71ed26f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 639 zcmV-_0)YLAP)Xn*@Atm@&e$nFMdF<=ZWhW>Ex(aC zqCGuzRu1~AVZe*CA)=LRN+11|^p@)J;>o7V^(_X;yynL>u(Q!t&|1YK#nn*Fm^9$U zbJ>PSXK8)XAWEKak`&c8PQ0bDwdj+mK{1orFqoR!HNmH^WUcl{MkoHZH*cU#iOI(H z_6sgGGP3ESUf+N1SZIJ#3iS}r)s7P)ocPx-=c6Q(at4~4&(c;BnUFBCu>WY06Q5j| zNF8QCO+>_iPYvV_qoyvK3iAkt^Kk6MNytDc6S{Nyfv*FMLu4Qn?(1$c2>ZM^_r|?b zl!4^NoR~Yu1keWs+PHTGq)A4&a<9|>uj(dsmXUoLvS2Y%bU7GtEphH5<*OSShlw;xCXWODrrXKQ<(5OAD)8iiMQ2A|hK0N+_Y5 ztdwktD7ul3K5zGXdO1Jt!j)T}^Stl#Jn!@Up7Y)h_Kv@pcvt(sFpF|}eI}0R;NUmQ zf}V02h{PF+XsN;U&|9i6sU8-8szu^TDE|IlXP~_wUt_?ZlPc~vm1`Xof0`GG=XZZ8 z=i>SGzJc4k(Zh+?Rn&)B^K-cygM))d6MXulbH!`ToF^?O-Zxw@&|sn(h>eY32)4O- z>!Kdha}SneK=o45iBC>^j`d|3sIC1N>sO+9t%3Gg(TVS$?FC5&bPzG%Q-kuajZT~) zGLU9McTO+xWq@@SEj1Rxa(`6_{xwD748Q9COL@@w8ou5oF#D}_&P~^xcTta+xC$63ocy)!)*lhui+>C-gQ$96#-q~9Q8^-e@@Y^X?_G+O$x(X(00960bzT|>00006Nkl%A_P)|7 z5<|Zg-AKp%cCFnx_ndo(IQ5-%_S$Q&@0`7F_lJD*id^wo^t}6|D{}j>qo>_V-^zVO!nnQpXdqT|*v>uy-gapv{QxHTCs>&2VGm!9=}H z%|44;s`;>JgcIYxeKldy%F3U<`u8S`aPMq45+v0o2!L$_&3_~sAq!QSNvvl`EwBT? zv(g+B2bTKE9SGWPE7V0qmAV`9Wt<^mpaytRBv2R45uisVd_sOaKr?VJL<+aZr&5%) zYX}l0n>wXpct+;dq$TxDWBOab!5(L@EWUG1B8`AWz3=|?^(e%=dD2#zQ z{i4y8e?~+;6G+{2fx@SgO@a2oV?B#Hw2>Thns@~O0RR6t1l;=o000I_L_t&o0I#Hq)$ diff --git a/images/GoblinWorker/spritePics/26.png b/images/GoblinWorker/spritePics/26.png deleted file mode 100644 index f2f192f5a14e76aa62699dad2e125e597c258d54..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 462 zcmV;<0WtoGP)?xXt#@kxKQNs91bAw;l(_pMuCp_IA6qZtpNrBGGB*2#loMC`H_&Oo5l-$IjfG!SZ3YCcl9fCyN8u{ z8?}dLlOovMpEt1{i1;>|b6bf%d8^Q8o=!6eMBbj2TvR0jG#BG_nThof{s}A5XE5z3)w({PQnRI5*u_4x-jt{uCmLM4BZCdi>Iw zLK+eIoBc68^t$<)!pv2>EX+12Gw6!qR}@2BnEZ1&4QS#kO>6IsE>{|F-Riu zp(B^U!FmSS+y4@zDvZT%<>vlHa@$*447#{dlezsWbQ9}~M{X!?i~!goR5bnuDm=+Z z=rUi>)O7exC5T{Yxuki!*cn=EXURxTg-i^@JuOKAayy%iV$H;?j5914hvKlXI^YKPdqisRGI$U&Mo&m!4D@x_R7a$M)X;)+nFvdnuu8}q2e!=0 zj8d*!<|kV{E)Ki&ugL>8#-DI0RYJB4RBaoGh-1gEVh~$C8h;dyj9i6~HdSlG#7e&{Rh*)fReE373gN2QiY)Md9Pg{?KrG+}3A8m)bbFl8ik{WDy>$e3F zMD_ZoAm+v5v^$hit~|7i!mNN1S<~*#=9f+@l{o>Vi-bX83H5)K6n1t#ko9a!Zm%8{ z;_uGil{TY+zKPs^LG)D>2Bf;TDZ9Bv2aGa$@fjdq4*|KnnAILRGGqZNOgquAm0ym= z_yxekP76El!X2ldQP@paGL5@uL9hL?@MOZ65j!G`I0VG$<0XS&D2xCL#GEGsJUyOa zsp3@;U_`O~(#nuQtR0L6!oX7jaxef*^wSiBVKyLhfPfJnt%32-_mv1U!=Se+XnSo# zOx1%0Ysc=1F#Zu1YFvMaF9`JTF!vRMVLB>2$#?Hwg_&1E%&m?GFE!II00030|7e~Y iw*UYD21!IgR09BPDd%%2JsTGQ0000X7N z(%M&nV~M|gj>?U9?>ao!KW@I-dM7XSK99ikowXcy=kHaRd64}^^?av24Ld`xt)CFK zV0o@%$}C+DVWw3AaTXD4xgvSJ-=$C3tRtDb^!0lYzuGj#77-)qWBd(r3Q7unVGRN@ zjFJ9aj3&XFDNop<{Tm_zmnD{XeYHryRAeS*SO!*YR_bq MPgg&ebxsLQ0CNXT&j0`b diff --git a/images/GoblinWorker/spritePics/32.png b/images/GoblinWorker/spritePics/32.png deleted file mode 100644 index f337bfc25c42db25fb3b8e1e9cfabf529ba73be9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 454 zcmV;%0XhDOP)Y5I`r2AP7nj3oRst?MXt=EY`-9Oeph23?K-H z!kQUo-M%Ms56D-RN&@5|p)6ArE@#!AsQJ9?&3sWQvypp&kSj>~`M%dAdK;WyY^ z1zen190e}s8FOxb7Z*3_^qbmv(@3@A({~^5t=@ciYZTBn>_GCy)z{KD^32!C{og(H zwSE2GE8*{7zKgrhP$}%t^5*SV-kkO=Ilg{;c^_A=-4|v*#aOaKfYHSxIrz=DX=~3d zTV5~nc-b_lV0=kpsf?7=+ls%pPaSHz9usXf`{vw}4lNuCPAme7Oc0H`H+;Ku@X7l7 zQ$H);4V!uNsQv7H&-|2`1(g~&GDA3}ZOyj5T+Vy>d1UIb^ZTXZL&W<3C>#fvH?TCZnxs7um zmP=i2J?ryU``GsPe^HGPt*@(@?eTk;0(Rfc+Slu~?}n@iK35f5 zRg(C{6zI*xyEcSG@ue-ZvR7Umd@JZ>@kT4@wy%A~JR$x!4EeE*<=Gj+JcW z++?|If7h~U$mprPGJkUX`C@ zRlj7%zr@U)68v#CfjzHfe$JTtH?rq-Nl@vjn5aX2d}qZUZ-2YTo*5Pbo3Co=C$9Yc zo-ce|@#j;Gy!Q`pHa{)9-hRiIt&hLH{2t%6QOGSG7=s|oy-!EJ`g|(l_|MeT)oWBr zfA7!SKK0bzoTU&a^m;D+KiN)sx80wOMgLBJdwI(8?z+oMp2ur~tYX2QXh5PHoc}UE W@0~NdZ1SHr5Z}|)&t;ucLK6T7*hruN diff --git a/main.py b/main.py index c847971..1b3bd2b 100644 --- a/main.py +++ b/main.py @@ -2,6 +2,7 @@ import pygame import sys pygame.init() +pygame.mixer.init() # ===================================================== # НАСТРОЙКИ @@ -13,7 +14,10 @@ pygame.display.set_caption("Goblin & Knight") CLOCK = pygame.time.Clock() BLACK = (0, 0, 0) -GRAVITY = 1 +GRAVITY = 0.9 +GROUND_Y = HEIGHT - 60 + +FPS = 60 # ===================================================== # ЗАГРУЗКА ФОНОВ @@ -23,16 +27,24 @@ BACKGROUND = pygame.image.load("images/back.png") BACK_MAIN = pygame.image.load("images/back_main.jpg") BACK_MAIN = pygame.transform.scale(BACK_MAIN, (WIDTH, HEIGHT)) -# ===================================================== -# ФУНКЦИЯ ВЫРЕЗКИ СПРАЙТОВ -# ===================================================== +# Попытаться загрузить музыку/звуки, если есть +BG_MUSIC = None +try: + BG_MUSIC = pygame.mixer.music + pygame.mixer.music.load('music/theme.mp3') + pygame.mixer.music.set_volume(0.5) +except Exception: + BG_MUSIC = None -def get_image(sheet, frame_x, frame_y, width, height, scale, color): - image = pygame.Surface((width, height)).convert_alpha() - image.blit(sheet, (0, 0), (frame_x * width, frame_y * height, width, height)) - image = pygame.transform.scale(image, (width * scale, height * scale)) - image.set_colorkey(color) - return image +# Шрифты и HUD +FONT = pygame.font.SysFont(None, 32) + +# Игровые счётчики +score_goblin = 0 +score_knight = 0 + +# Пауза +paused = False # ===================================================== @@ -40,34 +52,39 @@ def get_image(sheet, frame_x, frame_y, width, height, scale, color): # ===================================================== class Player: - def __init__(self, x, y, sprite_sheet, frame_size, scale, controls): + def __init__(self, x, y, sprites, scale, controls): self.start_x = x self.start_y = y - self.x = x - self.y = y + self.x = float(x) + self.y = float(y) - self.y_velocity = 0 - self.jump_power = 20 + self.y_velocity = 0.0 + self.jump_power = 18 self.jumping = False self.facing_right = True self.moving = False + self.speed = 5.5 self.controls = controls self.anim_counter = 0 self.ANIM_SPEED = 8 - w, h = frame_size + # Загрузка спрайтов из файлов + self.stand = pygame.image.load(sprites["stand"]).convert_alpha() + self.walk_left = pygame.image.load(sprites["walk_left"]).convert_alpha() + self.walk_right = pygame.image.load(sprites["walk_right"]).convert_alpha() + self.jump_img = pygame.image.load(sprites["jump"]).convert_alpha() - # Анимации - self.stand = get_image(sprite_sheet, 0, 0, w, h, scale, BLACK) - self.walk1 = get_image(sprite_sheet, 1, 0, w, h, scale, BLACK) - self.walk2 = get_image(sprite_sheet, 2, 0, w, h, scale, BLACK) - self.jump_img = get_image(sprite_sheet, 3, 0, w, h, scale, BLACK) + # Масштабирование + self.stand = pygame.transform.scale(self.stand, (int(self.stand.get_width() * scale), int(self.stand.get_height() * scale))) + self.walk_left = pygame.transform.scale(self.walk_left, (int(self.walk_left.get_width() * scale), int(self.walk_left.get_height() * scale))) + self.walk_right = pygame.transform.scale(self.walk_right, (int(self.walk_right.get_width() * scale), int(self.walk_right.get_height() * scale))) + self.jump_img = pygame.transform.scale(self.jump_img, (int(self.jump_img.get_width() * scale), int(self.jump_img.get_height() * scale))) self.surface = self.stand - self.rect = self.surface.get_rect(center=(self.x, self.y)) + self.rect = self.surface.get_rect(midbottom=(self.x, self.y)) # ------------------------- # СБРОС ПЕРСОНАЖА @@ -80,7 +97,7 @@ class Player: self.moving = False self.anim_counter = 0 self.facing_right = True - self.rect = self.surface.get_rect(center=(self.x, self.y)) + self.rect = self.surface.get_rect(midbottom=(self.x, self.y)) # ------------------------- # УПРАВЛЕНИЕ @@ -89,18 +106,18 @@ class Player: self.moving = False if keys[self.controls["right"]]: - self.x += 5 + self.x += self.speed self.facing_right = True self.moving = True if keys[self.controls["left"]]: - self.x -= 5 + self.x -= self.speed self.facing_right = False self.moving = True if keys[self.controls["jump"]] and not self.jumping: self.jumping = True - self.y_velocity = self.jump_power + self.y_velocity = -self.jump_power # Ограничение по экрану if self.x < 0: @@ -112,11 +129,11 @@ class Player: # ГРАВИТАЦИЯ # ------------------------- def apply_gravity(self): - self.y_velocity -= GRAVITY - self.y -= self.y_velocity + self.y_velocity += GRAVITY + self.y += self.y_velocity - if self.y >= HEIGHT: - self.y = HEIGHT + if self.y >= GROUND_Y: + self.y = GROUND_Y self.y_velocity = 0 self.jumping = False @@ -129,14 +146,14 @@ class Player: elif self.moving: self.anim_counter += 1 frame = (self.anim_counter // self.ANIM_SPEED) % 2 - self.surface = self.walk1 if frame == 0 else self.walk2 + self.surface = self.walk_left if frame == 0 else self.walk_right else: self.surface = self.stand if not self.facing_right: self.surface = pygame.transform.flip(self.surface, True, False) - self.rect = self.surface.get_rect(center=(self.x, self.y)) + self.rect = self.surface.get_rect(midbottom=(int(self.x), int(self.y))) # ------------------------- # ОТРИСОВКА @@ -145,17 +162,16 @@ class Player: screen.blit(self.surface, self.rect) -# ===================================================== -# ЗАГРУЗКА СПРАЙТОВ -# ===================================================== -goblin_sheet = pygame.image.load("images/GoblinWorker/GoblinWorker.png").convert_alpha() -knight_sheet = pygame.image.load("images/sprites/knight.png").convert_alpha() goblin = Player( - 200, 800, - goblin_sheet, - (48, 48), + 200, GROUND_Y, + { + "stand": "images/GoblinWorker/spritePics/stand_gob.png", + "walk_left": "images/GoblinWorker/spritePics/walkleft.png", + "walk_right": "images/GoblinWorker/spritePics/walkright.png", + "jump": "images/GoblinWorker/spritePics/Jump.png" + }, 3, { "left": pygame.K_a, @@ -165,9 +181,13 @@ goblin = Player( ) knight = Player( - 500, 800, - knight_sheet, - (32, 32), + 500, GROUND_Y, + { + "stand": "images/sprites/knight.png", + "walk_left": "images/sprites/knight.png", + "walk_right": "images/sprites/knight.png", + "jump": "images/sprites/knight.png" + }, 3, { "left": pygame.K_KP4, @@ -199,6 +219,7 @@ def restart_level(): # ===================================================== level = 0 +level_start_time = None while True: @@ -206,6 +227,12 @@ while True: if event.type == pygame.QUIT: pygame.quit() sys.exit() + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_ESCAPE and level == 1: + paused = not paused + if event.key == pygame.K_r: + restart_level() + level = 0 keys = pygame.key.get_pressed() mouse_pos = pygame.mouse.get_pos() @@ -217,38 +244,72 @@ while True: SCREEN.blit(BACK_MAIN, (0, 0)) SCREEN.blit(button_play, button_rect) + title_surf = FONT.render('Goblin & Knight', True, (255,255,255)) + SCREEN.blit(title_surf, (WIDTH//2 - title_surf.get_width()//2, 120)) + if button_rect.collidepoint(mouse_pos) and pygame.mouse.get_pressed()[0]: restart_level() level = 1 + level_start_time = pygame.time.get_ticks() + if BG_MUSIC: + try: + pygame.mixer.music.play(-1) + except Exception: + pass # ================= GAME ================= elif level == 1: - SCREEN.blit(BACKGROUND, (0, 0)) SCREEN.blit(door_image, door_rect) - # --- Goblin --- - goblin.handle_input(keys) - goblin.apply_gravity() - goblin.update_animation() - goblin.draw(SCREEN) + if not paused: + # --- Goblin --- + goblin.handle_input(keys) + goblin.apply_gravity() + goblin.update_animation() - # --- Knight --- - knight.handle_input(keys) - knight.apply_gravity() - knight.update_animation() + # --- Knight --- + knight.handle_input(keys) + knight.apply_gravity() + knight.update_animation() + + # Draw players (even when paused) + goblin.draw(SCREEN) knight.draw(SCREEN) + elapsed = 0 + if level_start_time: + elapsed = (pygame.time.get_ticks() - level_start_time) // 1000 + hud_g = FONT.render(f'Goblin: {score_goblin}', True, (255,255,255)) + hud_k = FONT.render(f'Knight: {score_knight}', True, (255,255,255)) + hud_t = FONT.render(f'Time: {elapsed}s', True, (255,255,255)) + SCREEN.blit(hud_g, (20, 20)) + SCREEN.blit(hud_k, (WIDTH - hud_k.get_width() - 20, 20)) + SCREEN.blit(hud_t, (WIDTH//2 - hud_t.get_width()//2, 20)) + + if paused: + p = FONT.render('PAUSED - press ESC to resume', True, (255,255,0)) + SCREEN.blit(p, (WIDTH//2 - p.get_width()//2, HEIGHT//2 - 20)) # Победа if goblin.rect.colliderect(door_rect) and keys[pygame.K_e]: - print("Goblin wins!") + score_goblin += 1 restart_level() level = 0 + if BG_MUSIC: + try: + pygame.mixer.music.stop() + except Exception: + pass if knight.rect.colliderect(door_rect) and keys[pygame.K_KP5]: - print("Knight wins!") + score_knight += 1 restart_level() level = 0 + if BG_MUSIC: + try: + pygame.mixer.music.stop() + except Exception: + pass pygame.display.update() - CLOCK.tick(60) \ No newline at end of file + CLOCK.tick(FPS) \ No newline at end of file