python and pygame game development guide [python game design and development]

Recently, I was developing games with python+pygame. After writing, I encountered great problems when sharing with friends. Only when I built an environment can I run python scripts.

This will scare off more than 99% of people... So it is imperative to package our game (pay attention to packaging rather than compiling, python is a script program after all) into an executable file.

I searched several programs about python packaging on the Internet. After using it, I found that py2exe is more practical and convenient (py2exe is free).

1. Introduction

Py2exe can package a python program into an EXE executable file, which is convenient for using the program on computers without Python environment. To package with py2exe, you need to write a packaging script. After execution, you can get the packaging file. For the 32-bit version, py2exe can package the program into a single file; For the 64 bit version, packaging into a single file is not supported yet. However, no matter how compressed, the programs packaged by py2exe are still too large.

2. Software preparation

First, go to the official website of py2exe http://www.py2exe.org/ Download the installation package and pay attention to the corresponding python version, otherwise there will be problems.

Double click the exe file and go all the way to next. It should be noted that the 32-bit version and 64 bit version must be matched with the version used by Python.

3. Packaging process

Py2exe needs to write a script for packaging. Using the following script specially written for pygame (refer to the official py2exe) can greatly facilitate the packaging operation. Pay attention to modifying the parameters in BuildExe before use.

Thank you very much for the script provided by "xishui" God. This script is really great!!!

#!python
# -*- coding: gb2312 -*-

# This script is optimized for pygame. Use py2exe to package code and resources to dist directory
#
# If you have any questions during use, you can leave a message to:
#  //eyehere.net/2011/python-pygame-novice-professional-py2exe/
#
# Installation requirements:
#         Python, pyGame and py2exe should be installed

# usage method:
#         1: Modify this file to specify the file to be packaged py and corresponding data
#         2: python pygame2exe.py
#         3: In the dist folder, enjoy it~

try:
    from distutils.core import setup
    import py2exe, pygame
    from modulefinder import Module
    import glob, fnmatch
    import sys, os, shutil
except ImportError, message:
    raise SystemExit,  "Sorry, you must install py2exe, pygame. %s" % message

# This function is used to determine whether the DLL is provided by the system (if so, there is no need to package)
origIsSystemDLL = py2exe.build_exe.isSystemDLL
def isSystemDLL(pathname):
    # Need to hack. The DLLs of freetype and ogg are not system DLLs
    if os.path.basename(pathname).lower() in ("libfreetype-6.dll", "libogg-0.dll", "sdl_ttf.dll"):
        return 0
    return origIsSystemDLL(pathname)
# Rewrite Hack's function back
py2exe.build_exe.isSystemDLL = isSystemDLL

# This new class is also a Hack, so that the default font of pygame will be copied
class pygame2exe(py2exe.build_exe.py2exe):
    def copy_extensions(self, extensions):
        # Get pygame default font
        pygamedir = os.path.split(pygame.base.__file__)[0]
        pygame_default_font = os.path.join(pygamedir, pygame.font.get_default_font())
        # Add copy file list
        extensions.append(Module("pygame.font", pygame_default_font))
        py2exe.build_exe.py2exe.copy_extensions(self, extensions)

