Сделал ещё одну очевидную оптимизацию - кэширование матриц препятствий, результат превзошёл всё ожидания. 300 объектов - плавные 60 фпс, 500 объектов - 60 фпс с микрофризами. Для масштабов игры этого уже более чем достаточно. Теперь следует добиться такого же для более слабых машин, надо выбрать минимальные системные требования.

This commit is contained in:
shiva404
2026-03-06 04:00:43 +03:00
parent fa189a4c3b
commit b1548ea182
6 changed files with 529 additions and 50 deletions

View File

@@ -38,6 +38,8 @@ class Map:
sprites: dict
sprites_refresh: int = 60
cells: dict = field(default_factory = dict)
walkable_matrix: list = field(default_factory = list)
rocks_matrix: list = field(default_factory = list)
color: str = "gray57"
target_color: str = "gold"
cell_size: int = 150
@@ -66,7 +68,16 @@ class Map:
final_cell.creature_obj = cell_classes[cell["creature_obj"]["sprite_name"]](**cell["creature_obj"])
final_cell.creature_obj.grid_pos = (line, col)
self.cells[line].append(final_cell)
self.cells[line].append(final_cell)
self.compute_walkable_rocks()
for j in range(len(self.cells)):
for cell in self.cells[j]:
if cell.creature_obj:
cell.creature_obj.walkable_matrix = self.walkable_matrix
cell.creature_obj.rocks_matrix = self.rocks_matrix
def move_obj(self, type, start, goal):
"""Перемещает объект типа 'terrain_obj', 'item_obj' или 'creature_obj'
@@ -114,10 +125,36 @@ class Map:
return (row, col)
def update_map(self, time_delta):
self.compute_walkable_rocks()
for j in range(len(self.cells)):
for cell in self.cells[j]:
if cell.creature_obj:
cell.creature_obj.update(time_delta, self.cell_size, self) # self!
cell.creature_obj.update(time_delta, self.cell_size, self)
def compute_walkable_rocks(self):
"""Вычисляет матрицы walkable и rocks_only БЕЗ учета стартовой позиции"""
rows = len(self.cells)
if rows == 0:
return None, None
cols = len(self.cells[0])
# ★ ИНИЦИАЛИЗАЦИЯ ★
self.walkable_matrix = [[True] * cols for _ in range(rows)]
self.rocks_matrix = [[False] * cols for _ in range(rows)]
# ★ ПОЛНЫЙ ПРОХОД ПО КАРТЕ
for r in range(rows):
for c in range(cols):
cell = self.cells[r][c]
# Запрещаем ВСЕ существа (включая стартовое!)
if cell.creature_obj or \
(cell.terrain_obj and cell.terrain_obj.sprite_name == "rock_small"):
self.walkable_matrix[r][c] = False
# Отмечаем маленькие камни
if cell.terrain_obj and cell.terrain_obj.sprite_name == "rock_small":
self.rocks_matrix[r][c] = True
# def draw_map(self, screen, current_frame, grid=True):
# terrain_list = []
@@ -168,7 +205,6 @@ class Map:
# color = self.target_color if cell.is_target else self.color
# pygame.draw.rect(screen, color, grid_rect, self.bord)
def draw_map(self, screen, current_frame, grid=True):
screen_rect = screen.get_rect()
terrain_list = []
@@ -238,9 +274,6 @@ class Map:
pygame.draw.rect(screen, color, grid_rect, self.bord)
@dataclass
class Engine:
sprites: dict = field(default_factory = dict)
@@ -328,14 +361,6 @@ 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()
background = pygame.Surface((1600, 800))
background.fill("chartreuse4")
@@ -380,7 +405,12 @@ class Engine:
col < len(easy_map.cells[row]) and
easy_map.cells[row][col].creature_obj is None):
elf = eb_objects.Creature(id=f"elf_{random.randint(1000,9999)}", name="Elf", sprite_name="elf_watching", grid_pos = pos)
elf = eb_objects.Creature(id=f"elf_{random.randint(1000,9999)}",
name="Elf", sprite_name="elf_watching",
grid_pos = pos,
walkable_matrix = easy_map.walkable_matrix,
rocks_matrix = easy_map.rocks_matrix)
r_move_short = eb_objects.Action(sprite_name="elf_watching", func=partial(elf.patrol, easy_map.cells, 3), duration=0.01)
r_move_long = eb_objects.Action(sprite_name="elf_watching", func=partial(elf.move_rand, easy_map.cells, 0, 99), duration=0.01)
elf.tasks.append([r_move_short]*5 + [r_move_long])
@@ -514,8 +544,7 @@ class Engine:
cell_coords = easy_map.get_cell_at_mouse(mouse_pos)
if cell_coords:
#print(f"Движение: {active_cell} -> {cell_coords}")
easy_map.cells[active_cell[0]][active_cell[1]].creature_obj.move(
easy_map.cells, cell_coords)
easy_map.cells[active_cell[0]][active_cell[1]].creature_obj.move(easy_map.cells, cell_coords)
if keys[pygame.K_ESCAPE]:
running = False