Pygame не загружает png после создания.exe с Pyinstaller

Я пытался сделать .exe от моего .py игра, и это было очень неприятно.

я использую Python 3.5.2, Pygame 1.9.2 и Pyinstaller 3.2.

игра работает отлично, как .py, но после того, как я войду pyinstaller --debug game.py действие .exe построен, и я запускаю его, я получаю следующее:

отладка экране

Это строки кода из game.py это может быть связано с ошибкой:

from os import path
img_dir = path.join(path.dirname(__file__), 'sprites')
title_screen = pygame.image.load(path.join(img_dir, 'title_screen.png'))

Я думаю, что это должно быть что-то связано с тем, что pyinstaler не может получить мою папку спрайтов, потому что когда я пытаюсь запустить pyinstaller --icon=/sprites/icon.ico game.py, Я получаю это:

экран ошибки значка

но если я использую pyinstaller --icon=icon.ico game.py он загружает значок просто отлично.

вот мой файл спецификации:

# -*- mode: python -*-

block_cipher = None

added_files = [
         ( '/sprites', 'sprites' ),
         ( '/music', 'music' ),
         ( 'Heavitas.ttf', '.'),
         ( 'Roboto-Light.ttf', '.'),
         ( 'high scores.csv', '.')
         ]


a = Analysis(['spec_file.py'],
             pathex=['C:UsersrodriDocumentsCodeThe Color That Fell From The Sky'],
             binaries=None,
             datas=added_files,
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             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='spec_file',
          debug=False,
          strip=False,
          upx=True,
          console=True )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='spec_file')

2 ответов


наконец-то!

вот краткое руководство о том, что я сделал, если Вы читаете это, потому что у вас есть аналогичная проблема. (Я использовал Python 3.5.2, Pygame 1.9.2 и Pyinstaller 3.2)

подготовьте код

как C._ объясняет другой ответ (Спасибо), в случае, если вы загружаете файлы, как это:

import os
folder_path = os.path.join(path.dirname(__file__), 'folder')
some_image = pygame.image.load(os.path.join(folder_path, 'some_image.png'))

вместо этого:

import sys
import os
# If the code is frozen, use this path:
if getattr(sys, 'frozen', False):
    CurrentPath = sys._MEIPASS
# If it's not use the path we're on now
else:
    CurrentPath = os.path.dirname(__file__)
# Look for the 'sprites' folder on the path I just gave you:
spriteFolderPath = os.path.join(CurrentPath, 'sprites')
# From the folder you just opened, load the image file 'some_image.png'
some_image = pygame.image.load(path.join(spriteFolderPath, 'some_image.png'))

это необходимо, потому что, когда вы заморозите свой код, файлы будут переместился в другую папку, чем та, которую вы использовали раньше. Убедитесь, что вы сделали это со всеми файлами.

вот еще один пример:

if hasattr(sys, '_MEIPASS'):  # the same logic used to set the image directory
    font = path.join(sys._MEIPASS, 'some_font.otf')  # specially useful to make a singlefile .exe
font = pygame.font.Font(font, size)
# Don't ask me the difference between hasattr and getattr because I don't know. But it works.
(необязательный)

если вы хотите значок, который не pyinstaller по умолчанию, вы можете выбрать png изображение и преобразовать его.ico с помощью некоторого онлайн-конвертера (Google it). После этого, положите .ICO файл в той же папке, где ваш .файл py есть.

сделайте файл спецификации

в этот момент Вы следует знать, если вы хотите один автономный .exe файл или куча отдельных файлов, которые вы будете zip и отправить людям. В любом случае, откройте терминал на папке, где ваш.файл py есть.

если вы хотите один файл, используйте этот:

pyinstaller --onefile --icon=icon_file.ico game_file.py

если вы этого не делаете, используйте это:

pyinstaller --icon=icon_file.ico game_file.py

если вы не хотите устанавливать значок сейчас, просто не используйте --icon часть. Вы можете изменить его позже. Что вы не можете изменить это параметр --onefile (по крайней мере, насколько мне известно).

файл с именем game_file.будет создана спецификация. Он автоматически получит имя от game_file.py - ... Вы можете испортить его, если у них разные имена,так что не творите сейчас. Если вы выбрали один файл, он должен выглядеть так:

# -*- mode: python -*-

block_cipher = None

a = Analysis(['game_file.py'],
             pathex=['C:\some\path\The path where your .py and .spec are'],
             binaries=None,
             datas=None,
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             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='game_file',
          debug=False,
          strip=False,
          upx=True,
          console=True , icon='icon_file.ico')

если вы решили иметь кучу файлов, вы увидите в этом фильме часть:

coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas,
               strip=False,
               upx=True,
               name='game_file')

после block_cipher = None вы добавите файлы, которые загружает ваша игра. Вот так:

added_files = [
         ( 'a folder', 'b folder' ),  # Loads the 'a folder' folder (left) and creates
                                      # an equivalent folder called 'b folder' (right)
                                      # on the destination path
         ( 'level_1/level2', 'level_2' ),  # Loads the 'level_2' folder
                                           # that's inside the 'level_1' folder
                                           # and outputs it on the root folder
         ( 'comic_sans.ttf', '.'),  # Loads the 'comic_sans.ttf' file from
                                    # your root folder and outputs it with
                                    # the same name on the same place.
         ( 'folder/*.mp3', '.')  # Loads all the .mp3 files from 'folder'.
         ]

теперь вы должны добавить "added_files" здесь:

a = Analysis(['game_file.py'],
                 pathex=['C:\some\path\The path where your .py and .spec are'],
                 binaries=None,
                 datas=added_files,  # Change 'None' to 'added_files' here
                                     # Leave everything else the way it is.
                 hiddenimports=[],
                 hookspath=[],
                 runtime_hooks=[],
                 excludes=[],
                 win_no_prefer_redirects=False,
                 win_private_assemblies=False,
                 cipher=block_cipher)

вы также можете изменить некоторые параметры:

exe = EXE(pyz,
              a.scripts,
              exclude_binaries=True,
              name='game_file',  # Name of the output file. Equivalent to '--name'
                                 # Don't change it.
              debug=False,  # If True shows a debug screen on start. Equivalent to '--debug'.
              strip=False,
              upx=True,  # Compresses executable files and libraries
              # If console=True, a console screen will be shown on start up.
              # icon= is the location of the icon of the exe.
              console=True , icon='icon_file.ico')

если вы не изменили путь или выходное имя exe, как я сказал вам не в комментариях, нам просто нужно запустить его и .exe-файл, который был ранее создан, будет обновлен. Введите это в командном окне:

pyinstaller game_file.spec

помните, что game_file.spec это файл, который мы только что отредактировали, а "game_file" - случайное имя, которое я использовал в качестве примера. Заметить также что нет --some_option потому что они не будут работать с файлом спецификации. Вот почему вы должны изменить их непосредственно в скрипт. --onefile также не работает здесь и не может быть сделано из сценария, поэтому я сказал вам сделать это раньше.

вы увидите, что были созданы в той же папке, где две папки .Spec-файл. Тот, который называется "Dist", содержит exe-файл, и если вы не использовали --onefile, он также должен иметь кучу других файлов, которые вам нужно сжать вместе с exe, чтобы поделиться приложением с другими людьми. Там также будет папка "Buid", но я не знаю, для чего это, так как вам не нужно использовать приложение.

так вот оно что. Это должно сработать для тебя.

мои ошибки, когда я сделал вопрос в том, что я не знаю sys._MEIPASS часть (еще раз спасибо C._), имя моего файла спецификации отличалось от моего файла py, я использовал '/sprites' вместо 'sprites' на added_files и не знал, что я должен выполнить Spec-файл вместо файл py.

для получения дополнительной информации о Pyinstaller, взгляните на руководство, но поскольку это далеко не хорошо и иногда вводит в заблуждение, вам лучше с Google.


при компиляции с помощью PyInstaller все файлы перемещаются в другой каталог при запуске exe. Итак, чтобы добраться до этого места, добавьте это в начало своего кода, прежде чем создавать пути

import sys

if getattr(sys, 'frozen', False): # PyInstaller adds this attribute
    # Running in a bundle
    CurrentPath = sys._MEIPASS
else:
    # Running in normal Python environment
    CurrentPath = os.path.dirname(__file__)

все ваши пути к папкам могут быть сгенерированы из вашего местоположения

spriteFolderPath = path.join(CurrentPath, 'sprites') # Do the same for all your other files

затем, когда у вас есть место, в котором вы выполняете, вы можете получить все свои файлы оттуда:

title_screen = pygame.image.load(path.join(spriteFolderPath, 'title_screen.png')) # Use spriteFolderPath instead of img_dir

я тоже вижу, что у вас есть другие шрифты / вещи, вы можете сделать то же самое, чтобы загрузить их

fontRobotoLight = pygame.font.Font(path.join(CurrentPath, 'Roboto-Light.ttf'))

для вашего значка просто вставьте временный icon.ico в главной папке и типа pyinstaller -i "icon.ico" "spec_file.spec"

наконец, я была такая же проблема раньше, я рекомендую вам составить свой exe просто работает pyinstaller "spec_file.spec"