小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

用Python和Pygame寫游戲

 gljin_cn 2014-09-15

我們終于把pygame的方方面面都說了一遍,也經(jīng)過了兩個小游戲的洗禮,如果您真的好好學(xué)習(xí)了每一部分并自動動手演練過,那就是一個很不錯的Python游戲開發(fā)人員啦!

但是,不得不說我們到現(xiàn)在為止,寫的東西都不夠酷!pygame就這點能耐么?第一篇介紹pygame的時候,我就說了pygame很適合做一個植物大戰(zhàn)僵尸之類的游戲,OK,那么,這次開始我們就來用pygame山寨一個吧哈哈。

pygame版植物大戰(zhàn)僵尸

游戲介紹就省略了,不過說實話這游戲我也沒玩幾關(guān),感受了一下就關(guān)了。所以現(xiàn)在仿制的與真品相比肯定差了很多,這里只是稍微把我們學(xué)習(xí)的東西溫習(xí)應(yīng)用一下而已,如果各位看到什么不對勁兒的東西,只要不是很致命,也就一笑而過吧。

創(chuàng)意(抄襲)

游戲是否賣座,創(chuàng)意是極為重要的。所有其他技術(shù)性的東西,比如畫面音樂都是有可替代性的,也就是說,可以通過學(xué)習(xí)獲得的,而創(chuàng)意則不同,植物大戰(zhàn)僵尸之前,有無數(shù)的塔防游戲,為什么沒有這么火?首先制作精良,上手容易,然后兩者的結(jié)合給人耳目一新,闖關(guān)的模式更是易于上手難于精通,非常具有可挖掘性。當(dāng)然原因肯定不止這么多,不管是游戲還是電影,成功永遠(yuǎn)有規(guī)律可循,然而卻永遠(yuǎn)無法復(fù)制??梢詫W(xué)習(xí)一下它的好的地方,但光學(xué)習(xí)是不可能突破的。

這個雖然極為重要,但不是我們的重點,我們這里基本就是抄襲——哦不,是參考,所以就不多講了(也沒有人能講出什么東西來)。

資源

好的游戲往往需要極為漂亮的畫面,這里也還是發(fā)揮拿來主義吧~ 各種背景角色啊音樂都解包復(fù)制過來就是了。怎么解包?網(wǎng)上搜一下。

不過如果分析一下資源包里的文件,會發(fā)現(xiàn)它分的特別細(xì),比如說一個太陽花,周圍一圈花瓣,居然是一個一個分開來存放的!這個引擎還挺有意思。我們的pygame不太適合用這樣的圖片資源,還是把每一幀完整的分別存放吧。當(dāng)然可以一幀一個文件,有些麻煩,還增加讀盤時間?;叵胂耂urface里學(xué)習(xí)的東西,我們可以把這么多幀拼成一個圖片,然后取一部分就可以了。比如說太陽花,處理以后會是下面的樣子:

每個幀都并列排開,太陽花的話一共有18個畫面,很長的一張圖。每個畫面都有共同的高度和寬度,所以一旦我們讀進(jìn)這個文件并轉(zhuǎn)成Surface以后,就拆成18個Subsurface,在渲染的時候,分別畫出來,就有動態(tài)的效果了。

很顯然我們在分割的時候需要知道寬度(高度的話,如果只有一行,就無所謂了),可以在代碼里寫好,我這里就是這么做的。不過也許自己在寫游戲的時候,美工和程序不在一起做,那么就需要良好溝通,或者這種小制作的話,就把圖片文件名規(guī)定一下,叫【sunflower_82x77_18.png】好了,意思是【名字_寬x高_(dá)數(shù).后綴】,這樣代碼可以根據(jù)讀入的文件名自動轉(zhuǎn)換。只是舉個例子,總之,游戲資源繁多,好好的管理是很重要的。

構(gòu)架

因為只是做一個demo,太復(fù)雜的構(gòu)架也就免了,這次我就隨便寫寫了。而且也沒有什么絕對優(yōu)秀的構(gòu)架可以放到哪里都好用,根據(jù)要求自己選擇判斷才是重要的。

開始——太陽花擺起來

我們之前的各種動畫,變化的只有位置,在一款優(yōu)秀的游戲中,這個是不允許存在的,飛機什么的可能還好說一些,要是有人物走動的時候,腳也不動一下豈不見鬼了?不過,難道每畫一幀就換一個圖片貼上去么?好像很麻煩啊……

