# 坦克大战游戏,pygame游戏引擎的安装
# 流程:(1)确定程序所需要的类;(2)框架搭建;(3)加载主窗口(参考pygame的网址)--在主类中实现
"""
(1)程序的所有类:
1.主类:
开始游戏
结束游戏
2.坦克类(我方坦克、敌方坦克--继承):
显示坦克的方法
射击
移动类
3.子弹类
显示子弹的方法
移动
4.墙体类
属性:是否能够通过
5.爆炸效果类
展示爆炸效果
6.音效类
播放音乐
"""
#导入pygame模块
import pygame
#导入时间模块,可用于调整循环的快慢
#导入随机数生成模块
import time,random
width = 700
height = 600
bg=pygame.Color(0,0,0) #RGB(0,0,0)颜色为黑色,赋予bg
#另一种写法 bg=pygame.Color("black")
tc=pygame.Color("red")
#主类
class MainGame():
#类对象
window=None #窗口对象
mt = None #坦克在多个地方需要调用,所以定义为类变量
ememylist=[] #创建存储敌方坦克的列表(多个)
ememynum=5 #敌方坦克数量
Bullet_list=[] #存储我方子弹列表
Bullet_enemylist=[] #存储敌方子弹列表
# 初始化方法
def __init__(self):
pass
#开始游戏的方法
def start(self):
#加载主窗口
pygame.display.init() # 窗口初始化
# set_mode((width,height),a,色深)--a(不用什么特性可指定0),set_mode()返回一个surface对象,表示窗口
MainGame.window=pygame.display.set_mode([width,height]) #设置窗口大小,通过列表导入
pygame.display.set_caption("Tank_fight!") #设置窗口标题
#初始化我方坦克--不需要一直创建,初始化时创建一次即可
MainGame.mt=Tank(350,200)
#创建初始化敌方坦克的方法,并添加到列表中
self.createt()
while True:
#让坦克运动速度减慢
time.sleep(0.02)
# pygame.surface.fill()--代表对返回surface对象填充颜色
MainGame.window.fill(bg)
# 保持窗口一直处于刷新显示的状态,才能反映窗口内部的变化,背景不断刷新
# 添加事件
self.getevent()
# 绘制文字,将图像绘制到另一个blit("文本内容",相对于左上角坐标(0,0)的文本放置坐标位置)
#getTest('文本内容%d'%整数)
MainGame.window.blit(self.getTest('敌方坦克剩余数量%d'%len(MainGame.ememylist)),(10,20))
#调用显示坦克的方法--调用Tank中的tank_display()
MainGame.mt.tank_display()
#调用坦克移动方法--坦克按键后因为循环执行一直处于移动状态
# 展示敌方坦克
self.displayenemy()
#如果坦克开关开启,开始移动
if not MainGame.mt.stop: #初始设置为True,一开始进入循环就会发生移动,所以应先设置移动的开关
MainGame.mt.move() #如果为False则进入移动函数move()
# 将子弹展示到窗口中
self.blitbullet()
#调用敌方子弹列表的方法
self.enemybullet()
#刷新窗口,保持不消失
pygame.display.update()
def createt(self):
#循环生成敌方坦克
for i in range(MainGame.ememynum):
left=random.randint(0,600)
top=random.randint(0,500)
speed = random.randint(1, 4)
enemy=Enemytank(left,top,speed) #随机生成一个敌方坦克
MainGame.ememylist.append(enemy) #将敌方坦克加入坦克生成列表
def displayenemy(self): #通过循环实现敌方坦克列表的坦克显示
for enemy in MainGame.ememylist:
enemy.tank_display()
#敌方坦克移动--由于到边界会停止,所以考虑修改敌方坦克方向
enemy.ranmove()
#调用敌方坦克的射击
eb=enemy.shot() #敌方坦克调用shot(),可能为空
# 判断敌方子弹是否是None,如果不为None则添加到敌方子弹列表中
if eb:
# 将敌方子弹存储到敌方子弹列表中
MainGame.Bullet_enemylist.append(eb)
# 遍历子弹列表,将敌方子弹加入窗口
def enemybullet(self):
for eb in MainGame.Bullet_enemylist:
if eb.live: #判断敌方列表是否存活
eb.Bullet_display()
# 让子弹移动
eb.move()
else:
MainGame.Bullet_enemylist.remove(eb)
#遍历子弹列表,将我方子弹加入窗口
def blitbullet(self):
for Bullet in MainGame.Bullet_list:
if Bullet.live:
Bullet.Bullet_display()
# 让子弹移动
Bullet.move()
else:
MainGame.Bullet_list.remove(Bullet)
#结束游戏的方法
def end(self):
print("游戏结束!")
quit() #退出窗口
#获取事件--关闭退出、按键是在整个程序都要实现的写在主类中,pygame.event.get()返回所有事件
def getevent(self):
eventlist=pygame.event.get()
for event in eventlist: #对eventlist遍历,如果满足一下条件,执行相关命令
if event.type==pygame.QUIT: #事件类型为退出--pygame.QUIT
self.end()
if event.type==pygame.KEYDOWN: #事件类型为按键--pygame.KEYDOWN
if event.key==pygame.K_LEFT: #事件按键event.key,对应左键K_LEFT:
MainGame.mt.direction = 'L' #调用Tank()的direction属性
#MainGame.mt.move()
#修改坦克的开关状态
MainGame.mt.stop=False
print("向左移动")
elif event.key==pygame.K_RIGHT:
MainGame.mt.direction = 'R'
#MainGame.mt.move()
#修改坦克的开关状态
MainGame.mt.stop=False
print("向右移动")
elif event.key == pygame.K_UP:
MainGame.mt.direction = 'U'
#MainGame.mt.move()
#修改坦克的开关状态
MainGame.mt.stop=False
print("向上移动")
elif event.key == pygame.K_DOWN:
MainGame.mt.direction = 'D'
#MainGame.mt.move()
#修改坦克的开关状态
MainGame.mt.stop=False
print("向下移动")
elif event.key == pygame.K_SPACE:
print("发射子弹")
#产生一颗子弹,将子弹加入子弹列表
#控制发射子弹数量--即控制子弹加入子弹列表的列表数
if len (MainGame.Bullet_list)<3: #最多发射3个
m=Bullet(MainGame.mt)
MainGame.Bullet_list.append(m)
else:
print("子弹已用完!")
print("当前一次性发射子弹数量为%d"%len(MainGame.Bullet_list))
if event.type==pygame.KEYUP: #键盘松开
#但实际上松开方向键的时候,才会停止,对于其余键不会有这个影响会照常前进执行
if event.key == pygame.K_LEFT\
or event.key ==pygame.K_RIGHT \
or event.key ==pygame.K_UP \
or event.key ==pygame.K_DOWN:
MainGame.mt.stop=True
#左上角文字绘制,输出坦克量,作为文本内容text为变量反映坦克量的变化
def getTest(self,text):
#初始化字体模块
pygame.font.init()
#获取所有字体pygame.font.get_fonts()--可以从中任选一个
#print(pygame.font.get_fonts())
#获取字体对象设置字体与大小pygame.font.SysFont('字体',大小)
font=pygame.font.SysFont('kaiti',18)
#绘制文字信息 font.render(文本信息,抗锯齿True or False,字体颜色)返回surface
textSurface=font.render(text,True,tc)
return textSurface #返回绘制结果
# 要将文本添加到窗口,且一直显示变化,需要保持循环,所以在循环内部写入
#坦克类
class Tank(): #存在direction属性
#添加距离左边,距离上边
def __init__(self,left,top):
#保存加载图片 self.image.load("文件路径")返回surface
self.images={
'U':pygame.image.load('imgs/p1tankU.gif'),
'R': pygame.image.load('imgs/p1tankR.gif'),
'L': pygame.image.load('imgs/p1tankL.gif'),
'D': pygame.image.load('imgs/p1tankD.gif')
}
#方向
self.direction='U' #默认方向朝上
#根据当前图片方向获取图片
self.image=self.images[self.direction]
#根据图片获取区域--默认左上角,通过离左边、上边的距离确定区域位置
#self.rect--图片区域;self.rect.left--图片左上角离左侧的距离;self.rect.top--图片左上角离上侧的距离
self.rect=self.image.get_rect()
self.rect.left=left
self.rect.top =top
#坦克移动的速度--即坐标位置增量的代销
self.speed=5
#坦克移动停止开关(属性)
self.stop=True
#坦克展示的方法
def tank_display(self):
#获取展示的对象
self.image=self.images[self.direction]
#调用blit方法展示
MainGame.window.blit(self.image,self.rect)
#射击方法
def shot(self):
#返回发射子弹
return Bullet(self)
#移动方法
def move(self):
#判断坦克方向并进行移动
if self.direction=='U':
if self.rect.top>0:
self.rect.top -= self.speed
# self.rect.height--图片的高度;self.rect.width--图片的宽度
elif self.direction=='D':
if self.rect.top+self.rect.height < height:
self.rect.top += self.speed
elif self.direction=='L':
if self.rect.left > 0:
self.rect.left -= self.speed
elif self.direction=='R':
if self.rect.left+self.rect.width < width:
self.rect.left += self.speed
#我方坦克
#坦克运动四个方向有四张图
class Mytank(Tank):
def __init__(self):
pass
#敌方坦克
class Enemytank(Tank):
def __init__(self,left,top,speed):
#加载地方坦克图片
self.images={
'U':pygame.image.load('imgs/enemy1U.gif'),
'R': pygame.image.load('imgs/enemy1R.gif'),
'L': pygame.image.load('imgs/enemy1L.gif'),
'D': pygame.image.load('imgs/enemy1D.gif')
}
#随机生成敌方他坦克方向
self.direction=self.randdirection()
#根据方向获取图片
self.image = self.images[self.direction]
#获取区域
self.rect=self.image.get_rect()
#对left和top赋值,不赋值则默认左上角
self.rect.left=left
self.rect.top=top
#速度
self.speed=speed
#移动开关键
self.stopf=True #默认停止
#设定初次移动步数参数
self.step=40
def randdirection(self):
num=random.randint(1,4) #随机生成1-4范围的数
if num==1:
return 'U'
if num==2:
return 'D'
if num==3:
return 'L'
if num==4:
return 'R'
# 敌方坦克随机移动的方法:
def ranmove(self):
if self.step <= 0: # 满足条件后修改方向
self.direction = self.randdirection()
#让步数复位,否则将会一直执行改变方向的命令
self.step=60
else:
self.move()
self.step-=1
#子弹类
class Bullet():
def __init__(self,tank):
#加载子弹图片,由于坦克方向与子弹发生位置相关,所以需要再传一个变量tank
self.image=pygame.image.load('imgs/enemymissile.gif')
self.direction=tank.direction
#获取区域
self.rect=self.image.get_rect()
#子弹发射位置与坦克朝向相关
if self.direction=='U':
self.rect.left= tank.rect.left+tank.rect.width/2-self.rect.width/2
self.rect.top = tank.rect.top-self.rect.height
if self.direction=='D':
self.rect.left= tank.rect.left+tank.rect.width/2-self.rect.width/2
self.rect.top = tank.rect.top+tank.rect.height
if self.direction=='L':
self.rect.left= tank.rect.left-self.rect.width/2
self.rect.top = tank.rect.top+tank.rect.height/2-self.rect.width/2
if self.direction=='R':
self.rect.left= tank.rect.left+tank.rect.width+self.rect.width/2
self.rect.top = tank.rect.top+tank.rect.height/2-self.rect.width/2
self.speed=6
self.live = True
#记录子弹是否存在(碰到墙壁视作消失)
#子弹展示的方法
def Bullet_display(self):
#将图片加载到窗口
MainGame.window.blit(self.image,self.rect)
#子弹移动的方法
def move(self):
#子弹移动,左右侧left大小改变,上下侧top大小改变
if self.direction=='U':
if self.rect.top>0: #未碰到墙壁
#以移动速度于东,上部距离减小
self.rect.top-=self.speed
else: #碰到墙壁
self.live = False
elif self.direction=='D':
if self.rect.top <height-self.rect.height:
# 以移动速度于东,上部距离减小
self.rect.top += self.speed
else:
self.live = False
elif self.direction == 'L':
if self.rect.left>0:
# 以移动速度于东,上部距离减小
self.rect.left -= self.speed
else:
self.live = False
elif self.direction == 'R':
if self.rect.left <width-self.rect.width:
# 以移动速度于东,上部距离减小
self.rect.left += self.speed
else:
self.live = False
#由于父类shot()的频率太高,所以在子类重写shot(),降低射击频率
def shot(self):
num=random.randint(1,100) #在一定范围随机产生一个数
if num==1: #在这些范围内只有一种可能满足进入Bullet(self)的方法
return Bullet(self) #不为1,则会返回空
#墙壁类
class Wall():
def __init__(self,across):
pass
#展示墙壁类的方法
def Wall_display(self):
pass
#爆炸类
class Explode():
def __init__(self):
pass
# 展示爆炸效果的方法
def Explode_display(self):
pass
#音效类
class Music():
def __init__(self):
pass
#播放音乐的方法
def diaplay(self):
pass
if __name__=='__main__':
MainGame().start()
老师,请问我这个代码为什么在Bullet类中重写的shot()函数中概率改变对产生结果并没有影响,好像这个传的仍旧是一个固定的概率,这个是为什么呢?