【python遊戲編程之旅】第九篇---嗷大喵快跑小遊戲開發實例

本系列博客介紹以python+pygame庫進行小遊戲的開發。有寫的不對之處還望各位海涵。html

 

前幾期博客咱們一塊兒學習了,pygame中的衝突檢測技術以及一些經常使用的數據結構python

此次咱們來一塊兒作一個簡單的酷跑類遊戲綜合運用之前學到的知識。git

程序下載地址:https://pan.baidu.com/s/1Ji2Ubsds6z2brBx8Gz1OOw 提取碼:dff4 github

源代碼網盤地址:https://pan.baidu.com/s/1T7tlYbTNUPRhtJ45B6PAPw  提取碼:mhip 數據結構

github地址:https://github.com/XINCGer/catRunFastdom

效果圖:ide

 

如今咱們來分析一下製做流程:函數

遊戲中一共有嗷大喵,惡龍,火焰,爆炸動畫和果實(就是上方藍色的矩形塊)這幾種精靈。這裏咱們使用到了前幾期博客中的MyLibrary.py。上述這幾個精靈都是 MySprite類實例化的對象。學習

爲了方便管理。咱們創建了幾個精靈組,而且將一些精靈塞到了裏面:動畫

#建立精靈組
group = pygame.sprite.Group()
group_exp = pygame.sprite.Group()
group_fruit = pygame.sprite.Group()
#建立怪物精靈
dragon = MySprite()
dragon.load("dragon.png", 260, 150, 3)
dragon.position = 100, 230
group.add(dragon)

#建立爆炸動畫
explosion = MySprite()
explosion.load("explosion.png",128,128,6)
#建立玩家精靈
player = MySprite()
player.load("sprite.png", 100, 100, 4)
player.position = 400, 270
group.add(player)

#建立子彈精靈
arrow = MySprite()
arrow.load("flame.png", 40, 16, 1)
arrow.position = 800,320
group.add(arrow)

 

在程序開始的時候咱們能夠看到有一個歡迎界面,爲了簡單我這裏是直接在ps裏面作好了圖片,而後加載到程序中的:

interface = pygame.image.load("interface.png")

界面上面還有一個按鈕,當鼠標通過的時候,會變成灰底的,所以咱們設計一個button類:

簡單來講就是預先加載一張正常狀態下在的button圖片和一個按下狀態的button圖片,而後判斷鼠標的pos是否和button的位置有重合,若是有則顯示button被按下時的圖片。

關於button的設計我參考了這位博友的教程:http://www.cnblogs.com/SRL-Southern/p/4949624.html,他的教程寫的很是不錯。

#定義一個按鈕類
class Button(object):
    def __init__(self, upimage, downimage,position):
        self.imageUp = pygame.image.load(upimage).convert_alpha()
        self.imageDown = pygame.image.load(downimage).convert_alpha()
        self.position = position
        self.game_start = False
        
    def isOver(self):
        point_x,point_y = pygame.mouse.get_pos()
        x, y = self. position
        w, h = self.imageUp.get_size()

        in_x = x - w/2 < point_x < x + w/2
        in_y = y - h/2 < point_y < y + h/2
        return in_x and in_y

    def render(self):
        w, h = self.imageUp.get_size()
        x, y = self.position
        
        if self.isOver():
            screen.blit(self.imageDown, (x-w/2,y-h/2))
        else:
            screen.blit(self.imageUp, (x-w/2, y-h/2))
    def is_start(self):
        if self.isOver():
            b1,b2,b3 = pygame.mouse.get_pressed()
            if b1 == 1:
                self.game_start = True
                bg_sound.play_pause()
                btn_sound.play_sound()
                bg_sound.play_sound()

能夠看到這個button類裏面我還添加了一個isStart的方法,他是用來判斷是否開始遊戲的。當鼠標的位置與button重合,且按下鼠標左鍵的時候,遊戲就開始。

(將game_start變量置爲True)而後經過btn_sound.play_sound(),bg_sound.play_sound() 這兩句來播放按鈕被按下的聲音和遊戲的背景音樂。

關於pygame中聲音的操做,我稍後介紹一下。

 

能夠看到程序中還有一個不停滾動的地圖,讓咱們來實現這個滾動地圖類:

#定義一個滾動地圖類
class MyMap(pygame.sprite.Sprite):
    
    def __init__(self,x,y):
        self.x = x
        self.y = y
        self.bg = pygame.image.load("background.png").convert_alpha()
    def map_rolling(self):
        if self.x < -600:
            self.x = 600
        else:
            self.x -=5
    def map_update(self):
        screen.blit(self.bg, (self.x,self.y))
    def set_pos(x,y):
        self.x =x
        self.y =y