放心,一點都不比移動困難,溫習(xí)一下之前的Sprite篇(其實AI部分結(jié)束那個時候我就開始穿插寫實戰(zhàn)了,發(fā)現(xiàn)缺少Sprite的知識實在不方便,就加了一個Sprite的介紹,實戰(zhàn)就挪到了最后),我們既然把畫圖全部交給Sprite來做,那么圖片的切換也可以交給它來做。

Python
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
MAIN_DIR = os.path.split(os.path.abspath(__file__))[0]
def load_image(file, width=None, number=None):
    file = os.path.join(MAIN_DIR, 'data/image', file)
    try:
        surface = pygame.image.load(file).convert_alpha()
    except pygame.error:
        raise SystemExit('Could not load image "%s" %s'%(file, pygame.get_error()))
    if width == None:
        return surface
    height = surface.get_height()
    return [surface.subsurface(
        Rect((i * width, 0), (width, height))
        ) for i in xrange(number)]
class SunFlower(pygame.sprite.Sprite):
    _width = 82
    _height = 77
    _number = 18
    images = []
    def __init__(self):
        self.order = 0
        pygame.sprite.Sprite.__init__(self)
        if len(self.images) == 0:
            self.images = load_image("sunflower.png", self._width, self._number)
        self.image = self.images[self.order]
        self.rect = Rect(0, 0, self._width, self._height)
    def update(self):
        if self.order >= self._number - 1:
            self.order = -1
        self.order += 1
        self.image = self.images[self.order]

這里有兩個內(nèi)容,一個是load_image函數(shù),它接受三個參數(shù),圖片文件名、每一幀的寬度和總幀數(shù),它所做的事情就是把圖片讀入之后分割Subsurface,把一個Subsurface的列表返回。這個函數(shù)被SunFlower類的初始化函數(shù)調(diào)用,返回值存放在靜態(tài)變量images里。

為什么把Subsurface列表存為靜態(tài)變量,也是有含義的。這樣一來這個圖片只會第一次新建SunFlower類的實例的時候加載一次,下一次在新建一個太陽花的時候,就不會再讀取sunflower.png文件了,節(jié)約內(nèi)存和時間。

然后看update方法,這里做的事情便是是SunFlower當(dāng)前的image指向下一個Subsurface(到頭的話重新開始),這樣每次blit的時候,就會和上一次有些差別,動態(tài)效果就出來了。

不過對于“基于時間的移動”那部分學(xué)習(xí)的比較好的話,很肯會考慮到一個問題。我們這里是一幀切換一個畫面,萬一游戲變得很復(fù)雜或者運行的機器很糟糕,每一幀都花了大量時間的話,豈不是就動的很慢了?牛機器上的話,又要擺的像螺旋槳一樣看著就要飛起來似地……怎么辦?一樣,使用基于時間的幀切換!

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class SunFlower(pygame.sprite.Sprite):
    _rate = 100
    _width = 82
    _height = 77
    _number = 18
    images = []
    def __init__(self):
        self.order = 0
        pygame.sprite.Sprite.__init__(self)
        if len(self.images) == 0:
            self.images = load_image("sunflower.png", self._width, self._number)
        self.image = self.images[self.order]
        self.rect = Rect(0, 0, self._width, self._height)
        self.life = self._life
        self.passed_time = 0
    def update(self, passed_time):
        self.passed_time += passed_time
        self.order = ( self.passed_time / self._rate ) % self._number
        if self.order == 0 and self.passed_time > self._rate:
            self.passed_time = 0
        self.image = self.images[self.order]

與上一個SunFlower類相比,我們多了一個_rate靜態(tài)變量,然后初始化的時候也多了一個passed_time靜態(tài)變量,update也多了一個參數(shù)。盡管看起來有變得復(fù)雜了一些,這一切都是值得的!_rate意味著一幀畫面要保持多少毫秒,passed_time則記錄著游戲經(jīng)過了多少毫秒(為了避免passed_time無限增大,我在合適的時候把它歸零了),我們通過這兩個參數(shù)計算出現(xiàn)在應(yīng)該顯示第幾幀,盡管形式不同,這和基于時間的移動是一個道理。希望大家能看明白(不明白的話多看幾遍……再看不明白的去復(fù)習(xí)第8部分,再不明白的,面壁去……哦,我是說咱倆都得去面壁)。

這里不就先不給出完整的程序了,相信有了前面的經(jīng)驗很容易就可以寫一個框子運行起來,自己試一下?如果你能看到類似左邊的畫面,你就贏了!準(zhǔn)備迎接下一波驚喜吧。

如果沒能成功的運行起來(雖然似乎有點不應(yīng)該),也沒關(guān)系,這個系列完成以后會放出完整代碼的。

本次使用的太陽花資源圖片: sunflower.png

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約