web-dev-qa-db-ja.com

Pyinstallerで.exeを作成した後、Pygameがpngをロードしない

私は.pyゲームから.exeを作成しようとしていましたが、本当にイライラしていました。

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'))
_

_pyinstaller --icon=/sprites/icon.ico game.py_を実行しようとすると、次のようになるので、pyinstalerが私のスプライトフォルダーを取得できないことに関係があると思います。

アイコンエラー画面

しかし、_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:\\Users\\rodri\\Documents\\Code\\The 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')
_
7

ついに完成!

同様の問題があるためにこれを読んでいる場合に備えて、私が何をしたかについての簡単なガイドを次に示します。 (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画像を選択して、オンラインコンバーター(Google it)を使用して.icoに変換できます。その後、.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.specという名前のファイルが作成されます。名前は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ファイルと同じフォルダに2つのフォルダが作成されたことがわかります。 「Dist」と呼ばれるものにはexeファイルが含まれており、--onefileを使用しなかった場合、他の人とアプリケーションを共有するためにexeとともにZipする必要のある他のファイルもたくさんあるはずです。 「Buid」フォルダもありますが、アプリケーションを使用するために必要がないため、その目的はわかりません。

これでおしまいです。それはあなたのために働くはずです。

質問したときの間違いは、sys._MEIPASSの部分がわからなかった(C._に感謝)。スペックファイルの名前がpyファイルとは異なり、代わりに'/sprites'を使用しました。の'sprites'added_filesと、pyファイルの代わりにspecファイルを実行することになっていることを知りませんでした。

Pyinstallerの詳細については、 manual を参照してください。ただし、これはあまりよくなく、時には誤解を招く可能性があるため、Googleの方が適しています。

16

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"と入力します

最後に、以前同じ問題があったので、pyinstaller "spec_file.spec"を実行するだけでexeをコンパイルすることをお勧めします

1
underscoreC