initial sprite animation support

This commit is contained in:
shiva404
2026-02-15 18:17:31 +03:00
parent ffc87c9591
commit ab58803373
30 changed files with 228 additions and 173 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -6,7 +6,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -18,7 +18,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -30,7 +30,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -42,7 +42,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -54,7 +54,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -66,7 +66,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -78,7 +78,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -90,7 +90,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -102,7 +102,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -114,7 +114,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -128,7 +128,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -140,7 +140,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -152,7 +152,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -164,7 +164,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -176,7 +176,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -188,7 +188,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -200,7 +200,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -212,7 +212,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -224,7 +224,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -236,7 +236,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -250,7 +250,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -262,7 +262,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -274,7 +274,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -286,7 +286,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -298,7 +298,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -310,7 +310,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -322,7 +322,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -334,7 +334,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -346,7 +346,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -358,7 +358,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -372,7 +372,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -384,7 +384,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -396,7 +396,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -408,7 +408,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -420,7 +420,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -432,7 +432,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -444,7 +444,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -456,7 +456,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -468,7 +468,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -480,7 +480,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -494,7 +494,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -506,7 +506,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -518,7 +518,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -530,7 +530,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -542,7 +542,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -554,7 +554,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -566,7 +566,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -578,7 +578,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -590,7 +590,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -602,7 +602,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -616,7 +616,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -628,7 +628,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -640,7 +640,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -652,7 +652,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -664,7 +664,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -676,7 +676,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -688,7 +688,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -700,7 +700,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -712,7 +712,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -724,7 +724,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -738,7 +738,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -750,7 +750,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -762,7 +762,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -774,7 +774,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -786,7 +786,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -798,7 +798,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -810,7 +810,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -822,7 +822,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -834,7 +834,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -846,7 +846,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -860,7 +860,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -872,7 +872,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -884,7 +884,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -896,7 +896,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -908,7 +908,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -920,7 +920,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -932,7 +932,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -944,7 +944,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -956,7 +956,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}
@@ -968,7 +968,7 @@
"terrain_obj": {
"id": "1",
"name": "2",
"sprite": "grass_small"
"sprite_name": "grass_small"
},
"creature_obj": {},
"item_obj": {}

View File

@@ -1,12 +1,11 @@
from common import pygame, os, json, uuid, deepcopy, dataclass, field
import eb_objects
import eb_terrain
import eb_creatures
import eb_terrain_objects
import eb_creature_objects
cell_classes = {"Ground": eb_terrain.Ground}
cell_classes = {"Ground": eb_terrain_objects.Ground}
main_dir = os.path.dirname(os.path.abspath(__file__))
sprites_dir = os.path.join(main_dir, "res", "sprites")
#file_path = os.path.join(main_dir, "res", "sprites", "grass_small.png")
def scale_image(image, n):
orig_size = image.get_size()
@@ -22,16 +21,18 @@ class Cell:
@dataclass
class Map:
name: str
cells: dict = field(default_factory = dict)
color: str = "gray57"
target_color: str = "gold"
size: int = 150
bord: int = 5
scale: float = 1
cam_x: int = 0
cam_y: int = 0
cell_dist: int = 2
name: str
sprites: dict
sprites_refresh: int = 60
cells: dict = field(default_factory = dict)
color: str = "gray57"
target_color: str = "gold"
size: int = 150
bord: int = 3
scale: float = 1
cam_x: int = 0
cam_y: int = 0
cell_dist: int = 1
def __post_init__(self):
self.cells = {}
@@ -43,7 +44,7 @@ class Map:
final_cell = Cell(cell_classes[cell["type"]](**cell["cell"]["terrain_obj"]))
self.cells[line].append(deepcopy(final_cell))
def draw(self, screen, sprites, grid = True):
def draw(self, screen, current_frame, grid = True):
for l in range(len(self.cells)):
for i, cell in enumerate(self.cells[l]):
x = int((i * self.size + self.cam_x) * self.scale)
@@ -51,11 +52,19 @@ class Map:
w = int(self.size * self.scale - self.cell_dist)
h = int(self.size * self.scale - self.cell_dist)
#add if scale != prev_scale: no scale
scaled = scale_image(sprites[cell.terrain_obj.sprite], self.scale)
# add if scale != prev_scale: no scale
# current frame to decide, upgrade sprite or not sprite_state
scaled = scale_image(self.sprites[cell.terrain_obj.sprite_name][cell.terrain_obj.sprite_state], self.scale)
scaled_rect = scaled.get_rect(center = (x + w/2, y + h/2))
screen.blit(scaled, scaled_rect)
if cell.terrain_obj.sprite_state == len(self.sprites[cell.terrain_obj.sprite_name]) - 1:
if current_frame % self.sprites_refresh == 0:
cell.terrain_obj.sprite_state = 0
elif current_frame % self.sprites_refresh == 0:
cell.terrain_obj.sprite_state += 1
if grid:
pygame.draw.rect(screen, self.color, pygame.Rect(x, y, w, h), self.bord)
@@ -74,19 +83,37 @@ class Engine:
pygame.display.set_caption('Elvenbane')
self.screen = pygame.display.set_mode((self.width, self.height))
self.load_sprites()
print("The engine has started. Sprites were successfully loaded.\n")
def load_sprites(self, folder_path = sprites_dir):
for filename in os.listdir(folder_path):
if filename.lower().endswith('.png'):
name = os.path.splitext(filename)[0]
self.sprites[name] = pygame.image.load(os.path.join(folder_path, filename)).convert_alpha()
self.sprites = {}
files = [f for f in os.listdir(folder_path) if f.lower().endswith('.png')]
groups = {}
for f in files:
name = os.path.splitext(f)[0]
if '_' in name and name.rsplit('_', 1)[0].count('_') >= 1:
prefix = name.rsplit('_', 1)[0]
num = int(name.rsplit('_', 1)[1])
groups.setdefault(prefix, []).append((num, f))
for prefix, items in groups.items():
items.sort()
self.sprites[prefix] = [
pygame.image.load(os.path.join(folder_path, f)).convert_alpha()
for num, f in items
]
def main_loop(self):
easy_map = Map("def_map.json", self.sprites)
#sp = eb_objects.Sprite(self.sprites, "elf_watching")
#gr = pygame.image.load(file_path).convert_alpha()
clock = pygame.time.Clock()
running = True
unlock = True
easy_map = Map("def_map.json")
#gr = pygame.image.load(file_path).convert_alpha()
current_frame = 0
max_fps = 60
while running:
# poll for events
@@ -98,18 +125,18 @@ class Engine:
# fill the screen with a color to wipe away anything from last frame
self.screen.fill("chartreuse4")
easy_map.draw(self.screen, self.sprites)
easy_map.draw(self.screen, current_frame + 1)
if unlock:
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
easy_map.cam_y -= self.camera_step
if keys[pygame.K_s]:
easy_map.cam_y += self.camera_step
if keys[pygame.K_s]:
easy_map.cam_y -= self.camera_step
if keys[pygame.K_a]:
easy_map.cam_x -= self.camera_step
if keys[pygame.K_d]:
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
if keys[pygame.K_e] and easy_map.scale >= self.scale_step:
@@ -117,9 +144,12 @@ class Engine:
if keys[pygame.K_ESCAPE]:
running = False
#print(current_frame + 1)
current_frame = (current_frame + 1) % max_fps
# flip() the display to put your work on screen
pygame.display.flip()
# limits FPS to 60
clock.tick(60)
clock.tick(max_fps)
pygame.quit()