建立兩個地圖對象:

#建立地圖對象
bg1 = MyMap(0,0)
bg2 = MyMap(600,0)

在程序中直接調用update和rolling方法就可讓地圖無限的滾動起來了。

bg1.map_update()
bg2.map_update()
bg1.map_rolling()
bg2.map_rolling()

你看明白這個無限滾動地圖是如何工做的了嗎。首先渲染兩張地圖背景,一張展現在屏幕上面,一張在屏幕以外預備着(咱們暫時看不到),以下圖所示:

而後兩張地圖一塊兒以相同的速度向左移動:

當地圖1徹底離開屏幕範圍的時候,再次將它的座標置爲600,0(這樣就又回到了狀態1):

這樣經過兩張圖片的不斷顛倒位置,而後平移,在咱們的視覺中就造成了一張不斷滾動的地圖了。

 

下面介紹一下如何在pygame中加載而且使用聲音:

1.初始化音頻模塊:

咱們要使用的音頻系統包含在了pygame的pygame.mixer模塊裏面。所以在使用音頻以前要初始化這個模塊:

pygame.mixer.init()

這個初始化模塊語句在程序中執行一次就好。

2.加載音頻文件:

使用的是pygame.mixer.Sound類來加載和管理音頻文件,pygame支持兩種音頻文件:未壓縮的WAV和OGG音頻文件,若是要播放長時間的音樂,我推薦你使用OGG格式音頻文件,由於它的體積比較小,適合長時間的加載和播放。當你要播放比較短的音頻的時候能夠選擇WAV。

hit_au = pygame.mixer.Sound("exlposion.wav")

3.播放音樂:

上面的pygame.mixer.Sound函數返回了一個sound對象,咱們可使用play和stop方法來播放和中止播放音樂。

可是這裏咱們介紹一種更爲高級的用法,使用pygame.mixer.Channel,這個類提供了比sound對象更爲豐富的功能。

首先咱們先申請一個可用的音頻頻道:

channel = pygame.mixer.find_channel(True)

一旦有了頻道以後咱們就可使用Channel.play()方法來播放一個sound對象了。

channel.play(sound)

 

好了如今讓咱們來實現一下和音頻有關的模塊:

首先定義一個初始化的函數,它初始化了音頻模塊,而且加載了一些音頻文件以方便咱們在程序中使用:

def audio_init():
    global hit_au,btn_au,bg_au,bullent_au
    pygame.mixer.init()
    hit_au = pygame.mixer.Sound("exlposion.wav")
    btn_au = pygame.mixer.Sound("button.wav")
    bg_au = pygame.mixer.Sound("background.ogg")
    bullent_au = pygame.mixer.Sound("bullet.wav")

而後咱們實現了一個Music類,這個類能夠控制聲音的播放和暫停(set_volume函數是用來設置音樂聲音大小的):

class Music():
    def __init__(self,sound):
        self.channel = None
        self.sound = sound     
    def play_sound(self):
        self.channel = pygame.mixer.find_channel(True)
        self.channel.set_volume(0.5)
        self.channel.play(self.sound)
    def play_pause(self):
        self.channel.set_volume(0.0)
        self.channel.play(self.sound)

 

跳躍函數:

當按下空格鍵的時候,嗷大喵會跳起,這個是如何實現的呢?

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
    keys = pygame.key.get_pressed()
    if keys[K_ESCAPE]:
        pygame.quit()
        sys.exit()
        
    elif keys[K_SPACE]:
        if not player_jumping:
            player_jumping = True
            jump_vel = -12.0

當按下空格鍵的時候,會將player_jumping變量置爲True 而且給jump_vel一個初速度-12.0

而後在每次循環的時候,將jump_vel 加0.6,當嗷大喵回到起跳位置的時候,將速度置爲0,令人物再也不在y方向上有移動。

 

            #檢測玩家是否處於跳躍狀態
            if player_jumping:
                if jump_vel <0:
                    jump_vel += 0.6
                elif jump_vel >= 0:
                    jump_vel += 0.8
                player.Y += jump_vel
                if player.Y > player_start_y:
                    player_jumping = False
                    player.Y = player_start_y
                    jump_vel = 0.0

 

而後咱們還須要一個不斷髮出的子彈:

#更新子彈
            if not game_over:
                arrow.X -= arrow_vel
            if arrow.X < -40: reset_arrow()
#重置火箭函數
def reset_arrow():
    y = random.randint(270,350)
    arrow.position = 800,y
    bullent_sound.play_sound()

 

