《零基礎入門學習Python》第091講:Pygame:飛機大戰2
上節課我們實現了遊戲的背景和背景音樂,接下來,我們應該讓主角閃亮登場了,創建一個名為myplane 的模塊,然後把我方飛機的所有屬性和方法定義在裡邊。
-
#myplane.py
-
import pygame
-
-
class Myplane(pygame.sprite.Sprite):
-
def __init__(self, bg_size):
-
pygame.sprite.Sprite.__init__(self)
-
-
self.image = pygame.image.load("images/me1.png").convert_alpha()
-
self.rect = self.image.get_rect()
-
self.width, self.height = bg_size[0], bg_size[1]
-
self.rect.left, self.rect.top = \
-
(self.width - self.rect.width) // 2, \
-
self.height - self.rect.height - 60 #减60留给状态栏
-
self.speed = 10
-
-
def moveUp(self):
-
if self.rect.top > 0:
-
self.rect.top -= self.speed
-
else:
-
self.rect.top = 0
-
-
def moveDown(self):
-
if self.rect.bottom < self.height - 60:
-
self.rect.top += self.speed
-
else:
-
self.rect.bottom = self.height - 60
-
-
def moveLeft(self):
-
if self.rect.left > 0:
-
self.rect.left -= self.speed
-
else:
-
self.rect.left = 0
-
-
def moveRight(self):
-
if self.rect.right < self.width:
-
self.rect.left += self.speed
-
else:
-
self.rect.right = self.width
目前就實現這麼多。
那麼接下來我們就需要在main 模塊中響應用戶的鍵盤操作,響應用戶的鍵盤操作有兩種方法:
1、通過檢測事件消息,檢測到如果有KEYDOWN 或者KEYUP 事件,我們就知道是用戶按下了鍵盤按鍵。(這是我們之前常用的一種方法)
2、調用key 模塊裡的 get_pressed() 方法,會返回一個序列,該序列包含鍵盤上所有按鍵的布爾類型的值,如果這個值是True 的話,表示該按鍵被按下。
我們這裡有一個建議:對於檢測偶然觸發的鍵盤事件,我們推薦使用方法1,例如該遊戲中會設置一個全屏炸彈,按下空格鍵時爆炸,這是偶然觸發的,沒有經常觸發,這時使用第1種方法較好;對於頻繁觸發的鍵盤事件,我們則建議使用第二種方法,例如控制飛機移動的4個方向鍵,我們就使用方法2。
我們就來改一下我們的main 函數:
-
#main.py
-
import pygame
-
import sys
-
import traceback #为了更好地退出
-
import myplane
-
-
from pygame.locals import *
-
-
pygame.init()
-
pygame.mixer.init() #混音器初始化
-
-
bg_size = width, height = 480, 700
-
screen = pygame.display.set_mode(bg_size)
-
pygame.display.set_caption("飞机大战 -- Python Demo")
-
-
background = pygame.image.load("images/background.png").convert()
-
-
# 载入游戏音乐
-
pygame.mixer.music.load("sound/game_music.ogg")
-
pygame.mixer.music.set_volume(0.2)
-
bullet_sound = pygame.mixer.Sound("sound/bullet.wav")
-
bullet_sound.set_volume(0.2)
-
bomb_sound = pygame.mixer.Sound("sound/use_bomb.wav")
-
bomb_sound.set_volume(0.2)
-
supply_sound = pygame.mixer.Sound("sound/supply.wav")
-
supply_sound.set_volume(0.2)
-
get_bomb_sound = pygame.mixer.Sound("sound/get_bomb.wav")
-
get_bomb_sound.set_volume(0.2)
-
get_bullet_sound = pygame.mixer.Sound("sound/get_bullet.wav")
-
get_bullet_sound.set_volume(0.2)
-
upgrade_sound = pygame.mixer.Sound("sound/upgrade.wav")
-
upgrade_sound.set_volume(0.2)
-
enemy3_fly_sound = pygame.mixer.Sound("sound/enemy3_flying.wav")
-
enemy3_fly_sound.set_volume(0.2)
-
enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.wav")
-
enemy1_down_sound.set_volume(0.2)
-
enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.wav")
-
enemy2_down_sound.set_volume(0.2)
-
enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.wav")
-
enemy3_down_sound.set_volume(0.5)
-
me_down_sound = pygame.mixer.Sound("sound/me_down.wav")
-
me_down_sound.set_volume(0.2)
-
-
def main():
-
pygame.mixer.music.play(-1)
-
-
# 生成我方飞机
-
me = myplane.Myplane(bg_size)
-
-
clock = pygame.time.Clock()
-
-
running = True
-
-
while running:
-
for event in pygame.event.get():
-
if event.type == QUIT:
-
pygame.quit()
-
sys.exit()
-
#检测用户的键盘操作
-
key_pressed = pygame.key.get_pressed()
-
-
if key_pressed[K_w] or key_pressed[K_UP]:
-
me.moveUp()
-
if key_pressed[K_s] or key_pressed[K_DOWN]:
-
me.moveDown()
-
if key_pressed[K_a] or key_pressed[K_LEFT]:
-
me.moveLeft()
-
if key_pressed[K_d] or key_pressed[K_RIGHT]:
-
me.moveRight()
-
-
screen.blit(background, (0, 0))
-
-
#绘制我方飞机
-
screen.blit(me.image, me.rect)
-
-
pygame.display.flip()
-
-
clock.tick(60)
-
-
if __name__ == "__main__":
-
try:
-
main()
-
except SystemExit:
-
pass
-
except:
-
traceback.print_exc()
-
pygame.quit()
-
input()