View File

@@ -1,10 +1,12 @@
from common import dataclass
from common import dataclass, field
@dataclass
class Object:
id: str
name: str
sprite: str
sprite_name: str
sprite_state: int = 0
@dataclass
class Terrain(Object):
@@ -13,6 +15,9 @@ class Terrain(Object):
@dataclass
class Creature(Object):
pass
#actions
#tasks
#items
@dataclass
class Item(Object):

16
main.py
View File

@@ -9,18 +9,22 @@ if __name__ == "__main__":
# Отрисовка голой сетки, прокрутка, масштаб +
# Отрисовка спрайтов:
# - сделать масштабирование в соотв. с клеткой +
# - посмотреть класс спрайта или сделать свой
# - добавить отрисовку существ и предметов
# - посмотреть класс спрайта или сделать свой +
# - добавить отрисовку существ и предметов с анимацией +
# почитать про Surface, Display, доку к pygame-gui
# Начало гуя - кнопка, строка ввода, клик
# Поиск пути
# Поиск пути, очередь задач для существ
# Редактор карты
# Охотник -> деревня
# Простой, но основательный гуй внизу экрана, глобальная карта и перемещение
# деревня на соседской локации и торговля с ней
# перемещение по воде, течение
# проверить у ллм на ошибки:
# - deepcopy
# - общие
# проверить у ллм на ошибки - РЕГУЛЯРНАЯ АКТИВНОСТЬ:
# - deepcopy +
# - общие +
main()
#instead of Sprite flow load_sprites function was changed:
#gathering the number of sprites with the same names before second _ and hold it at
#sprites dict. also now sprites must be named as objectname_action_number

37
problems.txt Normal file
View File

