python 初阶
'''
v1.16 实现音效类
'''
import pygame,time,random
SCREEN_WIDTH = 900
SCREEN_HEIGHT = 550
VERSION = 'V1.16'
# v1.07新增 记录敌方坦克的数量
ENEMY_TANK_COUNT = 5
# 主逻辑类
class MainGame():
# 游戏主窗口
window = None
# 我方坦克(唯一性)设置成类属性
tank1 = None
# v1.07新增存储敌方坦克的列表
enemy_tanklist = []
# v1.09 新增存储我方子弹的列表
mybullet_list = []
# v1.11 新增存储敌方子弹的列表
enemybullet_list = []
# v1.13 新增 存储爆炸效果的列表
explode_list = []
# v.14 新增 创建存储墙壁的列表
wall_list = []
def startGame(self):
# 调用窗口初始化方法
pygame.display.init()
# 在窗口左上角设置游戏标题
pygame.display.set_caption('坦克大战'+VERSION)
# 创建一个窗口屏幕显示表面
MainGame.window = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
# 调用创建我方坦克的方法
self.createMytank()
# 调用创建敌方坦克的方法
self.createEnemytank()
# v1.14 新增 调用创建墙壁的方法
self.createWalls()
while True:
# 填充窗口背景色
MainGame.window.fill((100,100,200))
# 将获取的事件类型在填充完窗口背景色后时刻处于循环中
self.getEvents()
# v1.14 新增 调用展示墙壁的方法
self.showWalls()
# 展示我方坦克
self.showMytank()
# 调用展示敌方坦克的方法
self.showEnemyTank()
# v1.09 新增调用展示我方子弹的方法
self.showMyBullet()
# v1.11 新增调用展示敌方子弹的方法
self.showEnemyBullet()
# v1.13 调用展示爆炸效果的方法
self.showExplode()
# 更新
pygame.display.update()
# v1.06 新增程序休眠,优化坦克的移动速度
time.sleep(0.025)
# 获取所有事件处理的方法
def getEvents(self):
# 获取队列中的所有事件,遍历事件,对type为QUIT和KEYDOWN的两种事件类型进行处理
eventList = pygame.event.get()
# 遍历所有事件
for e in eventList:
# 当事件类型是QUIT时,退出游戏
if e.type == pygame.QUIT:
self.showMytank()
# 退出游戏
self.gameOver()
# 当事件类型是KEYDOWN时,进行细化处理
elif e.type == pygame.KEYDOWN:
# 按下键盘上的向上按键时的处理
if e.key == pygame.K_UP:
print('向上移动')
MainGame.tank1.direction = 'U'
# v1.06修改坦克的移动状态
MainGame.tank1.stop = False
# 按下键盘上的向下按键时的处理
elif e.key == pygame.K_DOWN:
print('向下移动')
MainGame.tank1.direction = 'D'
# v1.06修改坦克的移动状态
MainGame.tank1.stop = False
# 按下键盘上的向左按键时的处理
elif e.key == pygame.K_LEFT:
print('向左移动')
MainGame.tank1.direction = 'L'
MainGame.tank1.stop = False
# 按下键盘上的向右按键时的处理
elif e.key == pygame.K_RIGHT:
print('向右移动')
MainGame.tank1.direction = 'R'
MainGame.tank1.stop = False
# 按下键盘上的空格按键时的处理
elif e.key == pygame.K_SPACE:
print('biubiu~')
# v1.09 新增调用发射方法,并将子弹装进列表
b = MainGame.tank1.shoot()
# v1.11 新增我方子弹数量控制
if len(MainGame.mybullet_list) < 3:
MainGame.mybullet_list.append(b)
print('子弹的数量%d'%len(MainGame.mybullet_list))
#v1.06新增按键松开的事件处理
elif e.type == pygame.KEYUP:
if e.key == pygame.K_UP or e.key == pygame.K_DOWN or\
e.key == pygame.K_LEFT or e.key == pygame.K_RIGHT:
# 将坦克的移动状态改为停止
MainGame.tank1.stop = True
# 创建我方坦克
def createMytank(self):
# 创建我方坦克并赋予其位置属性坐标
MainGame.tank1 = MyTank(SCREEN_WIDTH/2,SCREEN_HEIGHT/3*2)
# v1.15 新增 创建我方坦克时,播放背景音效
audio = Audio('img/start.wav')
audio.playAudio()
#展示我方坦克
def showMytank(self):
MainGame.tank1.displayTank()
# v1.08 新增将 我方坦克移动代码 移动位置
if not MainGame.tank1.stop:
# 我方坦克移动
MainGame.tank1.move()
# v1.15 调用是否撞墙的方法
MainGame.tank1.hitWall()
# v1.07创建敌方坦克
def createEnemytank(self):
# 循环创建敌方坦克
for i in range(ENEMY_TANK_COUNT):
num = random.randint(1,7)
# v1.08新增 随机速度
randomspeed = random.randint(3,10)
# 创建第一个敌方坦克,出现位置为y=150,x随机出现在(100-700),坦克移动的随机速度是randomspeed
# v1.08新增调用修改后的init方法
etank = EnemyTank(100*num,150,randomspeed)
# 创建敌方坦克列表,存入所有的敌方坦克
MainGame.enemy_tanklist.append(etank)
# v1.07展示敌方坦克
def showEnemyTank(self):
# 遍历展示敌方坦克
for etank in MainGame.enemy_tanklist:
#v1.12 新增 根据敌方坦克状态,进行相关业务处理
if etank.live:
etank.displayTank()
# v1.08 新增敌方坦克的移动
etank.move()
# v1.11 新增敌方坦克射击,并把敌方子弹加入列表
# v.15 调用是否撞墙的方法
etank.hitWall()
b = etank.shoot()
# if b != None:或 if b: 即在敌方坦克重写射击方法中,如果随机概率是5%,把敌方子弹添加到敌方子弹列表中
if b != None:
MainGame.enemybullet_list.append(b)
else:
MainGame.enemy_tanklist.remove(etank)
# v1.09 展示我方子弹的方法
def showMyBullet(self):
for b in MainGame.mybullet_list:
# 如果子弹活着,展示并移动子弹
if b.live:
b.displayBullet()
# v1.10 新增调用子弹的移动方法
b.move()
#如果子弹死亡,移除子弹,给子弹列表腾空间,保证打到墙上的子弹消失
#v1.12 新增调用是否打中敌方坦克
b.hitEnemyTank()
# v1.14 新增 调用是否打中墙壁的方法
b.hitWall()
else:
MainGame.mybullet_list.remove(b)
# v1.11 新增展示敌方子弹方法
def showEnemyBullet(self):
for b in MainGame.enemybullet_list:
if b.live:
b.displayBullet()
b.move()
# v1.14 新增 调用是否打中墙壁的方法
b.hitWall()
else:
MainGame.enemybullet_list.remove(b)
# v1.13 展示爆炸效果
def showExplode(self):
for e in MainGame.explode_list:
if e.live:
e.displayExplode()
else:
MainGame.explode_list.remove(e)
# v1.14 创建墙壁的方法
def createWalls(self):
for i in range(1,7):
w = Wall(130*i,300)
MainGame.wall_list.append(w)
# v1.14 展示墙壁的方法
def showWalls(self):
for wall in MainGame.wall_list:
wall.displayWall()
def gameOver(self):
exit()
# 基本坦克类
# v1.12 新增基本坦克类调用精灵类
class BaseTank( pygame.sprite.Sprite):
# 基本坦克属性 位置 方向 速度 图片
def __init__(self):
# v1.12 调用精灵类的初始化
pygame.sprite.Sprite.__init__(self)
self.direction = None
self.rect = None
self.images = None
self.image = None
self.speed = 0
#v1.06新增属性,用来控制坦克是否移动
self.stop = True
# v1.12 新增基本属性,判断坦克是否还活着
self.live = True
# v1.15 新增 两个基本属性记录坦克移动之前的坐标
self.oldx = None
self.oldy = None
# v1.08 优化移动
def move(self):
# v1.15 移动之前先记录下坐标
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 < SCREEN_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_WIDTH - self.rect.height/2:
self.rect.centerx += self.speed
# v1.15 新增 封装还原坐标的方法
def stay(self):
self.rect.centerx = self.oldx
self.rect.centery = self.oldy
# v1.15 新增 坦克撞墙的方法
def hitWall(self):
for wall in MainGame.wall_list:
if pygame.sprite.collide_rect(self,wall):
self.stay()
# v1.09 新增射击方法
def shoot(self):
bullet = Bullet(self)
return bullet
# 我方坦克类
class MyTank(BaseTank):
def __init__(self,x,y):
#引用父类属性
super(MyTank, self).__init__()
# 设置具体的图片集
self.images = {
'U':pygame.image.load('img/p1tankU.gif'),
'D':pygame.image.load('img/p1tankD.gif'),
'L':pygame.image.load('img/p1tankL.gif'),
'R':pygame.image.load('img/p1tankR.gif')
}
# 我方坦克的初始方向
self.direction = 'U'
# 设置坦克的图片(self.image 返回的是一个surface)
self.image = self.images[self.direction]
# 先基于图像获取坦克的位置和大小
self.rect = self.image.get_rect()
# 修改坦克坐标,改成自定义位置
self.rect.centerx = x
self.rect.centery = y
# 设置坦克速度
self.speed = 5
#将我方坦克加入到窗口中
def displayTank(self):
self.image = self.images[self.direction]
# 把坦克的图像(即表面)和位置放到另一个图像或表面窗口
MainGame.window.blit(self.image,self.rect)
# 敌方坦克类
class EnemyTank(BaseTank):
# v1.08新增随机速度参数
def __init__(self,x,y,randSpeed):
# v1.08新增调用父类的初始化
super(EnemyTank, self).__init__()
# 设置具体的图片集
self.images = {
'U':pygame.image.load('img/enemy1U.gif'),
'D':pygame.image.load('img/enemy1D.gif'),
'L':pygame.image.load('img/enemy1L.gif'),
'R':pygame.image.load('img/enemy1R.gif')
}
# v1.07敌方坦克的初始方向为随机方向
self.direction = self.randomDirection()
# 设置坦克的图片(self.image 返回的是一个surface)
self.image = self.images[self.direction]
# 先基于图像获取坦克的位置和大小
self.rect = self.image.get_rect()
# 修改坦克坐标,改成自定义位置
self.rect.centerx = x
self.rect.centery = y
# v1.08新增速度为参数传进来的速度
self.speed = randSpeed
# v1.08新增记录敌方坦克移动的步数
self.step = 25
# v1.07生成敌方坦克的随机方向
def randomDirection(self):
num = random.randint(1,4)
if num == 1:
return 'U'
elif num == 2:
return 'D'
elif num == 3:
return 'L'
elif num == 4:
return 'R'
# v1.08新增重写父类中的移动move方法,方法中新增随机方向的处理
def move(self):
if self.step == 0:
# 变换方向
self.direction = self.randomDirection()
# 将步数重新归置成25
self.step = 25
else:
super(EnemyTank, self).move()
self.step -= 1
# v1.11 新增重写父类的射击方法
def shoot(self):
num = random.randint(1,100)
if num <= 5:
return super(EnemyTank, self).shoot()
# 将敌方坦克加入到窗口中
def displayTank(self):
self.image = self.images[self.direction]
# 把坦克的图像(即表面)和位置放到另一个图像或表面窗口
MainGame.window.blit(self.image, self.rect)
#v1.09 新增实现子弹类
# v1.12 新增子弹类继承于精灵类
class Bullet(pygame.sprite.Sprite):
def __init__(self,tank):
# v1.12 新增调用精灵类的初始化
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('img/enemymissile.gif')
# 让子弹的方向和坦克的方向保持一致
self.direction = tank.direction
# 基于图像获取子弹的位置和区域大小 子弹的区域默认为左上角
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.centerx = tank.rect.centerx - tank.rect.height/2 - self.rect.height/2
self.rect.centery = tank.rect.centery
elif self.direction == 'R':
self.rect.centerx = tank.rect.centerx + tank.rect.height / 2 + self.rect.height / 2
self.rect.centery = tank.rect.centery
#v1.10 新增子弹移动速度
self.speed = 11
# v1.10 新增子弹的存活状态,用来记录子弹是否活着
self.live = True
# v1.12 新增 子弹是否碰撞到敌方坦克 方法
def hitEnemyTank(self):
for etank in MainGame.enemy_tanklist:
# 调用pygame.sprite.collide_rect(left,right),判断子弹与敌方坦克的碰撞
if pygame.sprite.collide_rect(self,etank):
# v1.13 产生爆炸效果,并把爆炸效果装进爆炸效果列表
explode = Explode(etank.rect)
MainGame.explode_list.append(explode)
# 修改子弹的状态
self.live = False
# 修改敌方坦克的状态
etank.live = False
# v1.14 新增 子弹碰撞墙壁的方法
def hitWall(self):
for wall in MainGame.wall_list:
if pygame.sprite.collide_rect(self,wall):
self.live = False
# v1.10 新增子弹的移动方法
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 < SCREEN_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_WIDTH - self.rect.height / 2:
self.rect.centerx += self.speed
else:
self.live = False
#将子弹的图像展示到游戏主窗口
def displayBullet(self):
MainGame.window.blit(self.image,self.rect)
#v1.13 新增 完善爆炸类
class Explode():
def __init__(self,rect):
# 指定一个区域进行爆炸效果的释放
self.rect = rect
self.images = [
pygame.image.load('img/blast0.gif'),
pygame.image.load('img/blast1.gif'),
pygame.image.load('img/blast2.gif'),
pygame.image.load('img/blast3.gif'),
pygame.image.load('img/blast4.gif'),
pygame.image.load('img/blast5.gif')
]
# 记录图片的索引值
self.step = 0
self.image = self.images[self.step]
# 用来判断爆炸效果是否活着的属性
self.live = True
def displayExplode(self):
if self.step < len(self.images):
MainGame.window.blit(self.image,self.rect)
self.image = self.images[self.step]
self.step += 1
else:
self.step = 0
self.live = False
#v1.14 完善墙壁类
class Wall(pygame.sprite.Sprite):
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('img/steels.gif')
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.centery = y
def displayWall(self):
MainGame.window.blit(self.image,self.rect)
#v1.16 完善音效类
class Audio():
def __init__(self,music):
# 对混合模块初始化
pygame.mixer.init()
# 载入音乐文件
pygame.mixer.music.load(music)
def playAudio(self):
# 播放音乐文件
pygame.mixer.music.play(5)
#创建一个主逻辑类的对象
game = MainGame()
# 开始游戏
game.startGame()