I’m just a scripting hack, and an idiot when it comes to command line tools. But I REALLY wanted to package up my python game into a Windows executable. I wrestled with pyinstaller for days, and read all of the threads of others who are also trying to figure it out, and I also read all the pyinstaller docs several times. No one solution worked for me, but after much trial and error I finally stumbled onto a recipe for success and want to share it in case there are other pygame developers out there banging their heads against this. The solution contains bits and pieces of several threads.
How to create a single file exe of a multi-file python pygame with several asset directories using pyinstaller on Windows:
First, install pyinstaller.
Open Windows Command Prompt, type:
pip install pyinstaller
Make a python game. Say the main game file is called main_game_script.py, located in
C:\Users\USERNAME\Documents\python\game_dir
Add this function to main_game_script.py. Make sure to import os and sys. (I never would have figured out on my own that I needed to add this function to my game, but it works, so thanks to whoever posted it in some other thread)
import sys
import os
def resource_path(relative_path):
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)
To load images into game, call that function, like such:
asset_url = resource_path('assets/chars/hero.png')
hero_asset = pygame.image.load(asset_url)
When your game is ready to be wrapped in an EXE, open Windows Command Prompt. Go to the main game directory and type:
pyinstaller --onefile main_game_script.py
It’ll look like this:
C:\Users\USERNAME\Documents\python\game_dir>pyinstaller --onefile main_game_script.py
This will create four important items:
- a main_game_script.spec file in the game_dir
- a 'build' dir in the game_dir
- a 'dist' directory in the game_dir
- a main_game_script.exe will be created in the 'dist' directory.
Running the command spits out a ton of warnings and logs. I don’t know what it all means. But as long as the final output line says success, you’re probably good.
Your exe will not work yet. First, you must modify the .spec file (which now exists in the game_dir) to add the needed game asset paths to the exe:
Open the main_game_script.spec file in notepad or whatever.
Replace the empty datas[] list with asset directory paths like such (using tuples!):
datas=[('assets/chars/*','assets/chars'),('assets/tiles/*.png','assets/tiles'),('assets/fonts/*','assets/fonts')],
The first value of each tuple is the actual file names you want to import.
The second value is the relative path from you main_game_script.py
The syntax and paths must be perfect, or it won’t work and may not throw an error
Save and close the ‘main_game_script.spec’ file. Return to your windows command prompt. Type:
pyinstaller main_game_script.spec
Like this:
C:\Users\USERNAME\Documents\python\game_dir>pyinstaller main_game_script.spec
This somehow embeds the asset dir paths into the exe that you’ve already built
After all this (which only takes a couple minutes after you’ve done it 100 times), you finally have a single file EXE of your python game that includes all of the game assets. If you’ve done everything right, double click on the EXE to play your python game.
Note: getting it right the first time took me a couple days. I started with a simple test_game_script.py with minimal code and iterated methodically, adding more asset paths and complexity with each iteration so I could isolate what was broken and why. If your game isn’t converting to EXE properly, start with a simple 5 line game script with one asset and slowly build on it until you have a pipeline that works, THEN apply that functioning asset pipeline your ACTUAL game. Otherwise isolating the problem will be impossible.