准备挑战一下坦克大战的游戏,感觉要比飞机游戏复杂一些,坦克移动时候需要考虑图片跟随方向改变,地图是游戏元素的一部分,需要增加这部分的载入和碰撞检测。
参考网上的教程,按照自己的理解和思路来尝试实现。一步步来吧,遇到问题再说,基本还是按以前的思维方式来写。
一、先写出坦克游戏主循环框架:
import pygame
import sys
pygame.init()
WIDTH = 900
HEIGHT = 600
FPS = 60
running = True
game_window = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
def control():
global running
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
def main():
while running:
control()
clock.tick(FPS)
pygame.display.set_caption('Tank ' + '{0:0.2f}'.format(clock.get_fps()))
pygame.display.update()
pygame.quit()
sys.exit()
if __name__ == '__main__':
main()
二、玩家坦克类
从网上找到的资料,玩家坦克每个方向都有6个图片,代表坦克的装甲,不同装甲坦克图片不同,这里先每个方向复制出1个,搞明白怎么让坦克跟随按键改变方向再说。
开始写玩家坦克类,还是按照以前飞机的思路来,利用sprite精灵组调用draw和update来进行绘制和移动:
导入四个方向的图片:
player_tank_up = pygame.image.load(os.path.join('image', 'player_tank', 'up1.png'))
player_tank_down = pygame.image.load(os.path.join('image', 'player_tank', 'down1.png'))
player_tank_left = pygame.image.load(os.path.join('image', 'player_tank', 'left1.png'))
player_tank_right = pygame.image.load(os.path.join('image', 'player_tank', 'right1.png'))
class PlayerTank(pygame.sprite.Sprite):
player_tank_list = {
'up': [player_tank_up],
'down': [player_tank_down],
'left': [player_tank_left],
'right': [player_tank_right]
}
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.direction = 'up'
self.life = 3
self.image = self.player_tank_list[self.direction][0]
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.speed = 2
def update(self):
key_pressed = pygame.key.get_pressed()
if key_pressed[pygame.K_UP] and self.rect.top >= 0:
self.direction = 'up'
self.rect.y -= self.speed
if key_pressed[pygame.K_DOWN] and self.rect.bottom <= HEIGHT:
self.direction = 'down'
self.rect.y += self.speed
if key_pressed[pygame.K_LEFT] and self.rect.x >= 0:
self.direction = 'left'
self.rect.x -= self.speed
if key_pressed[pygame.K_RIGHT] and self.rect.right <= WIDTH:
self.direction = 'right'
self.rect.x += self.speed
三、玩家坦克移动及图片载入
主函数中实例化玩家坦克类后,坦克实现了移动,但方向没有跟随改变。检查发现,在按键响应里面写了跟随按键来改变direction的值,在控制台打印direction,direction值跟随按键方向实现了改变,但是坦克却没有跟随方向键改变图片方向。
后来又想采用图片翻转旋转的方式,需要写在update方法里面,这才想到,是不是应该在upate里面重新载入图片呢?哈哈,居然实现了。原来问题出在改变direction值后需要在主循环中重新刷新载入,可以进行下一步了。
def update(self):
self.image = self.player_tank_list[self.direction][0]
key_pressed = pygame.key.get_pressed()
现在解决一个方向多个图片的导入问题,多个图片是为了实现不同坦克装甲值有不同的图片显示,可以在游戏过程中看到坦克被击中后图片产生变化。
先建立玩家坦克字典,键是4个方向,值是各自方向中的6个图片列表,总不能写24个图片导入代码吧!改好图片名称,删掉原来的图片导入,采用for循环逐步将图片导入到各自方向的列表中,然后给玩家坦克属性中增加一个装甲属性amour,后期可以根据不同装甲值变化绘制不同坦克图片,amour在这里类似生命值。
class PlayerTank(pygame.sprite.Sprite):
player_tank_dict = {
'up': [],
'down': [],
'left': [],
'right': []
}
for i in range(6):
player_tank_dict['up'].append(
pygame.image.load(os.path.join('image', 'player_tank', 'up' + str(i + 1) + '.png')))
player_tank_dict['down'].append(
pygame.image.load(os.path.join('image', 'player_tank', 'down' + str(i + 1) + '.png')))
player_tank_dict['left'].append(
pygame.image.load(os.path.join('image', 'player_tank', 'left' + str(i + 1) + '.png')))
player_tank_dict['right'].append(
pygame.image.load(os.path.join('image', 'player_tank', 'right' + str(i + 1) + '.png')))
移动的时候还有点问题,坦克游戏的移动方式和飞机游戏的移动方式不太一样,比如同时按下左键和上键,坦克会斜45度移动,这不符合坦克类游戏体验。
增加横向和纵向方向移动开关,限定移动方向唯一。最后的update方法如下:
def update(self):
self.image = self.player_tank_dict[self.direction][self.amour]
key_pressed = pygame.key.get_pressed()
if key_pressed[pygame.K_UP] and self.rect.top >= 0:
self.direction = 'up'
if self.direction_y:
self.rect.y -= self.speed
if key_pressed[pygame.K_DOWN] and self.rect.bottom <= HEIGHT:
self.direction = 'down'
if self.direction_y:
self.rect.y += self.speed
if key_pressed[pygame.K_LEFT] and self.rect.x >= 0:
self.direction = 'left'
if self.direction_x:
self.rect.x -= self.speed
if key_pressed[pygame.K_RIGHT] and self.rect.right <= WIDTH:
self.direction = 'right'
if self.direction_x:
self.rect.x += self.speed
if self.direction == 'up' or self.direction == 'down':
self.direction_x = False
self.direction_y = True
if self.direction == 'left' or self.direction == 'right':
self.direction_x = True
self.direction_y = False
四、现阶段的完整代码:
# 导入使用到的库
import os.path
import pygame
import sys
# 初始化pygame
pygame.init()
# 定义常量
WIDTH = 900
HEIGHT = 600
BLACK = (0, 0, 0)
FPS = 60
# 定义变量,running用来控制主循环
running = True
level = 0
# 确定游戏窗口,设定游戏时钟
game_window = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
# 建立精灵组,all_sprites用来存放全部的精灵组,通过调用draw函数和update函数实现图片绘制及更新移动
all_sprites = pygame.sprite.Group()
# 玩家坦克类,继承精灵属性,图片存放于字典中,并按照方向归类
class PlayerTank(pygame.sprite.Sprite):
player_tank_dict = {
'up': [],
'down': [],
'left': [],
'right': []
}
# 通过for循环,将图片分别加入字典中个方向值的列表
for i in range(6):
player_tank_dict['up'].append(
pygame.image.load(os.path.join('image', 'player_tank', 'up' + str(i + 1) + '.png')))
player_tank_dict['down'].append(
pygame.image.load(os.path.join('image', 'player_tank', 'down' + str(i + 1) + '.png')))
player_tank_dict['left'].append(
pygame.image.load(os.path.join('image', 'player_tank', 'left' + str(i + 1) + '.png')))
player_tank_dict['right'].append(
pygame.image.load(os.path.join('image', 'player_tank', 'right' + str(i + 1) + '.png')))
# 初始化函数,定义方向、装甲、移动开关、速度
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.direction = 'up'
self.amour = 5
self.life = 3
self.image = self.player_tank_dict[self.direction][self.amour]
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.direction_x = None
self.direction_y = None
self.speed = 2
# 重写update函数,重新加载图片,实现图片跟随direction值改变方向,实现玩家坦克移动
def update(self):
self.image = self.player_tank_dict[self.direction][self.amour]
key_pressed = pygame.key.get_pressed()
if key_pressed[pygame.K_UP] and self.rect.top >= 0:
self.direction = 'up'
if self.direction_y:
self.rect.y -= self.speed
if key_pressed[pygame.K_DOWN] and self.rect.bottom <= HEIGHT:
self.direction = 'down'
if self.direction_y:
self.rect.y += self.speed
if key_pressed[pygame.K_LEFT] and self.rect.x >= 0:
self.direction = 'left'
if self.direction_x:
self.rect.x -= self.speed
if key_pressed[pygame.K_RIGHT] and self.rect.right <= WIDTH:
self.direction = 'right'
if self.direction_x:
self.rect.x += self.speed
# 设定移动方向开关,控制坦克只能在横向或纵向移动
if self.direction == 'up' or self.direction == 'down':
self.direction_x = False
self.direction_y = True
if self.direction == 'left' or self.direction == 'right':
self.direction_x = True
self.direction_y = False
# 事件响应函数,接受键盘控制响应
def control():
global running
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
pass
# 开始界面函数
def start_interface():
pass
# 结束界面函数
def end_interface():
pass
# 游戏主循环
def main():
# 实例化玩家坦克,初始位置为家的左侧
player = PlayerTank(325, 550)
# 主循环
while running:
# 接受键盘控制并响应
control()
# 游戏窗口背景,暂时填充为黑色
game_window.fill(BLACK)
# 如果玩家生命数量大于0,游戏开始,小于0则游戏结束
if player.life > 0:
# 设定level为0是为开始界面,游戏选择及玩法说明
if level == 0:
start_interface()
# 第一关游戏,更换地图等
elif level == 1:
all_sprites.add(player)
all_sprites.draw(game_window)
all_sprites.update()
# 第二关游戏,更换地图等
elif level == 2:
pass
# 玩家生命数量为0时,结束游戏,显示得分及重新开始
else:
end_interface()
# 设定游戏帧率
clock.tick(FPS)
# 设定游戏窗口名称,并显示实时帧率
pygame.display.set_caption('Tank ' + '{0:0.2f}'.format(clock.get_fps()))
# 刷新游戏窗口
pygame.display.update()
# 退出pygame/python
pygame.quit()
sys.exit()
if __name__ == '__main__':
main()