Finally fixed sprite caching. For now it works only for one map, need to develop mapmanager and have a list of cached sprites for each map.

This commit is contained in:
shiva404
2026-02-16 02:46:28 +03:00
parent f89e0a86c4
commit 0e0bf1f84e
7 changed files with 57 additions and 57 deletions

Binary file not shown.

View File

@@ -5,12 +5,6 @@ from dataclasses import dataclass, field
from copy import deepcopy from copy import deepcopy
import pygame import pygame
def scale_image(image, n):
orig_size = image.get_size()
new_size = (int(orig_size[0] * n), int(orig_size[1] * n))
return pygame.transform.smoothscale(image, new_size)
def path_exists(data, path): def path_exists(data, path):
current = data current = data
for key in path: for key in path:

View File

@@ -12,6 +12,10 @@ cell_classes = {"grass_small": eb_terrain_objects.Ground,
main_dir = os.path.dirname(os.path.abspath(__file__)) main_dir = os.path.dirname(os.path.abspath(__file__))
sprites_dir = os.path.join(main_dir, "res", "sprites") sprites_dir = os.path.join(main_dir, "res", "sprites")
#class MapManager
#class Event
#class EventManager
@dataclass @dataclass
class Cell: class Cell:
terrain_obj: any terrain_obj: any
@@ -23,16 +27,16 @@ class Cell:
class Map: class Map:
name: str name: str
sprites: dict sprites: dict
sprites_refresh: int = 60 sprites_refresh: int = 60
cells: dict = field(default_factory = dict) cells: dict = field(default_factory = dict)
color: str = "gray57" color: str = "gray57"
target_color: str = "gold" target_color: str = "gold"
size: int = 150 size: int = 150
bord: int = 3 bord: int = 3
scale: float = 1 scale: float = 1
cam_x: int = 0 cam_x: int = 0
cam_y: int = 0 cam_y: int = 0
cell_dist: int = 1 cell_dist: int = 1
def __post_init__(self): def __post_init__(self):
self.cells = {} self.cells = {}
@@ -60,8 +64,10 @@ class Map:
"screen": screen} "screen": screen}
cell.terrain_obj.draw(dd) cell.terrain_obj.draw(dd)
if cell.item_obj: if cell.item_obj:
cell.item_obj.draw(dd) cell.item_obj.draw(dd)
if cell.creature_obj: if cell.creature_obj:
cell.creature_obj.draw(dd) cell.creature_obj.draw(dd)
@@ -70,20 +76,25 @@ class Map:
@dataclass @dataclass
class Engine: class Engine:
sprites: dict = field(default_factory = dict) sprites: dict = field(default_factory = dict)
screen: pygame.Surface = ((1, 1)) cached_sprites: dict = field(default_factory = dict)
width: int = 1600 screen: pygame.Surface = ((1, 1))
height: int = 800 width: int = 1600
camera_step: int = 10 height: int = 800
scale_step: float = 0.01 camera_step: int = 10
scale_step: float = 0.01
spr_scale: float = 1
def __post_init__(self): def __post_init__(self):
self.sprites = {} self.sprites = {}
pygame.init() pygame.init()
pygame.display.set_caption('Elvenbane') pygame.display.set_caption('Elvenbane')
self.screen = pygame.display.set_mode((self.width, self.height), pygame.HWSURFACE | pygame.DOUBLEBUF) self.screen = pygame.display.set_mode((self.width, self.height), pygame.HWSURFACE | pygame.DOUBLEBUF)
self.load_sprites()
print("The engine has started. Sprites were successfully loaded.\n") print("The engine has started. Sprites were successfully loaded.\n")
self.load_sprites()
print("Sprites were successfully loaded.\n")
self.cached_sprites = deepcopy(self.sprites)
print("Sprites were successfully cached.\n")
def load_sprites(self, folder_path = sprites_dir): def load_sprites(self, folder_path = sprites_dir):
self.sprites = {} self.sprites = {}
@@ -104,8 +115,20 @@ class Engine:
for num, f in items for num, f in items
] ]
def scale_image(self, image):
orig_size = image.get_size()
new_size = (int(orig_size[0] * self.spr_scale), int(orig_size[1] * self.spr_scale))
return pygame.transform.smoothscale(image, new_size)
def scale_sprites(self):
for sp_name, sprite_list in self.sprites.items():
for i, sprite in enumerate(sprite_list):
scaled = self.scale_image(sprite)
self.cached_sprites[sp_name][i] = scaled
def main_loop(self): def main_loop(self):
easy_map = Map("def_map.json", self.sprites) easy_map = Map("def_map.json", self.cached_sprites)
#sp = eb_objects.Sprite(self.sprites, "elf_watching") #sp = eb_objects.Sprite(self.sprites, "elf_watching")
#gr = pygame.image.load(file_path).convert_alpha() #gr = pygame.image.load(file_path).convert_alpha()
@@ -119,16 +142,16 @@ class Engine:
# profiling # profiling
process = psutil.Process(os.getpid()) #process = psutil.Process(os.getpid())
gc.collect() #gc.collect()
mem_before = process.memory_info().rss / 1024 #mem_before = process.memory_info().rss / 1024
while running: while running:
#pygame.event.clear() #pygame.event.clear()
if global_counter % 1000 == 0: #if global_counter % 1000 == 0:
gc.collect() # gc.collect()
mem_after = process.memory_info().rss / 1024 # mem_after = process.memory_info().rss / 1024
print(f"Leak: {mem_after - mem_before:.1f} KB per 1000 frames") # print(f"Leak: {mem_after - mem_before:.1f} KB per 1000 frames")
# poll for events # poll for events
# pygame.QUIT event means the user clicked X to close your window # pygame.QUIT event means the user clicked X to close your window
@@ -154,8 +177,12 @@ class Engine:
easy_map.cam_x -= self.camera_step easy_map.cam_x -= self.camera_step
if keys[pygame.K_q]: if keys[pygame.K_q]:
easy_map.scale += self.scale_step easy_map.scale += self.scale_step
self.spr_scale += self.scale_step
self.scale_sprites()
if keys[pygame.K_e] and easy_map.scale >= self.scale_step: if keys[pygame.K_e] and easy_map.scale >= self.scale_step:
easy_map.scale -= self.scale_step easy_map.scale -= self.scale_step
self.spr_scale -= self.scale_step
self.scale_sprites()
if keys[pygame.K_ESCAPE]: if keys[pygame.K_ESCAPE]:
running = False running = False

