本文转载自:http://eyehere.net/2011/python-pygame-novice-professional-py2exe/
这次不是直接讲解下去,而是谈一下如何把我们写的游戏做成一个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里的各个参数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
#!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的。
欢迎大家试用并提出建议,不断完善这个脚本。