我們的飛機就生成了,也可以根據鍵盤上的AWSD 或者方向鍵進行移動控制。
我們剛才說過,為了增加我方飛機的動態效果,我們可以通過兩張圖片(me1,png 和me2.png)的切換來實現飛機冒煙的效果。

我們就只需要:
1、在myplane.py 中加多一種圖片
-
#myplane.py
-
class Myplane(pygame.sprite.Sprite):
-
def __init__(self, bg_size):
-
pygame.sprite.Sprite.__init__(self)
-
-
self.image1 = pygame.image.load("images/me1.png").convert_alpha()
-
self.image2 = pygame.image.load("images/me2.png").convert_alpha()
-
self.rect = self.image1.get_rect()
-
self.width, self.height = bg_size[0], bg_size[1]
-
self.rect.left, self.rect.top = \
-
(self.width - self.rect.width) // 2, \
-
self.height - self.rect.height - 60 #减60,留给状态栏
-
self.speed = 10
2、在main.py 中
首先計算一個布爾類型的變量用於控制切換圖片;然後在繪製我方飛機這裡交叉顯示兩張圖片。
-
#main.py
-
def main():
-
pygame.mixer.music.play(-1)
-
-
# 生成我方飞机
-
me = myplane.Myplane(bg_size)
-
-
clock = pygame.time.Clock()
-
-
#用于切换图片
-
switch_image = True
-
-
running = True
-
-
while running:
-
for event in pygame.event.get():
-
if event.type == QUIT:
-
pygame.quit()
-
sys.exit()
-
#检测用户的键盘操作
-
key_pressed = pygame.key.get_pressed()
-
-
if key_pressed[K_w] or key_pressed[K_UP]:
-
me.moveUp()
-
if key_pressed[K_s] or key_pressed[K_DOWN]:
-
me.moveDown()
-
if key_pressed[K_a] or key_pressed[K_LEFT]:
-
me.moveLeft()
-
if key_pressed[K_d] or key_pressed[K_RIGHT]:
-
me.moveRight()
-
-
screen.blit(background, (0, 0))
-
-
#绘制我方飞机
-
switch_image = not switch_image
-
if switch_image:
-
screen.blit(me.image1, me.rect)
-
else:
-
screen.blit(me.image,2 me.rect)
-
-
pygame.display.flip()
-
-
clock.tick(60)
但是我們這樣改,飛機還是沒有理想中"突突突" 的感覺,畢竟我們的幀率為60(每秒切換60次),我們最好在不影響遊戲性能的情況來延遲圖片的切換,這裡我們就使用單片機開發中常常用到的一招,增加一個延時變量:
-
#main.py
-
def main():
-
pygame.mixer.music.play(-1)
-
-
# 生成我方飞机
-
me = myplane.Myplane(bg_size)
-
-
clock = pygame.time.Clock()
-
-
#用于切换图片
-
switch_image = True
-
-
#用于延迟
-
delay = 100
-
-
running = True
-
-
while running:
-
for event in pygame.event.get():
-
if event.type == QUIT:
-
pygame.quit()
-
sys.exit()
-
#检测用户的键盘操作
-
key_pressed = pygame.key.get_pressed()
-
-
if key_pressed[K_w] or key_pressed[K_UP]:
-
me.moveUp()
-
if key_pressed[K_s] or key_pressed[K_DOWN]:
-
me.moveDown()
-
if key_pressed[K_a] or key_pressed[K_LEFT]:
-
me.moveLeft()
-
if key_pressed[K_d] or key_pressed[K_RIGHT]:
-
me.moveRight()
-
-
screen.blit(background, (0, 0))
-
-
#绘制我方飞机
-
if switch_image:
-
screen.blit(me.image1, me.rect)
-
else:
-
screen.blit(me.image2, me.rect)
-
-
#切换图片
-
if not(delay % 5): #5帧切换一次,一秒就只切换12次
-
switch_image = not switch_image
-
-
delay -= 1
-
if not delay:
-
delay = 100
-
-
pygame.display.flip()
-
-
clock.tick(60)
接下來就來創造敵機啦:
敵機分為小中大三個尺寸,它們的速度一次就是快中慢(越小越快),在頁面上方,我們就需要隨機創建一些敵機,可以通過在頁面外部上方5個屏幕高度範圍內隨機生成一個敵機以保證不讓敵機在一排出現。
-
#enemy.py
-
import pygame
-
from random import *
-
-
class SmallEnemy(pygame.sprite.Sprite): #小敌机
-
def __init__(self, bg_size):
-
pygame.sprite.Sprite.__init__(self)
-
-
self.image = pygame.image.load("images/enemy1.png").convert_alpha()
-
self.rect = self.image.get_rect()
-
self.width, self.height = bg_size[0], bg_size[1]
-
self.speed = 2
-
self.rect.left, self.rect.top = \
-
randint(0, self.width - self.rect.width), \
-
randint(-5 * self.height, 0) #在页面外部上方5个屏幕高度范围内随机生成一个敌机
-
-
def move(self):
-
if self.rect.top < self.height:
-
self.rect.top += self.speed
-
else:
-
self.reset()
-
-
def reset(self):
-
self.rect.left, self.rect.top = \
-
randint(0, self.width - self.rect.width), \
-
randint(-5 * self.height, 0)
-
-
class MidEnemy(pygame.sprite.Sprite):
-
def __init__(self, bg_size):
-
pygame.sprite.Sprite.__init__(self)
-
-
self.image = pygame.image.load("images/enemy2.png").convert_alpha()
-
self.rect = self.image.get_rect()
-
self.width, self.height = bg_size[0], bg_size[1]
-
self.speed = 1
-
self.rect.left, self.rect.top = \
-
randint(0, self.width - self.rect.width), \
-
randint(-10 * self.height, -self.height) #在页面外部上方1个到10个屏幕高度范围内随机生成一个敌机(1-10个,就保证了不会一开始出大一个大的)
-
-
def move(self):
-
if self.rect.top < self.height:
-
self.rect.top += self.speed
-
else:
-
self.reset()
-
-
def reset(self):
-
self.rect.left, self.rect.top = \
-
randint(0, self.width - self.rect.width), \
-
randint(-10 * self.height, -self.height)
-
-
class BigEnemy(pygame.sprite.Sprite):
-
def __init__(self, bg_size):
-
pygame.sprite.Sprite.__init__(self)
-
-
#大型敌机有飞行特效,两张图片切换
-
self.image1 = pygame.image.load("images/enemy3_n1.png").convert_alpha()
-
self.image2 = pygame.image.load("images/enemy3_n2.png").convert_alpha()
-
self.rect = self.image1.get_rect()
-
self.width, self.height = bg_size[0], bg_size[1]
-
self.speed = 1
-
self.rect.left, self.rect.top = \
-
randint(0, self.width - self.rect.width), \
-
randint(-15 * self.height, -5 * self.height) #在页面外部上方5-15个屏幕高度范围内随机生成一个敌机
-
-
def move(self):
-
if self.rect.top < self.height:
-
self.rect.top += self.speed
-
else:
-
self.reset()
-
-
def reset(self):
-
self.rect.left, self.rect.top = \
-
randint(0, self.width - self.rect.width), \
-
randint(-15 * self.height, -5 * self.height)
敵機的定義有了,我們接下來就在main 模塊中將它們實例化:
-
#main.py
-
import pygame
-
import sys
-
import traceback #为了更好地退出
-
import myplane
-
import enemy
-
-
from pygame.locals import *
-
-
pygame.init()
-
pygame.mixer.init() #混音器初始化
-
-
bg_size = width, height = 480, 700
-
screen = pygame.display.set_mode(bg_size)
-
pygame.display.set_caption("飞机大战 -- Python Demo")
-
-
background = pygame.image.load("images/background.png").convert()
-
-
# 载入游戏音乐
-
pygame.mixer.music.load("sound/game_music.ogg")
-
pygame.mixer.music.set_volume(0.2)
-
bullet_sound = pygame.mixer.Sound("sound/bullet.wav")
-
bullet_sound.set_volume(0.2)
-
bomb_sound = pygame.mixer.Sound("sound/use_bomb.wav")
-
bomb_sound.set_volume(0.2)
-
supply_sound = pygame.mixer.Sound("sound/supply.wav")
-
supply_sound.set_volume(0.2)
-
get_bomb_sound = pygame.mixer.Sound("sound/get_bomb.wav")
-
get_bomb_sound.set_volume(0.2)
-
get_bullet_sound = pygame.mixer.Sound("sound/get_bullet.wav")
-
get_bullet_sound.set_volume(0.2)
-
upgrade_sound = pygame.mixer.Sound("sound/upgrade.wav")
-
upgrade_sound.set_volume(0.2)
-
enemy3_fly_sound = pygame.mixer.Sound("sound/enemy3_flying.wav")
-
enemy3_fly_sound.set_volume(0.2)
-
enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.wav")
-
enemy1_down_sound.set_volume(0.2)
-
enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.wav")
-
enemy2_down_sound.set_volume(0.2)
-
enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.wav")
-
enemy3_down_sound.set_volume(0.5)
-
me_down_sound = pygame.mixer.Sound("sound/me_down.wav")
-
me_down_sound.set_volume(0.2)
-
-
def add_small_enemies(group1, group2, num):
-
for i in range(num):
-
e1 = enemy.SmallEnemy(bg_size)
-
group1.add(e1)
-
group2.add(e1)
-
-
def add_mid_enemies(group1, group2, num):
-
for i in range(num):
-
e2 = enemy.MidEnemy(bg_size)
-
group1.add(e2)
-
group2.add(e2)
-
-
def add_big_enemies(group1, group2, num):
-
for i in range(num):
-
e3 = enemy.BigEnemy(bg_size)
-
group1.add(e3)
-
group2.add(e3)
-
-
def main():
-
pygame.mixer.music.play(-1)
-
-
# 生成我方飞机
-
me = myplane.Myplane(bg_size)
-
-
#生成敌方飞机
-
enemies = pygame.sprite.Group()
-
-
# 生成敌方小型飞机
-
small_enemies = pygame.sprite.Group()
-
add_small_enemies(small_enemies, enemies, 15)
-
-
# 生成敌方中型飞机
-
mid_enemies = pygame.sprite.Group()
-
add_mid_enemies(mid_enemies, enemies, 4)
-
-
# 生成敌方大型飞机
-
big_enemies = pygame.sprite.Group()
-
add_big_enemies(big_enemies, enemies, 2)
-
-
-
clock = pygame.time.Clock()
-
-
#用于切换图片
-
switch_image = True
-
-
#用于延迟
-
delay = 100
-
-
running = True
-
-
while running:
-
for event in pygame.event.get():
-
if event.type == QUIT:
-
pygame.quit()
-
sys.exit()
-
#检测用户的键盘操作
-
key_pressed = pygame.key.get_pressed()
-
-
if key_pressed[K_w] or key_pressed[K_UP]:
-
me.moveUp()
-
if key_pressed[K_s] or key_pressed[K_DOWN]:
-
me.moveDown()
-
if key_pressed[K_a] or key_pressed[K_LEFT]:
-
me.moveLeft()
-
if key_pressed[K_d] or key_pressed[K_RIGHT]:
-
me.moveRight()
-
-
screen.blit(background, (0, 0))
-
-
#绘制大型敌机
-
for each in big_enemies:
-
each.move()
-
if switch_image:
-
screen.blit(each.image1, each.rect)
-
else:
-
screen.blit(each.image2, each.rect)
-
#即将出现在界面中,播放音效
-
if each.rect.bottom > -50:
-
enemy3_fly_sound.play()
-
-
#绘制中型敌机
-
for each in mid_enemies:
-
each.move()
-
screen.blit(each.image, each.rect)
-
-
#绘制小型敌机
-
for each in small_enemies:
-
each.move()
-
screen.blit(each.image, each.rect)
-
-
-
#绘制我方飞机
-
if switch_image:
-
screen.blit(me.image1, me.rect)
-
else:
-
screen.blit(me.image2, me.rect)
-
-
#切换图片
-
if not(delay % 5): #5帧切换一次,一秒就只切换12次
-
switch_image = not switch_image
-
-
delay -= 1
-
if not delay:
-
delay = 100
-
-
pygame.display.flip()
-
-
clock.tick(60)
-
-
if __name__ == "__main__":
-
try:
-
main()
-
except SystemExit:
-
pass
-
except:
-
traceback.print_exc()
-
pygame.quit()
-
input()

我們可以看到敵機依次出來,由於我們現在還沒有做碰撞檢測,所以它們可以友好的交叉飛過,我們在下節課中會教大家如何做完美的碰撞檢測,因為飛機是不規則的圖形,所有我們沒辦法像之前講小球一樣弄一個半徑。但是別擔心,這種不規則的圖形也可以做完美的碰撞檢測,大家拭目以待吧。
0 留言:
發佈留言