用Python和Pygame写游戏-从入门到精通(py2exe篇)

By | 2011/06/19

这次不是直接讲解下去,而是谈一下如何把我们写的游戏做成一个exe文件,这样一来,用户不需要安装python就可以玩了。扫清了游戏发布一大障碍啊!

perl,python,java等编程语言,非常好用,语法优美,功能强大;VB啥的,功能上编写的时候总有那么点不舒服的地方(个人见解),可是用户和受众极多,一个很大的原因就是:VB是微软提供的,可以很方便的编译(伪?)生成exe文件。有了exe,所有的Windows都能方便的使用了。

我们不能指望用户在玩我们的游戏之前都安装一个python和pygame,甚至还要装一些其他额外的库(比如上一章的gameobjects),这会吓退99%以上的人……所以把我们的游戏打包(注意是打包而不是编译,python毕竟是脚本程序)成一个可执行文件势在必行。

父亲节

今天是父亲节啊,祝天下父亲快乐平安~

perl有perlcc(免费高效但配置极其复杂),perlapp(简单效果也不错但是收费)等工具;而对python来说,py2exe是不二之选,首先是免费的,而且压出来的文件,虽然不能和编译软件相比,还是不错的了。

到py2exe的官方网站下载安装包,注意要对应自己的python版本。

py2exe是需要写一个脚本进行打包的操作,使用下面这个专为pygame写就的脚本(参考py2exe官方),可以极大的方便打包操作,注意在使用前修改BuildExe里的各个参数。

可以先从简单的程序开始,有了一点经验再尝试打包复杂的游戏。
一些Tips:

  • 如果执行出错,会生成一个xxx.exe.log,参考这里的log信息看是不是少打包了东西。
  • 一开始可以使用console来打包,这样可以在命令行里看到更多的信息。
  • 对于每一个游戏,基本都需要拷贝上面的原始代码修改为独一无二的打包执行文件。
  • 即使一个很小的py文件,最终生成的exe文件也很大(看安装的库而定,我这里最小4.7M左右),事实上py2exe在打包的时候会把无数的不需要的库都打进来导致最终文件臃肿,如果你安装了很繁杂的库(wxPython等)更是如此。使用zip打包以后查看里面的库文件,把不需要的逐一加入到self.exclude_modules中,最后可以把文件尺寸控制在一个可以接受的范围内。

2011/08/21 追记:
很多人在打包使用Font模块时出现问题,这里需要把sdl_ttf.dll声明为非系统文件,我已经修改了脚本默认就加入了。而且建议,如果将来是确定要打包为exe的,那么就不要使用系统字体,即”pygame.font.SysFont(xxx)”,而是使用字体文件,然后打包时将文件当作图片等一起打包,这样出问题的概率会大大降低。

2011/09/24 追记:
感谢blues_city网友,“dist_dir”应该是属于py2exe的特有options而不是setup的。

欢迎大家试用并提出建议,不断完善这个脚本。