View File

@@ -1,4 +1,4 @@
from common import deepcopy, dataclass, field, scale_image, path_exists from common import deepcopy, dataclass, field, path_exists
@dataclass @dataclass
class Object: class Object:
@@ -6,37 +6,15 @@ class Object:
name: str name: str
sprite_name: str sprite_name: str
sprite_state: int = 0 sprite_state: int = 0
#sprite_scale: int = 1
#sprite_cache: dict = field(default_factory = dict)
#sprite_cache_upd: int = 100
#
#def cache_sprite(self, sprites):
# if self.sprite_name not in self.sprite_cache:
# self.sprite_cache[self.sprite_name] = {}
# self.sprite_cache[self.sprite_name][self.sprite_state] = deepcopy(sprites[self.sprite_name][self.sprite_state])
#
#def scale_cached(self, draw_data):
# if self.sprite_scale != draw_data["scale"]:
# self.sprite_scale = draw_data["scale"]
# self.sprite_cache[self.sprite_name][self.sprite_state] = deepcopy(scale_image(draw_data["sprites"][self.sprite_name][self.sprite_state], draw_data["scale"]))
def draw(self, draw_data): def draw(self, draw_data):
#if draw_data["global_counter"] > self.sprite_cache_upd:
# self.sprite_cache = {}
if draw_data["spr_up"] == 0: if draw_data["spr_up"] == 0:
if self.sprite_state == len(draw_data["sprites"][self.sprite_name]) - 1: if self.sprite_state == len(draw_data["sprites"][self.sprite_name]) - 1:
self.sprite_state = 0 self.sprite_state = 0
else: else:
self.sprite_state += 1 self.sprite_state += 1
#if path_exists(self.sprite_cache, [self.sprite_name, self.sprite_state]): sp = draw_data["sprites"][self.sprite_name][self.sprite_state]
# self.scale_cached(draw_data)
#else:
# self.cache_sprite(draw_data["sprites"])
sp = scale_image(draw_data["sprites"][self.sprite_name][self.sprite_state], draw_data["scale"])
rect = sp.get_rect(center = (draw_data["x"] + draw_data["w"] /2, draw_data["y"] + draw_data["h"]/ 2)) 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) draw_data["screen"].blit(sp, rect)

View File

@@ -17,6 +17,7 @@ if __name__ == "__main__":
# - кнопка отключить сетку # - кнопка отключить сетку
# - строка ввода # - строка ввода
# - клик # - клик
# - вывод stdout на отдельную панель, полный экран, потом масштабирование всего под размер экрана
# Поиск пути, очередь задач для существ # Поиск пути, очередь задач для существ
# Редактор карты # Редактор карты
# Охотник -> деревня # Охотник -> деревня
@@ -37,5 +38,5 @@ if __name__ == "__main__":
#size = width, height = 640, 480 #size = width, height = 640, 480
## Use HWSURFACE and DOUBLEBUF flags ## Use HWSURFACE and DOUBLEBUF flags
#screen = pygame.display.set_mode(size, pygame.HWSURFACE | pygame.DOUBLEBUF) #screen = pygame.display.set_mode(size, pygame.HWSURFACE | pygame.DOUBLEBUF)
# кэширование спрайтов - скалировать сразу все на уровне движка!
# изучить pypmler # изучить pypmler
# настроить логирование всего