關於嗷大喵和子彈衝突檢測咱們使用了以前學過的矩形衝突檢測技術,當玩家和子彈產生衝突的時候,重置子彈,播放爆炸動畫,而後將人物的x座標值向左移動10,以表示人物受到傷害。惡龍和子彈的衝突和這個是同樣的,這裏就再也不贅述了。

#碰撞檢測,子彈是否擊中玩家
            if pygame.sprite.collide_rect(arrow, player):
                reset_arrow()
                explosion.position =player.X,player.Y
                player_hit = True
                hit_sound.play_sound()
                if p_first:
                    group_exp.add(explosion)
                    p_first = False
                player.X -= 10

而後咱們還須要考慮一下玩家被惡龍追上的時候的情形,仍是應用矩形檢測技術:

            if pygame.sprite.collide_rect(player, dragon):
                game_over = True

 

爲了使果實移動,咱們須要遍歷group_fruit裏面的果實,而後依次將他們左移5個單位,而後咱們還須要判斷玩家吃到果實的場景,果實會消失,而後玩家的積分增長。

這裏使用了以前學過的pygame.sprite.spritecollide(sprite,sprite_group,bool)。

調用這個函數的時候,一個組中的全部精靈都會逐個地對另一個單個精靈進行衝突檢測,發生衝突的精靈會做爲一個列表返回。

這個函數的第一個參數就是單個精靈,第二個參數是精靈組,第三個參數是一個bool值,最後這個參數起了很大的做用。當爲True的時候,會刪除組中全部衝突的精靈,False的時候不會刪除衝突的精靈。所以咱們這裏將第三個參數設置爲True,這樣就會刪除掉和精靈衝突的對象了,看起來就好像是玩家吃掉了這些果實同樣。

#遍歷果實,使果實移動
            for e in group_fruit:
                e.X -=5
            collide_list = pygame.sprite.spritecollide(player,group_fruit,False)
            score +=len(collide_list)

 

最後仍是看一下所有的代碼:

  1 # -*- coding: utf-8 -*-
  2 import sys, time, random, math, pygame,locale
  3 from pygame.locals import *
  4 from MyLibrary import *
  5 
  6 #重置火箭函數
  7 def reset_arrow():
  8     y = random.randint(270,350)
  9     arrow.position = 800,y
 10     bullent_sound.play_sound()
 11 
 12 #定義一個滾動地圖類
 13 class MyMap(pygame.sprite.Sprite):
 14     
 15     def __init__(self,x,y):
 16         self.x = x
 17         self.y = y
 18         self.bg = pygame.image.load("background.png").convert_alpha()
 19     def map_rolling(self):
 20         if self.x < -600:
 21             self.x = 600
 22         else:
 23             self.x -=5
 24     def map_update(self):
 25         screen.blit(self.bg, (self.x,self.y))
 26     def set_pos(x,y):
 27         self.x =x
 28         self.y =y
 29 #定義一個按鈕類
 30 class Button(object):
 31     def __init__(self, upimage, downimage,position):
 32         self.imageUp = pygame.image.load(upimage).convert_alpha()
 33         self.imageDown = pygame.image.load(downimage).convert_alpha()
 34         self.position = position
 35         self.game_start = False
 36         
 37     def isOver(self):
 38         point_x,point_y = pygame.mouse.get_pos()
 39         x, y = self. position
 40         w, h = self.imageUp.get_size()
 41 
 42         in_x = x - w/2 < point_x < x + w/2
 43         in_y = y - h/2 < point_y < y + h/2
 44         return in_x and in_y
 45 
 46     def render(self):
 47         w, h = self.imageUp.get_size()
 48         x, y = self.position
 49         
 50         if self.isOver():
 51             screen.blit(self.imageDown, (x-w/2,y-h/2))
 52         else:
 53             screen.blit(self.imageUp, (x-w/2, y-h/2))
 54     def is_start(self):
 55         if self.isOver():
 56             b1,b2,b3 = pygame.mouse.get_pressed()
 57             if b1 == 1:
 58                 self.game_start = True
 59                 bg_sound.play_pause()
 60                 btn_sound.play_sound()
 61                 bg_sound.play_sound()
 62 
 63 def replay_music():
 64     bg_sound.play_pause()
 65     bg_sound.play_sound()
 66 
 67 #定義一個數據IO的方法
 68 def data_read():
 69     fd_1 = open("data.txt","r")
 70     best_score = fd_1.read()
 71     fd_1.close()
 72     return best_score
 73 
 74    
 75 #定義一個控制聲音的類和初始音頻的方法
 76 def audio_init():
 77     global hit_au,btn_au,bg_au,bullent_au
 78     pygame.mixer.init()
 79     hit_au = pygame.mixer.Sound("exlposion.wav")
 80     btn_au = pygame.mixer.Sound("button.wav")
 81     bg_au = pygame.mixer.Sound("background.ogg")
 82     bullent_au = pygame.mixer.Sound("bullet.wav")
 83 class Music():
 84     def __init__(self,sound):
 85         self.channel = None
 86         self.sound = sound     
 87     def play_sound(self):
 88         self.channel = pygame.mixer.find_channel(True)
 89         self.channel.set_volume(0.5)
 90         self.channel.play(self.sound)
 91     def play_pause(self):
 92         self.channel.set_volume(0.0)
 93         self.channel.play(self.sound)
 94       
 95 #主程序部分
 96 pygame.init()
 97 audio_init()
 98 screen = pygame.display.set_mode((800,600),0,32)
 99 pygame.display.set_caption("嗷大喵快跑!")
