坦克大戰(zhàn)的需求
坦克大戰(zhàn)游戲包含很多個物體,現(xiàn)在要對這些物體進(jìn)行總結(jié)
類名 | 包含的操作 | 包含的屬性 |
---|---|---|
敵方坦克類 | 射擊,移動,顯示 | 生命,速度,傷害,方向,類型 |
我方坦克類 | 射擊,移動,顯示 | 生命,速度,傷害,方向,裝甲,等級 |
子彈類 | 移動,顯示 | 方向,傷害,發(fā)射源,速度 |
墻壁類、草類、石磚類、河類 | 顯示 | 是否可以摧毀 |
音效類 | 播放,停止,設(shè)置音樂 | - |
爆炸效果類 | 顯示 | 是否可以摧毀 |
主類 | … | … |
物體總結(jié)完畢后,規(guī)劃一下窗口的大小,下面是我設(shè)置的窗口大小
素材鏈接:百度網(wǎng)盤
鏈接:https://pan.baidu.com/s/19sCyH7rp37f6DzRj0iXDCA?pwd=tkdz
提取碼:tkdz
坦克大戰(zhàn)代碼鏈接:百度網(wǎng)盤
鏈接:https://pan.baidu.com/s/1qFV-0hi0cgZS1Hnvx6mK6Q?pwd=90tk
提取碼:90tk
開始編寫坦克大戰(zhàn)
一切都準(zhǔn)備就緒啦,現(xiàn)在開始編寫坦克大戰(zhàn)的代碼吧
1. 搭建主類框架
主類是整個游戲運(yùn)作的類,當(dāng)然你也可以不用使用類,直接創(chuàng)建一個函數(shù)也可以,這里使用了面向?qū)ο蟮乃枷?/p>
import pygame
SCREEN_WIDTH = 1100
SCREEN_HEIGHT = 600
BACKGROUND_COLOR = pygame.Color(0, 0, 0)
FONT_COLOR = (255, 255, 255)
class MainGame:
# 窗口Surface對象
window = None
def __init__(self):
pass
def startGame(self):
# 初始化展示模塊
pygame.display.init()
# 設(shè)置窗口大小
size = (SCREEN_WIDTH, SCREEN_HEIGHT)
# 初始化窗口
MainGame.window = pygame.display.set_mode(size)
# 設(shè)置窗口標(biāo)題
pygame.display.set_caption('Tank Battle')
while 1:
# 設(shè)置背景顏色
MainGame.window.fill(BACKGROUND_COLOR)
# 更新窗口
pygame.display.update()
if __name__ == '__main__':
MainGame().startGame()
運(yùn)行結(jié)果
主類中運(yùn)用到的知識,都是學(xué)習(xí) Python 之 Pygame 開發(fā)坦克大戰(zhàn)(一)中所包含的
2. 獲取窗口中的事件
坦克大戰(zhàn)關(guān)鍵是對玩家自己的坦克進(jìn)行操控,消滅敵人的坦克,所以鍵盤事件響應(yīng)是必不可少的
def getPlayingModeEvent(self):
# 獲取所有事件
eventList = pygame.event.get()
for event in eventList:
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.KEYDOWN:
print('鍵盤按鍵按下')
if event.key == pygame.K_w:
print('w按下')
elif event.key == pygame.K_s:
print('s按下')
elif event.key == pygame.K_a:
print('a按下')
elif event.key == pygame.K_d:
print('d按下')
elif event.key == pygame.K_j:
print('j按下')
if event.type == pygame.KEYUP:
print('鍵盤按鍵抬起')
if event.key == pygame.K_w:
print('w抬起')
elif event.key == pygame.K_s:
print('s抬起')
elif event.key == pygame.K_a:
print('a抬起')
elif event.key == pygame.K_d:
print('d抬起')
獲取窗口中的事件,用于玩家操控坦克、發(fā)射坦克子彈等操作
游戲中,我規(guī)定aswd操控坦克,j攻擊,當(dāng)然你也可以上下左右鍵移動,空格攻擊,如果你想設(shè)置雙人游戲,這也是可以的
import pygame
import sys
SCREEN_WIDTH = 1100
SCREEN_HEIGHT = 600
BACKGROUND_COLOR = pygame.Color(0, 0, 0)
FONT_COLOR = (255, 255, 255)
class MainGame:
# 窗口Surface對象
window = None
def __init__(self):
pass
def startGame(self):
# 初始化展示模塊
pygame.display.init()
# 設(shè)置窗口大小
size = (SCREEN_WIDTH, SCREEN_HEIGHT)
# 初始化窗口
MainGame.window = pygame.display.set_mode(size)
# 設(shè)置窗口標(biāo)題
pygame.display.set_caption('Tank Battle')
while 1:
# 設(shè)置背景顏色
MainGame.window.fill(BACKGROUND_COLOR)
# 獲取窗口事件
self.getPlayingModeEvent()
# 更新窗口
pygame.display.update()
def getPlayingModeEvent(self):
# 獲取所有事件
eventList = pygame.event.get()
for event in eventList:
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.KEYDOWN:
print('鍵盤按鍵按下')
if event.key == pygame.K_w:
print('w按下')
elif event.key == pygame.K_s:
print('s按下')
elif event.key == pygame.K_a:
print('a按下')
elif event.key == pygame.K_d:
print('d按下')
elif event.key == pygame.K_j:
print('j按下')
if event.type == pygame.KEYUP:
print('鍵盤按鍵抬起')
if event.key == pygame.K_w:
print('w抬起')
elif event.key == pygame.K_s:
print('s抬起')
elif event.key == pygame.K_a:
print('a抬起')
elif event.key == pygame.K_d:
print('d抬起')
if __name__ == '__main__':
MainGame().startGame()
3. 創(chuàng)建基類
坦克操控事件完成后,現(xiàn)在就是實(shí)現(xiàn)坦克啦,首先場景中的物體都需要發(fā)生物體間的碰撞,簡單來說就是檢測兩個屏幕上的圖片是否發(fā)生了重疊,如果發(fā)生了,就要觸發(fā)一些事件,這里創(chuàng)建ParentObject類,用于繼承pygame.sprite.Sprite類
pygame.sprite.Sprite類可以用來檢測物體碰撞,是pygame提供的一個類,非常的方便
import pygame.sprite
class ParentObject(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
4. 初始化我方坦克類
創(chuàng)建我方坦克類,并且繼承基類
import pygame as pg
import pygame.image
from ParentObject import ParentObject
class PlayerTank(ParentObject):
def __init__(self, x, y, order, amour):
"""
:param x: 坦克橫坐標(biāo)
:param y: 坦克縱坐標(biāo)
:param order: 玩家坦克序號,1表示一號玩家,2表示二號玩家
:param amour: 坦克初始護(hù)甲
"""
super().__init__()
self.images = []
if order == 1:
self.images.append({
'UP': pygame.image.load('../Image/Player1/45x45/UP1.png'),
'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN1.png'),
'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT1.png'),
'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT1.png')
})
self.images.append({
'UP': pygame.image.load('../Image/Player1/45x45/UP2.png'),
'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN2.png'),
'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT2.png'),
'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT2.png')
})
self.images.append({
'UP': pygame.image.load('../Image/Player1/45x45/UP3.png'),
'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN3.png'),
'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT3.png'),
'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT3.png')
})
self.images.append({
'UP': pygame.image.load('../Image/Player1/45x45/UP4.png'),
'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN4.png'),
'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT4.png'),
'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT4.png')
})
self.images.append({
'UP': pygame.image.load('../Image/Player1/45x45/UP5.png'),
'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN5.png'),
'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT5.png'),
'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT5.png')
})
self.images.append({
'UP': pygame.image.load('../Image/Player1/45x45/UP6.png'),
'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN6.png'),
'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT6.png'),
'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT6.png')
})
# 生命
self.life = 3
# 裝甲
self.armor = amour
# 方向
self.direction = 'UP'
# 根據(jù)護(hù)甲選擇坦克的樣子
self.image: pg.Surface = self.images[max(self.armor - 1, 0)][self.direction]
self.rect = self.image.get_rect()
self.rect.left = x
self.rect.top = y
# 速度
self.accumulation: float = 0
self.speed = 2
# 移動開關(guān)
self.stop = True
# 等級
self.level = 1
# 傷害
self.damage = 1
def move(self):
pass
def shot(self):
pass
def draw(self):
pass
5. 完善我方坦克的移動
accumulation 可以更細(xì)的控制坦克的移動速度
當(dāng) accumulation 累加到 1 時,坦克移動一次,如果不設(shè)置這個屬性,即使是速度每次 +1,坦克移動的也速度很快,所以增加這個屬性,可以減慢坦克的移動速度
def move(self):
if self.accumulation >= 1:
self.accumulation = 0
if self.direction == 'LEFT':
if self.rect.left > 0:
self.rect.left -= self.speed
elif self.direction == 'UP':
if self.rect.top > 0:
self.rect.top -= self.speed
elif self.direction == 'DOWN':
if self.rect.top < 555:
self.rect.top += self.speed
elif self.direction == 'RIGHT':
if self.rect.left < 855:
self.rect.left += self.speed
else:
self.accumulation += 0.20
這里需要設(shè)置坦克的邊界范圍
防止坦克跑出窗口
坦克的圖片是45x45
5. 完善我方坦克的顯示
坦克的顯示就是把坦克的圖片顯示在窗口中
def draw(self, window):
# window傳入主窗口
# 坦克生命中為0,表示已經(jīng)死亡,不再展示坦克
if self.life <= 0:
return
# 獲取展示的對象
self.image = self.images[max(self.armor - 1, 0)][self.direction]
window.blit(self.image, self.rect)
我方坦克類完整代碼
import pygame as pg
import pygame.image
from ParentObject import ParentObject
class PlayerTank(ParentObject):
def __init__(self, x, y, order, amour):
"""
:param x: 坦克橫坐標(biāo)
:param y: 坦克縱坐標(biāo)
:param order: 玩家坦克序號,1表示一號玩家,2表示二號玩家
:param amour: 坦克初始護(hù)甲
"""
super().__init__()
self.images = []
if order == 1:
self.images.append({
'UP': pygame.image.load('../Image/Player1/45x45/UP1.png'),
'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN1.png'),
'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT1.png'),
'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT1.png')
})
self.images.append({
'UP': pygame.image.load('../Image/Player1/45x45/UP2.png'),
'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN2.png'),
'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT2.png'),
'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT2.png')
})
self.images.append({
'UP': pygame.image.load('../Image/Player1/45x45/UP3.png'),
'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN3.png'),
'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT3.png'),
'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT3.png')
})
self.images.append({
'UP': pygame.image.load('../Image/Player1/45x45/UP4.png'),
'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN4.png'),
'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT4.png'),
'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT4.png')
})
self.images.append({
'UP': pygame.image.load('../Image/Player1/45x45/UP5.png'),
'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN5.png'),
'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT5.png'),
'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT5.png')
})
self.images.append({
'UP': pygame.image.load('../Image/Player1/45x45/UP6.png'),
'DOWN': pygame.image.load('../Image/Player1/45x45/DOWN6.png'),
'LEFT': pygame.image.load('../Image/Player1/45x45/LEFT6.png'),
'RIGHT': pygame.image.load('../Image/Player1/45x45/RIGHT6.png')
})
# 生命
self.life = 3
# 裝甲
self.armor = amour
# 方向
self.direction = 'UP'
# 根據(jù)護(hù)甲選擇坦克的樣子
self.image: pg.Surface = self.images[max(self.armor - 1, 0)][self.direction]
self.rect = self.image.get_rect()
self.rect.left = x
self.rect.top = y
# 速度
self.accumulation: float = 0
self.speed = 2
# 移動開關(guān)
self.stop = True
# 碰撞前的坐標(biāo)
self.prvX = self.rect.left
self.prvY = self.rect.top
# 等級
self.level = 1
# 傷害
self.damage = 1
def move(self):
if self.accumulation >= 1:
self.accumulation = 0
if self.direction == 'LEFT':
if self.rect.left > 0:
self.rect.left -= self.speed
elif self.direction == 'UP':
if self.rect.top > 0:
self.rect.top -= self.speed
elif self.direction == 'DOWN':
if self.rect.top < 555:
self.rect.top += self.speed
elif self.direction == 'RIGHT':
if self.rect.left < 855:
self.rect.left += self.speed
else:
self.accumulation += 0.20
def shot(self):
pass
def draw(self, window):
# 坦克生命中為0,表示已經(jīng)死亡,不再展示坦克
if self.life <= 0:
return
# 獲取展示的對象
self.image = self.images[max(self.armor - 1, 0)][self.direction]
# 畫出圖片
window.blit(self.image, self.rect)
6. 在主類中加入我方坦克并完成坦克移動
我方坦克類中移動和顯示函數(shù)實(shí)現(xiàn)后,就要讓它們在主類中調(diào)用
添加類變量playerTank
,用于存放我方坦克的對象
修改循環(huán)中的代碼
while 1:
# 設(shè)置背景顏色
MainGame.window.fill(BACKGROUND_COLOR)
# 獲取窗口事件
self.getPlayingModeEvent()
# 顯示我方坦克
MainGame.playerTank.draw(MainGame.window)
# 我方坦克移動
if not MainGame.playerTank.stop:
MainGame.playerTank.move()
# 更新窗口
pygame.display.update()
完整我方坦克類代碼
import pygame
import sys
from PlayerTank import PlayerTank
SCREEN_WIDTH = 1100
SCREEN_HEIGHT = 600
BACKGROUND_COLOR = pygame.Color(0, 0, 0)
FONT_COLOR = (255, 255, 255)
PLAYER_TANK_POSITION = (325, 550)
class MainGame:
# 窗口Surface對象
window = None
# 玩家坦克
playerTank = None
def __init__(self):
pass
def startGame(self):
# 初始化展示模塊
pygame.display.init()
# 設(shè)置窗口大小
size = (SCREEN_WIDTH, SCREEN_HEIGHT)
# 初始化窗口
MainGame.window = pygame.display.set_mode(size)
# 設(shè)置窗口標(biāo)題
pygame.display.set_caption('Tank Battle')
# 初始化我方坦克
MainGame.playerTank = PlayerTank(PLAYER_TANK_POSITION[0], PLAYER_TANK_POSITION[1], 1, 1)
while 1:
# 設(shè)置背景顏色
MainGame.window.fill(BACKGROUND_COLOR)
# 獲取窗口事件
self.getPlayingModeEvent()
# 顯示我方坦克
MainGame.playerTank.draw(MainGame.window)
# 我方坦克移動
if not MainGame.playerTank.stop:
MainGame.playerTank.move()
# 更新窗口
pygame.display.update()
def getPlayingModeEvent(self):
# 獲取所有事件
eventList = pygame.event.get()
for event in eventList:
if event.type == pygame.QUIT:
sys.exit()
"""
stop屬性用來控制坦克移動,當(dāng)鍵盤按鍵按下時,坦克可以移動,一直按住一直移動,當(dāng)按鍵抬起時,停止移動
如果沒有該屬性,按一下按鍵移動一次,按一下移動一下,不能一直按住一直移動
"""
if event.type == pygame.KEYDOWN:
print('鍵盤按鍵按下')
if event.key == pygame.K_w:
MainGame.playerTank.direction = 'UP'
MainGame.playerTank.stop = False
elif event.key == pygame.K_s:
MainGame.playerTank.direction = 'DOWN'
MainGame.playerTank.stop = False
elif event.key == pygame.K_a:
MainGame.playerTank.direction = 'LEFT'
MainGame.playerTank.stop = False
elif event.key == pygame.K_d:
MainGame.playerTank.direction = 'RIGHT'
MainGame.playerTank.stop = False
elif event.key == pygame.K_j:
print('j按下')
if event.type == pygame.KEYUP:
print('鍵盤按鍵抬起')
if event.key == pygame.K_w:
MainGame.playerTank.stop = True
elif event.key == pygame.K_s:
MainGame.playerTank.stop = True
elif event.key == pygame.K_a:
MainGame.playerTank.stop = True
elif event.key == pygame.K_d:
MainGame.playerTank.stop = True
if __name__ == '__main__':
MainGame().startGame()
運(yùn)行結(jié)果
7. 初始化子彈類
現(xiàn)在已經(jīng)實(shí)現(xiàn)了坦克的移動啦,下面就要實(shí)現(xiàn)坦克的發(fā)射子彈
實(shí)際上,子彈也是一幅圖片,當(dāng)我們按下開火按鍵后,就在坦克的正前方畫出子彈,隨著時間的流逝,要讓子彈按照當(dāng)前方向一直運(yùn)動下去
import pygame
from ParentObject import ParentObject
class Bullet(ParentObject):
def __init__(self, tank):
super().__init__()
self.images = {
'UP': pygame.image.load('../Image/Bullet/Bullet(UP).png'),
'DOWN': pygame.image.load('../Image/Bullet/Bullet(DOWN).png'),
'LEFT': pygame.image.load('../Image/Bullet/Bullet(LEFT).png'),
'RIGHT': pygame.image.load('../Image/Bullet/Bullet(RIGHT).png')
}
# 方向
self.direction = tank.direction
self.image: pygame.Surface = self.images[self.direction]
self.rect = self.image.get_rect()
# 坦克發(fā)射子彈的位置
if self.direction == 'UP':
self.rect.left = tank.rect.left + 17.5
self.rect.top = tank.rect.top - 25
elif self.direction == 'DOWN':
self.rect.left = tank.rect.left + 17.5
self.rect.top = tank.rect.top + 25
elif self.direction == 'LEFT':
self.rect.left = tank.rect.left - 25
self.rect.top = tank.rect.top + 17.5
elif self.direction == 'RIGHT':
self.rect.left = tank.rect.left + 25
self.rect.top = tank.rect.top + 17.5
# 速度
self.accumulationMax: float = 0
self.accumulation = 0.25
self.speed = 10
# 銷毀開關(guān)
self.isDestroy = False
# 發(fā)射源
self.source = tank
# 傷害
self.damage = tank.damage
def move(self, explodeList):
pass
def draw(self, window):
window.blit(self.image, self.rect)
下面是確定子彈的位置:
子彈圖片是25x10,坦克發(fā)射子彈是在坦克中間位置發(fā)射
8. 完善子彈的移動
子彈的初始位置確定后,一旦創(chuàng)建出來,就要一直移動下去,實(shí)際上就是刷新屏幕,然后把原來位置上的子彈圖片去掉,在新的位置上再畫出子彈圖片,坦克移動的原理也是這樣
修改move函數(shù),添加檢查子彈出界函數(shù)
def move(self):
if self.accumulation >= 1:
self.accumulation = 0
if self.direction == 'LEFT':
self.rect.left -= self.speed
elif self.direction == 'UP':
self.rect.top -= self.speed
elif self.direction == 'DOWN':
self.rect.top += self.speed
elif self.direction == 'RIGHT':
self.rect.left += self.speed
# 檢查子彈是否出界
self.checkBullet()
else:
self.accumulation += 0.20
def checkBullet(self):
toDestroy = False
# 如果出界,就設(shè)置為銷毀
if self.rect.top < 0 or self.rect.top > 600:
toDestroy = True
if self.rect.left < 0 or self.rect.right > 900:
toDestroy = True
if toDestroy:
self.isDestroy = True
子彈類完整代碼
import pygame
from ParentObject import ParentObject
class Bullet(ParentObject):
def __init__(self, tank):
super().__init__()
self.images = {
'UP': pygame.image.load('../Image/Bullet/Bullet(UP).png'),
'DOWN': pygame.image.load('../Image/Bullet/Bullet(DOWN).png'),
'LEFT': pygame.image.load('../Image/Bullet/Bullet(LEFT).png'),
'RIGHT': pygame.image.load('../Image/Bullet/Bullet(RIGHT).png')
}
# 方向
self.direction = tank.direction
self.image: pygame.Surface = self.images[self.direction]
self.rect = self.image.get_rect()
# 坦克發(fā)射子彈的位置
if self.direction == 'UP':
self.rect.left = tank.rect.left + 17.5
self.rect.top = tank.rect.top - 25
elif self.direction == 'DOWN':
self.rect.left = tank.rect.left + 17.5
self.rect.top = tank.rect.top + 25
elif self.direction == 'LEFT':
self.rect.left = tank.rect.left - 25
self.rect.top = tank.rect.top + 17.5
elif self.direction == 'RIGHT':
self.rect.left = tank.rect.left + 25
self.rect.top = tank.rect.top + 17.5
# 速度
self.accumulationMax: float = 0
self.accumulation = 0.25
self.speed = 10
# 銷毀開關(guān)
self.isDestroy = False
# 發(fā)射源
self.source = tank
# 傷害
self.damage = tank.damage
def move(self):
if self.accumulation >= 1:
self.accumulation = 0
if self.direction == 'LEFT':
self.rect.left -= self.speed
elif self.direction == 'UP':
self.rect.top -= self.speed
elif self.direction == 'DOWN':
self.rect.top += self.speed
elif self.direction == 'RIGHT':
self.rect.left += self.speed
# 檢查子彈是否出界
self.checkBullet()
else:
self.accumulation += 0.20
def checkBullet(self):
toDestroy = False
# 如果出界,就設(shè)置為銷毀
if self.rect.top < 0 or self.rect.top > 600:
toDestroy = True
if self.rect.left < 0 or self.rect.right > 900:
toDestroy = True
if toDestroy:
self.isDestroy = True
def draw(self, window):
window.blit(self.image, self.rect)
9. 完善坦克開火
有了子彈類,就可以讓坦克發(fā)射子彈了
在主類中設(shè)置玩家子彈數(shù)量的最大值
... ...
class MainGame:
# 窗口Surface對象
window = None
# 指定的子彈個數(shù),這里設(shè)置玩家的子彈最多只有3顆子彈可以同時在場
playerBulletNumber = 3
# 玩家坦克
playerTank = None
... ...
修改坦克的 shot() 函數(shù)
def shot(self):
return Bullet(self)
修改 getPlayingModeEvent() 函數(shù)
當(dāng) j鍵按下,發(fā)射子彈
def getPlayingModeEvent(self):
# 獲取所有事件
eventList = pygame.event.get()
for event in eventList:
if event.type == pygame.QUIT:
sys.exit()
"""
stop屬性用來控制坦克移動,當(dāng)鍵盤按鍵按下時,坦克可以移動,一直按住一直移動,當(dāng)按鍵抬起時,停止移動
如果沒有該屬性,按一下按鍵移動一次,按一下移動一下,不能一直按住一直移動
"""
if event.type == pygame.KEYDOWN:
print('鍵盤按鍵按下')
if event.key == pygame.K_w:
MainGame.playerTank.direction = 'UP'
MainGame.playerTank.stop = False
elif event.key == pygame.K_s:
MainGame.playerTank.direction = 'DOWN'
MainGame.playerTank.stop = False
elif event.key == pygame.K_a:
MainGame.playerTank.direction = 'LEFT'
MainGame.playerTank.stop = False
elif event.key == pygame.K_d:
MainGame.playerTank.direction = 'RIGHT'
MainGame.playerTank.stop = False
elif event.key == pygame.K_j:
# 判斷子彈數(shù)量是否超過指定的個數(shù)
if len(MainGame.playerBulletList) < MainGame.playerBulletNumber:
bullet = MainGame.playerTank.shot()
MainGame.playerBulletList.append(bullet)
if event.type == pygame.KEYUP:
print('鍵盤按鍵抬起')
if event.key == pygame.K_w:
MainGame.playerTank.stop = True
elif event.key == pygame.K_s:
MainGame.playerTank.stop = True
elif event.key == pygame.K_a:
MainGame.playerTank.stop = True
elif event.key == pygame.K_d:
MainGame.playerTank.stop = True
子彈有了,但是沒有顯示在窗口,此時寫一個函數(shù)讓子彈在窗口顯示出來
def drawPlayerBullet(self, playerBulletList):
# 遍歷整個子彈列表,如果是沒有被銷毀的狀態(tài),就把子彈顯示出來,否則從列表中刪除
for bullet in playerBulletList:
if not bullet.isDestroy:
bullet.draw(MainGame.window)
bullet.move()
else:
playerBulletList.remove(bullet)
有了函數(shù)還需要調(diào)用,在while循環(huán)中加入該函數(shù)
while 1:
# 設(shè)置背景顏色
MainGame.window.fill(BACKGROUND_COLOR)
# 獲取窗口事件
self.getPlayingModeEvent()
# 顯示我方坦克
MainGame.playerTank.draw(MainGame.window)
# 我方坦克移動
if not MainGame.playerTank.stop:
MainGame.playerTank.move()
# 顯示我方坦克子彈
self.drawPlayerBullet(MainGame.playerBulletList)
# 更新窗口
pygame.display.update()
運(yùn)行游戲看看結(jié)果
當(dāng)我們按下開火鍵時,子彈就發(fā)射了
注意:MainGame.playerBulletList 需要定義出來,否則程序運(yùn)行會報錯
添加位置如下:
... ...
class MainGame:
# 窗口Surface對象
window = None
playerBulletList = []
playerBulletNumber = 3
# 玩家坦克
playerTank = None
... ...
10. 實(shí)現(xiàn)敵方坦克類
現(xiàn)在我的坦克可以移動和開火,那么就要有點(diǎn)靶子給我們練習(xí)了,是時候?qū)崿F(xiàn)敵方坦克類了
敵方坦克類的大部分代碼跟我方坦克類一樣,這里可以用繼承,即父類是坦克類,實(shí)現(xiàn)兩個類的一樣的代碼,然后我方坦克類和敵方坦克類繼承這個類,不過我沒有使用繼承
import random
import pygame
import pygame.image
from ParentObject import ParentObject
from Bullet import Bullet
class EnemyTank(ParentObject):
def __init__(self, x, y):
super().__init__()
types = [(1, 3), (2, 1), (3, 2), (4, 10)]
# 隨機(jī)產(chǎn)生一種坦克
self.type = types[random.randint(0, len(types) - 1)]
up = []
down = []
left = []
right = []
for i in range(1, self.type[1] + 1):
up.append(
pygame.image.load(
'../Image/Enemy/EnemyTank' + str(self.type[0]) + '/EnemyTank'+ str(self.type[0]) + 'Lv' + str(i) + '(UP).png'
)
)
down.append(
pygame.image.load(
'../Image/Enemy/EnemyTank' + str(self.type[0]) + '/EnemyTank'+ str(self.type[0]) + 'Lv' + str(i) + '(DOWN).png'
)
)
left.append(
pygame.image.load(
'../Image/Enemy/EnemyTank' + str(self.type[0]) + '/EnemyTank' + str(self.type[0]) + 'Lv' + str(
i) + '(LEFT).png'
)
)
right.append(
pygame.image.load(
'../Image/Enemy/EnemyTank' + str(self.type[0]) + '/EnemyTank' + str(self.type[0]) + 'Lv' + str(
i) + '(RIGHT).png'
)
)
self.images = {
'UP': up,
'DOWN': down,
'LEFT': left,
'RIGHT': right
}
# 生命
self.life = self.type[1]
# 方向
self.direction = 'DOWN'
self.image: pygame.Surface = self.images[self.direction][self.life - 1]
self.rect = self.image.get_rect()
self.rect.left = x
self.rect.top = y
# 速度
self.accumulationMax: float = 0
self.accumulation = 0.1
speed = 0
maxBulletCount = 0
damage = 1
if self.type[0] == 1:
speed = 3
self.level = 1
maxBulletCount = 1
elif self.type[0] == 2:
speed = 5
self.level = 2
maxBulletCount = 1
damage = 3
elif self.type[0] == 3:
speed = 7
self.level = 1
maxBulletCount = 3
damage = 2
elif self.type[0] == 4:
speed = 6
self.level = 2
maxBulletCount = 3
damage = 1
self.speed = speed
# 移動開關(guān)
self.stop = True
# 開火開關(guān)
self.fire = True
# 步數(shù)
self.step = 30
# 傷害
self.damage = damage
# 子彈個數(shù)
self.bulletCount = 0
self.maxBulletCount = maxBulletCount
def move(self):
"""
新增步數(shù)變量, 當(dāng)坦克移動時, 步數(shù)進(jìn)行減少, 當(dāng)步數(shù)小于等于0的時候, 修改地方坦克的方向
:return: None
"""
if self.stop:
if self.step <= 0:
self.direction = self.randDirection()
self.step = 30
else:
if self.accumulationMax >= 1:
self.accumulationMax = 0
if self.direction == 'LEFT':
if self.rect.left > 0:
self.rect.left -= self.speed
elif self.direction == 'UP':
if self.rect.top > 0:
self.rect.top -= self.speed
elif self.direction == 'DOWN':
if self.rect.top < 555:
self.rect.top += self.speed
elif self.direction == 'RIGHT':
if self.rect.left < 855:
self.rect.left += self.speed
self.step -= 1
else:
self.accumulationMax += self.accumulation
def shot(self):
if self.fire:
if self.bulletCount < self.maxBulletCount:
num = random.randint(0, 100)
if num == 5 or num == 6:
self.bulletCount += 1
return Bullet(self)
return None
def draw(self, window):
# 獲取展示的對象
self.image = self.images[self.direction][self.life - 1]
window.blit(self.image, self.rect)
def randDirection(self):
directions = ['UP', 'DOWN', 'LEFT', 'RIGHT']
index = random.randint(0, 3)
return directions[index]
我實(shí)際上設(shè)置了四種坦克的種類,下面types變量中記錄著四種種類的序號和生命值,我規(guī)定,生命中不同坦克的樣子也不同
types = [(1, 3), (2, 1), (3, 2), (4, 10)]
# 隨機(jī)產(chǎn)生一種坦克
self.type = types[random.randint(0, len(types) - 1)]
元組中的第二個元素表示生命值, 直接獲取
# 生命
self.life = self.type[1]
根據(jù)方向和生命值獲取對應(yīng)的圖片
self.image: pygame.Surface = self.images[self.direction][self.life - 1]
坦克的屬性
根據(jù)坦克種類的不同,傷害、等級、生命值也不同
等級是子彈的穿透性,1級只能打爛磚墻,2級可以打爛石墻,3級以上可以打爛黑曜石墻,這個黑曜石墻是我自己新加入的,我們以前玩的坦克大戰(zhàn)是沒有的,而且規(guī)則和我這個不太一樣,當(dāng)然你也可以修改,比如給坦克加入能量,當(dāng)坦克在一定時間內(nèi)連續(xù)擊殺多個敵人,可以獲得怒氣,短時間傷害提升,這些都可以實(shí)現(xiàn)
speed = 0
maxBulletCount = 0
damage = 1
# 每種坦克都有不同的屬性
if self.type[0] == 1:
speed = 3
self.level = 1
maxBulletCount = 1
elif self.type[0] == 2:
speed = 5
self.level = 2
maxBulletCount = 1
damage = 3
elif self.type[0] == 3:
speed = 7
self.level = 1
maxBulletCount = 3
damage = 2
elif self.type[0] == 4:
speed = 6
self.level = 2
maxBulletCount = 3
damage = 1
坦克的移動
step是步數(shù),每次按照30次循環(huán)作為一次坦克的操作
if self.stop:
if self.step <= 0:
# 隨機(jī)產(chǎn)生一個方向,接下來朝這個方向移動
self.direction = self.randDirection()
self.step = 30
else:
if self.accumulationMax >= 1:
self.accumulationMax = 0
if self.direction == 'LEFT':
if self.rect.left > 0:
self.rect.left -= self.speed
elif self.direction == 'UP':
if self.rect.top > 0:
self.rect.top -= self.speed
elif self.direction == 'DOWN':
if self.rect.top < 555:
self.rect.top += self.speed
elif self.direction == 'RIGHT':
if self.rect.left < 855:
self.rect.left += self.speed
self.step -= 1
else:
self.accumulationMax += self.accumulation
坦克開火
隨機(jī)產(chǎn)生一個0到100的數(shù)字,當(dāng)為5或者6時,坦克就開火
def shot(self):
if self.fire:
if self.bulletCount < self.maxBulletCount:
num = random.randint(0, 100)
if num == 5 or num == 6:
self.bulletCount += 1
return Bullet(self)
return None
在上面的代碼中,下面的變量用來設(shè)置敵方坦克是否移動,是否開火
# 移動開關(guān)
self.stop = True
# 開火開關(guān)
self.fire = True
11. 在主類中加入敵方坦克并完成坦克移動和開火
在主類中創(chuàng)建類變量
class MainGame:
# 窗口Surface對象
window = None
# 玩家坦克
playerTank = None
# 玩家子彈
playerBulletList = []
playerBulletNumber = 3
# 敵人坦克
enemyTankList = []
enemyTankTotalCount = 5
# 用來給玩家展示坦克的數(shù)量
enemyTankCurrentCount = 5
# 敵人坦克子彈
enemyTankListBulletList = []
創(chuàng)建展示敵方坦克函數(shù)
這里我規(guī)定一次展示三輛敵方坦克,當(dāng)全部被消滅后,再展示3輛,直到全部被消滅
def drawEnemyTank(self):
# 如果當(dāng)前坦克為0,那么就該重新生成坦克
if len(MainGame.enemyTankList) == 0:
# 一次性產(chǎn)生三個,如果剩余坦克數(shù)量超過三,那只能產(chǎn)生三個
n = min(3, MainGame.enemyTankTotalCount)
# 如果最小是0,就說明敵人坦克沒有了,那么就贏了
if n == 0:
print('贏了')
return
# 沒有贏的話,就產(chǎn)生n個坦克
self.initEnemyTank(n)
# 總個數(shù)減去產(chǎn)生的個數(shù)
MainGame.enemyTankTotalCount -= n
# 遍歷坦克列表,展示坦克并且移動
for tank in MainGame.enemyTankList:
# 坦克還有生命值
if tank.life > 0:
tank.draw(MainGame.window)
tank.move()
bullet = tank.shot()
if bullet is not None:
MainGame.enemyTankBulletList.append(bullet)
# 坦克生命值為0,就從列表中剔除
else:
MainGame.enemyTankCurrentCount -= 1
MainGame.enemyTankList.remove(tank)
坦克開火之后子彈加入敵方坦克子彈列表,把里面的子彈畫出來,然后在while中調(diào)用它
def drawEnemyBullet(self):
for bullet in MainGame.enemyTankBulletList:
if not bullet.isDestroy:
bullet.draw(MainGame.window)
bullet.move()
else:
bullet.source.bulletCount -= 1
MainGame.enemyTankBulletList.remove(bullet)
while 1:
# 設(shè)置背景顏色
MainGame.window.fill(BACKGROUND_COLOR)
# 獲取窗口事件
self.getPlayingModeEvent()
# 顯示我方坦克
MainGame.playerTank.draw(MainGame.window)
# 我方坦克移動
if not MainGame.playerTank.stop:
MainGame.playerTank.move()
# 顯示我方坦克子彈
self.drawPlayerBullet(MainGame.playerBulletList)
# 展示敵方坦克
self.drawEnemyTank()
# 展示敵方坦克子彈
self.drawEnemyBullet()
# 更新窗口
pygame.display.update()
完整的主類代碼
import pygame
import sys
from PlayerTank import PlayerTank
from EnemyTank import EnemyTank
SCREEN_WIDTH = 1100
SCREEN_HEIGHT = 600
BACKGROUND_COLOR = pygame.Color(0, 0, 0)
FONT_COLOR = (255, 255, 255)
PLAYER_TANK_POSITION = (325, 550)
class MainGame:
# 窗口Surface對象
window = None
# 玩家坦克
playerTank = None
# 玩家子彈
playerBulletList = []
playerBulletNumber = 3
# 敵人坦克
enemyTankList = []
enemyTankTotalCount = 5
# 用來給玩家展示坦克的數(shù)量
enemyTankCurrentCount = 5
# 敵人坦克子彈
enemyTankBulletList = []
def __init__(self):
pass
def startGame(self):
# 初始化展示模塊
pygame.display.init()
# 設(shè)置窗口大小
size = (SCREEN_WIDTH, SCREEN_HEIGHT)
# 初始化窗口
MainGame.window = pygame.display.set_mode(size)
# 設(shè)置窗口標(biāo)題
pygame.display.set_caption('Tank Battle')
# 初始化我方坦克
MainGame.playerTank = PlayerTank(PLAYER_TANK_POSITION[0], PLAYER_TANK_POSITION[1], 1, 1)
while 1:
# 設(shè)置背景顏色
MainGame.window.fill(BACKGROUND_COLOR)
# 獲取窗口事件
self.getPlayingModeEvent()
# 顯示我方坦克
MainGame.playerTank.draw(MainGame.window)
# 我方坦克移動
if not MainGame.playerTank.stop:
MainGame.playerTank.move()
# 顯示我方坦克子彈
self.drawPlayerBullet(MainGame.playerBulletList)
# 展示敵方坦克
self.drawEnemyTank()
# 展示敵方坦克子彈
self.drawEnemyBullet()
# 更新窗口
pygame.display.update()
def getPlayingModeEvent(self):
# 獲取所有事件
eventList = pygame.event.get()
for event in eventList:
if event.type == pygame.QUIT:
sys.exit()
"""
stop屬性用來控制坦克移動,當(dāng)鍵盤按鍵按下時,坦克可以移動,一直按住一直移動,當(dāng)按鍵抬起時,停止移動
如果沒有該屬性,按一下按鍵移動一次,按一下移動一下,不能一直按住一直移動
"""
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
MainGame.playerTank.direction = 'UP'
MainGame.playerTank.stop = False
elif event.key == pygame.K_s:
MainGame.playerTank.direction = 'DOWN'
MainGame.playerTank.stop = False
elif event.key == pygame.K_a:
MainGame.playerTank.direction = 'LEFT'
MainGame.playerTank.stop = False
elif event.key == pygame.K_d:
MainGame.playerTank.direction = 'RIGHT'
MainGame.playerTank.stop = False
elif event.key == pygame.K_j:
# 判斷子彈數(shù)量是否超過指定的個數(shù)
if len(MainGame.playerBulletList) < MainGame.playerBulletNumber:
bullet = MainGame.playerTank.shot()
MainGame.playerBulletList.append(bullet)
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
MainGame.playerTank.stop = True
elif event.key == pygame.K_s:
MainGame.playerTank.stop = True
elif event.key == pygame.K_a:
MainGame.playerTank.stop = True
elif event.key == pygame.K_d:
MainGame.playerTank.stop = True
def drawPlayerBullet(self, playerBulletList):
# 遍歷整個子彈列表,如果是沒有被銷毀的狀態(tài),就把子彈顯示出來,否則從列表中刪除
for bullet in playerBulletList:
if not bullet.isDestroy:
bullet.draw(MainGame.window)
bullet.move()
else:
playerBulletList.remove(bullet)
def drawEnemyTank(self):
# 如果當(dāng)前坦克為0,那么就該重新生成坦克
if len(MainGame.enemyTankList) == 0:
# 一次性產(chǎn)生三個,如果剩余坦克數(shù)量超過三,那只能產(chǎn)生三個
n = min(3, MainGame.enemyTankTotalCount)
# 如果最小是0,就說明敵人坦克沒有了,那么就贏了
if n == 0:
print('贏了')
return
# 沒有贏的話,就產(chǎn)生n個坦克
self.initEnemyTank(n)
# 總個數(shù)減去產(chǎn)生的個數(shù)
MainGame.enemyTankTotalCount -= n
# 遍歷坦克列表,展示坦克并且移動
for tank in MainGame.enemyTankList:
# 坦克還有生命值
if tank.life > 0:
tank.draw(MainGame.window)
tank.move()
bullet = tank.shot()
if bullet is not None:
MainGame.enemyTankBulletList.append(bullet)
# 坦克生命值為0,就從列表中剔除
else:
MainGame.enemyTankCurrentCount -= 1
MainGame.enemyTankList.remove(tank)
def initEnemyTank(self, number):
y = 0
position = [0, 425, 850]
index = 0
for i in range(number):
x = position[index]
enemyTank = EnemyTank(x, y)
MainGame.enemyTankList.append(enemyTank)
index += 1
def drawEnemyBullet(self):
for bullet in MainGame.enemyTankBulletList:
if not bullet.isDestroy:
bullet.draw(MainGame.window)
bullet.move()
else:
bullet.source.bulletCount -= 1
MainGame.enemyTankBulletList.remove(bullet)
if __name__ == '__main__':
MainGame().startGame()
運(yùn)行一下,看看結(jié)果文章來源:http://www.zghlxwxcb.cn/news/detail-785212.html
哈哈,終于實(shí)現(xiàn)發(fā)射子彈啦文章來源地址http://www.zghlxwxcb.cn/news/detail-785212.html
到了這里,關(guān)于學(xué)習(xí) Python 之 Pygame 開發(fā)坦克大戰(zhàn)(二)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!