63 thoughts on “用Python和Pygame写游戏-从入门到精通(py2exe篇)

  1. roy

    博主好,我参考了您的setup文件打包我写的pygame的小游戏,编译之后打开exe文件出现错误
    MemoryLoadLibrary failed loading pygamefont.pyd

    google了一下,有人说不要用单一文件,于是我编辑了BuildExe.zipfile_name打包成zip文件。并声明”sdl_ttf.dll”为非系统文件,重新打包之后执行,报错:

    Runtime Error!
    This application has requested the Runtime to terminate it in an unusual way.
    Please contact the application’s support team for more information.

    目前仍未找到解决方案,可以确定的是错误源于读取字体。另外搜索过程中找到这位有类似问题:
    http://www.daniweb.com/software-development/python/threads/247249
    最后一位回帖者称是版本问题。

    为寻求答案来此留言,期待博主抽空提出意见,先谢过

    Reply
    1. xishui Post author

      我在遇到这个问题的时候,还是用了打包,仅仅是将”sdl_ttf.dll”加一下就解决了。不介意的话可以把您的代码发给我测试一下(可以把其他都删除,仅保留必要和使用font那部分能够出现问题便可)。另外请告知系统、python、pygame的版本。

      Reply
      1. junjun

        大神你好,我用的2.7,转出来的EXE文件打不开,log:
        E:\python\bird\dist\bird.exe:17: RuntimeWarning: use mixer: DLL load failed: 找不到指定的模块。
        (ImportError: DLL load failed: 找不到指定的模块。)
        Traceback (most recent call last):
        File “bird.py”, line 17, in
        File “pygame\__init__.pyc”, line 70, in __getattr__
        NotImplementedError: mixer module not available
        (ImportError: DLL load failed: 找不到指定的模块。)
        我看了一下源代码第十七行,是pygame.mixer.init(),可是我前面已经import pygame了啊,这是怎么回事

        Reply
  2. Comix

    xishui大神好~~

    你的入门到精通系列实在是太棒了~按着教程,我写了个俄罗斯方块,打包exe的时候把上面代码直接复制了,可是打包出的exe不能用……

    log信息:
    C:Python27distnoname.exezipextimporter.py:82: RuntimeWarning: import display: No module named _view
    (ImportError: No module named _view)
    C:Python27distnoname.exezipextimporter.py:82: RuntimeWarning: import draw: No module named _view
    (ImportError: No module named _view)
    C:Python27distnoname.exezipextimporter.py:82: RuntimeWarning: import image: No module named _view
    (ImportError: No module named _view)
    C:Python27distnoname.exezipextimporter.py:82: RuntimeWarning: import pixelcopy: No module named _view
    (ImportError: No module named _view)
    C:Python27distnoname.exezipextimporter.py:82: RuntimeWarning: import transform: No module named _view
    (ImportError: No module named _view)
    Traceback (most recent call last):
    File “noname.py”, line 27, in
    File “pygame__init__.pyo”, line 70, in __getattr__
    NotImplementedError: display module not available
    (ImportError: No module named _view)

    能帮忙看一下吗?我的py是2.7
    万分感谢

    Reply
    1. xishui Post author

      太客气了,能让大家学到一点有用的东西再好不过了。
      我从没遇到过 _view库丢失的问题…… 有试着先编译一个简单的脚本么?我用的是2.6,虽然应该不至于但并不能确定在2.7下一定是正常的,如果没头绪并且不介意的话,可以把你的代码发给我来测试一下,邮箱在About里。

      Reply
      1. 吴斌伟

        不知道,博主是怎么解决2.7下, _view库丢失的问题的??希望博主解释一下,因为我也遇到了这个问题!!

        Reply
        1. partical

          row 76: self.extra_modules=[‘pygame._view’]

          Reply
      2. Tangmeii

        博主您好,我打包也出现了这个问题,目前还没有解决!求助

        C:\py2exe\dist\MyGames.exe\zipextimporter.py:82: RuntimeWarning: import display: No module named _view
        (ImportError: No module named _view)
        C:\py2exe\dist\MyGames.exe\zipextimporter.py:82: RuntimeWarning: import draw: No module named _view
        (ImportError: No module named _view)
        C:\py2exe\dist\MyGames.exe\zipextimporter.py:82: RuntimeWarning: import image: No module named _view
        (ImportError: No module named _view)
        C:\py2exe\dist\MyGames.exe\zipextimporter.py:82: RuntimeWarning: import pixelcopy: No module named _view
        (ImportError: No module named _view)
        C:\py2exe\dist\MyGames.exe\zipextimporter.py:82: RuntimeWarning: import transform: No module named _view
        (ImportError: No module named _view)
        Traceback (most recent call last):
        File “MyGames.py”, line 11, in
        File “pygame\__init__.pyo”, line 70, in __getattr__
        NotImplementedError: display module not available
        (ImportError: No module named _view)

        Reply
        1. xishui Post author

          真是对不住,我已经很久没有玩Python了,源码等也已经不知去向,没法帮到你了……

          Reply
  3. Comix

    @xishui: 我在self.extra_modules里加了”pygame”,就解决了~虽然不知什么原理,不过总算OK了呵呵

    Reply
  4. Lucy

    main.exe:10: RuntimeWarning: use font: DLL load failed: 找不到指定的模块。
    (ImportError: DLL load failed: 找不到指定的模块。)
    Traceback (most recent call last):
    File “main.py”, line 10, in
    File “pygame__init__.pyc”, line 70, in __getattr__
    NotImplementedError: font module not available
    (ImportError: DLL load failed: 找不到指定的模块。)
    我也出现了这个错误,请问下博主是怎么解决的?谢谢~~

    Reply
  5. blues_city

    试下一个你这个脚本,有几个地方有错呀,虽然并不是什么重要的问题倒是了。
    这个设定输出目录有错呀。
    dist_dir = self.dist_dir
    这个应该是在给py2exe的参数里的
    修正办法在 156 - 157 这几行中随便加入一行如下代码。

    “dist_dir” : self.dist_dir , #生成目录

    Reply
    1. xishui Post author

      Thank you! 一直以来用默认名字dist都没有发现这个问题,马上修改,感谢您的提醒。

      Reply
  6. 东方美铃颂

    又是一年父亲节,在此留个名。博主的博客都很不错,支持ing 🙂

    Reply
  7. 1111

    line 27 in
    origIsSystemDLL = py2exe.bulid_exe.isSystemDLL
    AttributeError: ‘module’ object has no attribute ‘bulid_exe’

    报错信息是这个,我百度了找不到解决方法。。

    Reply
    1. xishui Post author

      技术问题请勿用百度,尽管Google被百般和谐,还是比度娘好用~ 您有没有觉得build和bulid长得很像?

      Reply
  8. wangke

    if len(sys.argv) < 2:

    提示我这句语法错误,怎么回事啊

    Reply
    1. xishui Post author

      不知为何小于号<被改成了&lt;,估计是上次数据导入导出的时候出了点小差池……

      Reply
  9. Soul_Eater

    我用的是Win7 64位,python26,pygame是1.9.1的
    给入门到精通(8)中的最后一个例子打包时
    会有pywintypes26.dll找不到

    然后我将这个dll排除就好了……
    self.exclude_dll = [‘pywintypes26.dll’]

    Reply
  10. abcd1234

    出现了问题,但是log文件没找到,应该在哪里找?

    Reply
  11. 六六

    打包时出错了:SystemExit: error: bundle-files 1 not yet supported on win64这个是什么意思啊?求大神指点

    Reply
    1. xishui Post author

      很简单的方法,安装32位的Python和相应的库,有些功能64位的并不支持…… 感觉个人学习,32位完全足够了。

      Reply
  12. jack

    SystemExit: error: command ‘”D:pythonw.exe”‘ failed with exit status 1
    我在打包时出现了上述错误,请问应该如何解决?

    Reply
  13. blackmoon4

    File “D:my_python_studyfighterpy2exe_dabao.py”, line 32, in isSystemDLL
    return origIsSystemDLL(pathname)
    File “D:my_python_studyfighterpy2exe_dabao.py”, line 30, in isSystemDLL
    if os.path.basename(pathname).lower() in (“libfreetype-6.dll”, “libogg-0.dll”, “sdl_ttf.dll”):
    File “F:Program FilesPython25libntpath.py”, line 200, in basename
    return split(p)[1]
    File “F:Program FilesPython25libntpath.py”, line 164, in split
    d, p = splitdrive(p)
    File “F:Program FilesPython25libntpath.py”, line 119, in splitdrive
    if p[1:2] == ‘:’:
    RuntimeError: maximum recursion depth exceeded in cmp
    请教一下,打包出现上面错误,这是最后几句的
    我只改了self.script这个参数,是哪里不对呢??

    Reply
    1. xishui Post author

      如果是仅改了”self.script”,请确定那个文件名是你写的一个脚本,而且那个脚本可以正常运行,如果您确实要递归很多次——虽然我觉得不太有那个可能性——您可以使用sys.setrecursionlimit来暂时增加这个次数限制。

      Reply
  14. blackmoon4

    谢谢啦~虽然还是没搞懂。。。。不过。。暂时先不纠结这块了,从您这里确实学到了不少东西,十分感谢~

    Reply
  15. blues1863

    请教,runtime error!错误如何解决?

    Reply
  16. xuxu

    游戏需要额外的音频、图片的话,那么self.icon_file = None怎么改呢?

    Reply
  17. xuxu

    游戏需要额外的音频、图片的话,为何生成的exe无法打开:

    Traceback (most recent call last):
    File “game.py”, line 22, in
    pygame.error: Couldn’t open resources/images/dude.png
    难道不支持pygame游戏的打包吗?

    Reply
  18. yzkk

    请问self.extra_datas里的是只是文件名吗?用不用包含路径?
    运行的时候出现:
    File “D:pythonlibntpath.py”, line 256, in walk
    names = os.listdir(top)
    TypeError: coercing to Unicode: need string or buffer, NoneType found

    Reply
  19. done

    请问下楼主有没有用过pyinstaller 打包pygame 程序。
    我试过打包单个py文件,pygame文件打包后执行会闪退。
    多谢楼主的辛勤付出。

    Reply
  20. xumaomao

    我的打包出现错误,显示no module named numpy.distutils.tests.
    之后我找到numpy\distutils.tests\目录,建立了一个空白的__init__.py文件,仍然无法解决。在exclude_modules中加上它也不行。

    后来又尝试用pyinstaller,也是像@done一样的问题,执行闪退。
    希望楼主帮助。

    Reply
  21. xumaomao

    update我自己:我在 self.extra_modules 中干脆删除了numpy。运行脚本貌似成功了,但是运行exe的时候出错,打开log文件显示无法打开图片资源文件:
    pygame.error: Couldn’t open G:\tdgame_multithreaded\tdgame\dist\missions.exe\objects\image_riflebullet_1x5x1x15.png

    其中missions.exe是在zipfile_name设为None之后生成的,如果设为别的什么就相应变成设置的名字,结果仍然不能打开。如果在option中把zipfile去掉,它自动生成一个library.zip文件,但是无法打开它,所以图片文件还是不能读取。总之我猜测应该是这里有问题,但是不知道怎么解决。

    Reply
  22. xumaomao

    update myself。py2exe仍然是什么图片也打不开。不过我在pyinstaller 上成功了!font还是需要自己打包进ttf文件才行。不过至少运行成功,虽然其间运行不太流畅。我觉得这种破烂游戏不应该有什么大运算啊,为什么这么卡呢?

    Reply
    1. xishui Post author

      能分享一下吗,让大家瞧瞧慢的罪魁祸首是什么

      Reply
      1. xumaomao

        可以啊。不过慢的问题已经解决了,原来是放了不必要的图形操作进入了主循环,然后内存就满了。
        给出我网盘上分享的地址欢迎博主和其他朋友去下载玩玩。
        http://pan.baidu.com/s/1dD9p6Pr

        Reply
  23. 哈喽楼租

    谢谢楼主,
    可以详细说下打包的步骤吗?
    我用你给的那个脚本总报错,no such file or directory
    然后我用py2exe.org的那个三行的脚本就转出来exe了。
    不知道用它那个少的转pygame可以吗?

    Reply
  24. 晴天小猪

    受教了 这个东西的确很有用 支持博主有空的时候把那本英文书全部翻译出版一下 我会支持正版滴~ :)

    Reply
  25. 王杨

    大神你好:我运行你的程序,也改了bulidExe,可是我的dist文件夹里什么都没有

    Reply
  26. andy

    运行时总出现mixer module not available找不到指定模块

    Reply
  27. from distutils.core import setup
    import glob
    import py2exe
    import sys,os
    import pygame
    from pygame.locals import *
    import math
    import random
    import pygame.mixer
    from pygame import mixer

    sys.path.append(“D:/Program Files/Python2.7/Lib/site-packages/pygame”)

    INCLUDES = [“encodings”, “encodings.*”,”pygame.mixer”,”pygame.font”]
    extra_modules = [‘pygame’]

    options = {“py2exe” :
    {“compressed” : 1,
    “optimize” : 2,
    “bundle_files” : 2,
    “includes” : INCLUDES,
    “packages” :extra_modules,
    “dll_excludes”: [ “MSVCP71.dll”, “mswsock.dll”, “powrprof.dll”,”w9xpopen.exe”]
    }}

    setup(
    options = options,
    windows=[“game.py”],
    zipfile = None,
    data_files=[(“resources/audio”,
    glob.glob(“resources/audio/\*.wav”)),
    (“resources/images”, glob.glob(“resources/images/\*.png”))])

    Traceback (most recent call last):
    File “game.py”, line 7, in
    File “zipextimporter.pyo”, line 98, in load_module
    ImportError: MemoryLoadLibrary failed loading pygame\mixer.pyd

    产生这个错误该怎么解决,查了好多资料都不行。谢谢啊!

    Reply
  28. piratf

    xishui楼主你好,感谢你提供的脚本。
    我的python游戏已经编译成功了,但是运行时出现
    “Fatal Python error: (pygame parachute) Segmentation Fault”
    这样的错误,请问您有遇到过类似的问题吗?

    代码挂在‘https://github.com/piratf/Mytools/tree/master/myCastle’
    一共两百行 有注释,python环境下运行没问题,2.7 求楼主帮忙看下哪里出了问题。。

    再次感谢楼主啦

    Reply
    1. piratf

      debug后发现是字体出了问题,我使用的是在resources文件夹里单独放的字体文件,还是不能用。
      e:\Code\game\myCastle\myCastle.exe:144: RuntimeWarning: use font: MemoryLoadLibrary failed loading pygame\font.pyd
      (ImportError: MemoryLoadLibrary failed loading pygame\font.pyd)
      Traceback (most recent call last):
      File “myCastle.py”, line 144, in
      font = pygame.font.SysFont(“Yahei Consolas Hybrid”, 24)
      File “pygame\__init__.pyo”, line 70, in __getattr__
      NotImplementedError: font module not available
      (ImportError: MemoryLoadLibrary failed loading pygame\font.pyd)

      请问xishui大大“把sdl_ttf.dll声明为非系统文件”应该怎么做呢?或者还有别的方法吗? 谢谢!

      Reply
      1. piratf

        抱歉刚才粘贴的是系统字体出问题的内容。。 单独字体文件也是不行

        Reply
        1. piratf

          后来用pyinstall编译过了,还是不知道为什么这个脚本过不了。不过还是谢谢楼主的脚本!希望有空一起交流,谢谢!

          Reply
  29. answer100

    ———- python ———-
    running py2exe
    creating D:\python\Mydoc\PYGAME\PyGame\build
    creating D:\python\Mydoc\PYGAME\PyGame\build\bdist.win32
    creating D:\python\Mydoc\PYGAME\PyGame\build\bdist.win32\winexe
    creating D:\python\Mydoc\PYGAME\PyGame\build\bdist.win32\winexe\collect-2.7
    creating D:\python\Mydoc\PYGAME\PyGame\build\bdist.win32\winexe\bundle-2.7
    creating D:\python\Mydoc\PYGAME\PyGame\build\bdist.win32\winexe\temp
    creating D:\python\Mydoc\PYGAME\PyGame\dist
    *** searching for required modules ***
    Traceback (most recent call last):
    File “game_to_exe.py”, line 172, in
    BuildExe().run()
    File “game_to_exe.py”, line 163, in run
    data_files = extra_datas,
    File “D:\python\lib\distutils\core.py”, line 151, in setup
    dist.run_commands()
    File “D:\python\lib\distutils\dist.py”, line 953, in run_commands
    self.run_command(cmd)
    File “D:\python\lib\distutils\dist.py”, line 972, in run_command
    cmd_obj.run()
    File “D:\python\lib\site-packages\py2exe\build_exe.py”, line 243, in run
    self._run()
    File “D:\python\lib\site-packages\py2exe\build_exe.py”, line 296, in _run
    self.find_needed_modules(mf, required_files, required_modules)
    File “D:\python\lib\site-packages\py2exe\build_exe.py”, line 1306, in find_needed_modules
    mf.import_hook(f)
    File “D:\python\lib\site-packages\py2exe\mf.py”, line 719, in import_hook
    return Base.import_hook(self,name,caller,fromlist,level)
    File “D:\python\lib\site-packages\py2exe\mf.py”, line 136, in import_hook
    q, tail = self.find_head_package(parent, name)
    File “D:\python\lib\site-packages\py2exe\mf.py”, line 181, in find_head_package
    if ‘.’ in name:
    TypeError: argument of type ‘module’ is not iterable

    输出完毕 (耗时 27 秒) – 正常终止
    这种错误怎么解决啊?

    Reply
  30. Pingback: 用Python和Pygame写游戏-从入门到精通(py2exe篇)-演道网

  31. cxq

    感谢博主,学到了很多xd
    不过话说这个脚本怎么换图标icon?
    我怎么写都不对,直接self.icon_file = “icon.png”也是错的

    Reply
  32. 丁建琦

    大神你好,我运行后总是有这样的错误AttributeError: ‘module’ object has no attribute ‘build_exe’

    Reply
  33. 土匪

    python3.6使用pyinstaller发布:
    首先,安装pyinstaller,直接pip3 install pyinstaller即可。
    然后按以下步骤:
    1、需要在py中添加函数:
    # 用来加载图片的函数,后续所有需要用到图片的地方,都通过该函数来加载。
    def resource_path(relative):
    if hasattr(sys, “_MEIPASS”):
    return os.path.join(sys._MEIPASS, relative)
    return os.path.join(relative)

    2、需要加载图片的地方,以前直接用的路径,现在都使用:
    resource_path(os.path.join(data_dir, ‘ant.png’))
    PS:data_dir是指和脚本同级的用来存放图片的路径,一般使用images。

    3、执行pyi-makespec 参数 要打包的py脚本
    如:pyi-makespec -F game1.py

    4、修改生成的xxx.spec文件
    指定要添加的图片:
    a.datas += [(‘images\\ant.png’,”D:\\PyCharm\\PycharmProjects\\pygame\\images\\ant.png”,’DATA’),(‘images\\leaf.png’,”D:\\PyCharm\\PycharmProjects\\pygame\\images\\leaf.png”,’DATA’),(‘images\\spider.png’,”D:\\PyCharm\\PycharmProjects\\pygame\\images\\spider.png”,’DATA’)]

    如果有多个图片,则可以考虑使用:
    dict_tree = Tree(“D:\PyCharm\PycharmProjects\pygame\images”, prefix = “images”)
    a.datas += dict_tree

    说明:Tree(“实际存放图片的文件夹”,prefix = “代码中图片文件的上级目录。”)
    比如说,在代码中希望load(’images/aaa.jpg’),aaa.jpg在本地实际存储路径是:d:\images\
    则Tree(“d:\\images”,prefix = “images”)
    5、执行pyinstaller xxx.spec

    Reply

发表评论

电子邮件地址不会被公开。 必填项已用*标注