Pygame实战:对象突然想玩坦克大战,我用Python三十分钟实现(他开心的笑了。)
Posted 顾木子吖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Pygame实战:对象突然想玩坦克大战,我用Python三十分钟实现(他开心的笑了。)相关的知识,希望对你有一定的参考价值。
导语
今天是回忆童年的一天,文章游戏代码的话小编写了蛮多还,等啥时候有时间了我整理下笔记归类放着!!
《坦克大战》当年算是红遍大江南北的热门游戏。
别看这游戏画面简陋,它可是集合了所有经典游戏的成功要素——
上手容易、升级强化、关卡丰富、可以双打,甚至还有良心到爆的编辑模式。
虽然是个低K游戏,但在当时的国人看来,这游戏买得非常值!
今天小编带大家写一款经典版的坦克大战游戏项目,期待叭~
正文
(1)准备的图片素材很多分类处理:以下是部分截图。
(2)不同的音乐背景:当熟悉的背景音乐响起,扑面而来的是整个童年啊!
(3)游戏规则:
游戏有单人和双人两种模式,己方大本营被破或者己方坦克被歼灭则游戏失败,成功通过所有关卡则游戏胜利。另外,玩家可以通过射击特定的坦克使地图上随机出现一个道具,若己方坦克捡到该道具,则触发一个事件,例如坦克能力的增强。
玩家操作方式如下:
玩家一:
wsad键:上下左右;
空格键:射击。
玩家二:
↑↓←→键:上下左右;
小键盘0键:射击。
# 玩家一, WSAD移动, 空格键射击 if tank_player1.num_lifes >= 0: if key_pressed[pygame.K_w]: player_tanks_group.remove(tank_player1) tank_player1.move('up', self.scene_elems, player_tanks_group, enemy_tanks_group, home) player_tanks_group.add(tank_player1) elif key_pressed[pygame.K_s]: player_tanks_group.remove(tank_player1) tank_player1.move('down', self.scene_elems, player_tanks_group, enemy_tanks_group, home) player_tanks_group.add(tank_player1) elif key_pressed[pygame.K_a]: player_tanks_group.remove(tank_player1) tank_player1.move('left', self.scene_elems, player_tanks_group, enemy_tanks_group, home) player_tanks_group.add(tank_player1) elif key_pressed[pygame.K_d]: player_tanks_group.remove(tank_player1) tank_player1.move('right', self.scene_elems, player_tanks_group, enemy_tanks_group, home) player_tanks_group.add(tank_player1) elif key_pressed[pygame.K_SPACE]: bullet = tank_player1.shoot() if bullet: self.sounds['fire'].play() if tank_player1.tanklevel < 2 else self.sounds['Gunfire'].play() player_bullets_group.add(bullet) # 玩家二, ↑↓←→移动, 小键盘0键射击 if self.is_dual_mode and (tank_player2.num_lifes >= 0): if key_pressed[pygame.K_UP]: player_tanks_group.remove(tank_player2) tank_player2.move('up', self.scene_elems, player_tanks_group, enemy_tanks_group, home) player_tanks_group.add(tank_player2) elif key_pressed[pygame.K_DOWN]: player_tanks_group.remove(tank_player2) tank_player2.move('down', self.scene_elems, player_tanks_group, enemy_tanks_group, home) player_tanks_group.add(tank_player2) elif key_pressed[pygame.K_LEFT]: player_tanks_group.remove(tank_player2) tank_player2.move('left', self.scene_elems, player_tanks_group, enemy_tanks_group, home) player_tanks_group.add(tank_player2) elif key_pressed[pygame.K_RIGHT]: player_tanks_group.remove(tank_player2) tank_player2.move('right', self.scene_elems, player_tanks_group, enemy_tanks_group, home) player_tanks_group.add(tank_player2) elif key_pressed[pygame.K_KP0]: bullet = tank_player2.shoot() if bullet: player_bullets_group.add(bullet) self.sounds['fire'].play() if tank_player2.tanklevel < 2 else self.sounds['Gunfire'].play()
加载游戏素材中:
附:
# 加载游戏素材 sounds = for key, value in cfg.AUDIO_PATHS.items(): sounds[key] = pygame.mixer.Sound(value) sounds[key].set_volume(1)
(4)在坦克移动中、打到对方等肯定有碰撞:
# 碰撞检测 # --子弹和砖墙 pygame.sprite.groupcollide(player_bullets_group, self.scene_elems.get('brick_group'), True, True) pygame.sprite.groupcollide(enemy_bullets_group, self.scene_elems.get('brick_group'), True, True) # --子弹和铁墙 for bullet in player_bullets_group: if pygame.sprite.spritecollide(bullet, self.scene_elems.get('iron_group'), bullet.is_stronger, None): player_bullets_group.remove(bullet) pygame.sprite.groupcollide(enemy_bullets_group, self.scene_elems.get('iron_group'), True, False) # --子弹撞子弹 pygame.sprite.groupcollide(player_bullets_group, enemy_bullets_group, True, True) # --我方子弹撞敌方坦克 for tank in enemy_tanks_group: if pygame.sprite.spritecollide(tank, player_bullets_group, True, None): if tank.food: foods_group.add(tank.food) tank.food = None if tank.decreaseTankLevel(): self.sounds['bang'].play() self.total_enemy_num -= 1 # --敌方子弹撞我方坦克 for tank in player_tanks_group: if pygame.sprite.spritecollide(tank, enemy_bullets_group, True, None): if tank.is_protected: self.sounds['blast'].play() else: if tank.decreaseTankLevel(): self.sounds['bang'].play() if tank.num_lifes < 0: player_tanks_group.remove(tank) # --我方子弹撞我方大本营 if pygame.sprite.spritecollide(home, player_bullets_group, True, None): is_win = False is_running = False home.setDead() # --敌方子弹撞我方大本营 if pygame.sprite.spritecollide(home, enemy_bullets_group, True, None): is_win = False is_running = False home.setDead()
(5)坦克游戏中会随机生成食物:
# --坦克吃到食物 for player_tank in player_tanks_group: for food in foods_group: if pygame.sprite.collide_rect(player_tank, food): if food.name == 'boom': self.sounds['add'].play() for _ in enemy_tanks_group: self.sounds['bang'].play() self.total_enemy_num -= len(enemy_tanks_group) enemy_tanks_group = pygame.sprite.Group() elif food.name == 'clock': self.sounds['add'].play() for enemy_tank in enemy_tanks_group: enemy_tank.setStill() elif food.name == 'gun': self.sounds['add'].play() player_tank.improveTankLevel() elif food.name == 'iron': self.sounds['add'].play() self.__pretectHome() elif food.name == 'protect': self.sounds['add'].play() player_tank.setProtected() elif food.name == 'star': self.sounds['add'].play() player_tank.improveTankLevel() player_tank.improveTankLevel() elif food.name == 'tank': self.sounds['add'].play() player_tank.addLife() foods_group.remove(food)
游戏效果:
总结
这游戏的话经典哈,我第一关就没玩了哈,大家自己探索。
说实话代码真挺多的,你感觉这款坦克大战有还原多少呀??
源码基地免费分享项目:🎊🎊源码基地:关注小编获取哦~💝记得三连吖
..............更多内容敬请期待...........
学习 Python 之 Pygame 开发坦克大战
学习 Python 之 Pygame 开发坦克大战(二)
坦克大战的需求
坦克大战游戏包含很多个物体,现在要对这些物体进行总结
类名 | 包含的操作 | 包含的属性 |
---|---|---|
敌方坦克类 | 射击,移动,显示 | 生命,速度,伤害,方向,类型 |
我方坦克类 | 射击,移动,显示 | 生命,速度,伤害,方向,装甲,等级 |
子弹类 | 移动,显示 | 方向,伤害,发射源,速度 |
墙壁类、草类、石砖类、河类 | 显示 | 是否可以摧毁 |
音效类 | 播放,停止,设置音乐 | - |
爆炸效果类 | 显示 | 是否可以摧毁 |
主类 | … | … |
物体总结完毕后,规划一下窗口的大小,下面是我设置的窗口大小
素材链接:百度网盘
链接:https://pan.baidu.com/s/19sCyH7rp37f6DzRj0iXDCA?pwd=tkdz
提取码:tkdz
开始编写坦克大战
一切都准备就绪啦,现在开始编写坦克大战的代码吧
1. 搭建主类框架
主类是整个游戏运作的类,当然你也可以不用使用类,直接创建一个函数也可以,这里使用了面向对象的思想
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()
# 设置窗口大小
size = (SCREEN_WIDTH, SCREEN_HEIGHT)
# 初始化窗口
MainGame.window = pygame.display.set_mode(size)
# 设置窗口标题
pygame.display.set_caption('Tank Battle')
while 1:
# 设置背景颜色
MainGame.window.fill(BACKGROUND_COLOR)
# 更新窗口
pygame.display.update()
if __name__ == '__main__':
MainGame().startGame()
运行结果
主类中运用到的知识,都是学习 Python 之 Pygame 开发坦克大战(一)中所包含的
2. 获取窗口中的事件
坦克大战关键是对玩家自己的坦克进行操控,消灭敌人的坦克,所以键盘事件响应是必不可少的
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抬起')
获取窗口中的事件,用于玩家操控坦克、发射坦克子弹等操作
游戏中,我规定aswd操控坦克,j攻击,当然你也可以上下左右键移动,空格攻击,如果你想设置双人游戏,这也是可以的
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()
# 设置窗口大小
size = (SCREEN_WIDTH, SCREEN_HEIGHT)
# 初始化窗口
MainGame.window = pygame.display.set_mode(size)
# 设置窗口标题
pygame.display.set_caption('Tank Battle')
while 1:
# 设置背景颜色
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. 创建基类
坦克操控事件完成后,现在就是实现坦克啦,首先场景中的物体都需要发生物体间的碰撞,简单来说就是检测两个屏幕上的图片是否发生了重叠,如果发生了,就要触发一些事件,这里创建ParentObject类,用于继承pygame.sprite.Sprite类
pygame.sprite.Sprite类可以用来检测物体碰撞,是pygame提供的一个类,非常的方便
import pygame.sprite
class ParentObject(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
4. 初始化我方坦克类
创建我方坦克类,并且继承基类
import pygame as pg
import pygame.image
from ParentObject import ParentObject
class PlayerTank(ParentObject):
def __init__(self, x, y, order, amour):
"""
:param x: 坦克横坐标
:param y: 坦克纵坐标
:param order: 玩家坦克序号,1表示一号玩家,2表示二号玩家
:param amour: 坦克初始护甲
"""
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'
# 根据护甲选择坦克的样子
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
# 移动开关
self.stop = True
# 等级
self.level = 1
# 伤害
self.damage = 1
def move(self):
pass
def shot(self):
pass
def draw(self):
pass
5. 完善我方坦克的移动
accumulation 可以更细的控制坦克的移动速度
当 accumulation 累加到 1 时,坦克移动一次,如果不设置这个属性,即使是速度每次 +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
这里需要设置坦克的边界范围
防止坦克跑出窗口
坦克的图片是45x45
5. 完善我方坦克的显示
坦克的显示就是把坦克的图片显示在窗口中
def draw(self, window):
# window传入主窗口
# 坦克生命中为0,表示已经死亡,不再展示坦克
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: 坦克横坐标
:param y: 坦克纵坐标
:param order: 玩家坦克序号,1表示一号玩家,2表示二号玩家
:param amour: 坦克初始护甲
"""
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'
# 根据护甲选择坦克的样子
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
# 移动开关
self.stop = True
# 碰撞前的坐标
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,表示已经死亡,不再展示坦克
if self.life <= 0:
return
# 获取展示的对象
self.image = self.images[max(self.armor - 1, 0)][self.direction]
# 画出图片
window.blit(self.image, self.rect)