100 font = pygame.font.Font(None, 22)
101 font1 = pygame.font.Font(None, 40)
102 framerate = pygame.time.Clock()
103 upImageFilename = 'game_start_up.png'
104 downImageFilename = 'game_start_down.png'
105 #建立按鈕對象
106 button = Button(upImageFilename,downImageFilename, (400,500))
107 interface = pygame.image.load("interface.png")
108 
109 #建立地圖對象
110 bg1 = MyMap(0,0)
111 bg2 = MyMap(600,0)
112 #建立一個精靈組
113 group = pygame.sprite.Group()
114 group_exp = pygame.sprite.Group()
115 group_fruit = pygame.sprite.Group()
116 #建立怪物精靈
117 dragon = MySprite()
118 dragon.load("dragon.png", 260, 150, 3)
119 dragon.position = 100, 230
120 group.add(dragon)
121 
122 #建立爆炸動畫
123 explosion = MySprite()
124 explosion.load("explosion.png",128,128,6)
125 #建立玩家精靈
126 player = MySprite()
127 player.load("sprite.png", 100, 100, 4)
128 player.position = 400, 270
129 group.add(player)
130 
131 #建立子彈精靈
132 arrow = MySprite()
133 arrow.load("flame.png", 40, 16, 1)
134 arrow.position = 800,320
135 group.add(arrow)
136 
137 
138 
139 #定義一些變量
140 arrow_vel = 10.0
141 game_over = False
142 you_win = False
143 player_jumping = False
144 jump_vel = 0.0
145 player_start_y = player.Y
146 player_hit = False
147 monster_hit = False
148 p_first = True
149 m_first = True
150 best_score = 0
151 global bg_sound,hit_sound,btn_sound,bullent_sound
152 bg_sound=Music(bg_au)
153 hit_sound=Music(hit_au)
154 btn_sound=Music(btn_au)
155 bullent_sound =Music(bullent_au)
156 game_round = {1:'ROUND ONE',2:'ROUND TWO',3:'ROUND THREE',4:'ROUND FOUR',5:'ROUND FIVE'}
157 game_pause = True
158 index =0
159 current_time = 0
160 start_time = 0
161 music_time = 0
162 score =0
163 replay_flag = True
164 #循環
165 bg_sound.play_sound()
166 best_score = data_read()
167 while True:
168     framerate.tick(60)
169     ticks = pygame.time.get_ticks()
170     for event in pygame.event.get():
171         if event.type == pygame.QUIT:
172             pygame.quit()
173             sys.exit()
174     keys = pygame.key.get_pressed()
175     if keys[K_ESCAPE]:
176         pygame.quit()
177         sys.exit()
178         
179     elif keys[K_SPACE]:
180         if not player_jumping:
181             player_jumping = True
182             jump_vel = -12.0
183             
184     screen.blit(interface,(0,0))
185     button.render()
186     button.is_start()
187     if button.game_start == True:
188         if game_pause :
189             index +=1
190             tmp_x =0
191             if score >int (best_score):
192                 best_score = score
193             fd_2 = open("data.txt","w+")
194             fd_2.write(str(best_score))
195             fd_2.close()
196             #判斷遊戲是否通關
197             if index == 6:
198                 you_win = True
199             if you_win:
200                 start_time = time.clock()
201                 current_time =time.clock()-start_time
202                 while current_time<5:
203                     screen.fill((200, 200, 200))
204                     print_text(font1, 270, 150,"YOU WIN THE GAME!",(240,20,20))
205                     current_time =time.clock()-start_time
206                     print_text(font1, 320, 250, "Best Score:",(120,224,22))
207                     print_text(font1, 370, 290, str(best_score),(255,0,0))
208                     print_text(font1, 270, 330, "This Game Score:",(120,224,22))
209                     print_text(font1, 385, 380, str(score),(255,0,0))
210                     pygame.display.update()
211                 pygame.quit()
212                 sys.exit()
213                 
214             for i in range(0,100):
215                 element = MySprite()
216                 element.load("fruit.bmp", 75, 20, 1)
217                 tmp_x +=random.randint(50,120)
218                 element.X = tmp_x+300
219                 element.Y = random.randint(80,200)
220                 group_fruit.add(element)
221             start_time = time.clock()
222             current_time =time.clock()-start_time
223             while current_time<3:
224                 screen.fill((200, 200, 200))
225                 print_text(font1, 320, 250,game_round[index],(240,20,20))
226                 pygame.display.update()
227                 game_pause = False
228                 current_time =time.clock()-start_time
229             
230         else:
231             #更新子彈
232             if not game_over:
233                 arrow.X -= arrow_vel
234             if arrow.X < -40: reset_arrow()
235             #碰撞檢測,子彈是否擊中玩家
236             if pygame.sprite.collide_rect(arrow, player):
237                 reset_arrow()
238                 explosion.position =player.X,player.Y
239                 player_hit = True
240                 hit_sound.play_sound()
241                 if p_first:
242                     group_exp.add(explosion)
243                     p_first = False
244                 player.X -= 10
245 
246             #碰撞檢測,子彈是否擊中怪物
247             if pygame.sprite.collide_rect(arrow, dragon):
248                 reset_arrow()
249                 explosion.position =dragon.X+50,dragon.Y+50
250                 monster_hit = True
251                 hit_sound.play_sound()
252                 if m_first:
253                     group_exp.add(explosion)
254                     m_first = False
255                 dragon.X -= 10
256 
257             #碰撞檢測,玩家是否被怪物追上
258             if pygame.sprite.collide_rect(player, dragon):
259                 game_over = True
260             #遍歷果實,使果實移動
261             for e in group_fruit:
262                 e.X -=5
263             collide_list = pygame.sprite.spritecollide(player,group_fruit,False)
264             score +=len(collide_list)
265             #是否經過關卡
266             if dragon.X < -100:
267                 game_pause = True
268                 reset_arrow()
269                 player.X = 400
270                 dragon.X = 100
271                 
272             
273 
274             #檢測玩家是否處於跳躍狀態
275             if player_jumping:
276                 if jump_vel <0:
277                     jump_vel += 0.6
278                 elif jump_vel >= 0:
279                     jump_vel += 0.8
280                 player.Y += jump_vel
281                 if player.Y > player_start_y:
282                     player_jumping = False
283                     player.Y = player_start_y
284                     jump_vel = 0.0
285 
286 
287             #繪製背景
288             bg1.map_update()
289             bg2.map_update()
290             bg1.map_rolling()
291             bg2.map_rolling()
292             
293             #更新精靈組
294             if not game_over:
295                 group.update(ticks, 60)
296                 group_exp.update(ticks,60)
297                 group_fruit.update(ticks,60)
298             #循環播放背景音樂
299             music_time = time.clock()
300             if music_time   > 150 and replay_flag:
301                 replay_music()
302                 replay_flag =False
303             #繪製精靈組
304             group.draw(screen)
305             group_fruit.draw(screen)
306             if player_hit or monster_hit:
307                 group_exp.draw(screen)
308             print_text(font, 330, 560, "press SPACE to jump up!")
309             print_text(font, 200, 20, "You have get Score:",(219,224,22))
310             print_text(font1, 380, 10, str(score),(255,0,0))
311             if game_over:
312                 start_time = time.clock()
313                 current_time =time.clock()-start_time
314                 while current_time<5:
315                     screen.fill((200, 200, 200))
316                     print_text(font1, 300, 150,"GAME OVER!",(240,20,20))
317                     current_time =time.clock()-start_time
318                     print_text(font1, 320, 250, "Best Score:",(120,224,22))
319                     if score >int (best_score):
320                         best_score = score
321                     print_text(font1, 370, 290, str(best_score),(255,0,0))
322                     print_text(font1, 270, 330, "This Game Score:",(120,224,22))
323                     print_text(font1, 370, 380, str(score),(255,0,0))
324                     pygame.display.update()
325                 fd_2 = open("data.txt","w+")
326                 fd_2.write(str(best_score))
327                 fd_2.close()
328                 pygame.quit()
329                 sys.exit()
330     pygame.display.update()
相關文章
相關標籤/搜索