From ffc87c9591cdd0a901c6e09c59279c9ebaed73be Mon Sep 17 00:00:00 2001 From: shiva404 Date: Sat, 14 Feb 2026 05:24:52 +0300 Subject: [PATCH] Sprite scaling support and a little refactoring --- __pycache__/eb_engine.cpython-314.pyc | Bin 8434 -> 9581 bytes eb_engine.py | 97 +++++++++++++------------- main.py | 14 +++- slop.txt | 72 +++++++++++++++++++ 4 files changed, 130 insertions(+), 53 deletions(-) create mode 100644 slop.txt diff --git a/__pycache__/eb_engine.cpython-314.pyc b/__pycache__/eb_engine.cpython-314.pyc index 221639cc250f7a7c89d6d13fc617ff9f19e3d323..5771efdcba0e85e771c6024f2309517d8f8a5d81 100644 GIT binary patch delta 4437 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 delta 3576 zcmai1Z){W76~EVhetG_H$N%ELaYzU;q#-FuSN<#%(okqd<{E0s2rrez_uPBWz4x4xPoDj3mt&K|ZXwW?e|@2F#69n5qsjRV|4ttjeWZh=!~jXP z3>r{@kio`>sNQC;1ij`j^!oIX7U;9C^r`-op_3$R{5(CtuNb?jo!5;YaG!C2zazwf z`>n9vaEI`Zg<;ytdrTuc{4ke70iI$3K;~EhJ9c;g{{9^@OO`Ao5SiU~&q^r$CSf66 zi@$3OR*wOh1&yObr75BsCcUcBPs$`kRUu_iO(~-)PJUNynKY@=Bvs9mM76-5b<&{P zQbK^J_LP(|1xS&qjx^aq(G^8Wb*5TWSDL8q6on0$HRJwlWn2@dSoX}&mo#CjT+HWi z*;g}S$RN6LJz-vzhNy%8Qrb#4@xMu78sJv*dfLGU%o_ci+bmDhKk(-)JLxa3&RgoV zKW*Fq8?-ODsF{ExaDE)|y%ms!MR1_*syFoN(jKtf=T!$%YHg`CQEB58WDSk9^m1M{Jh{;2RVubXY` zz72I;xcf{dTdJ1IDx69tgZEAOHUPY_v*gdMzM9}$Ho+5H7KtZN6Qav4$VkNFuL<#G zGcp#Pi7n$xT(;>`+6yrhceg3CVS{Ee>90>J3c zIze@(B)0VUz_QfPJ3{l4C+;O6HUaqLQeIqot`r zNzOGNylx%O-AIUZ=O7TXWh@H3DZb^;{)^pZ3>@0NkcfP++vt}xs%udN{Grt^& z(;>bP2tR?3r#V?X-k8h=FCd?3L<~jqG$(vexRbZFo!yDE>Y*FHdc!rt#%y=qFyVS8 zR$K%rWUxtB=){Vz_%Vx*Z}EF+nr{yJ_(iLqzwNcGs~A=_ND^JKrX`*Ha~k#;Q-%tp zrHX0NQh_6_w4_PW4LzY~J4p*G>0s25hcF5WVRh04tB?Pq#mij=i60BL1f{g}s2nk2 z;IG*t{QE(tQ>X}IJ&k~!HYCHm!|QRHR`vsv(PR|EzcHSS@po+@KZs1L^V9s<#{4{E z?}tgvCUe>h#?OTZ+QEMj7`~k*yVvXy*tEz$4F`>=Yl#eW{2$$3J6{S1bnSBwY2zDT z)6!yZfGsy;uoTR{sWt}XJy^_`|~~00{=A9Tw8Qt`+Z#urfXWdr56j3W}7jT zf-AJ{hkr&R{B4_U{1FpB+8EY0&9>IqiahxQ@34AsKm4yzrwz{U{zl=>8IoJ^o``Tx z#^iRsE!N?LN3^O!k~{bnyO+NjvsOiT!Y!}-#?o1ie>pB6&p>)+*+QxB8CISt<$DHt zNhI&+Qw9Fw!^43m|<=i#+J&=1+Sr1lh)LP=4xrJUST?nQg$<1axjR{FlGe-mKn zA;sz!H4ipc@C8-W%spiDzUC{oy!>M3B;>4@lyd3d)b}o7yS8(WX3d?*GL^|Qiaa=; zXxF25BQ&)@2~pWw%%0IC1#;=ha$de4p)^4)oP?5Nq*%^PvoiQyGs$0v>P0g`;$<6A zAUyZ{zJr?ZVxd@Mqx|DoJUxP9<5)&P$m*FGsXW3dJv$=>HOg3K^uWljN%rde{gm3RYhzIxr$Jty52No(81*nDi!-BWY-{G{vh#-DC{FaQ4Z zmFb1V?(6Q6Iq_DbR#|j))Lb3cU7d5LdaHk~rSA64iFJS5oVD(2o3kv5#B5)bf;B04 zLkiy$iPJwf1=d6HA4V=k7P%wd6Y^XbdwuLJ`wd(7pKRU>`(NMxR`-v4-|4+!+sr58 zeZurj?*RW-Jovwemu`Cdbse1;@7Pj>In2(L=ntDr81Ls6{UFD|myaq6j-$t{&EOA( zB-78Ay#eB8(nqQj;K7`K6om*+V#hiH1+1R*>-~@4C4$MnWFs4gkSfx9j%~mbfW|)` zI4Tj~pL8A)x1g01{MoLJN2ZZ{6TyL?*A)6BVPqlVkY-}s0atUTC=atsAj2f1{0Lyl zNGZKdMifBNh0nb|9#hP!;;9u>th?@bT?fhh)`J?tV;$Y@9m*`DfQnW Ii27Xr0di9ucK`qY diff --git a/eb_engine.py b/eb_engine.py index e291d59..4052818 100644 --- a/eb_engine.py +++ b/eb_engine.py @@ -3,13 +3,16 @@ import eb_objects import eb_terrain import eb_creatures - - cell_classes = {"Ground": eb_terrain.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() + new_size = (int(orig_size[0] * n), int(orig_size[1] * n)) + return pygame.transform.scale(image, new_size) + @dataclass class Cell: terrain_obj: any @@ -19,16 +22,16 @@ class Cell: @dataclass class Map: - name: str - cells: dict = None - 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 + 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 def __post_init__(self): self.cells = {} @@ -47,47 +50,42 @@ class Map: y = int((l * self.size + self.cam_y) * self.scale) 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) + scaled_rect = scaled.get_rect(center = (x + w/2, y + h/2)) + screen.blit(scaled, scaled_rect) + if grid: pygame.draw.rect(screen, self.color, pygame.Rect(x, y, w, h), self.bord) - sp = sprites[cell.terrain_obj.sprite].get_rect(center = (x + w/2, y + h/2)) - screen.blit(sprites[cell.terrain_obj.sprite], sp) - +@dataclass class Engine: - def __init__(self, width, height, sprites = {}): - self.width = width - self.height = height - self.sprites = sprites + sprites: dict = field(default_factory = dict) + screen: pygame.Surface = ((1, 1)) + width: int = 1600 + height: int = 800 + camera_step: int = 10 + scale_step: float = 0.01 + + def __post_init__(self): + self.sprites = {} pygame.init() - + pygame.display.set_caption('Elvenbane') + self.screen = pygame.display.set_mode((self.width, self.height)) + self.load_sprites() + 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() - - def main_loop(self): - ''' - #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)) - ''' - - easy_map = Map("def_map.json") - # pygame setup - - screen = pygame.display.set_mode((self.width, self.height)) - clock = pygame.time.Clock() + def main_loop(self): + clock = pygame.time.Clock() running = True unlock = True - camera_step = 10 - scale_step = 0.1 - - - self.load_sprites() + easy_map = Map("def_map.json") #gr = pygame.image.load(file_path).convert_alpha() while running: @@ -98,24 +96,24 @@ class Engine: running = False # fill the screen with a color to wipe away anything from last frame - screen.fill("chartreuse4") + self.screen.fill("chartreuse4") - easy_map.draw(screen, self.sprites) + easy_map.draw(self.screen, self.sprites) if unlock: keys = pygame.key.get_pressed() if keys[pygame.K_w]: - easy_map.cam_y -= camera_step + easy_map.cam_y -= self.camera_step if keys[pygame.K_s]: - easy_map.cam_y += camera_step + easy_map.cam_y += self.camera_step if keys[pygame.K_a]: - easy_map.cam_x -= camera_step + easy_map.cam_x -= self.camera_step if keys[pygame.K_d]: - easy_map.cam_x += camera_step + easy_map.cam_x += self.camera_step if keys[pygame.K_q]: - easy_map.scale += scale_step - if keys[pygame.K_e]: - easy_map.scale -= scale_step + easy_map.scale += self.scale_step + if keys[pygame.K_e] and easy_map.scale >= self.scale_step: + easy_map.scale -= self.scale_step if keys[pygame.K_ESCAPE]: running = False @@ -124,5 +122,4 @@ class Engine: # limits FPS to 60 clock.tick(60) - pygame.quit() \ No newline at end of file diff --git a/main.py b/main.py index b5846a4..cba1a01 100644 --- a/main.py +++ b/main.py @@ -1,18 +1,26 @@ import eb_engine def main(): - e = eb_engine.Engine(1600, 900) + e = eb_engine.Engine() e.main_loop() if __name__ == "__main__": # pydantic instead of dataclasses? # Отрисовка голой сетки, прокрутка, масштаб + - # Отрисовка спрайтов + # Отрисовка спрайтов: + # - сделать масштабирование в соотв. с клеткой + + # - посмотреть класс спрайта или сделать свой + # - добавить отрисовку существ и предметов + # почитать про Surface, Display, доку к pygame-gui # Начало гуя - кнопка, строка ввода, клик # Поиск пути # Редактор карты - # Охотник - деревня + # Охотник -> деревня # Простой, но основательный гуй внизу экрана, глобальная карта и перемещение # деревня на соседской локации и торговля с ней # перемещение по воде, течение + + # проверить у ллм на ошибки: + # - deepcopy + # - общие main() \ No newline at end of file diff --git a/slop.txt b/slop.txt new file mode 100644 index 0000000..d5afcf7 --- /dev/null +++ b/slop.txt @@ -0,0 +1,72 @@ + #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)) + +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.scale(image, new_size) + +n = 1.5 # Example: 1.5x larger +scaled = scale_image(original, n) +scaled_rect = scaled.get_rect(center=(600, 300)) + +screen.blit(original, orig_rect) # Original size +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)} спрайтов") +