Python 坦克大战小游戏
程序员文章站
2024-02-20 08:13:40
...
import pygame
import random
SCREEN_WIDHT = 850
SCRREN_HEIGHT = 500
COLOR_GREEN = pygame.color.Color('LightCyan')
COLOR_RED = pygame.color.Color('red')
# COLOR_GREEN = pygame.color.Color('#3CB371')
# COLOR_GREEN = pygame.color.Color(60,179,113)
class BaseTank:
def __init__(self,x,y):
self.direction = 'U'# U,D,L,R,
self.images = {
'U':pygame.image.load('tank_img/p1tankU.gif'),
'D':pygame.image.load('tank_img/p1tankD.gif'),
'L':pygame.image.load('tank_img/p1tankL.gif'),
'R':pygame.image.load('tank_img/p1tankR.gif'),
}
self.image = self.images[self.direction]
self.live = True
self.speed = 3
# 获取图片默认的区域
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.centery = y
# v2.6 记录移动之前的坐标
self.oldx = 0
self.oldy = 0
# v1.4新增坦克的移动方法
def move(self):
# v2.6 实时记录移动之前的坐标
self.oldx = self.rect.centerx
self.oldy = self.rect.centery
if self.direction == 'U':
# 做边界判断处理
if self.rect.centery > self.rect.height // 2:
self.rect.centery -= self.speed
elif self.direction == 'D':
if self.rect.centery < SCRREN_HEIGHT - self.rect.height // 2:
self.rect.centery += self.speed
elif self.direction == 'L':
if self.rect.centerx > self.rect.height // 2:
self.rect.centerx -= self.speed
elif self.direction == 'R':
if self.rect.centerx < SCREEN_WIDHT - self.rect.height // 2:
self.rect.centerx += self.speed
# v2.6 新增坐标还原方法
def stay(self):
self.rect.centerx = self.oldx
self.rect.centery = self.oldy
# v2.6 新增坦克是否撞墙的方法
def hit_wall(self):
for wall in Game.wall_list:
if pygame.sprite.collide_rect(self,wall):
self.stay()
# 将坦克加入到窗口中
def display_tank(self):
self.image = self.images[self.direction]
# 在指定的位置绘制坦克
Game.window.blit(self.image,self.rect)
# v1.9 增加射击方法
def shot(self):
return Bullet(self)
class HeroTank(BaseTank):
# v1.5 重写父类中的move方法,增加按键控制
def move(self):# key
# 获取所有按键的状态列表
all_key = pygame.key.get_pressed()
if all_key[pygame.K_UP]:
# 1.修改坦克的方向属性
self.direction = 'U'
# 2.调用父类的移动super
super(HeroTank, self).move()
elif all_key[pygame.K_DOWN]:
self.direction = 'D'
super(HeroTank, self).move()
elif all_key[pygame.K_LEFT]:
self.direction = 'L'
super(HeroTank, self).move()
elif all_key[pygame.K_RIGHT]:
self.direction = 'R'
super(HeroTank, self).move()
# v1.6 完善敌方坦克类
class EnemyTank(BaseTank):
def __init__(self,x,y):
super(EnemyTank, self).__init__(x,y)
# 速度
self.speed = random.randint(2,5)
# 敌方出生时的方向(随机方向)
self.direction = self.random_direaction()
# 敌方坦克的图片集
self.images = {
'U': pygame.image.load('tank_img/enemy1U.gif'),
'D': pygame.image.load('tank_img/enemy1D.gif'),
'L': pygame.image.load('tank_img/enemy1L.gif'),
'R': pygame.image.load('tank_img/enemy1R.gif'),
}
# 图片
self.image = self.images[self.direction]
# v1.7 新增记录移动步数的变量
self.step = 0
# v2.1 计数器
self.count = 0
#v1.7 重写move方法
def move(self):
if self.step < 40:
super(EnemyTank, self).move()
self.step += 1
else:
# 重新生成方向
self.random_direaction()
# 步数还原
self.step = 0
# v2.1 重写父类中的射击方法
def shot(self):
self.count += 1
if self.count == 50:
self.count = random.randint(1,10)
return Bullet(self)
def random_direaction(self):
self.direction = random.choice(['U','D','L','R'])
return self.direction
# v1.9 实现子弹类
class Bullet:
def __init__(self,tank:BaseTank):
# 速度
self.speed = 10
# 方向
self.direction = tank.direction
# 图片
self.image = pygame.image.load('tank_img/enemymissile.gif')
# 是否活着
self.live = True
# 初始位置
self.rect = self.image.get_rect()
if self.direction == 'U':
self.rect.centerx = tank.rect.centerx
self.rect.centery = tank.rect.centery - tank.rect.height//2 - self.rect.height//2
elif self.direction == 'D':
self.rect.centerx = tank.rect.centerx
self.rect.centery = tank.rect.centery + tank.rect.height // 2 + self.rect.height // 2
elif self.direction == 'L':
self.rect.centery = tank.rect.centery
self.rect.centerx = tank.rect.centerx - tank.rect.height//2 - self.rect.height//2
elif self.direction == 'R':
self.rect.centery = tank.rect.centery
self.rect.centerx = tank.rect.centerx + tank.rect.height // 2 + self.rect.height // 2
# v2.0 更新子弹的移动方法
def move(self):
if self.direction == 'U':
if self.rect.centery > self.rect.height // 2:
self.rect.centery -= self.speed
else:
self.live = False
elif self.direction == 'D':
if self.rect.centery < SCRREN_HEIGHT - self.rect.height // 2:
self.rect.centery += self.speed
else:
self.live = False
elif self.direction == 'L':
if self.rect.centerx > self.rect.height // 2:
self.rect.centerx -= self.speed
else:
self.live = False
elif self.direction == 'R':
if self.rect.centerx < SCREEN_WIDHT - self.rect.height // 2:
self.rect.centerx += self.speed
else:
self.live = False
# v2.2 新增子弹是否打中
def hit_enemy_tank(self):
for etank in Game.enemy_tank_list:
# 如果碰撞到一起
if pygame.sprite.collide_rect(self,etank):
self.live = False
etank.live = False
# v2.3 创建一个爆炸对象
boom = Boom(etank)
Game.boom_list.append(boom)
# v2.8 新增子弹打中我方坦克的逻辑
def hit_hero_tank(self):
if pygame.sprite.collide_rect(self,Game.P1):
self.live = False
#创建一个爆炸,存储到爆炸列表中
boom = Boom(Game.P1)
Game.boom_list.append(boom)
Game.P1.live = False
# v2.5 子弹碰撞墙壁的处理
def hit_wall(self):
for wall in Game.wall_list:
if pygame.sprite.collide_rect(self,wall):
self.live = False
# 将子弹加入到窗口中
def display_bullet(self):
Game.window.blit(self.image,self.rect)
# v2.4 完善墙壁类
class Wall:
def __init__(self,x,y):
self.image = pygame.image.load('tank_img/steels.gif')
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.centery = y
def display_wall(self):
Game.window.blit(self.image,self.rect)
# v2.3 完善爆炸类
class Boom:
def __init__(self,tank):
pass
self.live = True
self.images = [
pygame.image.load('tank_img/blast0.gif'),
pygame.image.load('tank_img/blast1.gif'),
pygame.image.load('tank_img/blast2.gif'),
pygame.image.load('tank_img/blast3.gif'),
pygame.image.load('tank_img/blast4.gif'),
pygame.image.load('tank_img/blast5.gif')
]
self.image_index = 0
self.image = self.images[self.image_index]
self.rect = tank.rect
self.rect.centerx -= self.rect.width//2
self.rect.centery -= self.rect.height//2
# self.rect.centerx = tank.rect.centerx
def display_boom(self):
if self.image_index < len(self.images):
self.image = self.images[self.image_index]
Game.window.blit(self.image,self.rect)
self.image_index += 1
else:
self.image_index = 0
self.live = False
class Music:
pygame.mixer.init()
@classmethod
def play(cls,filename):
# 1.加载音乐文件
pygame.mixer.music.load(filename)
# 2.播放文件
pygame.mixer.music.play()
class Game:
# 用来存储游戏窗口
window = None
P1 = None
# v1.6 存储敌方坦克的列表
enemy_tank_list = []
# v1.9 新增存储我方子弹的列表
hero_bullet = []
# v2.1 新增存储敌方子弹的列表
enemy_bullet = []
# v2.3 存储所有爆炸效果的列表
boom_list = []
# v2.4 新增存储所有墙壁的列表
wall_list = []
# v1.2 创建坦克坦克
def creat_hero_tank(self):
if not Game.P1:
Game.P1 = HeroTank(200,300)
# v2.7 播放音效
# Music.play('tank_img/start.wav')
# Music().play('tank_img/start.wav')
Music().__class__.play('tank_img/start.wav')
# v1.2 加载我方坦克
def load_hero_tank(self):
# v2.8增加我方坦克的状态判断
if Game.P1 and Game.P1.live:
Game.P1.display_tank()
# v1.4 调用坦克的移动方法
Game.P1.move()
# v2.6 调用坦克是否撞墙的方法
Game.P1.hit_wall()
else:
Game.P1 = None
# v1.6 创建敌方坦克
def creat_enemy_tanks(self):
for i in range(5):
etank = EnemyTank(100*random.randint(1,6),100)
Game.enemy_tank_list.append(etank)
# v1.6 加载敌方坦克
def load_enemy_tanks(self):
for etank in Game.enemy_tank_list:
if etank.live:
etank.display_tank()
# v1.7 调用移动方法
etank.move()
# v2.6 调用坦克是否撞墙的方法
etank.hit_wall()
# v2.1 调用敌方发射
b = etank.shot()
if isinstance(b,Bullet):
Game.enemy_bullet.append(b)
# v2.2 新增,删除挂掉的敌方坦克
else:
Game.enemy_tank_list.remove(etank)
# v2.3 加载所有爆炸效果
def load_booms(self):
for boom in Game.boom_list:
if boom.live:
boom.display_boom()
else:
Game.boom_list.remove(boom)
# v1.8 使用指定的字体绘制指定的内容,得到一个表面
# v2.9 优化方法
def get_content_surface(self,content,fontname,fontsize):
# 字体模块初始化
pygame.font.init()
font = pygame.font.SysFont(fontname,fontsize)
sf = font.render(content,True,COLOR_RED)
return sf
#v1.8 加载文字提示
def load_text_sf(self):
Game.window.blit(self.get_content_surface(f'剩余敌方坦克{len(Game.enemy_tank_list)}辆','kaiti',20),(5,5))
# v1.1新增事件处理方法
def deal_events(self):
# 获取到产生的所有事件
all_events = pygame.event.get()
for event in all_events:
if event.type == pygame.QUIT:
print('点击退出按钮,退出程序')
exit(1)
elif event.type == pygame.MOUSEMOTION:
# print('鼠标事件')
pass
elif event.type == pygame.KEYDOWN:
print('键盘事件,按键键盘按键')
print(event)
if event.key == pygame.K_SPACE:
print('发射子弹')
# v1.9调用发射方法
# v2.8 新增我方坦克状态判断处理
if Game.P1 and Game.P1.live:
b = Game.P1.shot()
# 将子弹存到列表中
Game.hero_bullet.append(b)
print(f'当前的游戏中得子弹总数量为:{len(Game.hero_bullet)}')
# v2.0 完成所有我方子弹的加载
def load_hero_bullet(self):
for bullet in Game.hero_bullet:
if bullet.live:
bullet.display_bullet()
# 调用子弹的移动方法
bullet.move()
# v2.2 调用子弹是否打中敌方坦克的方法
bullet.hit_enemy_tank()
# v2.5 我方子弹调用是否碰撞墙壁的方法
bullet.hit_wall()
else:
Game.hero_bullet.remove(bullet)
# v2.1 加载敌方子弹
def load_enemy_bullet(self):
for ebullet in Game.enemy_bullet:
if ebullet.live:
ebullet.display_bullet()
ebullet.move()
# v2.5 调用子弹是否打中墙壁的方法
ebullet.hit_wall()
# v2.8 调用是否打中我方坦克
if Game.P1 and Game.P1.live:
ebullet.hit_hero_tank()
# v2.4 创建墙壁
def creat_walls(self):
for i in range(1,6):
wall = Wall(150*i,400)
Game.wall_list.append(wall)
#v2.4 负责加载墙壁
def load_walls(self):
for wall in Game.wall_list:
wall.display_wall()
def start_game(self):
# 加载游戏窗口
pygame.display.init()
Game.window = pygame.display.set_mode((SCREEN_WIDHT,SCRREN_HEIGHT))
pygame.display.set_caption('tank v2.4')
#v1.2 调用创建我方坦克
self.creat_hero_tank()
# v1.6 调用创建敌方坦克
self.creat_enemy_tanks()
# v2.4 调用创建墙壁的方法
self.creat_walls()
while True:
Game.window.fill(COLOR_GREEN)
# v2.4 调用加载所有的墙壁方法
self.load_walls()
# v1.2 调用加载我方坦克
self.load_hero_tank()
# v1.6 调用加载敌方坦克
self.load_enemy_tanks()
# v2.0 调用加载我方子弹的方法
self.load_hero_bullet()
# v2.1 调用加载敌方子弹的方法
self.load_enemy_bullet()
# v2.3 调用加载所有的爆炸效果的方法
self.load_booms()
# v1.1 调用事件处理方法
self.deal_events()
# v1.7 调用加载文字提示的方法
self.load_text_sf()
# v2.9 调用游戏结束方法
self.game_over()
# 刷新窗口
pygame.display.update()
#v1.5 增加休眠处理
pygame.time.wait(12)
# v2.9 游戏结束设置
def game_over(self):
if not Game.P1:
over_sf = self.get_content_surface('Game Over','kaiti',40)
Game.window.blit(over_sf, (SCREEN_WIDHT // 2 - 50, SCRREN_HEIGHT // 2))
game = Game()
game.start_game()
上一篇: Unix 脚本编程基础
下一篇: Java实现按中文首字母排序的具体实例