这次不是直接讲解下去,而是谈一下如何把我们写的游戏做成一个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里的各个参数。

 #!python
# -*- coding: gb2312 -*- # 这个脚本专为pygame优化,使用py2exe打包代码和资源至dist目录
#
# 使用中若有问题,可以留言至:
# //eyehere.net/2011/python-pygame-novice-professional-py2exe/
#
# 安装需求:
# python, pygame, py2exe 都应该装上 # 使用方法:
# 1: 修改此文件,指定需要打包的.py和对应数据
# 2: python pygame2exe.py
# 3: 在dist文件夹中,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 # 这个函数是用来判断DLL是否是系统提供的(是的话就不用打包)
origIsSystemDLL = py2exe.build_exe.isSystemDLL
def isSystemDLL(pathname):
# 需要hack一下,freetype和ogg的dll并不是系统DLL
if os.path.basename(pathname).lower() in ("libfreetype-6.dll", "libogg-0.dll", "sdl_ttf.dll"):
return 0
return origIsSystemDLL(pathname)
# 把Hack过的函数重新写回去
py2exe.build_exe.isSystemDLL = isSystemDLL # 这个新的类也是一个Hack,使得pygame的默认字体会被拷贝
class pygame2exe(py2exe.build_exe.py2exe):
def copy_extensions(self, extensions):
# 获得pygame默认字体
pygamedir = os.path.split(pygame.base.__file__)[0]
pygame_default_font = os.path.join(pygamedir, pygame.font.get_default_font())
# 加入拷贝文件列表
extensions.append(Module("pygame.font", pygame_default_font))
py2exe.build_exe.py2exe.copy_extensions(self, extensions) # 这个类是我们真正做事情的部分
class BuildExe:
def __init__(self):
#------------------------------------------------------#
##### 对于一个新的游戏程序,需要修改这里的各个参数 #####
#------------------------------------------------------# # 起始py文件
self.script = "MyGames.py"
# 游戏名
self.project_name = "MyGames"
# 游戏site
self.project_url = "about:none"
# 游戏版本
self.project_version = "0.0"
# 游戏许可
self.license = "MyGames License"
# 游戏作者
self.author_name = "xishui"
# 联系电邮
self.author_email = "blog@eyehere.net"
# 游戏版权
self.copyright = "Copyright (c) 3000 xishui."
# 游戏描述
self.project_description = "MyGames Description"
# 游戏图标(None的话使用pygame的默认图标)
self.icon_file = None
# 额外需要拷贝的文件、文件夹(图片,音频等)
self.extra_datas = []
# 额外需要的python库名
self.extra_modules = []
# 需要排除的python库
self.exclude_modules = []
# 额外需要排除的dll
self.exclude_dll = ['']
# 需要加入的py文件
self.extra_scripts = []
# 打包Zip文件名(None的话,打包到exe文件中)
self.zipfile_name = None
# 生成文件夹
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):
# 从源文件夹内获取文件
def walk_helper(arg, dirname, files):
# 当然你使用其他的版本控制工具什么的,也可以加进来
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): # 删除上次的生成结果
shutil.rmtree(self.dist_dir) # 获得默认图标
if self.icon_file == None:
path = os.path.split(pygame.__file__)[0]
self.icon_file = os.path.join(path, 'pygame.ico') # 获得需要打包的数据文件
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])) # 开始打包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, # 默认生成窗口程序,如果需要生成终端程序(debug阶段),使用:
# 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'): # 清除build文件夹
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.")

可以先从简单的程序开始,有了一点经验再尝试打包复杂的游戏。
一些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的。

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

