Compare commits
7 Commits
a707638e09
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ba8c8b3ab | ||
|
|
b1548ea182 | ||
|
|
fa189a4c3b | ||
|
|
45f2c71cb8 | ||
|
|
dafa95989f | ||
|
|
8834ac997f | ||
|
|
6b6ca341dc |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
__pycache__/
|
||||
.venv/
|
||||
19
README.md
Normal file
19
README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# ElvenBane
|
||||
|
||||
## Запуск с virtualenv
|
||||
#### Linux/WSL:
|
||||
```
|
||||
virtualenv .venv
|
||||
source .venv/bin/activate
|
||||
```
|
||||
|
||||
#### PowerShell:
|
||||
```
|
||||
python -m venv .venv
|
||||
.venv\Scripts\Activate.ps1
|
||||
```
|
||||
|
||||
#### Общее:
|
||||
```
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
483
common.py
483
common.py
@@ -1,17 +1,22 @@
|
||||
import os
|
||||
import json
|
||||
import uuid
|
||||
import random
|
||||
from dataclasses import dataclass, field
|
||||
from copy import deepcopy
|
||||
|
||||
from collections import defaultdict
|
||||
from heapq import heappush, heappop
|
||||
from functools import partial
|
||||
|
||||
import pygame
|
||||
import pygame_gui
|
||||
|
||||
from classes import Rock
|
||||
|
||||
from pathfinding.core.grid import Grid
|
||||
from pathfinding.finder.a_star import AStarFinder
|
||||
from collections import defaultdict
|
||||
from heapq import heappush, heappop
|
||||
from math import sqrt, inf
|
||||
|
||||
def path_exists(data, path):
|
||||
current = data
|
||||
for key in path:
|
||||
@@ -21,6 +26,12 @@ def path_exists(data, path):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def find_way(cells, start, goal, walkable, rocks_only):
|
||||
result = bfs_quick(cells, start, goal, walkable, rocks_only)
|
||||
return result
|
||||
|
||||
'''
|
||||
#def find_way(cells, start, goal):
|
||||
# """Находит путь от start=(row, col) к goal=(row, col). row=y (строка), col=x (столбец)"""
|
||||
# rows = len(cells)
|
||||
@@ -146,87 +157,421 @@ def path_exists(data, path):
|
||||
# print("Путь не найден (нет связи)")
|
||||
# return None
|
||||
|
||||
def find_way(cells, start, goal):
|
||||
"""Находит путь с диагональным движением, но БЕЗ прохода через углы"""
|
||||
#def find_way(cells, start, goal):
|
||||
# """Находит путь с диагональным движением, но БЕЗ прохода через углы"""
|
||||
# rows = len(cells)
|
||||
# if rows == 0:
|
||||
# return None
|
||||
# cols = len(cells[0])
|
||||
#
|
||||
# def is_passable(cell):
|
||||
# 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"Старт/гол непроходимы")
|
||||
# return None
|
||||
#
|
||||
# directions = [
|
||||
# (-1, 0), (1, 0), (0, -1), (0, 1), # ортогональ (1.0)
|
||||
# (-1, -1), (-1, 1), (1, -1), (1, 1) # диагональ (1.414)
|
||||
# ]
|
||||
#
|
||||
# def can_move_diagonal(current_r, current_c, dr, dc):
|
||||
# """Проверяет, можно ли двигаться по диагонали (НЕ через угол)"""
|
||||
# nr, nc = current_r + dr, current_c + dc
|
||||
#
|
||||
# # Ортогональные соседи ДОЛЖНЫ быть проходимыми для диагонального хода
|
||||
# ortho1_r, ortho1_c = current_r + dr, current_c # вертикальный сосед
|
||||
# ortho2_r, ortho2_c = current_r, current_c + dc # горизонтальный сосед
|
||||
#
|
||||
# # Проверяем границы для ортососедей
|
||||
# if not (0 <= ortho1_r < rows and 0 <= ortho1_c < cols):
|
||||
# return False
|
||||
# if not (0 <= ortho2_r < rows and 0 <= ortho2_c < cols):
|
||||
# return False
|
||||
#
|
||||
# return (is_passable(cells[ortho1_r][ortho1_c]) and
|
||||
# is_passable(cells[ortho2_r][ortho2_c]))
|
||||
#
|
||||
# open_set = []
|
||||
# h = max(abs(s_row - g_row), abs(s_col - g_col))
|
||||
# heappush(open_set, (h, 0, s_row, s_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:
|
||||
# target_cell = cells[nr][nc]
|
||||
#
|
||||
# if (nr, nc) != start and target_cell.creature_obj is not None:
|
||||
# continue
|
||||
# if not is_passable(target_cell):
|
||||
# continue
|
||||
#
|
||||
# if abs(dr) + abs(dc) == 2:
|
||||
# if not can_move_diagonal(row, col, dr, dc):
|
||||
# continue
|
||||
#
|
||||
# move_cost = 1.414 if abs(dr) + abs(dc) == 2 else 1.0
|
||||
# tentative_g = g_score[(row, col)] + move_cost
|
||||
# pos = (nr, nc)
|
||||
#
|
||||
# if tentative_g < g_score[pos]:
|
||||
# came_from[pos] = (row, col)
|
||||
# g_score[pos] = tentative_g
|
||||
# h = max(abs(nr - g_row), abs(nc - g_col))
|
||||
# f = tentative_g + h
|
||||
# heappush(open_set, (f, tentative_g, nr, nc))
|
||||
#
|
||||
# print("Путь не найден")
|
||||
# return None
|
||||
|
||||
|
||||
#def find_way(cells, start, goal):
|
||||
# """A* pathfinding — только новая библиотека"""
|
||||
# rows = len(cells)
|
||||
# if rows == 0:
|
||||
# print("Путь не найден: пустая карта")
|
||||
# return None
|
||||
#
|
||||
# cols = len(cells[0])
|
||||
#
|
||||
# # ★ Проверка границ ★
|
||||
# s_row, s_col = start
|
||||
# g_row, g_col = goal
|
||||
# if (s_row >= rows or s_col >= cols or
|
||||
# g_row >= rows or g_col >= cols):
|
||||
# print(f"Путь не найден: выход за границы карты {start} -> {goal}")
|
||||
# return None
|
||||
#
|
||||
# # ★ НАХОДИМ существо в start ★
|
||||
# start_creature = cells[s_row][s_col].creature_obj
|
||||
#
|
||||
# # Матрица препятствий
|
||||
# matrix = [[1 for _ in cells[row]] for row in range(rows)]
|
||||
#
|
||||
# for r in range(rows):
|
||||
# for c in range(cols):
|
||||
# cell_creature = cells[r][c].creature_obj
|
||||
# if cell_creature and cell_creature != start_creature:
|
||||
# matrix[r][c] = 0
|
||||
#
|
||||
# from pathfinding.core.grid import Grid
|
||||
# from pathfinding.finder.a_star import AStarFinder
|
||||
#
|
||||
# grid = Grid(matrix=matrix)
|
||||
# start_node = grid.node(s_row, s_col)
|
||||
# end_node = grid.node(g_row, g_col)
|
||||
#
|
||||
# finder = AStarFinder()
|
||||
# path_nodes, _ = finder.find_path(start_node, end_node, grid)
|
||||
#
|
||||
# if not path_nodes or len(path_nodes) <= 1:
|
||||
# print(f"Путь не найден: {start} -> {goal}")
|
||||
# return None
|
||||
#
|
||||
# path = [(node.x, node.y) for node in path_nodes]
|
||||
#
|
||||
# return path
|
||||
|
||||
'''
|
||||
|
||||
def bfs_quick(cells, start, goal, walkable, rocks_only):
|
||||
"""★СУПЕРБЫСТРЫЙ BFS: массивы вместо set/deque★"""
|
||||
rows = len(cells)
|
||||
if rows == 0:
|
||||
print("Путь не найден: пустая карта")
|
||||
return None
|
||||
|
||||
cols = len(cells[0])
|
||||
|
||||
def is_passable(cell):
|
||||
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):
|
||||
|
||||
if (s_row >= rows or s_col >= cols or
|
||||
g_row >= rows or g_col >= cols):
|
||||
#print(f"Путь не найден: выход за границы {start} -> {goal}")
|
||||
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"Старт/гол непроходимы")
|
||||
return None
|
||||
## ★ МАТРИЦЫ вместо set (10x быстрее хэширования) ★
|
||||
#walkable = [[True] * cols for _ in range(rows)]
|
||||
#rocks_only = [[False] * cols for _ in range(rows)]
|
||||
#start_creature = cells[s_row][s_col].creature_obj
|
||||
#
|
||||
#for r in range(rows):
|
||||
# for c in range(cols):
|
||||
# cell = cells[r][c]
|
||||
# if (cell.creature_obj and cell.creature_obj != start_creature) or \
|
||||
# (cell.terrain_obj and cell.terrain_obj.sprite_name == "rock_small"):
|
||||
# walkable[r][c] = False
|
||||
# if cell.terrain_obj and cell.terrain_obj.sprite_name == "rock_small":
|
||||
# rocks_only[r][c] = True
|
||||
|
||||
directions = [
|
||||
(-1, 0), (1, 0), (0, -1), (0, 1), # ортогональ (1.0)
|
||||
(-1, -1), (-1, 1), (1, -1), (1, 1) # диагональ (1.414)
|
||||
]
|
||||
# ★ ВЫЧИСЛЯЕМЫЕ МАССИВЫ ★
|
||||
visited = [[False] * cols for _ in range(rows)]
|
||||
parent = [[None] * cols for _ in range(rows)]
|
||||
|
||||
def can_move_diagonal(current_r, current_c, dr, dc):
|
||||
"""Проверяет, можно ли двигаться по диагонали (НЕ через угол)"""
|
||||
nr, nc = current_r + dr, current_c + dc
|
||||
# ★ БЫСТРАЯ ОЧЕРЕДЬ: индекс вместо deque ★
|
||||
queue_size = 0
|
||||
queue = [[0, 0] for _ in range(rows * cols)] # Предварительно выделяем
|
||||
queue[0] = [s_row, s_col]
|
||||
queue_size = 1
|
||||
front = 0
|
||||
|
||||
visited[s_row][s_col] = True
|
||||
|
||||
directions = [(-1,0), (1,0), (0,-1), (0,1),
|
||||
(-1,-1), (-1,1), (1,-1), (1,1)]
|
||||
|
||||
while front < queue_size:
|
||||
# ★ БЫСТРОЕ извлечение ★
|
||||
r, c = queue[front]
|
||||
front += 1
|
||||
|
||||
# Ортогональные соседи ДОЛЖНЫ быть проходимыми для диагонального хода
|
||||
ortho1_r, ortho1_c = current_r + dr, current_c # вертикальный сосед
|
||||
ortho2_r, ortho2_c = current_r, current_c + dc # горизонтальный сосед
|
||||
|
||||
# Проверяем границы для ортососедей
|
||||
if not (0 <= ortho1_r < rows and 0 <= ortho1_c < cols):
|
||||
return False
|
||||
if not (0 <= ortho2_r < rows and 0 <= ortho2_c < cols):
|
||||
return False
|
||||
|
||||
return (is_passable(cells[ortho1_r][ortho1_c]) and
|
||||
is_passable(cells[ortho2_r][ortho2_c]))
|
||||
|
||||
open_set = []
|
||||
h = max(abs(s_row - g_row), abs(s_col - g_col))
|
||||
heappush(open_set, (h, 0, s_row, s_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):
|
||||
if r == g_row and c == g_col:
|
||||
path = []
|
||||
current = (row, col)
|
||||
while current in came_from:
|
||||
path.append(current)
|
||||
current = came_from[current]
|
||||
path.append(start)
|
||||
cr, cc = g_row, g_col
|
||||
while True:
|
||||
path.append((cr, cc))
|
||||
if parent[cr][cc] is None:
|
||||
break
|
||||
pr, pc = parent[cr][cc]
|
||||
cr, cc = pr, pc
|
||||
return path[::-1]
|
||||
|
||||
for dr, dc in directions:
|
||||
nr, nc = row + dr, col + dc
|
||||
if 0 <= nr < rows and 0 <= nc < cols and is_passable(cells[nr][nc]):
|
||||
nr, nc = r + dr, c + dc
|
||||
|
||||
if (0 <= nr < rows and 0 <= nc < cols and
|
||||
walkable[nr][nc] and not visited[nr][nc]):
|
||||
|
||||
# ★ ПРОВЕРКА ДИАГОНАЛИ ★
|
||||
if abs(dr) + abs(dc) == 2: # диагональное движение
|
||||
if not can_move_diagonal(row, col, dr, dc):
|
||||
continue # пропускаем запрещённую диагональ
|
||||
|
||||
move_cost = 1.414 if abs(dr) + abs(dc) == 2 else 1.0
|
||||
tentative_g = g_score[(row, col)] + move_cost
|
||||
pos = (nr, nc)
|
||||
|
||||
if tentative_g < g_score[pos]:
|
||||
came_from[pos] = (row, col)
|
||||
g_score[pos] = tentative_g
|
||||
h = max(abs(nr - g_row), abs(nc - g_col))
|
||||
f = tentative_g + h
|
||||
heappush(open_set, (f, tentative_g, nr, nc))
|
||||
if dr * dc == 0 or can_move_diagonal(r, c, nr, nc, rocks_only, rows, cols):
|
||||
visited[nr][nc] = True
|
||||
parent[nr][nc] = (r, c)
|
||||
|
||||
# ★ БЫСТРОЕ добавление в очередь ★
|
||||
queue[queue_size] = [nr, nc]
|
||||
queue_size += 1
|
||||
|
||||
print("Путь не найден")
|
||||
return None
|
||||
#print(f"Путь не найден: {start} -> {goal}")
|
||||
return None
|
||||
|
||||
def can_move_diagonal(r, c, nr, nc, rocks_only, rows, cols):
|
||||
"""Запрет среза только около rock"""
|
||||
dr = nr - r
|
||||
dc = nc - c
|
||||
r1, c1 = r + dr, c
|
||||
r2, c2 = r, c + dc
|
||||
|
||||
check1_ok = (0 <= r1 < rows and 0 <= c1 < cols and not rocks_only[r1][c1])
|
||||
check2_ok = (0 <= r2 < rows and 0 <= c2 < cols and not rocks_only[r2][c2])
|
||||
|
||||
return check1_ok and check2_ok
|
||||
|
||||
'''
|
||||
#def bfs_quick_d(obstacle_matrix, start, goal):
|
||||
# rows = len(obstacle_matrix)
|
||||
# if rows == 0:
|
||||
# print("❌ DEBUG: ПУСТАЯ МАТРИЦА")
|
||||
# return None
|
||||
#
|
||||
# cols = len(obstacle_matrix[0])
|
||||
# s_row, s_col = start
|
||||
# g_row, g_col = goal
|
||||
#
|
||||
# print(f"🔍 DEBUG: start={start}, goal={goal}, размер={rows}x{cols}")
|
||||
#
|
||||
# if (s_row >= rows or s_col >= cols or
|
||||
# g_row >= rows or g_col >= cols):
|
||||
# print(f"❌ DEBUG: ВЫХОД ЗА ГРАНИЦЫ: start({s_row},{s_col}) goal({g_row},{g_col})")
|
||||
# return None
|
||||
#
|
||||
# print(f"✅ DEBUG: Границы OK. obstacle[start]={obstacle_matrix[s_row][s_col]}, obstacle[goal]={obstacle_matrix[g_row][g_col]}")
|
||||
#
|
||||
# visited = [[False] * cols for _ in range(rows)]
|
||||
# parent = [[None] * cols for _ in range(rows)]
|
||||
#
|
||||
# queue_size = 0
|
||||
# queue = [[0, 0] for _ in range(rows * cols)]
|
||||
# queue[0] = [s_row, s_col]
|
||||
# queue_size = 1
|
||||
# front = 0
|
||||
#
|
||||
# visited[s_row][s_col] = True
|
||||
# print(f"✅ DEBUG: Старт добавлен в очередь. queue_size={queue_size}")
|
||||
#
|
||||
# directions = [(-1,0), (1,0), (0,-1), (0,1), (-1,-1), (-1,1), (1,-1), (1,1)]
|
||||
#
|
||||
# DEBUG_COUNTER = 0
|
||||
#
|
||||
# while front < queue_size:
|
||||
# r, c = queue[front]
|
||||
# front += 1
|
||||
# DEBUG_COUNTER += 1
|
||||
#
|
||||
# print(f"🔄 DEBUG[{DEBUG_COUNTER}]: обрабатываем ({r},{c}), очередь={front}/{queue_size}")
|
||||
#
|
||||
# if r == g_row and c == g_col:
|
||||
# print(f"✅ DEBUG: НАЙДЕН ЦЕЛЬ! Путь: ({r},{c})")
|
||||
# path = []
|
||||
# cr, cc = g_row, g_col
|
||||
# while True:
|
||||
# path.append((cr, cc))
|
||||
# if parent[cr][cc] is None:
|
||||
# break
|
||||
# pr, pc = parent[cr][cc]
|
||||
# cr, cc = pr, pc
|
||||
# return path[::-1]
|
||||
#
|
||||
# for dr, dc in directions:
|
||||
# nr, nc = r + dr, c + dc
|
||||
#
|
||||
# print(f" 📍 Проверяем соседа ({nr},{nc}): граница={0<=nr<rows and 0<=nc<cols}, "
|
||||
# f"visited={visited[nr][nc]}, obstacle={obstacle_matrix[nr][nc]}")
|
||||
#
|
||||
# if (0 <= nr < rows and 0 <= nc < cols and
|
||||
# not visited[nr][nc] and
|
||||
# not obstacle_matrix[nr][nc]):
|
||||
#
|
||||
# diagonal_ok = True
|
||||
# if dr * dc != 0:
|
||||
# diagonal_ok = can_move_diagonal(r, c, nr, nc, obstacle_matrix)
|
||||
# print(f" ↘️ Диагональ: {diagonal_ok}")
|
||||
#
|
||||
# if diagonal_ok:
|
||||
# visited[nr][nc] = True
|
||||
# parent[nr][nc] = (r, c)
|
||||
# queue[queue_size] = [nr, nc]
|
||||
# queue_size += 1
|
||||
# print(f" ✅ Добавили ({nr},{nc}) в очередь. queue_size={queue_size}")
|
||||
# else:
|
||||
# print(f" ❌ Диагональ заблокирована!")
|
||||
# else:
|
||||
# print(f" ❌ Сосед отклонен!")
|
||||
#
|
||||
# print(f"❌ DEBUG: ОЧЕРЕДЬ ОПУСТЕЛА! Обработано {DEBUG_COUNTER} узлов")
|
||||
# print(f" Последняя клетка в очереди: {queue[front-1] if front > 0 else 'ПУСТО'}")
|
||||
# print(f" Цель ({g_row},{g_col}) помечена как visited? {visited[g_row][g_col]}")
|
||||
# return None
|
||||
#
|
||||
#
|
||||
#def bfs_quick(obstacle_matrix, start, goal):
|
||||
# """★СУПЕРБЫСТРЫЙ BFS 8-направлений★
|
||||
# obstacle_matrix - ТОЛЬКО камни
|
||||
# """
|
||||
# rows = len(obstacle_matrix)
|
||||
# if rows == 0:
|
||||
# return None
|
||||
#
|
||||
# cols = len(obstacle_matrix[0])
|
||||
# s_row, s_col = start
|
||||
# g_row, g_col = goal
|
||||
#
|
||||
# if (s_row >= rows or s_col >= cols or
|
||||
# g_row >= rows or g_col >= cols):
|
||||
# return None
|
||||
#
|
||||
# # ★ МАТРИЦЫ состояния ★
|
||||
# visited = [[False] * cols for _ in range(rows)]
|
||||
# parent = [[None] * cols for _ in range(rows)]
|
||||
#
|
||||
# # ★ БЫСТРАЯ ОЧЕРЕДЬ ★
|
||||
# queue_size = 0
|
||||
# queue = [[0, 0] for _ in range(rows * cols)]
|
||||
# queue[0] = [s_row, s_col]
|
||||
# queue_size = 1
|
||||
# front = 0
|
||||
#
|
||||
# visited[s_row][s_col] = True
|
||||
#
|
||||
# # ★ 8 НАПРАВЛЕНИЙ ★
|
||||
# directions = [(-1,0), (1,0), (0,-1), (0,1), # Кардинальные (всегда)
|
||||
# (-1,-1), (-1,1), (1,-1), (1,1)] # Диагональные
|
||||
#
|
||||
# while front < queue_size:
|
||||
# r, c = queue[front]
|
||||
# front += 1
|
||||
#
|
||||
# if r == g_row and c == g_col:
|
||||
# # ★ Реконструкция пути ★
|
||||
# path = []
|
||||
# cr, cc = g_row, g_col
|
||||
# while True:
|
||||
# path.append((cr, cc))
|
||||
# if parent[cr][cc] is None:
|
||||
# break
|
||||
# pr, pc = parent[cr][cc]
|
||||
# cr, cc = pr, pc
|
||||
# return path[::-1]
|
||||
#
|
||||
# for dr, dc in directions:
|
||||
# nr, nc = r + dr, c + dc
|
||||
#
|
||||
# if not (0 <= nr < rows and 0 <= nc < cols):
|
||||
# continue
|
||||
# if visited[nr][nc] or obstacle_matrix[nr][nc]:
|
||||
# continue
|
||||
#
|
||||
# diagonal_ok = True
|
||||
# if dr * dc != 0:
|
||||
# diagonal_ok = can_move_diagonal(r, c, nr, nc, obstacle_matrix)
|
||||
# if diagonal_ok:
|
||||
# visited[nr][nc] = True
|
||||
# parent[nr][nc] = (r, c)
|
||||
# queue[queue_size] = [nr, nc]
|
||||
# queue_size += 1
|
||||
#
|
||||
# return None
|
||||
'''
|
||||
#def can_move_diagonal(r, c, nr, nc, obstacle_matrix):
|
||||
# """Диагональ БЛОКИРУЕТСЯ только камнями по углам"""
|
||||
# rows, cols = len(obstacle_matrix), len(obstacle_matrix[0])
|
||||
# dr = nr - r
|
||||
# dc = nc - c
|
||||
#
|
||||
# r1, c1 = r + dr, c # Вертикальная соседка
|
||||
# r2, c2 = r, c + dc # Горизонтальная соседка
|
||||
#
|
||||
# check1_ok = (0 <= r1 < rows and 0 <= c1 < cols and not obstacle_matrix[r1][c1])
|
||||
# check2_ok = (0 <= r2 < rows and 0 <= c2 < cols and not obstacle_matrix[r2][c2])
|
||||
#
|
||||
# return check1_ok and check2_ok
|
||||
|
||||
#def can_move_diagonal(r, c, nr, nc, obstacle_matrix):
|
||||
# """Проверка диагонали с границами"""
|
||||
# rows, cols = len(obstacle_matrix), len(obstacle_matrix[0])
|
||||
# dr = nr - r
|
||||
# dc = nc - c
|
||||
#
|
||||
# # ★ ПРОВЕРКА ГРАНИЦ ПОПЕРЕДУ ★
|
||||
# r1, c1 = r + dr, c # вертикальная
|
||||
# r2, c2 = r, c + dc # горизонтальная
|
||||
#
|
||||
# # Если УЖЕ за границей - False
|
||||
# if not (0 <= r1 < rows and 0 <= c1 < cols):
|
||||
# return False
|
||||
# if not (0 <= r2 < rows and 0 <= c2 < cols):
|
||||
# return False
|
||||
#
|
||||
# return not obstacle_matrix[r1][c1] and not obstacle_matrix[r2][c2]
|
||||
20
def_map.json
20
def_map.json
@@ -11,7 +11,9 @@
|
||||
"name": "2",
|
||||
"sprite_name": "sword_default"
|
||||
},
|
||||
"creature_obj": {}
|
||||
"creature_obj": {"id": "1",
|
||||
"name": "2",
|
||||
"sprite_name": "elf_watching"}
|
||||
},
|
||||
{
|
||||
"terrain_obj": {
|
||||
@@ -20,17 +22,15 @@
|
||||
"sprite_name": "grass_small"
|
||||
},
|
||||
"item_obj": {},
|
||||
"creature_obj": {
|
||||
"id": "1",
|
||||
"creature_obj": {"id": "1",
|
||||
"name": "2",
|
||||
"sprite_name": "elf_watching"
|
||||
}
|
||||
"sprite_name": "elf_watching"}
|
||||
},
|
||||
{
|
||||
"terrain_obj": {
|
||||
"id": "1",
|
||||
"name": "2",
|
||||
"sprite_name": "rock_small"
|
||||
"sprite_name": "grass_small"
|
||||
},
|
||||
"item_obj": {},
|
||||
"creature_obj": {}
|
||||
@@ -932,7 +932,7 @@
|
||||
"terrain_obj": {
|
||||
"id": "1",
|
||||
"name": "2",
|
||||
"sprite_name": "rock_small"
|
||||
"sprite_name": "grass_small"
|
||||
},
|
||||
"item_obj": {},
|
||||
"creature_obj": {}
|
||||
@@ -950,7 +950,7 @@
|
||||
"terrain_obj": {
|
||||
"id": "1",
|
||||
"name": "2",
|
||||
"sprite_name": "rock_small"
|
||||
"sprite_name": "grass_small"
|
||||
},
|
||||
"item_obj": {},
|
||||
"creature_obj": {}
|
||||
@@ -1843,7 +1843,7 @@
|
||||
"terrain_obj": {
|
||||
"id": "1",
|
||||
"name": "2",
|
||||
"sprite_name": "rock_small"
|
||||
"sprite_name": "grass_small"
|
||||
},
|
||||
"item_obj": {},
|
||||
"creature_obj": {}
|
||||
@@ -1852,7 +1852,7 @@
|
||||
"terrain_obj": {
|
||||
"id": "1",
|
||||
"name": "2",
|
||||
"sprite_name": "rock_small"
|
||||
"sprite_name": "grass_small"
|
||||
},
|
||||
"item_obj": {},
|
||||
"creature_obj": {}
|
||||
|
||||
210
eb_engine.py
210
eb_engine.py
@@ -1,4 +1,5 @@
|
||||
from common import os, json, uuid, deepcopy, dataclass, field
|
||||
from common import os, json, uuid, deepcopy, random
|
||||
from common import dataclass, field, partial
|
||||
from common import pygame, pygame_gui
|
||||
import eb_objects
|
||||
import eb_terrain_objects
|
||||
@@ -37,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
|
||||
@@ -45,7 +48,8 @@ class Map:
|
||||
cam_x: int = 0
|
||||
cam_y: int = 0
|
||||
cell_dist: int = 1
|
||||
|
||||
|
||||
#effects[]
|
||||
#action_time_multiplier
|
||||
|
||||
def __post_init__(self):
|
||||
@@ -54,7 +58,7 @@ class Map:
|
||||
buff = json.load(file)
|
||||
for line in range(len(buff)):
|
||||
self.cells[line] = []
|
||||
for cell in buff[str(line)]:
|
||||
for col, cell in enumerate(buff[str(line)]):
|
||||
final_cell = Cell(cell_classes[cell["terrain_obj"]["sprite_name"]](**cell["terrain_obj"]))
|
||||
|
||||
if cell["item_obj"]:
|
||||
@@ -62,12 +66,34 @@ class Map:
|
||||
|
||||
if cell["creature_obj"]:
|
||||
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 draw_obj(self, obj, draw_data):
|
||||
if draw_data["spr_up"] == 0:
|
||||
if obj.sprite_state == len(draw_data["sprites"][obj.sprite_name]) - 1:
|
||||
obj.sprite_state = 0
|
||||
else:
|
||||
obj.sprite_state += 1
|
||||
|
||||
sp = draw_data["sprites"][obj.sprite_name][obj.sprite_state]
|
||||
rect = sp.get_rect(center = (draw_data["x"] + draw_data["w"] /2, draw_data["y"] + draw_data["h"]/ 2))
|
||||
draw_data["screen"].blit(sp, rect)
|
||||
|
||||
def move_obj(self, type, start, goal):
|
||||
"""Перемещает объект типа 'terrain_obj', 'item_obj' или 'creature_obj'
|
||||
из клетки start=(row, col) в goal=(row, col)"""
|
||||
if goal is None:
|
||||
return False
|
||||
|
||||
s_y, s_x = start
|
||||
d_y, d_x = goal
|
||||
|
||||
@@ -79,12 +105,14 @@ class Map:
|
||||
source_cell = self.cells[s_y][s_x]
|
||||
dest_cell = self.cells[d_y][d_x]
|
||||
obj = getattr(source_cell, type)
|
||||
check = getattr(dest_cell, type)
|
||||
|
||||
if obj is None:
|
||||
if obj is None or check is not None:
|
||||
return False
|
||||
|
||||
setattr(source_cell, type, None)
|
||||
setattr(dest_cell, type, obj)
|
||||
#obj.grid_pos = goal
|
||||
return True
|
||||
|
||||
def get_cell_at_mouse(self, mouse_pos):
|
||||
@@ -106,12 +134,38 @@ 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 and cell.creature_obj.current_target:
|
||||
cell.creature_obj.update(time_delta, self.cell_size, self) # self!
|
||||
if cell.creature_obj:
|
||||
cell.creature_obj.update(time_delta, self.cell_size, self)
|
||||
|
||||
def draw_map(self, screen, current_frame, grid=True):
|
||||
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 OLDSTABLE_draw_map(self, screen, current_frame, grid=True):
|
||||
terrain_list = []
|
||||
creature_list = []
|
||||
|
||||
@@ -160,7 +214,73 @@ 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 = []
|
||||
creature_list = []
|
||||
|
||||
# Вычисляем видимую область в координатах карты (аналогично get_cell_at_mouse)
|
||||
left_map = (self.cam_x * self.scale) / self.scale / self.cell_size
|
||||
top_map = (self.cam_y * self.scale) / self.scale / self.cell_size
|
||||
right_map = ((self.cam_x * self.scale + screen_rect.width) / self.scale / self.cell_size)
|
||||
bottom_map = ((self.cam_y * self.scale + screen_rect.height) / self.scale / self.cell_size)
|
||||
|
||||
min_row = max(0, int(top_map - 1)) # -1 для буфера
|
||||
max_row = min(len(self.cells), int(bottom_map + 2)) # +2 для буфера
|
||||
min_col = max(0, int(left_map - 1))
|
||||
max_col = min(len(self.cells[0]) if self.cells and self.cells[0] else 0, int(right_map + 2))
|
||||
|
||||
# ★ 1 ПАСС: собираем только видимые terrain и creatures ★
|
||||
for j in range(min_row, max_row):
|
||||
if j not in self.cells: continue
|
||||
row_cells = self.cells[j]
|
||||
for i in range(min_col, min(max_col, len(row_cells))):
|
||||
cell = row_cells[i]
|
||||
|
||||
base_x = i * self.cell_size + self.cam_x
|
||||
base_y = j * self.cell_size + self.cam_y
|
||||
|
||||
# Terrain данные
|
||||
terrain_dd = {
|
||||
"x": int(base_x * self.scale), "y": int(base_y * self.scale),
|
||||
"w": int(self.cell_size * self.scale - self.cell_dist),
|
||||
"h": int(self.cell_size * self.scale - self.cell_dist),
|
||||
"spr_up": current_frame % self.sprites_refresh,
|
||||
"sprites": self.sprites, "scale": self.scale, "screen": screen
|
||||
}
|
||||
terrain_list.append((cell.terrain_obj, terrain_dd))
|
||||
|
||||
# Creature данные (если есть)
|
||||
if cell.creature_obj:
|
||||
offset_x, offset_y = cell.creature_obj.render_offset
|
||||
creature_dd = terrain_dd.copy()
|
||||
creature_dd["x"] = int((base_x + offset_x) * self.scale)
|
||||
creature_dd["y"] = int((base_y + offset_y) * self.scale)
|
||||
creature_list.append((cell.creature_obj, creature_dd))
|
||||
|
||||
# ★ 2 ПАСС: рисуем terrain ★
|
||||
for obj, dd in terrain_list:
|
||||
self.draw_obj(obj, dd)
|
||||
|
||||
# ★ 3 ПАСС: рисуем ВСЕХ creatures ПОСЛЕ terrain ★
|
||||
for obj, dd in creature_list:
|
||||
self.draw_obj(obj, dd)
|
||||
|
||||
# ★ 4 ПАСС: grid только для видимых ячеек ★
|
||||
for j in range(min_row, max_row):
|
||||
if j not in self.cells: continue
|
||||
row_cells = self.cells[j]
|
||||
for i in range(min_col, min(max_col, len(row_cells))):
|
||||
cell = row_cells[i]
|
||||
base_x = i * self.cell_size + self.cam_x
|
||||
base_y = j * self.cell_size + self.cam_y
|
||||
grid_rect = pygame.Rect(
|
||||
int(base_x * self.scale), int(base_y * self.scale),
|
||||
int(self.cell_size * self.scale - self.cell_dist),
|
||||
int(self.cell_size * self.scale - self.cell_dist)
|
||||
)
|
||||
color = self.target_color if cell.is_target else self.color
|
||||
pygame.draw.rect(screen, color, grid_rect, self.bord)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -250,14 +370,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")
|
||||
|
||||
@@ -287,6 +399,32 @@ class Engine:
|
||||
gc.collect()
|
||||
mem_before = process.memory_info().rss / 1024
|
||||
|
||||
|
||||
NUM_ELVES = 2000
|
||||
elf_count = 0
|
||||
space_pressed = False
|
||||
spawn = False
|
||||
|
||||
def spawn_elves():
|
||||
spawn_positions = [(0,0), (0,99), (99,0), (99,99), (50,50)]
|
||||
|
||||
for pos in spawn_positions:
|
||||
row, col = pos
|
||||
if (row < len(easy_map.cells) and
|
||||
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,
|
||||
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])
|
||||
easy_map.cells[row][col].creature_obj = elf
|
||||
|
||||
while running:
|
||||
time_delta = clock.tick(60)/1000.0
|
||||
#pygame.event.clear()
|
||||
@@ -295,12 +433,42 @@ class Engine:
|
||||
mem_after = process.memory_info().rss / 1024
|
||||
print(f"Leak: {mem_after - mem_before:.1f} KB per 1000 frames")
|
||||
|
||||
if global_counter % 100 == 0 and spawn == True:
|
||||
spawn_elves()
|
||||
elf_count += 5
|
||||
|
||||
# poll for events
|
||||
# pygame.QUIT event means the user clicked X to close your window
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
running = False
|
||||
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_SPACE and elf_count < NUM_ELVES and not space_pressed:
|
||||
#spawn_elf()
|
||||
#elf_count += 1
|
||||
if spawn == False:
|
||||
spawn = True
|
||||
else: spawn = False
|
||||
space_pressed = True
|
||||
|
||||
if event.type == pygame.KEYUP:
|
||||
if event.key == pygame.K_SPACE:
|
||||
space_pressed = False
|
||||
|
||||
if event.type == pygame.MOUSEWHEEL:
|
||||
scroll_y = event.y
|
||||
|
||||
if scroll_y > 0:
|
||||
easy_map.scale += self.scale_step * 5
|
||||
self.spr_scale += self.scale_step * 5
|
||||
self.scale_sprites()
|
||||
elif scroll_y < 0 and easy_map.scale >= self.scale_step:
|
||||
easy_map.scale -= self.scale_step * 5
|
||||
self.spr_scale -= self.scale_step * 5
|
||||
self.scale_sprites()
|
||||
|
||||
|
||||
if event.type == pygame_gui.UI_TEXT_ENTRY_FINISHED and event.ui_element == input_entry:
|
||||
user_text = input_entry.get_text()
|
||||
exec(user_text)
|
||||
@@ -357,7 +525,9 @@ 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()
|
||||
@@ -374,7 +544,6 @@ class Engine:
|
||||
row, col = active_cell
|
||||
easy_map.cells[row][col].is_target = True
|
||||
|
||||
|
||||
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 3:
|
||||
mouse_pos = pygame.mouse.get_pos()
|
||||
console_rect = console_window.get_abs_rect()
|
||||
@@ -384,8 +553,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, active_cell, 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
|
||||
@@ -401,6 +569,6 @@ class Engine:
|
||||
|
||||
if global_counter % 10 == 0:
|
||||
current_fps = clock.get_fps()
|
||||
print(f"Current FPS: {current_fps:.2f}")
|
||||
print(f"Elves count: {elf_count} - Current FPS: {current_fps:.2f}")
|
||||
|
||||
pygame.quit()
|
||||
243
eb_objects.py
243
eb_objects.py
@@ -1,4 +1,21 @@
|
||||
from common import deepcopy, dataclass, field
|
||||
from common import deepcopy, dataclass, field, random
|
||||
|
||||
@dataclass
|
||||
class Action:
|
||||
sprite_name: str
|
||||
func: function
|
||||
duration: float
|
||||
progress: float = 0.0
|
||||
#status: str = "pending"
|
||||
#взаимодействие с инвентарем
|
||||
#взять предмет
|
||||
#бросить предмет
|
||||
#передать предмет
|
||||
#собрать ресурс
|
||||
#активное действие с оружием
|
||||
#колдовство
|
||||
|
||||
#class Task
|
||||
|
||||
@dataclass
|
||||
class Object:
|
||||
@@ -6,22 +23,10 @@ class Object:
|
||||
name: str
|
||||
sprite_name: str
|
||||
sprite_state: int = 0
|
||||
grid_pos: tuple = None
|
||||
# current_map
|
||||
# pos
|
||||
# weight
|
||||
# effects = {}
|
||||
|
||||
def draw(self, draw_data):
|
||||
if draw_data["spr_up"] == 0:
|
||||
if self.sprite_state == len(draw_data["sprites"][self.sprite_name]) - 1:
|
||||
self.sprite_state = 0
|
||||
else:
|
||||
self.sprite_state += 1
|
||||
|
||||
sp = draw_data["sprites"][self.sprite_name][self.sprite_state]
|
||||
rect = sp.get_rect(center = (draw_data["x"] + draw_data["w"] /2, draw_data["y"] + draw_data["h"]/ 2))
|
||||
draw_data["screen"].blit(sp, rect)
|
||||
|
||||
def update(self):
|
||||
pass
|
||||
|
||||
@@ -31,59 +36,212 @@ class Terrain(Object):
|
||||
|
||||
@dataclass
|
||||
class Creature(Object):
|
||||
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)
|
||||
#direction: int = 0 # tuple?
|
||||
move_progress: float = 0.0 # 0.0 = старт клетки, 1.0 = конец клетки
|
||||
current_target: tuple = None # (row, col) следующая клетка
|
||||
final_goal: tuple = None
|
||||
move_speed: float = 0.02 # пикселей/кадр
|
||||
render_offset: tuple = (0.0, 0.0)
|
||||
start_pos: tuple = None # (row, col) начальная позиция сегмента пути
|
||||
waypoints: list = field(default_factory = list)
|
||||
walkable_matrix: list = field(default_factory = list)
|
||||
rocks_matrix: list = field(default_factory = list)
|
||||
|
||||
move_progress: float = 0.0 # 0.0 = старт клетки, 1.0 = конец клетки
|
||||
current_target: tuple = None # (row, col) следующая клетка
|
||||
move_speed: float = 0.02 # пикселей/кадр (настройте)
|
||||
render_offset: tuple = (0.0, 0.0)
|
||||
start_pos: tuple = None # (row, col) начальная позиция сегмента пути
|
||||
inventory: dict = field(default_factory = dict)
|
||||
quick_actions: list = field(default_factory = list)
|
||||
tasks: list = field(default_factory = list)
|
||||
|
||||
action: Action = None
|
||||
action_time: float = 0.0
|
||||
action_counter: int = 0
|
||||
task_counter: int = 0
|
||||
|
||||
new_task: list = field(default_factory = list)
|
||||
interrupt_task: list = field(default_factory = list)
|
||||
|
||||
|
||||
def move(self, cells, start, goal):
|
||||
interrupt_action_status: str = "completed"
|
||||
|
||||
def replan(self, cells, pos):
|
||||
from common import find_way
|
||||
self.start_pos = start
|
||||
path = find_way(cells, start, goal)
|
||||
path = find_way(cells, pos, self.final_goal, self.walkable_matrix, self.rocks_matrix)
|
||||
if path and len(path) > 1:
|
||||
self.waypoints = path[1:] # Убираем текущую позицию
|
||||
self.waypoints = path[1:]
|
||||
self.current_target = self.waypoints[0]
|
||||
self.move_progress = 0.0
|
||||
self.start_pos = start # ★ ТУТ - текущая позиция как стартовая для первого шага ★
|
||||
self.render_offset = (0.0, 0.0)
|
||||
else:
|
||||
self.waypoints.clear()
|
||||
self.current_target = None
|
||||
self.final_goal = None
|
||||
|
||||
|
||||
def update(self, time_delta, cell_size, map_obj):
|
||||
def calc_step(self, time_delta, cell_size, map_obj):
|
||||
if self.current_target is None or not self.waypoints:
|
||||
self.render_offset = (0.0, 0.0)
|
||||
return
|
||||
|
||||
if self.current_target is None: return
|
||||
|
||||
#target_row, target_col = self.current_target
|
||||
#if (target_row in map_obj.cells and
|
||||
# target_col < len(map_obj.cells[target_row])):
|
||||
# target_cell = map_obj.cells[target_row][target_col]
|
||||
#if target_cell.creature_obj is not None:
|
||||
# self.current_target = None
|
||||
# self.waypoints.clear()
|
||||
# self.render_offset = (0.0, 0.0)
|
||||
# self.replan(map_obj.cells, self.start_pos)
|
||||
# return
|
||||
|
||||
self.move_progress += self.move_speed * time_delta * 60
|
||||
self.move_progress = min(self.move_progress, 1.0)
|
||||
|
||||
if self.move_progress >= 1.0:
|
||||
map_obj.move_obj('creature_obj', self.start_pos, self.current_target)
|
||||
if (map_obj.move_obj('creature_obj', self.start_pos, self.current_target)):
|
||||
self.grid_pos = self.current_target
|
||||
else:
|
||||
self.current_target = None
|
||||
self.waypoints.clear()
|
||||
self.render_offset = (0.0, 0.0)
|
||||
#если в матрице не считаем объекты, то:
|
||||
#добавляем клетку в матрицу, матрицу периодически чистим
|
||||
#посчитать как дорого обходится просчёт матрицы
|
||||
self.replan(map_obj.cells, self.start_pos)
|
||||
#тут сделать красивый переход в одну из соседних клеток
|
||||
return
|
||||
|
||||
self.waypoints.pop(0)
|
||||
if self.waypoints: self.waypoints.pop(0)
|
||||
|
||||
if self.waypoints:
|
||||
self.start_pos = self.current_target # Новая клетка как старт
|
||||
self.start_pos = self.current_target
|
||||
self.current_target = self.waypoints[0]
|
||||
self.move_progress = 0.0
|
||||
self.render_offset = (0.0, 0.0) # ← ДОБАВИТЬ!
|
||||
self.render_offset = (0.0, 0.0)
|
||||
else:
|
||||
#print(111111111111111)
|
||||
self.current_target = None
|
||||
self.final_goal = None
|
||||
self.render_offset = (0.0, 0.0)
|
||||
return
|
||||
|
||||
# ★ ТОЛЬКО интерполяция offset ★
|
||||
start_row, start_col = self.start_pos #or (0, 0)
|
||||
target_row, target_col = self.current_target
|
||||
|
||||
if self.current_target is None:
|
||||
self.render_offset = (0.0, 0.0)
|
||||
return
|
||||
|
||||
start_row, start_col = self.start_pos
|
||||
target_row, target_col = self.current_target
|
||||
offset_x = (target_col - start_col) * cell_size * self.move_progress
|
||||
offset_y = (target_row - start_row) * cell_size * self.move_progress
|
||||
self.render_offset = (offset_x, offset_y)
|
||||
|
||||
def move(self, cells, goal):
|
||||
from common import find_way
|
||||
self.final_goal = goal
|
||||
path = find_way(cells, self.grid_pos, self.final_goal, self.walkable_matrix, self.rocks_matrix)
|
||||
if path and len(path) > 1:
|
||||
self.waypoints = path[1:]
|
||||
self.current_target = self.waypoints[0]
|
||||
self.move_progress = 0.0
|
||||
self.start_pos = self.grid_pos
|
||||
self.render_offset = (0.0, 0.0)
|
||||
else:
|
||||
self.final_goal = None
|
||||
|
||||
def create_task(self):
|
||||
self.new_task = []
|
||||
|
||||
#add actions_default_durations dict {func1: dur1, ...}
|
||||
def add_action(self, sprite_name: str, func: function, duration: float):
|
||||
self.new_task.append(Action(sprite_name, func, duration))
|
||||
|
||||
def add_task(self):
|
||||
self.tasks.append(self.new_task)
|
||||
|
||||
def add_interr_task(self):
|
||||
pass
|
||||
#param resume_on_interrupt, Bool
|
||||
#if True
|
||||
# save goal to buffer
|
||||
#if False
|
||||
# action/task_counter = 0
|
||||
#clear goal/wp
|
||||
|
||||
def update(self, time_delta, cell_size, map_obj):
|
||||
self.walkable_matrix = map_obj.walkable_matrix
|
||||
self.rocks_matrix = map_obj.rocks_matrix
|
||||
|
||||
#quick_actions? here?
|
||||
#print(self.waypoints, self.final_goal, self.action_counter, self.task_counter)
|
||||
if self.final_goal is not None:
|
||||
#print(2)
|
||||
self.calc_step(time_delta, cell_size, map_obj)
|
||||
return
|
||||
|
||||
if self.interrupt_task and self.interrupt_action_status == "completed":
|
||||
#print(3)
|
||||
self.action_time = 0.0
|
||||
self.action = self.interrupt_task.pop(0)
|
||||
self.interrupt_action_status = "active"
|
||||
|
||||
#print(f" DEBUG: tasks={len(self.tasks)}, "
|
||||
# f"task_len={len(self.tasks[self.task_counter]) if self.tasks else 0}, "
|
||||
# f"action={self.action is not None}")
|
||||
|
||||
if self.action:
|
||||
#print(self.action_counter, self.task_counter)
|
||||
self.action_time += time_delta
|
||||
self.action.progress = min(1.0, self.action_time / self.action.duration)
|
||||
|
||||
if self.action_time >= self.action.duration:
|
||||
self.action.func()
|
||||
if self.interrupt_action_status == "active":
|
||||
self.interrupt_action_status == "completed"
|
||||
#if not self.inter_task and goal: move to buff_goal from self.pos (add to Object)
|
||||
self.action = None
|
||||
self.action_time = 0.0
|
||||
|
||||
|
||||
elif self.tasks:
|
||||
#print(6)
|
||||
if self.action_counter < len(self.tasks[self.task_counter]):
|
||||
self.action = self.tasks[self.task_counter][self.action_counter]
|
||||
self.action_counter += 1
|
||||
else:
|
||||
self.task_counter += 1
|
||||
self.action_counter = 0
|
||||
if self.task_counter == len(self.tasks):
|
||||
self.task_counter = 0
|
||||
|
||||
self.action = self.tasks[self.task_counter][self.action_counter]
|
||||
self.action_counter += 1
|
||||
self.action_time = 0.0
|
||||
|
||||
|
||||
#elif self.tasks:
|
||||
# if self.action_counter >= len(self.tasks[self.task_counter]):
|
||||
# self.task_counter += 1
|
||||
# self.action_counter = 0
|
||||
# if self.task_counter >= len(self.tasks):
|
||||
# self.task_counter = 0
|
||||
#
|
||||
# self.action = self.tasks[self.task_counter][self.action_counter]
|
||||
# self.action_counter += 1
|
||||
# self.action_time = 0.0
|
||||
|
||||
def patrol(self, cells, area):
|
||||
goal = (random.randint(self.grid_pos[0] - area,
|
||||
self.grid_pos[0] + area),
|
||||
random.randint(self.grid_pos[1] - area,
|
||||
self.grid_pos[1] + area))
|
||||
while goal == self.grid_pos:
|
||||
goal = (random.randint(self.grid_pos[0] - area,
|
||||
self.grid_pos[0] + area),
|
||||
random.randint(self.grid_pos[1] - area,
|
||||
self.grid_pos[1] + area))
|
||||
self.move(cells, goal)
|
||||
|
||||
def move_rand(self, cells, area_start, area_end):
|
||||
goal = (random.randint(area_start, area_end), random.randint(area_start, area_end))
|
||||
while goal == self.grid_pos:
|
||||
goal = (random.randint(area_start, area_end), random.randint(area_start, area_end))
|
||||
self.move(cells, goal)
|
||||
|
||||
@dataclass
|
||||
class Item(Object):
|
||||
@@ -96,7 +254,6 @@ class Container(Item):
|
||||
# content = {}
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class Building(Object):
|
||||
pass
|
||||
pass
|
||||
231
f.txt
Normal file
231
f.txt
Normal file
@@ -0,0 +1,231 @@
|
||||
Elves count: 500 - Current FPS: 58.82
|
||||
Elves count: 500 - Current FPS: 54.35
|
||||
Elves count: 500 - Current FPS: 57.14
|
||||
Elves count: 500 - Current FPS: 55.56
|
||||
Elves count: 500 - Current FPS: 58.14
|
||||
Elves count: 500 - Current FPS: 54.95
|
||||
Elves count: 500 - Current FPS: 61.35
|
||||
Elves count: 500 - Current FPS: 58.14
|
||||
Elves count: 500 - Current FPS: 61.73
|
||||
Elves count: 500 - Current FPS: 45.87
|
||||
Elves count: 500 - Current FPS: 54.35
|
||||
Elves count: 500 - Current FPS: 58.48
|
||||
Elves count: 500 - Current FPS: 59.52
|
||||
Elves count: 500 - Current FPS: 58.48
|
||||
Elves count: 500 - Current FPS: 50.51
|
||||
Elves count: 500 - Current FPS: 55.25
|
||||
Elves count: 500 - Current FPS: 52.36
|
||||
Elves count: 500 - Current FPS: 53.76
|
||||
Elves count: 500 - Current FPS: 52.36
|
||||
Elves count: 500 - Current FPS: 49.02
|
||||
Elves count: 500 - Current FPS: 61.73
|
||||
Elves count: 500 - Current FPS: 57.80
|
||||
Elves count: 500 - Current FPS: 59.52
|
||||
Elves count: 500 - Current FPS: 54.64
|
||||
Elves count: 500 - Current FPS: 54.95
|
||||
Elves count: 500 - Current FPS: 59.52
|
||||
Elves count: 500 - Current FPS: 59.52
|
||||
Elves count: 500 - Current FPS: 60.24
|
||||
Elves count: 500 - Current FPS: 61.73
|
||||
Elves count: 500 - Current FPS: 44.05
|
||||
Elves count: 500 - Current FPS: 58.82
|
||||
Elves count: 500 - Current FPS: 54.05
|
||||
Elves count: 500 - Current FPS: 55.56
|
||||
Elves count: 500 - Current FPS: 58.82
|
||||
Elves count: 500 - Current FPS: 49.50
|
||||
Elves count: 500 - Current FPS: 56.18
|
||||
Elves count: 500 - Current FPS: 58.82
|
||||
Elves count: 500 - Current FPS: 57.47
|
||||
Elves count: 500 - Current FPS: 34.13
|
||||
Elves count: 500 - Current FPS: 48.54
|
||||
Elves count: 500 - Current FPS: 54.64
|
||||
Elves count: 500 - Current FPS: 60.24
|
||||
Elves count: 500 - Current FPS: 57.14
|
||||
Elves count: 500 - Current FPS: 56.50
|
||||
Elves count: 500 - Current FPS: 50.00
|
||||
Elves count: 500 - Current FPS: 60.98
|
||||
Elves count: 500 - Current FPS: 59.88
|
||||
Elves count: 500 - Current FPS: 58.82
|
||||
Elves count: 500 - Current FPS: 43.10
|
||||
Leak: 2232.0 KB per 1000 frames
|
||||
Elves count: 500 - Current FPS: 50.25
|
||||
Elves count: 500 - Current FPS: 41.67
|
||||
Elves count: 500 - Current FPS: 57.80
|
||||
Elves count: 500 - Current FPS: 45.25
|
||||
Elves count: 500 - Current FPS: 49.50
|
||||
Elves count: 500 - Current FPS: 58.48
|
||||
Elves count: 500 - Current FPS: 56.18
|
||||
Elves count: 500 - Current FPS: 52.63
|
||||
Elves count: 500 - Current FPS: 49.02
|
||||
Elves count: 500 - Current FPS: 57.47
|
||||
Elves count: 500 - Current FPS: 55.56
|
||||
Elves count: 500 - Current FPS: 56.18
|
||||
Elves count: 500 - Current FPS: 55.56
|
||||
Elves count: 500 - Current FPS: 59.52
|
||||
Elves count: 500 - Current FPS: 60.24
|
||||
Elves count: 500 - Current FPS: 57.47
|
||||
Elves count: 500 - Current FPS: 60.61
|
||||
Elves count: 500 - Current FPS: 60.61
|
||||
Elves count: 500 - Current FPS: 46.30
|
||||
Elves count: 500 - Current FPS: 58.82
|
||||
Elves count: 500 - Current FPS: 59.52
|
||||
Elves count: 500 - Current FPS: 54.35
|
||||
Elves count: 500 - Current FPS: 59.17
|
||||
Elves count: 500 - Current FPS: 54.95
|
||||
Elves count: 500 - Current FPS: 54.64
|
||||
Elves count: 500 - Current FPS: 48.08
|
||||
Elves count: 500 - Current FPS: 41.49
|
||||
Elves count: 500 - Current FPS: 54.35
|
||||
Elves count: 500 - Current FPS: 56.50
|
||||
Elves count: 500 - Current FPS: 60.24
|
||||
Elves count: 500 - Current FPS: 61.35
|
||||
Elves count: 500 - Current FPS: 59.17
|
||||
Elves count: 500 - Current FPS: 50.25
|
||||
Elves count: 500 - Current FPS: 60.98
|
||||
Elves count: 500 - Current FPS: 52.63
|
||||
Elves count: 500 - Current FPS: 57.80
|
||||
Elves count: 500 - Current FPS: 54.05
|
||||
Elves count: 500 - Current FPS: 51.28
|
||||
Elves count: 500 - Current FPS: 52.08
|
||||
Elves count: 500 - Current FPS: 59.52
|
||||
Elves count: 500 - Current FPS: 61.73
|
||||
Elves count: 500 - Current FPS: 54.05
|
||||
Elves count: 500 - Current FPS: 59.17
|
||||
Elves count: 500 - Current FPS: 54.64
|
||||
Elves count: 500 - Current FPS: 50.51
|
||||
Elves count: 500 - Current FPS: 51.28
|
||||
Elves count: 500 - Current FPS: 59.52
|
||||
Elves count: 500 - Current FPS: 59.52
|
||||
Elves count: 500 - Current FPS: 60.61
|
||||
Elves count: 500 - Current FPS: 51.28
|
||||
Elves count: 500 - Current FPS: 60.98
|
||||
Elves count: 500 - Current FPS: 57.47
|
||||
Elves count: 500 - Current FPS: 52.63
|
||||
Elves count: 500 - Current FPS: 50.00
|
||||
Elves count: 500 - Current FPS: 59.88
|
||||
Elves count: 500 - Current FPS: 54.95
|
||||
Elves count: 500 - Current FPS: 58.14
|
||||
Elves count: 500 - Current FPS: 45.45
|
||||
Elves count: 500 - Current FPS: 52.91
|
||||
Elves count: 500 - Current FPS: 32.57
|
||||
Elves count: 500 - Current FPS: 29.07
|
||||
Elves count: 500 - Current FPS: 45.25
|
||||
Elves count: 500 - Current FPS: 30.03
|
||||
Elves count: 500 - Current FPS: 45.66
|
||||
Elves count: 500 - Current FPS: 43.86
|
||||
Elves count: 500 - Current FPS: 38.91
|
||||
Elves count: 500 - Current FPS: 35.97
|
||||
Elves count: 500 - Current FPS: 34.01
|
||||
Elves count: 500 - Current FPS: 44.84
|
||||
Elves count: 500 - Current FPS: 36.63
|
||||
Elves count: 500 - Current FPS: 39.84
|
||||
Elves count: 500 - Current FPS: 42.55
|
||||
Elves count: 500 - Current FPS: 31.65
|
||||
Elves count: 500 - Current FPS: 30.96
|
||||
Elves count: 500 - Current FPS: 37.59
|
||||
Elves count: 500 - Current FPS: 39.53
|
||||
Elves count: 500 - Current FPS: 45.87
|
||||
Elves count: 500 - Current FPS: 37.31
|
||||
Elves count: 500 - Current FPS: 35.34
|
||||
Elves count: 500 - Current FPS: 39.22
|
||||
Elves count: 500 - Current FPS: 47.17
|
||||
Elves count: 500 - Current FPS: 39.37
|
||||
Elves count: 500 - Current FPS: 25.25
|
||||
Elves count: 500 - Current FPS: 35.97
|
||||
Elves count: 500 - Current FPS: 48.54
|
||||
Elves count: 500 - Current FPS: 44.64
|
||||
Elves count: 500 - Current FPS: 43.67
|
||||
Elves count: 500 - Current FPS: 28.17
|
||||
Elves count: 500 - Current FPS: 35.97
|
||||
Elves count: 500 - Current FPS: 31.06
|
||||
Elves count: 500 - Current FPS: 47.62
|
||||
Elves count: 500 - Current FPS: 37.59
|
||||
Elves count: 500 - Current FPS: 42.19
|
||||
Elves count: 500 - Current FPS: 50.25
|
||||
Elves count: 500 - Current FPS: 35.59
|
||||
Elves count: 500 - Current FPS: 45.45
|
||||
Elves count: 500 - Current FPS: 45.45
|
||||
Elves count: 500 - Current FPS: 28.65
|
||||
Elves count: 500 - Current FPS: 24.15
|
||||
Elves count: 500 - Current FPS: 42.55
|
||||
Leak: 3284.0 KB per 1000 frames
|
||||
Elves count: 500 - Current FPS: 42.19
|
||||
Elves count: 500 - Current FPS: 35.09
|
||||
Elves count: 500 - Current FPS: 42.19
|
||||
Elves count: 500 - Current FPS: 51.55
|
||||
Elves count: 500 - Current FPS: 32.36
|
||||
Elves count: 500 - Current FPS: 39.22
|
||||
Elves count: 500 - Current FPS: 35.59
|
||||
Elves count: 500 - Current FPS: 28.57
|
||||
Elves count: 500 - Current FPS: 22.73
|
||||
Elves count: 500 - Current FPS: 31.85
|
||||
Elves count: 500 - Current FPS: 26.74
|
||||
Elves count: 500 - Current FPS: 24.94
|
||||
Elves count: 500 - Current FPS: 22.08
|
||||
Elves count: 500 - Current FPS: 24.51
|
||||
Elves count: 500 - Current FPS: 34.97
|
||||
Elves count: 500 - Current FPS: 30.40
|
||||
Elves count: 500 - Current FPS: 47.62
|
||||
Elves count: 500 - Current FPS: 40.16
|
||||
Elves count: 500 - Current FPS: 55.87
|
||||
Elves count: 500 - Current FPS: 33.78
|
||||
Elves count: 500 - Current FPS: 50.00
|
||||
Elves count: 500 - Current FPS: 50.51
|
||||
Elves count: 500 - Current FPS: 33.00
|
||||
Elves count: 500 - Current FPS: 54.64
|
||||
Elves count: 500 - Current FPS: 61.35
|
||||
Elves count: 500 - Current FPS: 51.02
|
||||
Elves count: 500 - Current FPS: 54.35
|
||||
Elves count: 500 - Current FPS: 50.51
|
||||
Elves count: 500 - Current FPS: 53.19
|
||||
Elves count: 500 - Current FPS: 53.76
|
||||
Elves count: 500 - Current FPS: 39.37
|
||||
Elves count: 500 - Current FPS: 49.50
|
||||
Elves count: 500 - Current FPS: 60.24
|
||||
Elves count: 500 - Current FPS: 47.17
|
||||
Elves count: 500 - Current FPS: 54.64
|
||||
Elves count: 500 - Current FPS: 60.61
|
||||
Elves count: 500 - Current FPS: 56.50
|
||||
Elves count: 500 - Current FPS: 58.48
|
||||
Elves count: 500 - Current FPS: 58.82
|
||||
Elves count: 500 - Current FPS: 52.36
|
||||
Elves count: 500 - Current FPS: 57.47
|
||||
Elves count: 500 - Current FPS: 61.73
|
||||
Elves count: 500 - Current FPS: 60.61
|
||||
Elves count: 500 - Current FPS: 39.06
|
||||
Elves count: 500 - Current FPS: 51.55
|
||||
Elves count: 500 - Current FPS: 56.82
|
||||
Elves count: 500 - Current FPS: 59.52
|
||||
Elves count: 500 - Current FPS: 54.64
|
||||
Elves count: 500 - Current FPS: 54.95
|
||||
Elves count: 500 - Current FPS: 56.50
|
||||
Elves count: 500 - Current FPS: 52.63
|
||||
Elves count: 500 - Current FPS: 59.17
|
||||
Elves count: 500 - Current FPS: 55.56
|
||||
Elves count: 500 - Current FPS: 58.82
|
||||
Elves count: 500 - Current FPS: 55.87
|
||||
Elves count: 500 - Current FPS: 48.08
|
||||
Elves count: 500 - Current FPS: 60.24
|
||||
Elves count: 500 - Current FPS: 51.55
|
||||
Elves count: 500 - Current FPS: 58.14
|
||||
Elves count: 500 - Current FPS: 57.14
|
||||
Elves count: 500 - Current FPS: 47.85
|
||||
Elves count: 500 - Current FPS: 50.00
|
||||
Elves count: 500 - Current FPS: 47.62
|
||||
Elves count: 500 - Current FPS: 56.18
|
||||
Elves count: 500 - Current FPS: 55.56
|
||||
Elves count: 500 - Current FPS: 53.48
|
||||
Elves count: 500 - Current FPS: 52.91
|
||||
Elves count: 500 - Current FPS: 60.98
|
||||
Elves count: 500 - Current FPS: 57.14
|
||||
Elves count: 500 - Current FPS: 34.60
|
||||
Elves count: 500 - Current FPS: 41.84
|
||||
Elves count: 500 - Current FPS: 59.88
|
||||
Elves count: 500 - Current FPS: 49.75
|
||||
Elves count: 500 - Current FPS: 47.62
|
||||
Elves count: 500 - Current FPS: 50.51
|
||||
Elves count: 500 - Current FPS: 35.97
|
||||
Elves count: 500 - Current FPS: 57.47
|
||||
Elves count: 500 - Current FPS: 55.56
|
||||
Elves count: 500 - Current FPS: 45.25
|
||||
Elves count: 500 - Current FPS: 35.59
|
||||
21
main.py
21
main.py
@@ -1,8 +1,27 @@
|
||||
import eb_engine
|
||||
#import os
|
||||
#os.environ['PYTHONJIT'] = '1'
|
||||
|
||||
def main():
|
||||
e = eb_engine.Engine()
|
||||
e.main_loop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
# todo:
|
||||
# прокрутка баг консоль и карта
|
||||
# устроить краш тест поиску пути, запустив много объектов на маленьком поле, успел заметить баги
|
||||
# добавить функцию движения за каким-то объектом
|
||||
# сделать, чтобы в случае отменненого движения не телепортировался назад, а плавно
|
||||
# приступаем к логике
|
||||
# сделать по аналогии с текущей клеткой текущий объект
|
||||
|
||||
# посмотреть как в clock = pygame.time.Clock() работает фпс
|
||||
# перемещать оъект в другую клетку при половине офсета
|
||||
|
||||
# техдолг Егору
|
||||
# убрать cells и mapobject creature - перенести нужную логику в методы Map
|
||||
# система имен спрайтов и Action - реализовать
|
||||
# рисовать группой спрайтов
|
||||
# нужен ли теперь start_pos? grid_pos?
|
||||
# class Task с проверками выполнения экшонов
|
||||
27
plan.txt
Normal file
27
plan.txt
Normal file
@@ -0,0 +1,27 @@
|
||||
1. Доработка системы задач: класс Task, новые задачи, проработка старых;
|
||||
|
||||
2. Доработка движка и приведение его структуры в порядок:
|
||||
- вынос всех функций карты в карту, объекты знают свою позицию и им этого хватит.
|
||||
взаимодействия с картой и другими объектами должно происходить только в методе движения, остальные методы должны абстрагироваться от карты;
|
||||
|
||||
- вынос рендера в класс Render. Карта занимается только своими клеткам. Метод
|
||||
draw_map должен только готовить текстуру для Render, который будет ее рисовать;
|
||||
|
||||
- мини-движок поиска пути. class Pathfinder, который хранит в себе кэши,
|
||||
выбирает оптимальный способ поиска пути для конкретной ситуации. Для этого
|
||||
нужно ещё раз протестировать все способы, привести к единообразию интерфейсов.
|
||||
Задокументировать. Возможно понадобится вынос поиска пути в отдельный движок
|
||||
на другом языке и многопоточностью;
|
||||
|
||||
- привести в порядок Main Loop;
|
||||
|
||||
- вынести хранение и обработку объектов из карты в ObjectManager;
|
||||
|
||||
- сделать фундамент для MapManager, пока не развивать, но надо исходить из того
|
||||
что одновременно может рендериться несколько карт;
|
||||
|
||||
3. Оптимизация.
|
||||
- проверяем, есть ли объект в клетке только перед непосредственным перемещением в ячейку
|
||||
Cells, а не каждый calc_step; + (исправить визуальный баг, см комменты calc_step)
|
||||
- перестаём учитывать объекты в алгоритме поиска пути; - (попробовать ещё раз, подумать)
|
||||
- заранее передаем в алгоритм карту препятствий; +
|
||||
@@ -50,8 +50,7 @@ scale_image() вызывается 150×150=22,500 раз в секунду пр
|
||||
# проверить у ллм на ошибки - РЕГУЛЯРНАЯ АКТИВНОСТЬ:
|
||||
# - deepcopy +
|
||||
# - общие +
|
||||
# !!! ДОБАВИТЬ ПРОКРУТКУ И МАСШТАБ КАРТЫ ДЛЯ МЫШИ !!!
|
||||
#
|
||||
#
|
||||
# ДОДЕЛАТЬ move для Creature - хранить pos в объекте ???
|
||||
#
|
||||
# ПРОВЕРИТЬ МЕНЯЕТСЯ ЛИ ПЕРЕДАННЫЙ В ОБЪЕКТ cells и если да,
|
||||
|
||||
6
requirements.txt
Normal file
6
requirements.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
pathfinding==1.0.20
|
||||
psutil==7.2.2
|
||||
pygame-ce==2.5.6
|
||||
pygame_gui==0.6.14
|
||||
python-i18n==0.3.9
|
||||
typing_extensions==4.15.0
|
||||
Reference in New Issue
Block a user