@@ -0,0 +1,37 @@
pygame.FULLSCREEN create a fullscreen display
pygame.DOUBLEBUF only applicable with OPENGL
pygame.HWSURFACE (obsolete in pygame 2) hardware accelerated, only in FULLSCREEN
pygame.OPENGL create an OpenGL-renderable display
pygame.RESIZABLE display window should be sizeable
pygame.NOFRAME display window will have no border or controls
pygame.SCALED resolution depends on desktop size and scale graphics
pygame.SHOWN window is opened in visible mode (default)
pygame.HIDDEN window is opened in hidden mode
Проблема 2: Копирование Cell
В цикле создания клеток final_cell = Cell(cell_classes[cell["type"]](**cell["cell"]["terrain_obj"])) создаётся terrain_obj, а затем deepcopy(final_cell) копирует Cell. Но если terrain_obj содержит мутабельные атрибуты (например, mutable sprite или вложенные объекты из eb_terrain), все клетки поделят эти вложенные объекты, вызывая визуальные артефакты (одинаковые спрайты изменяются вместе).
Исправление с deepcopy:
Примените deepcopy к terrain_obj перед передачей в Cell:
python
terrain_kwargs = deepcopy(cell["cell"]["terrain_obj"])
final_cell = Cell(cell_classes[cell["type"]](**terrain_kwargs))
self.cells[line].append(final_cell) # Без лишнего deepcopy, если terrain_obj уже глубокая копия
4. Неправильный доступ к JSON
python
for cell in buff[str(line)]: # ❌ buff[line] может отсутствовать
6. Отсутствует проверка существования спрайта
python
scaled = scale_image(sprites[cell.terrain_obj.sprite], self.scale) # KeyError!
Проблемы производительности
7. Масштабирование каждый кадр
scale_image() вызывается 150×150=22,500 раз в секунду при 60 FPS. Кэшируйте масштабированные спрайты.

View File

@@ -4,7 +4,7 @@ from copy import deepcopy
width = 10
height = 8
grass_def = {"id": "1", "name": "2", "sprite": "grass_small"}
grass_def = {"id": "1", "name": "2", "sprite_name": "grass_small"}
cell_def = {"type": "Ground", "cell": {"terrain_obj": grass_def, "creature_obj": {}, "item_obj": {}}}
out = {}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

BIN
res/sprites/elf_left_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 KiB

BIN
res/sprites/elf_right_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
res/textures/water-1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

BIN
res/textures/water-10.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 KiB

BIN
res/textures/water-3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

BIN
res/textures/water-4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
res/textures/water-6.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

BIN
res/textures/water-8.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

View File

@@ -1,15 +1,11 @@
#o = eb_terrain.Ground(1, 1, 1)
#c = eb_creatures.Unit(1, 1, 1)
#print(isinstance(o, eb_objects.Object))
#print(isinstance(o, eb_objects.Terrain))
#print(isinstance(c, eb_objects.Terrain))
o = eb_terrain.Ground(1, 1, 1)
c = eb_creatures.Unit(1, 1, 1)
print(isinstance(o, eb_objects.Object))
print(isinstance(o, eb_objects.Terrain))
print(isinstance(c, eb_objects.Terrain))
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
original = pygame.image.load('sprite.png').convert_alpha()
orig_rect = original.get_rect(center=(200, 300))
@@ -18,7 +14,6 @@ def scale_image(image, n):
new_size = (int(orig_size[0] * n), int(orig_size[1] * n))
return pygame.transform.scale(image, new_size)
n = 1.5 # Example: 1.5x larger
scaled = scale_image(original, n)
scaled_rect = scaled.get_rect(center=(600, 300))
@@ -27,46 +22,30 @@ screen.blit(scaled, scaled_rect) # Scaled by n
def load_sprites_from_folder(self, folder_path = sprites_dir):
"""
Загружает все PNG изображения из указанной папки в словарь.
Ключи - имена файлов без расширения, значения - pygame.Surface
"""
# Полный путь к папке со спрайтами относительно скрипта
script_dir = os.path.dirname(os.path.abspath(__file__))
full_path = os.path.join(script_dir, folder_path)
sprites = {}
if not os.path.exists(full_path):
print(f"❌ Папка не найдена: {full_path}")
return sprites
print(f"🔍 Сканируем папку: {full_path}")
# Проходим по всем файлам в папке
for filename in os.listdir(full_path):
if filename.lower().endswith('.png'):
# Убираем расширение .png для ключа
name = os.path.splitext(filename)[0]
filepath = os.path.join(full_path, filename)
try:
# Загружаем изображение
surface = pygame.image.load(filepath).convert_alpha()
self.sprites[name] = surface
print(f"✅ Загружен: {name} ({surface.get_size()})")
except pygame.error as e:
print(f"❌ Ошибка загрузки {filename}: {e}")
print(f"🎉 Загружено {len(sprites)} спрайтов")
def load_sprites_from_folder(self, folder_path = sprites_dir):
"""
Загружает все PNG изображения из указанной папки в словарь.
Ключи - имена файлов без расширения, значения - pygame.Surface
"""
# Полный путь к папке со спрайтами относительно скрипта
script_dir = os.path.dirname(os.path.abspath(__file__))
full_path = os.path.join(script_dir, folder_path)
sprites = {}
if not os.path.exists(full_path):
print(f"❌ Папка не найдена: {full_path}")
return sprites
print(f"🔍 Сканируем папку: {full_path}")
# Проходим по всем файлам в папке
for filename in os.listdir(full_path):
if filename.lower().endswith('.png'):
# Убираем расширение .png для ключа
name = os.path.splitext(filename)[0]
filepath = os.path.join(full_path, filename)
try:
# Загружаем изображение
surface = pygame.image.load(filepath).convert_alpha()
self.sprites[name] = surface
print(f"✅ Загружен: {name} ({surface.get_size()})")
except pygame.error as e:
print(f"❌ Ошибка загрузки {filename}: {e}")
print(f"🎉 Загружено {len(sprites)} спрайтов")