pre commit, make CAPS tasks from main

This commit is contained in:
shiva404
2026-02-20 02:09:43 +03:00
parent 197469350d
commit 171eff1434
10 changed files with 284 additions and 126 deletions

Binary file not shown.

Binary file not shown.

1
classes.py Normal file
View File

@@ -0,0 +1 @@
from eb_terrain_objects import Rock

View File

@@ -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:
@@ -14,3 +20,56 @@ def path_exists(data, path):
else:
return False
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

View File

@@ -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": {}

View File

@@ -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,9 +62,17 @@ 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)
@@ -74,8 +84,23 @@ class Map:
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,7 +122,18 @@ 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:
@@ -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()

View File

@@ -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):

27
main.py
View File

@@ -37,8 +37,35 @@ if __name__ == "__main__":
# - deepcopy +
# - общие +
main()
#
# ДОДЕЛАТЬ move для Creature - хранить pos в объекте
#
# ПРОВЕРИТЬ МЕНЯЕТСЯ ЛИ ПЕРЕДАННЫЙ В ОБЪЕКТ cells и еслт да,
# перенести всё взаимодействие с картой в объекты, карта только хранит cells
# и готовит данные для отрисовки Render'ом
#
# ИГРОВОЙ ТАКТ? или только для действий их длительность?
#
# ПОСМОТРЕТЬ ПО КОММИТАМ ЗАЧЕМ БЫЛ НУЖЕН path_exists, удалить?
#
# добавил гуй, динамическая консоль, всё работает, но:
# - слоп, почистить
# - мини-баг - если первые вводимые буквы совпадают с клавишами управления, один раз успевает проскочить до лока. некритично.
# - при вводе текста нет прокрутки к концу
# - плавающий баг - если повводить текст, а потом закрыть консоль, игра не закроется по эскейпу.
#
# исправить поиск пути чтобы он учитывал других существ
#
# в дальнейшем вся отрисовка переедет в класс рендер,
# карта будет только вовзращать поверхность для отрисовки или даже просто Cells
# active_cell переедет в класс Control
#
# НАЙТИ В КОДЕ ГДЕ Я ТАК НЕ СДЕЛАЛ И ИСПРАВИТЬ - НАШЕЛ ОДНУ, ПОИСКАТЬ ЕЩЕ
#if a is None:
# print("a это точно None")
#
# Альтернатива
#if a is not None:
# print("a не None")
#
#