# This class is part of what we really do
class BuildExe:
    def __init__(self):
        #------------------------------------------------------#
        ##### For a new game program, you need to modify the parameters here #####
        #------------------------------------------------------#

        # Start py file
        self.script = "MyGames.py"
        # Game name
        self.project_name = "MyGames"
        # Game site
        self.project_url = "about:none"
        # Game version
        self.project_version = "0.0"
        # Game license
        self.license = "MyGames License"
        # Game author
        self.author_name = "xishui"
        # Contact Email 
        self.author_email = "blog@eyehere.net"
        # Game copyright
        self.copyright = "Copyright (c) 3000 xishui."
        # Game Description
        self.project_description = "MyGames Description"
        # Game icon (if None, use the default icon of pygame)
        self.icon_file = None
        # Additional files and folders to be copied (pictures, audio, etc.)
        self.extra_datas = []
        # Additional required python library name
        self.extra_modules = []
        # python libraries that need to be excluded
        self.exclude_modules = []
        # Additional DLLs to exclude
        self.exclude_dll = ['']
        # py file to be added
        self.extra_scripts = []
        # Package Zip file name (if None, package into exe file)
        self.zipfile_name = None
        # Build folder
        self.dist_dir ='dist'

    def opj(self, *args):
        path = os.path.join(*args)
        return os.path.normpath(path)

    def find_data_files(self, srcdir, *wildcards, **kw):
        # Get files from source folder
        def walk_helper(arg, dirname, files):
            # Of course, you can also add other version control tools
            if '.svn' in dirname:
                return
            names = []
            lst, wildcards = arg
            for wc in wildcards:
                wc_name = self.opj(dirname, wc)
                for f in files:
                    filename = self.opj(dirname, f)

                    if fnmatch.fnmatch(filename, wc_name) and not os.path.isdir(filename):
                        names.append(filename)
            if names:
                lst.append( (dirname, names ) )

        file_list = []
        recursive = kw.get('recursive', True)
        if recursive:
            os.path.walk(srcdir, walk_helper, (file_list, wildcards))
        else:
            walk_helper((file_list, wildcards),
                        srcdir,
                        [os.path.basename(f) for f in glob.glob(self.opj(srcdir, '*'))])
        return file_list

    def run(self):
        if os.path.isdir(self.dist_dir): # Delete last generated result
            shutil.rmtree(self.dist_dir)

        # Get default icon
        if self.icon_file == None:
            path = os.path.split(pygame.__file__)[0]
            self.icon_file = os.path.join(path, 'pygame.ico')

        # Obtain the data file to be packaged
        extra_datas = []
        for data in self.extra_datas:
            if os.path.isdir(data):
                extra_datas.extend(self.find_data_files(data, '*'))
            else:
                extra_datas.append(('.', [data]))

        # Start packaging exe
        setup(
            cmdclass = {'py2exe': pygame2exe},
            version = self.project_version,
            description = self.project_description,
            name = self.project_name,
            url = self.project_url,
            author = self.author_name,
            author_email = self.author_email,
            license = self.license,

            # The default is to generate the window program. If you need to generate the terminal program (debug stage), use:
            # console = [{
            windows = [{
                'script': self.script,
                'icon_resources': [(0, self.icon_file)],
                'copyright': self.copyright
            }],
            options = {'py2exe': {'optimize': 2, 'bundle_files': 1,
                                  'compressed': True,
                                  'excludes': self.exclude_modules,
                                  'packages': self.extra_modules,
                                  'dist_dir': self.dist_dir,
                                  'dll_excludes': self.exclude_dll,
                                  'includes': self.extra_scripts} },
            zipfile = self.zipfile_name,
            data_files = extra_datas,
            )

        if os.path.isdir('build'): # Clear the build folder
            shutil.rmtree('build')

if __name__ == '__main__':
    if len(sys.argv) < 2:
        sys.argv.append('py2exe')
    BuildExe().run()
    raw_input("Finished! Press any key to exit.")

You can start with a simple program, have a little experience, and then try to package complex games. Some tips:

  • If there is an error in execution, a XXX will be generated exe. Log, refer to the log information here to see if there is less packaging.
  • You can see more information in the command line of console.
  • For each game, you basically need to copy the above original code and modify it into a unique packaged execution file.
  • Even for a small py file, the final generated EXE file is also large (depending on the installed library, the minimum here is about 4.7M). In fact, when py2exe is packaged, it will type in countless unnecessary libraries, resulting in bloated final files, especially if you install very complicated libraries (wxPython, etc.). After using zip package, check the library files inside and add unnecessary ones to self exclude_ Modules, you can finally control the file size within an acceptable range.

Supplement: Many people have problems when packaging and using the Font module. Here we need to use sdl_ttf.dll is declared as a non system file. I have modified the script and added it by default. It is also suggested that if you are sure to package as exe in the future, do not use the system Font, that is, "pyGame Font. Sysfont (xxx) ", but use Font files, and then package the files as pictures when packaging, which will greatly reduce the probability of problems.

"dist_dir" should be a unique option of py2exe, not setup.

Reference blog: http://eyehere.net/2011/python-pygame-novice-professional-py2exe/

This concludes today's article. Thank you for reading.

Added by hykc on Sun, 27 Feb 2022 08:52:51 +0200