用Python和Pygame写游戏-从入门到精通(py2exe篇)的更多相关文章

  1. Python基础知识详解 从入门到精通(七)类与对象

    本篇主要是介绍python,内容可先看目录其他基础知识详解,欢迎查看本人的其他文章Python基础知识详解 从入门到精通(一)介绍Python基础知识详解 从入门到精通(二)基础Python基础知识详 ...

  2. Java入门到精通——基础篇之多线程实现简单的PV操作的进程同步

    Java入门到精通——基础篇之多线程实现简单的PV操作的进程同步 一.概述     PV操作是对信号量进行的操作.     进程同步是指在并发进程之间存在一种制约关系,一个进程的执行依赖另一个进程的消 ...

  3. SaltStack 入门到精通第二篇:Salt-master配置文件详解

    SaltStack 入门到精通第二篇:Salt-master配置文件详解     转自(coocla):http://blog.coocla.org/301.html 原本想要重新翻译salt-mas ...

  4. SaltStack入门到精通第一篇:安装SaltStack

    SaltStack入门到精通第一篇:安装SaltStack 作者:纳米龙  发布日期:2014-06-09 17:50:36   实际环境的设定: 系统环境: centos6 或centos5 实验机 ...

  5. Promise入门到精通(初级篇)-附代码详细讲解

    Promise入门到精通(初级篇)-附代码详细讲解 ​     Promise,中文翻译为承诺,约定,契约,从字面意思来看,这应该是类似某种协议,规定了什么事件发生的条件和触发方法. ​     Pr ...

  6. 吴裕雄--天生自然python学习笔记:python 用pygame模块游戏开发

    游戏开发在软件开发领域占据了非常重要的位直.游 戏开发需要用到的技术相当广泛,除了多媒体.图片.动 画的处理外,程序设计更是游戏开发的核心内容. Py game 是为了让 Python 能够进行游戏开 ...

  7. Python 之pygame飞机游戏

    import pygame from pygame.locals import * import time import random # 我机 class HeroPlane(object): de ...

  8. python学习之“切片操作从入门到精通”

    在python学习开发的过程中,我们总是不断的要对List(列表),Tuple(元组)有取值操作:假如我们有一个列表List1现在想取出1其中的前5个元素,改怎么操作呢? >>> L ...

  9. Python必学Django框架,入门到精通学习视频教程全都在这可以领

    “人生苦短,我用python”,学python的小伙伴应该都了解这句话的含义.但是,学python,你真正了了解强大的Django框架吗!? 据说Django还是由吉普赛的一个吉他手的名字命名的呢,有 ...

随机推荐

  1. 整理好的一些mysql表详细操作

    一.创建表的完整语法#语法:create table 库名.表名( 字段名1 类型[(宽度) 约束条件], 字段名2 类型[(宽度) 约束条件], 字段名3 类型[(宽度) 约束条件]);约束条件:是 ...

  2. 迭代器Iterator与语法糖for-each

    一.为什么需要迭代器 设计模式迭代器 迭代器作用于集合,是用来遍历集合元素的对象.迭代器迭代器不是Java独有的,大部分高级语言都提供了迭代器来遍历集合.实际上,迭代器是一种设计模式: 迭代器模式提供 ...

  3. Python9-MySQL-pymysql模块-day44

    import pymysql user = input('username: ') pwd = input('password: ') conn = pymysql.connect(host=',da ...

  4. hihocoder 1097 最小生成树一·Prim算法

    #1097 : 最小生成树一·Prim算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 最近,小Hi很喜欢玩的一款游戏模拟城市开放出了新Mod,在这个Mod中,玩家可 ...

  5. B1056 组合数的和 (15分)

    B1056 组合数的和 (15分) 给定 N 个非 0 的个位数字,用其中任意 2 个数字都可以组合成 1 个 2 位的数字.要求所有可能组合出来的 2 位数字的和.例如给定2.5.8,则可以组合出: ...

  6. BFS:Nightmare(可返回路径)

    解题心得: 1.point:关于可以返回路径的BFS的标记方法,并非是简单的0-1,而是可以用时间比较之后判断是否push. 2.queue创建的地点(初始化问题),在全局中创建queue在一次调用B ...

  7. 最短路径:HDU2006-一个人的旅行(多个起点,多个终点)

    题目: 一个人的旅行 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  8. 如何使用DroidPlugin——DroidPlugin初体验

    最近研究了下360的黑科技--DroidPlugin 刚开始不知道怎么用,于是看了这篇博客:http://www.jianshu.com/p/f1217cce93ef  算是引导了我,于是开始自己写写 ...

  9. Android stadio

    Android stadio 最近遇到大问题,就是主功能行.但是让它做库工程,他就不管用. 但是在eclipse里面就可以.

  10. Creating Hyperv Agent Installer

    Creating Hyperv Agent Installer   Skip to end of metadata   Created by Anshul Gangwar, last modified ...