platform: Linux Ubunutu24
I am trying to make game into binary file using pyinstaller, when i run
pyinstaller zelda.spec
and run
./dist/zelda_game/zelda_game
I get following error with some weird path not found, i have no idea why are there ../../ and why is graphics being refered from maps/ directory when graphics audio are in project directory
pygame 2.5.2 (SDL 2.28.2, Python 3.12.3)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "main.py", line 46, in <module>
File "main.py", line 41, in main
File "main.py", line 17, in __init__
File "level.py", line 22, in __init__
File "tiledmaploader.py", line 9, in __init__
File "pytmx/util_pygame.py", line 183, in load_pygame
File "pytmx/pytmx.py", line 549, in __init__
File "pytmx/pytmx.py", line 633, in parse_xml
File "pytmx/pytmx.py", line 655, in reload_images
File "pytmx/util_pygame.py", line 131, in pygame_image_loader
FileNotFoundError: No such file or directory: '/home/rudy/Documents/pyinstaller/dist/zelda_game/_internal/maps/tmx/../tsx/../../graphics/tilemap/Floor.png'.
[28813] Failed to execute script 'main' due to unhandled exception!
project structure:
.
├── audio
│ └── attack
├── graphics
│ ├── font
│ ├── grass
│ ├── monsters
│ │ ├── bamboo
│ │ │ ├── attack
│ │ │ ├── idle
│ │ │ └── move
│ │ ├── raccoon
│ │ │ ├── attack
│ │ │ ├── idle
│ │ │ └── move
│ │ ├── spirit
│ │ │ ├── attack
│ │ │ ├── idle
│ │ │ └── move
│ │ └── squid
│ │ ├── attack
│ │ ├── idle
│ │ └── move
│ ├── objects
│ ├── particles
│ │ ├── aura
│ │ ├── bamboo
│ │ ├── claw
│ │ ├── flame
│ │ │ └── frames
│ │ ├── heal
│ │ │ └── frames
│ │ ├── leaf1
│ │ ├── leaf2
│ │ ├── leaf3
│ │ ├── leaf4
│ │ ├── leaf5
│ │ ├── leaf6
│ │ ├── leaf_attack
│ │ ├── nova
│ │ ├── raccoon
│ │ ├── slash
│ │ ├── smoke
│ │ ├── smoke2
│ │ ├── smoke_orange
│ │ ├── sparkle
│ │ └── thunder
│ ├── player
│ │ ├── down
│ │ ├── down_attack
│ │ ├── down_idle
│ │ ├── left
│ │ ├── left_attack
│ │ ├── left_idle
│ │ ├── right
│ │ ├── right_attack
│ │ ├── right_idle
│ │ ├── up
│ │ ├── up_attack
│ │ └── up_idle
│ ├── test
│ ├── tilemap
│ └── weapons
│ ├── axe
│ ├── lance
│ ├── rapier
│ ├── sai
│ └── sword
└── maps
├── tmx
└── tsx
my zelda.spec is as:
# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
['/home/rudy/Documents/zelda/main.py'],
pathex=['/home/rudy/Documents/zelda'],
binaries=[],
datas=[
('/home/rudy/Documents/zelda/graphics/*', 'graphics'),
('/home/rudy/Documents/zelda/maps/tmx/*', 'maps/tmx'),
('/home/rudy/Documents/zelda/maps/tsx/*', 'maps/tsx'),
('/home/rudy/Documents/zelda/audio/*', 'audio')
],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name='zelda_game',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
)
coll = COLLECT(
exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='zelda_game',
)
in settings.py
PROJECT_DIR = os.path.dirname(__file__)
tiledmaploader.py
import pygame
import pytmx
from settings import TILESIZE
from typing import Optional, Union
class TiledMapLoader:
def __init__(self, path: str):
map_data: pytmx.TiledMap = pytmx.load_pygame(path)
self.width = TILESIZE * map_data.width
self.height = TILESIZE * map_data.height
self.w = map_data.width
self.h = map_data.height
# data
self.ground = None
self.boundries: list[pygame.Rect, Optional[pygame.Surface]] = []
self.enemies: list[tuple[int, int, pygame.Surface]] = []
self.grasses: list[tuple[int, int, pygame.Surface]] = []
self.trees: list[tuple[int, int, pygame.Surface]] = []
self.blocks: list[tuple[int, int, pygame.Surface]] = []
self.player_pos = (0, 0)
self.load_map(map_data)
def load_map(self, map_data):
# main ground
ground: pytmx.TiledImageLayer = self.__get_layer_by_name("ground", map_data)
self.ground = ground.image
# player
player = self.__get_layer_by_name("player", map_data)[0]
self.player_pos = (player.x, player.y)
self.load_layer("boundry", self.boundries, map_data)
self.load_layer("grass", self.grasses, map_data)
self.load_layer("tree", self.trees, map_data)
self.load_layer("enemies", self.enemies, map_data)
self.load_layer("block", self.blocks, map_data)
def load_layer(self, layername: str, target: list, map_data):
layer: Union[pytmx.TiledTileLayer, pytmx.TiledObjectGroup] = (
self.__get_layer_by_name(layername, map_data)
)
if isinstance(layer, pytmx.TiledTileLayer):
for tree in layer:
x, y, gid = tree
image = self.__get_image_by_gid(gid, map_data)
if image:
target.append((x * TILESIZE, y * TILESIZE, image))
elif isinstance(layer, pytmx.TiledObjectGroup):
for obj in layer:
monster_type = obj.properties["monster_type"]
x, y, image = obj.x, obj.y, obj.image
target.append((monster_type, x, y, image))
def __get_layer_by_name(self, name: str, map_data: pytmx.TiledMap):
return map_data.layernames[name]
def __get_image_by_gid(self, gid, map_data):
return map_data.get_tile_image_by_gid(gid)
def __get_props_by_gid(self, map_data):
pass
level.py
from settings import TILESIZE, magic_data, PROJECT_DIR
import pygame
from pygame import Surface
from pygame.sprite import Group, GroupSingle, Sprite
from spotlight import Spotlight
from tile import Tile, Grass
from player import Player
from weapon import Weapon
from magic import StaticFlame, Flame, Heal
from enemy import Enemy
from particle import Particle, grass_destruction_particle
from upgrade import Upgrade
from ui import UI
from tiledmaploader import TiledMapLoader
from typing import Union
import os
class Level:
def __init__(self):
self.display_surface: Surface = pygame.display.get_surface()
self.map_data = TiledMapLoader(os.path.join(PROJECT_DIR, "maps/tmx/map.tmx"))
#other codes..