From 171eff1434e7f38af0c9a3d28e19acaecc3b049a Mon Sep 17 00:00:00 2001 From: shiva404 Date: Fri, 20 Feb 2026 02:09:43 +0300 Subject: [PATCH] pre commit, make CAPS tasks from main --- __pycache__/classes.cpython-314.pyc | Bin 0 -> 193 bytes __pycache__/common.cpython-314.pyc | Bin 630 -> 3704 bytes __pycache__/eb_engine.cpython-314.pyc | Bin 17972 -> 21829 bytes __pycache__/eb_objects.cpython-314.pyc | Bin 3446 -> 3661 bytes classes.py | 1 + common.py | 61 ++++++- def_map.json | 220 ++++++++++++------------- eb_engine.py | 86 ++++++++-- eb_objects.py | 13 +- main.py | 29 +++- 10 files changed, 284 insertions(+), 126 deletions(-) create mode 100644 __pycache__/classes.cpython-314.pyc create mode 100644 classes.py diff --git a/__pycache__/classes.cpython-314.pyc b/__pycache__/classes.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b35fa02a44a668574c6431d48a0e5d8913b57406 GIT binary patch literal 193 zcmdPqvii?78k3x#0wi)0i;Gi>^$IF)aoFVMr==_7FpmLaupKpq3Uh{5VvEOrduhU*`MbK`)^KSGD8lkW8L~mqq@bnT4QfLDCh!G@dkdO#Ou9 zNz|}WGPYv8VWe!>B$?DPHDVsNNEUT$9I+155LdL6-ziM1w*l*C@RLOC>INR2*n)cI6jo%XJAZ+xv5|> zCWWIR3CPW-xggIc#nXyO9VK|6p?rzZ*^q7@mTZKd0e(-`@os)bp|PX@cOfcDqEH1QD&QyfLYG1XdsS-aL4_l2 zSf!nr$a~TXz4;!!Ip?_DQmARZ5qoRsD@WaT7Q|G4XGJ#VDKMcBc9-7FFn~Gr^a&`J zLM0AEJBrTZ4Xj}T?K}a_0m>%T{8G9JRO+lXF3LyNBHqXn=fT}Vge6sYbpnl*CCT07 z&VG;wyEh@$uoJ8b@5AHQ4B%#PFHo5_P*EyX=LRbC1}aTf-3BVl8Wj``?5N6$nDDq! z-A~(fysXp`)>Jyfm>Icq7M@ic4PgjlO?{aR{4tYANkqc`FrE{yZ9MZ;%UFT;j> z)Ot=E+D_?GG>yBF&wPa7ZQY13_v2Df+xY1&^>EN;I!6h9=0*6fA~y!S-4EW;+W5aF z(0HVe(#xh5^&q~&Z_)8SW9{=?VI~mE05!P<&}_NxheJeok7_NHm)6*FU9atrj`GHq7o-tpnW|Ajg{YJRU;)l3#MYH+$JUq5bX)WY6n8rXyo~0}QtAm} zoz@L(9b4Z=@{Mc*P&bxR;wmi4dJ|-+@d7V5s_|B-wbAoz16k((mv1H1^-x(a$li7O zH9gNxww!GOEwR2O8R}g`>QQ}&@D8HV8Y|QNqScSbl8i&<$hYLV{2TJ;@<;M~{)$Wf zYyKzsEBT+f!p2u^h>OKUtmzg3E=Z)%Q8B>7 z?H!zqaZ2-4G#(C|56*P&i6uh8n7FUI1lQ7r`;W1Omwk&}KG}Rsz)ncM44wR|{1u2tDu1O%{uB0_Oa4s013>}D>QRzE z&0p&;hUTKFOAAN{nAaNAjOJIk3_y?PH83z~-;lzwfK`DBU3q%wHpAZ#dN`zw{UQqCa`d_UWIXzy& zeqg{>iId>56#9m?r<2$EQ-cK)oqqkNGxsYTt9U8%{kJb%+nXAELXyTY;;|W3*I)i# z>QKQ^s{&hj#<^^3&Q?PQERPMyy?Hjd+}4+qpwm`%_0Jz)-Z^r23_5M)2yv8A)l&qF3Y9fCnzGzd<>u6@1;%;9mOZ}2xKktd>6*;N6}s&n-S%PUTy&*l z|Gkd=tLAc<+5fl3FMhCa;Do&YqXMWeS)U@l< zgLlch$Nz5qbcI^{ z9*06gx>9GvL|mbg$!Hk9ZS-#+P89ITBv8=ds^ez_{BBcdsD@avhSb_sjQF$Xb*-4S zI_760P)>?fgMmmg3LhBwg9?P=Q(OHyP*YyOg|hA_n@)t2F>asW1q41+M0jtY#|DBR q9w5sDM8p3>)c#LY|1EMqMDDLq`2$q>EvkD$nF!`tRUg5q;{F2+3Rs>1 delta 158 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 T@cRW~UE>&)(a#lwGVgx@+4!sM diff --git a/__pycache__/eb_objects.cpython-314.pyc b/__pycache__/eb_objects.cpython-314.pyc index 50172413e991423348dfa05a94e1dd5b32fd46a3..32348cb17b04a3b8e20b27000d47aec4cc2ab949 100644 GIT binary patch delta 1555 zcmaJ>O>7%g5T3XH{!L3-hjm?IJJiJlw}B>UXe|pGBoYcP-GVu}$k=XVVS`fDp@U%QKoAzTHAt-~4 zym{4|VySOdSW#thudnScC(!FMgd9&I`bK}VQ4>u+cImzMn{{z2SlUR9bc7+?v!eXC zmkGV%{iZJ&)9B-ey^OKIlAdF1SjW+kXXyIQC`JwwdyF9KS>|fuIW*;FFUifgNtEf; zOnW98(&rx~m>%0L0An8mr$oqYna?y+LUowX90mJOee-&L#^?ZJxHM;ySV|sYE}@j;yq>AgCR0CY_bZ1IUtm)X`v>d2URTtRo!7{ z>7?)x#(z9`H~)&Uq$f1-RhTp&B94j}t-u-P;H|eU5p#4AuYfS890Pkay=|*Bn8kg9 z7BXl}+!4>>+MinG&6?=*=J<+EQuxyZbaHhKVeg@fLs?m)Q)v7n(M@d@Dp>S8PgK-B z*;SxB7U%#_v2@^^9C_wj*IM1iyC2j(EaN2@^++Y8^F!#|?6tbW&Fh>5qiuA|oWTcPE%7~)RD43+wmHFwX>e0AcM_M^RY zQ~NZ&FTE3Cp2I-Cir{@2%AQnwt=)2Qvqq~f@(Q0PRtk>l&kh5{6};a=$s=j>xMvam z`~*IN`-$Xjt>hgG7Y1YXQqpq%(1FUL4)_}c6vba7xJXbYc%6Xmhrdd2hCpg@iL7OW zN&OeeNsuO@1UN5P(Gc!ua^D`glPL|?z3;q5WPZnU}^|5MxBl$PK;8RrP({FAGk5AzG;K?wsVU2}N{^5-FES{|cpPnLH{ zW=m6`Od|hlR~16MsEo0np>P`tzp(JGl3=kNKp3f@M0VtI!Fw1@ YCn9Y5=JgTaYfPcFlk&2$H#OSiZ?I$^5&!@I delta 1395 zcmaJ>OKTHR6h3#}nRF77+L*Rjo8lu@OMSI8t)f zhozaOlk9(wMguN_%TB>86Kqxy%B(8XSxsoo!voDbmZ>Gc)pL6DLDDpknn<4{O$%uR z>8s?7jWn9G4ydFIa3K5v5y>f=U=Z9cj5|5~uej~Th9DjPO!;ZekFtIzh~CJHYnQxR zrJATc+rg$(=J-XeGnT-d8bjF5`w#=8exsNdUf`U$eBCREk>h9u!dS!H>GcWKWkPcmtVj*aa~|jUQiTsYgTD0$SlUUE`PTY0_OBTc>LstCz~fQswG@ zWV0koAp12*mK+ATvgv4G6sijg)e5Ko6s{4-DHz1$Cn>)a+1EK(M5laDsk*)~fi<;I zE!NB4VLp!!GrVh$5n3u^>;q)pLS}{89c2@9T7b}2L5a4cIfCq~!dPVaN*kvWSq&j; a88T!tXZdCu%-FBT(9`Pne>n3RRr3>NLkF4w diff --git a/classes.py b/classes.py new file mode 100644 index 0000000..5d3ee5a --- /dev/null +++ b/classes.py @@ -0,0 +1 @@ +from eb_terrain_objects import Rock \ No newline at end of file diff --git a/common.py b/common.py index 5947690..5fc7d41 100644 --- a/common.py +++ b/common.py @@ -3,9 +3,15 @@ import json import uuid from dataclasses import dataclass, field from copy import deepcopy + +from collections import defaultdict +from heapq import heappush, heappop + import pygame import pygame_gui +from classes import Rock + def path_exists(data, path): current = data for key in path: @@ -13,4 +19,57 @@ def path_exists(data, path): current = current[key] else: return False - return True \ No newline at end of file + return True + +def find_way(cells, start, goal): + """Находит путь от start=(row, col) к goal=(row, col). row=y (строка), col=x (столбец)""" + rows = len(cells) + if rows == 0: + return None + cols = len(cells[0]) + def is_passable(cell): + # Проходимо, если НЕ Rock в terrain И creature_obj отсутствует + return (cell.terrain_obj is None or not isinstance(cell.terrain_obj, Rock)) + # Проверка границ и проходимости старт/гол + s_row, s_col = start + g_row, g_col = goal + if not (0 <= s_row < rows and 0 <= s_col < cols and 0 <= g_row < rows and 0 <= g_col < cols): + return None + start_cell = cells[s_row][s_col] + goal_cell = cells[g_row][g_col] + if not is_passable(start_cell) or not is_passable(goal_cell): + print(f"Старт/гол непроходимы: start={is_passable(start_cell)}, goal={is_passable(goal_cell)}") + return None + # A* поиск (используем прямые row,col вместо ID для простоты) + directions = [(-1, 0), (1, 0), (0, -1), (0, 1)] # вверх, вниз, лево, право + open_set = [] + # f_score = g + h (h=манхэттен) + h = abs(s_row - g_row) + abs(s_col - g_col) + heappush(open_set, (h, 0, s_row, s_col)) # f, g, row, col + came_from = {} + g_score = defaultdict(lambda: float('inf')) + g_score[(s_row, s_col)] = 0 + while open_set: + _, _, row, col = heappop(open_set) + if (row, col) == (g_row, g_col): + # Восстанавливаем путь + path = [] + current = (row, col) + while current in came_from: + path.append(current) + current = came_from[current] + path.append(start) + return path[::-1] + for dr, dc in directions: + nr, nc = row + dr, col + dc + if 0 <= nr < rows and 0 <= nc < cols: + if is_passable(cells[nr][nc]): + tentative_g = g_score[(row, col)] + 1 + pos = (nr, nc) + if tentative_g < g_score[pos]: + came_from[pos] = (row, col) + g_score[pos] = tentative_g + f = tentative_g + abs(nr - g_row) + abs(nc - g_col) + heappush(open_set, (f, tentative_g, nr, nc)) + print("Путь не найден (нет связи)") + return None \ No newline at end of file diff --git a/def_map.json b/def_map.json index 9b9c343..0f2b5e2 100644 --- a/def_map.json +++ b/def_map.json @@ -30,7 +30,7 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -928,6 +928,15 @@ "item_obj": {}, "creature_obj": {} }, + { + "terrain_obj": { + "id": "1", + "name": "2", + "sprite_name": "rock_small" + }, + "item_obj": {}, + "creature_obj": {} + }, { "terrain_obj": { "id": "1", @@ -937,6 +946,15 @@ "item_obj": {}, "creature_obj": {} }, + { + "terrain_obj": { + "id": "1", + "name": "2", + "sprite_name": "rock_small" + }, + "item_obj": {}, + "creature_obj": {} + }, { "terrain_obj": { "id": "1", @@ -977,7 +995,7 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -1013,25 +1031,7 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" - }, - "item_obj": {}, - "creature_obj": {} - }, - { - "terrain_obj": { - "id": "1", - "name": "2", - "sprite_name": "grass_small" - }, - "item_obj": {}, - "creature_obj": {} - }, - { - "terrain_obj": { - "id": "1", - "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -1843,7 +1843,25 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" + }, + "item_obj": {}, + "creature_obj": {} + }, + { + "terrain_obj": { + "id": "1", + "name": "2", + "sprite_name": "rock_small" + }, + "item_obj": {}, + "creature_obj": {} + }, + { + "terrain_obj": { + "id": "1", + "name": "2", + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -1888,7 +1906,16 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" + }, + "item_obj": {}, + "creature_obj": {} + }, + { + "terrain_obj": { + "id": "1", + "name": "2", + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -1924,34 +1951,7 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" - }, - "item_obj": {}, - "creature_obj": {} - }, - { - "terrain_obj": { - "id": "1", - "name": "2", - "sprite_name": "grass_small" - }, - "item_obj": {}, - "creature_obj": {} - }, - { - "terrain_obj": { - "id": "1", - "name": "2", - "sprite_name": "grass_small" - }, - "item_obj": {}, - "creature_obj": {} - }, - { - "terrain_obj": { - "id": "1", - "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -2763,7 +2763,7 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -2826,7 +2826,16 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" + }, + "item_obj": {}, + "creature_obj": {} + }, + { + "terrain_obj": { + "id": "1", + "name": "2", + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -2844,7 +2853,7 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -2853,16 +2862,7 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" - }, - "item_obj": {}, - "creature_obj": {} - }, - { - "terrain_obj": { - "id": "1", - "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -3638,7 +3638,16 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" + }, + "item_obj": {}, + "creature_obj": {} + }, + { + "terrain_obj": { + "id": "1", + "name": "2", + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -3674,7 +3683,7 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -3683,7 +3692,7 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -3692,16 +3701,7 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" - }, - "item_obj": {}, - "creature_obj": {} - }, - { - "terrain_obj": { - "id": "1", - "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -4549,7 +4549,7 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -6335,7 +6335,25 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" + }, + "item_obj": {}, + "creature_obj": {} + }, + { + "terrain_obj": { + "id": "1", + "name": "2", + "sprite_name": "rock_small" + }, + "item_obj": {}, + "creature_obj": {} + }, + { + "terrain_obj": { + "id": "1", + "name": "2", + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -6380,7 +6398,16 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" + }, + "item_obj": {}, + "creature_obj": {} + }, + { + "terrain_obj": { + "id": "1", + "name": "2", + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -6416,7 +6443,7 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -6425,7 +6452,7 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} @@ -6434,34 +6461,7 @@ "terrain_obj": { "id": "1", "name": "2", - "sprite_name": "grass_small" - }, - "item_obj": {}, - "creature_obj": {} - }, - { - "terrain_obj": { - "id": "1", - "name": "2", - "sprite_name": "grass_small" - }, - "item_obj": {}, - "creature_obj": {} - }, - { - "terrain_obj": { - "id": "1", - "name": "2", - "sprite_name": "grass_small" - }, - "item_obj": {}, - "creature_obj": {} - }, - { - "terrain_obj": { - "id": "1", - "name": "2", - "sprite_name": "grass_small" + "sprite_name": "rock_small" }, "item_obj": {}, "creature_obj": {} diff --git a/eb_engine.py b/eb_engine.py index 33a8a4d..d5cd630 100644 --- a/eb_engine.py +++ b/eb_engine.py @@ -15,9 +15,11 @@ main_dir = os.path.dirname(os.path.abspath(__file__)) sprites_dir = os.path.join(main_dir, "res", "sprites") #class Render +#class ObjectManager #class MapManager #class Event #class EventManager +#class Control @dataclass class Cell: @@ -60,22 +62,45 @@ class Map: self.cells[line].append(final_cell) - def move_obj(self, type, s_x, s_y, d_x, d_y): - if d_y >= len(self.cells) or d_x >= len(self.cells[s_y]) or s_y >= len(self.cells) or s_x >= len(self.cells[s_y]): - return False + def move_obj(self, type, start, goal): + """Перемещает объект типа 'terrain_obj', 'item_obj' или 'creature_obj' + из клетки start=(row, col) в goal=(row, col)""" + s_y, s_x = start + d_y, d_x = goal + + # Проверка границ + if (s_y >= len(self.cells) or s_x >= len(self.cells[s_y]) or + d_y >= len(self.cells) or d_x >= len(self.cells[d_y])): + return False + source_cell = self.cells[s_y][s_x] dest_cell = self.cells[d_y][d_x] obj = getattr(source_cell, type) if obj is None: return False - + setattr(source_cell, type, None) setattr(dest_cell, type, obj) return True - def get_way(self, s_x, s_y, d_x, d_y): - pass + def get_cell_at_mouse(self, mouse_pos): + """Возвращает индексы клетки (row, col) по позиции мыши или None если вне карты""" + mx, my = mouse_pos + # Переводим экранные координаты в координаты карты с учетом камеры и масштаба + map_x = (mx - self.cam_x * self.scale) / self.scale / self.size + map_y = (my - self.cam_y * self.scale) / self.scale / self.size + + # Получаем индексы ближайшей клетки + col = int(map_x) + row = int(map_y) + + # Проверяем границы карты + if (row < 0 or row >= len(self.cells) or + col < 0 or col >= len(self.cells[row])): + return None + + return (row, col) def draw_map(self, screen, current_frame, grid = True): for j in range(len(self.cells)): @@ -97,8 +122,19 @@ class Map: cell.creature_obj.draw(dd) if grid: - pygame.draw.rect(screen, self.color, pygame.Rect(dd["x"], dd["y"], dd["w"], dd["h"]), self.bord) - + if cell.is_target: + pygame.draw.rect(screen, self.target_color, pygame.Rect(dd["x"], dd["y"], dd["w"], dd["h"]), self.bord) + else: + pygame.draw.rect(screen, self.color, pygame.Rect(dd["x"], dd["y"], dd["w"], dd["h"]), self.bord) + + def update_map(self, current_frame): + for j in range(len(self.cells)): + for i, cell in enumerate(self.cells[j]): + if cell.creature_obj is not None and len(cell.creature_obj.waypoints) > 1 and current_frame % 57 == 0: + del cell.creature_obj.waypoints[0] + self.move_obj("creature_obj", (j, i), (cell.creature_obj.waypoints[0])) + + @dataclass class Engine: sprites: dict = field(default_factory = dict) @@ -186,6 +222,11 @@ class Engine: def main_loop(self): easy_map = Map("def_map.json", self.cached_sprites) + #print(easy_map.find_way((1, 1), (5, 5))) + #print(easy_map.find_way((0, 0), (1, 1))) + #print(easy_map.find_way((0, 0), (0, 1))) + #print(easy_map.find_way((0, 0), (0, 0))) + #sp = eb_objects.Sprite(self.sprites, "elf_watching") #gr = pygame.image.load(file_path).convert_alpha() @@ -210,6 +251,8 @@ class Engine: global_counter = 0 global_counter_cap = 100000 + active_cell = [] + # profiling process = psutil.Process(os.getpid()) @@ -262,12 +305,13 @@ class Engine: # fill the screen with a color to wipe away anything from last frame #self.screen.fill("chartreuse4") self.screen.blit(background, (0, 0)) - + easy_map.update_map(global_counter) easy_map.draw_map(self.screen, current_frame + 1) manager.draw_ui(self.screen) if not console_active: keys = pygame.key.get_pressed() + if keys[pygame.K_w]: easy_map.cam_y += self.camera_step if keys[pygame.K_s]: @@ -276,6 +320,7 @@ class Engine: easy_map.cam_x += self.camera_step if keys[pygame.K_d]: easy_map.cam_x -= self.camera_step + if keys[pygame.K_q]: easy_map.scale += self.scale_step self.spr_scale += self.scale_step @@ -284,6 +329,27 @@ class Engine: easy_map.scale -= self.scale_step self.spr_scale -= self.scale_step self.scale_sprites() + + if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: # Левая кнопка + mouse_pos = pygame.mouse.get_pos() + console_rect = console_window.get_abs_rect() + if not console_rect.collidepoint(mouse_pos): + cell_coords = easy_map.get_cell_at_mouse(mouse_pos) + if cell_coords: + if active_cell: + easy_map.cells[active_cell[0]][active_cell[1]].is_target = False + active_cell = cell_coords + easy_map.cells[active_cell[0]][active_cell[1]].is_target = True + + + if event.type == pygame.MOUSEBUTTONDOWN and event.button == 3: + mouse_pos = pygame.mouse.get_pos() + cell_coords = easy_map.get_cell_at_mouse(mouse_pos) + console_rect = console_window.get_abs_rect() + if not console_rect.collidepoint(mouse_pos) and easy_map.cells[active_cell[0]][active_cell[1]].creature_obj is not None: + easy_map.cells[active_cell[0]][active_cell[1]].creature_obj.move(easy_map.cells, (active_cell[0], active_cell[1]), (cell_coords[0], cell_coords[1])) + + if keys[pygame.K_ESCAPE]: running = False @@ -298,6 +364,6 @@ class Engine: if global_counter % 10 == 0: current_fps = clock.get_fps() - #print(f"Current FPS: {current_fps:.2f}") + print(f"Current FPS: {current_fps:.2f}") pygame.quit() \ No newline at end of file diff --git a/eb_objects.py b/eb_objects.py index 17321fd..eaf6527 100644 --- a/eb_objects.py +++ b/eb_objects.py @@ -1,4 +1,4 @@ -from common import deepcopy, dataclass, field, path_exists +from common import deepcopy, dataclass, field @dataclass class Object: @@ -6,7 +6,8 @@ class Object: name: str sprite_name: str sprite_state: int = 0 - + # current_map + # pos # weight # effects = {} @@ -30,7 +31,7 @@ class Terrain(Object): @dataclass class Creature(Object): - current_action: int = 0 + waypoints: list = field(default_factory = list) quick_actions: list = field(default_factory = list) tasks: list = field(default_factory = list) inventory: dict = field(default_factory = dict) @@ -38,6 +39,10 @@ class Creature(Object): def update(self): pass + def move(self, cells, start, goal): + from common import find_way + self.waypoints = find_way(cells, start, goal) + @dataclass class Item(Object): @@ -53,4 +58,4 @@ class Container(Item): @dataclass class Building(Object): - pass \ No newline at end of file + pass diff --git a/main.py b/main.py index f63a54d..d357117 100644 --- a/main.py +++ b/main.py @@ -37,8 +37,35 @@ if __name__ == "__main__": # - deepcopy + # - общие + main() + # + # ДОДЕЛАТЬ move для Creature - хранить pos в объекте + # + # ПРОВЕРИТЬ МЕНЯЕТСЯ ЛИ ПЕРЕДАННЫЙ В ОБЪЕКТ cells и еслт да, + # перенести всё взаимодействие с картой в объекты, карта только хранит cells + # и готовит данные для отрисовки Render'ом + # + # ИГРОВОЙ ТАКТ? или только для действий их длительность? + # + # ПОСМОТРЕТЬ ПО КОММИТАМ ЗАЧЕМ БЫЛ НУЖЕН path_exists, удалить? + # # добавил гуй, динамическая консоль, всё работает, но: # - слоп, почистить # - мини-баг - если первые вводимые буквы совпадают с клавишами управления, один раз успевает проскочить до лока. некритично. # - при вводе текста нет прокрутки к концу - # - плавающий баг - если повводить текст, а потом закрыть консоль, игра не закроется по эскейпу. \ No newline at end of file + # - плавающий баг - если повводить текст, а потом закрыть консоль, игра не закроется по эскейпу. + # + # исправить поиск пути чтобы он учитывал других существ + # + # в дальнейшем вся отрисовка переедет в класс рендер, + # карта будет только вовзращать поверхность для отрисовки или даже просто Cells + # active_cell переедет в класс Control + # + # НАЙТИ В КОДЕ ГДЕ Я ТАК НЕ СДЕЛАЛ И ИСПРАВИТЬ - НАШЕЛ ОДНУ, ПОИСКАТЬ ЕЩЕ + #if a is None: + # print("a это точно None") + # + # Альтернатива + #if a is not None: + # print("a не None") + # + # \ No newline at end of file