Pygame是脚本语言Python的一个扩展包就是SDL的封装包,是用Python 和C语言开发;开发人是Pete Shinners。专门用于开发各类游戏。SDL意思是Simple Directmedia Library即“简单媒体类库”,这是一个跨平台的控制多媒体的C语言类库,类似于 DirectX。这里说的媒体包括CDROM即光驱、键盘鼠标、音频视频、操纵杆等 输入输出设备,Pygame写了关于这些对象的类库可在官方网站上找到。因为是“面向对象”就是所谓Object-Oriented编程语言,所以我们可 以继承这些类的性质来编写我们自己的游戏。
Pygame的官方网站:
可惜中文的Pygame文档还没有。因为Pygame是面向对象脚本编程语言 Python的一个扩展,所以在使用Pygame之前要求基本的Python的知识和技术。
不 管在什么平台上开发,所有游戏的代码通常会有的结构包含六个部分:
- (一)加载Pygame的或者其他工具软件的模块,在 Python是使用import语法完成;
- (二)资源处理类包括处理图象、声音、连接或断开网络等;
- (三)游戏本身 的对象类;
- (四)其他函数。包括不能归类的必要函数,它们可以归入游戏的逻辑代码块里但是这样处理会增加理解代 码的难度,所以把这类函数单独处理;
- (五)初始化。包括Pygame本身对象的初始化;游戏对象的初始化;背景、鼠标的初始化等;
- (六) 主循环就是def main()。处理用户输入、更新游戏对象和显示区等。
实 际上,游戏的结构是个风格问题,不同的人、从不同的侧重点出发会使用不同的方法组织自己的游戏代码。中国人学太极拳的时候有这样的一个讲究,刚刚开始学的 时候要有严格的“架式”就是动作规范,但是等到悟到用意不用力、用意念引导动作的阶段就可以随心所欲,不必太拘泥于一招一式细节了。
例如有从xx另外的角度的方法,把代码按照一下四个方面组织:(请查看的 资源作为参考)
- 模块和对象的初始化;
- 处理用户输入和事件循环;
- 动画和模拟;
- 提 交;
不管使用什么方式组织代码,上面例子中最主要的结构有两个:一个是主程 序即mail() loop;一个是游戏对象的类。主程序是游戏脚本开始时执行的,包括处理Pygame模块本身的初始化和游戏对象的初始化,还包括所谓事件循环就是处理游 戏玩家的输入如鼠标、键盘动作和其他事件的队列;而游戏类对象封装了游戏角色的数据和逻辑。对于初学者来说,先理解这两个结构可收提纲协领的效果。有些简 单的游戏只有一个游戏对象(没办法,我们总是要从最简单的例子开始),可能没有xx按照上面的格式写,但总是包含了这样的模式在里面。
这里有一个Pygame的代码库,各种游戏代码可供研究:
{dy}个简单的例程hello.py:
#Find place where Python interpretor located 让游戏脚本找到Python解释器安装的地方
#!/usr/bin/python
#Import using modules 输入要用到的模块
import pygame
from pygame.locals import *
def main():
#Initialise screen 初始化。初始化软件模块、初始化屏幕
pygame.init()
screen = pygame.display.set_mode((150, 50))
pygame.display.set_caption(’Basic Pygame program’)
#Fill background 添入背景
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((250, 250, 250))
#Display some text 显示区里显示文本
font = pygame.font.Font(None, 36)
text = font.render(”Hello There”, 1, (10, 10, 10))
textpos = text.get_rect()
textpos.centerx = background.get_rect().centerx
background.blit(text, textpos)
#Blit everything to the screen 把所有东西画到屏幕上
screen.blit(background, (0, 0))
pygame.display.flip()
#Event loop事件循环
while 1:
for event in pygame.event.get():
if event.type == QUIT:
return
screen.blit(background, (0, 0))
pygame.display.flip()
#start main() 启动脚本时执行主循环
if __name__ == ‘__main__’: main()
把这段代码用自己的编辑器写入你 的一个名字叫py/的目录里,这个目录里只包含作为测试和学习用的代码样例(当然你也可以有其他的安排,你肯定有自己的打算 。注意你下载这个程序时不要使用中文注释,特别不要使用中文的#号,Python的解释器不能识别。请只下载代码。我这里加中文是为了解释代码的方便。注 意给这个脚本一个名字hello.py。
用这个简单的程序我们完成了一个框架,多数应用程序特别 是一个游戏就是写在这上面的,如下图:
不算空格,加注释行,就是以#号开始的,以上总共31行代码。还有其他的语言能用同样的代码量来完成同样的工作 吗?也许你用可视化工具可以很容易地作出这了来,但那只是“依样画葫芦”!而你用Python写出这个简单的框架,你学会了一种功能强大的语言!也许你会 说Java的Applet能用更少的代码完成这些工作,实际上不是这样的,因为Java/Applet是在用户端的浏览器帮助下完成的,而这个是 stand alone。Python还是一种标准的黑客工具,世界上顶极黑客正在使用她!
是很 简单吗?但是你已经开始了!这个简单的程序里已经包含了游戏的主要结构。
首先你要在计算机监视器上创建一个游戏执行的框架区域,一般叫做 screen。
***********************************************
课 堂实验一
使用命令python进入命令行模式:
>>> import pygame
>>> from pygame.locals import *
>>> screen = pygame.display.set_mode((800,400))
这样 你创建了一块屏幕面积,宽800个像素,高400个像素,它的左上角的坐标为(0,0)这样你就完成了屏幕初始化的工作。
********************************************
学习一种语言{zh0}的办法就是实验,通过观察软件的行为,输入输出的变化来理解代码的功能。跟随我的路线图保证你 能在最短时间内顺利掌握语言和技术精髓,不必从基本教程开始。牛顿说过:“在科学发展上实例比理论更重要!”,我相信在学习技术上也是这样。我们先仔细地 研究这个程序样例,深入剖析,彻底理解,举一反三,触类旁通。
- (1)pygame.init( ) ——实现模块初始化,就是把你要输入的模块进行初始化,准备工作;
- (2)screen. = pygame.display.set_mode((150,50)) ——初始化游戏屏幕,宽150高50个像素。
- (3)pygame.display.set_caption( ‘Basic Pygame Program’) ——在屏幕的页眉上写字;
- (4)background = pygame.Surface(screen.get_size() ) ——开始填满背景,.get_size()表示跟屏幕一样大。引用Surface创建的实例相当于在前面创建的screen上敷上一张画布,所以后面的 blit( )方法实际上是在这张画布上画,而不是直接在screen上画;
- (5)background.fill((255,255,255)) —— 把RGB格式的颜色写入背景;
- (6)font = pygame.font.Font( );text = font.render(”Hello There”,1,(10,10,10))以及上面的screen是模块的对象,区别于游戏本身的对象。font创建字体对象,text创建文本对象就是 框架中间的Hello There,(10,10,10)是文本字体的颜色,而中间的数字1是对字体性质的限定,这里我们先忽略;
- (7)textpos = text.get_rect( ) —— 是为font.render( )提交变量的text准备一个矩形框,让提交的文本放在这里;
- (8)background.blit ( text,textpos ) —— 可能blit ( )是最值得注意的方法,这不是一个常用词,本copy和past是同义词,就是拷贝和粘貼的意思,把什么什么拷贝/粘貼在什么什么上面,这里就是把 text粘貼在textpos上的意思;
- (9)screen.blit(background,(0,0)) —— 接着又一次出现blit( )方法,这次是把上一步粘貼好文本的background再拷贝在screen上,(0,0)表示从坐标原点开始就是从左上角开始;
- (10)pygame.display.flip( ) —— flip英文意思是轻拍、快速翻转,这个方法xx各个元素,以后我们还会碰到方法update( ),这二者的作用有些相似,从字面上可以看出这个意思;
- (11)While 1 : —— 下面就开始事件循环,把可能的用户输入和其他输入的动作队列循环测试,给出应有的反应;
- (12){zh1}又出现了blit()、 flip()方法,在每次检测之后更新画面;
- (13)if —— 语句告诉游戏脚本执行定义的主循环程序即def main()。
第 二个有动画的例程ball.py:(可在下载/拷贝/测试)
import sys, pygame
pygame.init()
size = width, height = 320, 240
speed = [2, 2]
black = 0, 0, 0
screen = pygame.display.set_mode(size)
ball = pygame.image.load(”ball.bmp”)
ballrect = ball.get_rect()
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
ballrect = ballrect.move(speed)
if ballrect.left < 0 or ballrect.right > width:
speed[0] = -speed[0]
if ballrect.top < 0 or ballrect.bottom > height:
speed[1] = -speed[1]
screen.fill(black)
screen.blit(ball, ballrect)
pygame.display.flip()
在这个例 程中有了一个游戏对象就是一个运动的球,有了处理资源的语句就是ball = pygame.image.load(”ball.bmp”)。资源包括图像文件、声音文件、互联网接入等。Pygame能接受几乎所有图像音频视频文件 格式如bmp、jpeg、mp3等。
第三个例程是更完整的chimp.py:(可在下载/拷贝/测 试)
#/usr/bin/env python """ This simple example is used for the line-by-line tutorial that comes with pygame. It is based on a 'popular' web banner. Note there are comments here, but for the full explanation, follow along in the tutorial. """ #Import Modules import os, pygame from pygame.locals import * if not pygame.font: print 'Warning, fonts disabled' if not pygame.mixer: print 'Warning, sound disabled' #functions to create our resources一下是处理资源的函数,如下载图像文件或者声音文件 def load_image(name, colorkey=None): fullname = os.path.join('data', name) try: image = pygame.image.load(fullname) except pygame.error, message: print 'Cannot load image:', fullname raise SystemExit, message image = image.convert() if colorkey is not None: if colorkey is -1: colorkey = image.get_at((0,0)) image.set_colorkey(colorkey, RLEACCEL) return image, image.get_rect() def load_sound(name): class NoneSound: def play(self): pass if not pygame.mixer or not pygame.mixer.get_init(): return NoneSound() fullname = os.path.join('data', name) try: sound = pygame.mixer.Sound(fullname) except pygame.error, message: print 'Cannot load sound:', fullname raise SystemExit, message return sound #classes for our game objects以下是本游戏仅有的两个对象的类Fist和Chimp,这是游戏中涉及模拟和动画的部分 class Fist(pygame.sprite.Sprite): """moves a clenched fist on the screen, following the mouse""" def __init__(self): pygame.sprite.Sprite.__init__(self) #call Sprite initializer self.image, self.rect = load_image('fist.bmp', -1) self.punching = 0 def update(self): "move the fist based on the mouse position" pos = pygame.mouse.get_pos() self.rect.midtop = pos if self.punching: self.rect.move_ip(5, 10) def punch(self, target): "returns true if the fist collides with the target" if not self.punching: self.punching = 1 hitbox = self.rect.inflate(-5, -5) return hitbox.colliderect(target.rect) def unpunch(self): "called to pull the fist back" self.punching = 0 class Chimp(pygame.sprite.Sprite): """moves a monkey critter across the screen. it can spin the monkey when it is punched.""" def __init__(self): pygame.sprite.Sprite.__init__(self) #call Sprite intializer self.image, self.rect = load_image('chimp.bmp', -1) screen = pygame.display.get_surface() self.area = screen.get_rect() self.rect.topleft = 10, 10 self.move = 9 self.di = 0 def update(self): "walk or spin, depending on the monkeys state" if self.di: self._spin() else: self._walk() def _walk(self): "move the monkey across the screen, and turn at the ends" newpos = self.rect.move((self.move, 0)) if self.rect.left < self.area.left or \ self.rect.right > self.area.right: self.move = -self.move newpos = self.rect.move((self.move, 0)) self.image = pygame.transform.flip(self.image, 1, 0) self.rect = newpos def _spin(self): "spin the monkey image" center = self.rect.center self.di = self.di + 12 if self.di >= 360: self.di = 0 self.image = self.original else: rotate = pygame.transform.rotate self.image = rotate(self.original, self.di) self.rect = self.image.get_rect(center=center) def punched(self): "this will cause the monkey to start spinning" if not self.di: self.di = 1 self.original = self.image #主循环开始。当游戏脚本开始这个函数即被调用,并初始化模块和游戏对象,执行事件循环直到返回 def main(): """this function is called when the program starts. it initializes everything it needs, then runs in a loop until the function returns.""" #Initialize Everything初始化 pygame.init() screen = pygame.display.set_mode((468, 60)) pygame.display.set_caption('Monkey Fever') pygame.mouse.set_visible(0) #Create The Backgound创建背景 background = pygame.Surface(screen.get_size()) background = background.convert() background.fill((250, 250, 250)) #Put Text On The Background, Centered把文本贴在或者拷贝在背景上。{dy}次出现blit( )函数 if pygame.font: font = pygame.font.Font(None, 36) text = font.render("Pummel The Chimp, And Win $$$", 1, (10, 10, 10)) textpos = text.get_rect(centerx=background.get_width()/2) background.blit(text, textpos) #Display The Background显示背景并更新。第二次出现blit( )函数 screen.blit(background, (0, 0)) pygame.display.flip() #Prepare Game Objects准备好游戏对象包括时钟控制、模拟的对象、资源对象等 clock = pygame.time.Clock() whiff_sound = load_sound('whiff.wav') punch_sound = load_sound('punch.wav') chimp = Chimp() fist = Fist() allsprites = pygame.sprite.RenderPlain((fist, chimp)) #Main Loop 事件循环,鼠标、键盘等的事件队列 while 1: clock.tick(60) #Handle Input Events 处理用户输入事件 for event in pygame.event.get(): if event.type == QUIT: return elif event.type == KEYDOWN and event.key == K_ESCAPE: return elif event.type == MOUSEBUTTONDOWN: if fist.punch(chimp): punch_sound.play() #punch chimp.punched() else: whiff_sound.play() #miss elif event.type is MOUSEBUTTONUP: fist.unpunch() allsprites.update() #Draw Everything 第三次出现blit( )函数 screen.blit(background, (0, 0)) allsprites.draw(screen) pygame.display.flip() #Game Over #this calls the 'main' function when this script is executed 当本游戏脚本执行时调用main( )函数 if __name__ == '__main__': main()
首 先在代码开始的地方有三重的双括号”"” “”",括号内的叫docstring就是关于代码的文档说明,规范地说,每个程序代码都应该包含这部分内容,开发者自己或开发团队可以从这里获得关于代 码的功能、许可证等方面的信息。这是Python所特有的所谓“自省”功能,英语叫“Introspection”。这里有必要加以简单的介绍。在命令行 里使用dir(module/function),在实验中用 Python的模块、函数、方法os、sys、 pygame等等甚至是一个数字如2来代替括号里的斜体字,可以查看对象的性质。因为在Python里,一切都是对象,所以这些都可以使用dir()函数 查看对象的性质,这包括对象的结构、包含的函数和方法、类的继承关系、子类、可以接受的变量、返回的结果等详细信息。另外有同等功能的是在命令行的符 号>>>里使用help( )函数,用法与dir( )相同,但是得到的信息有所不同。这些都内嵌在Python的解释器里所以叫做内省的。非常形象。
***********************************************
课 堂实验二
>>> import pygame
>>> print dir(pygame)
>>> print dir(pygame.Rect)
>>> print help(pygame.Rect)
例 如:使用print dir(pygame.Rect)得到以下信息:
['__class__', '__cmp__', '__coerce__', '__copy__', '__delattr__', '__delitem__', '__delslice__', '__doc__', '__getattribute__', '__getitem__', '__getslice__', '__hash__', '__init__', '__len__', '__new__', '__nonzero__', '__reduce__', '__reduce_ex__', '__repr__', '__safe_for_unpickling__', '__setattr__', '__setitem__', '__setslice__', '__str__', 'bottom', 'bottomleft', 'bottomright', 'center', 'centerx', 'centery', 'clamp', 'clamp_ip', 'clip', 'collidedict', 'collidedictall', 'collidelist', 'collidelistall', 'collidepoint', 'colliderect', 'contains', 'fit', 'h', 'height', 'inflate', 'inflate_ip', 'left', 'midbottom', 'midleft', 'midright', 'midtop', 'move', 'move_ip', 'normalize', 'right', 'size', 'top', 'topleft', 'topright', 'union', 'union_ip', 'unionall', 'unionall_ip', 'w', 'width', 'x', 'y']
信息给出了Pygame的模块Rect包含的函数、需要 的变量和子类。这样你就知道怎样使用这个模块,例如由Rect创建的矩形面积有bottonleft、bottonright,就是左按钮、右按钮,那么 跟按钮绑定的动作就是可引用的。面向对象包含的封装就是把对象的性质和动作封装在一个类里面。
如果使用 help(pygame.Rect)得到信息如下:
Help on class Rect in module pygame:
class Rect(__builtin__.object)
| The rectangle object is a useful object
| representing a rectangle area. Rectangles are
| created from the pygame.Rect() function. This routine
| is also in the locals module, so importing the locals
| into your namespace allows you to just use Rect().
|
| Rect contains helpful methods, as well as a list of
| modifiable members:
| top, bottom, left, right, topleft, topright,
| bottomleft, bottomright, size, width, height,
| center, centerx, centery, midleft, midright, midtop,
| midbottom.
| When changing these members, the rectangle
| will be moved to the given assignment. (except when
| changing the size, width, or height member, which will
| resize the rectangle from the topleft corner)
|
| The rectstyle arguments used frequently with the
| Rect object (and elsewhere in pygame) is one of
| the following things.
… …
这 些信息告诉我们库类Rect能为我们作些什么工作,它创建一个矩形的面积把Sprite创建的对象就是图像放在里面等等。
********************************************
我 们在注释里强调了三次出现blit( )函数,所以这个函数对于理解游戏代码是个关键!{dy}个blit()的语法是background.blit(text,textpos),即把文本 text拷贝在text的位置textpos上,并把textpos拷贝在background上;第二个blit()的语法是 screen.blit(background,(0,0)),是把有了文本的background拷贝在screen上;第三个 screen.blit(background,(0,0))把上面刚创建、并拷贝在background上的游戏模拟对象fist和chimp再拷贝到 screen上;还有要注意的是,每个blit()后面都跟随一个flip(),上面在简单例子里我们已经介绍了英语flip的意义,这是要更新画面,动 画就是每一个循环给游戏对象一个新的位置,然后用flip()使得动画不断翻转,得到运动的感觉。而语句clock.tick(60)是由创建游戏对象的 部分里的clock = pagame.time.Clock()语句对象化得到的,这个对象告诉游戏脚本按照每秒60桢的速度更新屏幕。
PyGame的库类介绍
Pygame的类库:
|| || || || || || || || || || || || || || || || || || || || ||
这 些库类的功能可以望文生义,如Crom是处理光盘的类,Cursors是处理光标的类,Key是处理键盘的类,Joystick是处理游戏操纵杆的类, Mouse是处理鼠标的,而Music显然是处理音乐的。等大家有了一些基础之后就应该仔细地研究这些类库,熟练地掌握他们做起游戏来得心应手,左右逢 源。下面我们将就最常用的加以说明,在上面的样例涉及到的就是最重要的类库。
下面我们将以sprite、Display、Event、 Image等为例说明类库的使用。