游戲中需要用到很多對(duì)象,比如人物、野怪、建筑物、UI控件等等,他們的行為不盡相同,但是總有那么些共同點(diǎn),如果將所有的東西都封裝成各自的類難免會(huì)寫上很多重復(fù)的代碼,因?yàn)閮蓚€(gè)對(duì)象如果具有相同的行為(比如人物和野怪都可以行走)如果寫兩個(gè)move()函數(shù),以后改起來就要修改兩個(gè)地方,不容易維護(hù)而且擴(kuò)展很麻煩,但是人物和野怪又有其它不相同的行為,比如技能之類的不同。所以比較好的處理方法是抽象出一個(gè)生物類,然后讓人物和野怪去繼承它,舉個(gè)例子:
class RenderObject(pygame.sprite.Sprite) :
# 靜態(tài)變量
images = []
def __init__(self, selfdata) :
self.image = self.images[ int(selfdata[0]) ]
self.size = [self.image.get_width(), self.image.get_height()]
self.offset = [0,0]
self.position = [0,0]
self.speed = [0.0,0.0]
def move(self, xgo, ygo) :
do_move()
def draw(self, screen) :
do_draw()
以上這個(gè)類RenderObject是自己定義的用于渲染的類的基類,它繼承自pygame.sprite.Sprite,這里有必要先介紹一下pygame.sprite,這個(gè)模塊在pygame中是選擇性使用的,他可以作為游戲中很多對(duì)象的基類,并且將它擁有的東西繪制到Surface上,還有一個(gè)Group類是Sprite類的容器類,可以包含很多Sprite。
RenderObject有三個(gè)類函數(shù),__init__是Python中的特殊函數(shù),類似C語(yǔ)言中的構(gòu)造函數(shù),當(dāng)類實(shí)例被創(chuàng)建的時(shí)候,這個(gè)函數(shù)會(huì)被自動(dòng)執(zhí)行,它的目的是執(zhí)行一些該對(duì)象的必要的初始化工作(我在這個(gè)函數(shù)中加入了一個(gè)selfdata的列表,以便于不同類型的控件添加初始化信息)。move函數(shù)是執(zhí)行移動(dòng)操作,而draw函數(shù)則負(fù)責(zé)渲染。
首先來看下__init__函數(shù),在Python中使用變量不需要提前聲明,所以要用到的變量我把它放在了__init__函數(shù)中進(jìn)行初始化,注意到每個(gè)函數(shù)都有一個(gè)self參數(shù),這個(gè)就好比C語(yǔ)言中的this指針,但是它是顯式聲明,隱式調(diào)用的。在使用類內(nèi)部變量的時(shí)候需要加self做修飾,我們可以看到該類的一些成員變量:
self.image # 該渲染對(duì)象對(duì)應(yīng)的Surface
self.size # 該渲染對(duì)象在Surface的矩形區(qū)域的寬高
self.offset # 該渲染對(duì)象在Surface的左上角坐標(biāo)
self.position # 該渲染對(duì)象將被繪制到屏幕的位置
self.speed # 該渲染對(duì)象的速度
之所以要用到offset和size,是因?yàn)樵?/span>Surface不是完全被用來顯示的,我們只取某一張Surface的某一部分用于顯示,如果不是很明白,那么參看Player類的相關(guān)描述就知道為什么了。
對(duì)于move(self, xgo, ygo)函數(shù),我們暫時(shí)可以這樣實(shí)現(xiàn):
if xgo :
self.position[0] += self.speed[0] * xgo
if ygo :
self.position[1] += self.speed[1] * ygo
xgo和ygo都是三值變量(1,0,-1),分別表示在兩個(gè)坐標(biāo)軸方向是否發(fā)生了位移,并且這個(gè)位移是正向的還是逆向的。于是我們可以通過鍵盤輸入來傳遞對(duì)應(yīng)的參數(shù),position的值就會(huì)隨之變化了。注意如果這里速度為0,則表示靜態(tài)物體,position不會(huì)做任何變化。
對(duì)于draw(self, screen)函數(shù),用于將當(dāng)前對(duì)象繪制到屏幕上,screen參數(shù)是上一節(jié)中提到的屏幕Surface,我們調(diào)用Surface的blit函數(shù)就可以在屏幕上繪制當(dāng)前對(duì)象了,像這樣:
screen.blit( self.image, self.position, (self.offset, self.size))
(self.offset, self.size)表示self.image這個(gè)Surface上對(duì)應(yīng)的矩形區(qū)域。
基類完成后,我們需要派生出一些子類,例如:
class Player(RenderObject) :
actionwait = 50
def __init__(self, selfdata) :
RenderObject.__init__(self, selfdata)
self.size[0] /= 4
self.size[1] /= 4
self.speed = [0.1,0.1]
self.direction=3
self.action=0
def move(self, xgo, ygo) :
RenderObject.move(self, xgo, ygo)
if xgo or ygo :
self.action = (self.action + 1) % (self.actionwait * 4)
self.offset[0] = (self.action / self.actionwait) * self.size[0]
self.offset[1] = self.direction * self.size[1]