版权声明:本文为博主原创文章,未经博主允许不得转载。
# coding:utf-8
import pygame, sys,time
from random import randint
from pygame.locals import *
"""坦克大战的主窗口"""
class TankMain(object):
width = 600
height= 500
my_tank_missile_list = []
my_tank = None
enemy_list = []
# 开始游戏的方法
def startGame(self):
pygame.init() #模块初始化:加载系统的资源
# 创建一个屏幕,屏幕的大小((宽,高),窗口的特性[0,RESIZEBLE,FULLSCREEM],颜色位数)
screem = pygame.display.set_mode((TankMain.width,TankMain.height), 0, 32) # 0:窗口不可变
# 给窗口设置一个标题
pygame.display.set_caption("坦克大战")
# my_tank = Tank(screem,275,400) 创建一个我方坦克,坦克显示在屏幕的中下部位置
TankMain.my_tank = My_Tank(screem)
for i in range(1,6):
TankMain.enemy_list.append(Enemy_Tank(screem))
while True:
# color RGB(0,0,0),(255,255,255)
# 设置屏幕的背景色为黑色
screem.fill((0, 0, 0))
# 显示左上角的文字
for i, text in enumerate(self.write_test(), 0):
screem.blit(text, (0, 5+(15*i)))
# screem.blit(self.write_test(),(0,5))
# 获取事件:根据获取的事件处理
self.get_event(TankMain.my_tank)
TankMain.my_tank.display() # 在屏幕上显示我方坦克
TankMain.my_tank.move() # 在屏幕行移动我方坦克
# 显示和随机移动 所有的敌方敌方坦克
for enemy in TankMain.enemy_list:
enemy.display()
enemy.random_move()
# 显示所有的我方炮弹
for m in TankMain.my_tank_missile_list:
if m.live:
m.display()
m.move()
else:
TankMain.my_tank_missile_list.remove(m)
# 显示重置
time.sleep(0.05) # 多少秒画一帧 —— 每次休眠0.05秒
pygame.display.update()
# 获取所有的事件:敲击键盘,鼠标点击
def get_event(self,my_tank):
for event in pygame.event.get():
if event.type == QUIT:
self.stopGame() # 程序退出
if event.type == KEYDOWN: # 键盘事件
if event.key == K_LEFT or event.key == K_a:
my_tank.direction ="L" # 仅仅改变坦克的方向:左
my_tank.stop = False
# my_tank.move()
if event.key == K_RIGHT or event.key == K_d:
my_tank.direction = "R"
my_tank.stop = False
# my_tank.move()
if event.key == K_UP or event.key == K_w:
my_tank.direction = "U"
my_tank.stop = False
# my_tank.move()
if event.key == K_DOWN or event.key == K_s:
my_tank.direction = "D"
my_tank.stop = False
# my_tank.move()
if event.key == K_ESCAPE: # 敲击键盘的Esc键
self.stopGame() # 程序退出
if event.key == K_SPACE: # 敲击键盘的空格键,发射炮弹
TankMain.my_tank_missile_list.append(my_tank.fire())
if event.type == KEYUP:
if event.key == K_LEFT or event.key == K_RIGHT or event.key == K_UP or event.key == K_DOWN:
my_tank.stop = True
if event.type == MOUSEBUTTONUP: # 鼠标事件
pass
# 关闭游戏
def stopGame(self):
sys.exit()
# 在屏幕的左上角显示文字内容
def write_test(self):
font = pygame.font.SysFont("simsunnsimsun",20) # 定义一个字体
text_sf1 = font.render("敌方坦克数量为:%d"%len(TankMain.enemy_list),True,(255,0,0)) # 根据字体创建一个文字的图像
text_sf2 = font.render("我方坦克炮弹的数量为:%d"%len(TankMain.my_tank_missile_list), True, (255, 0, 0))
return text_sf1, text_sf2
# 设计游戏窗口的标题
def set_title(self):
pass
# 坦克大战游戏中所有对象的父类
class BaseItem(pygame.sprite.Sprite):
def __init__(self,screem):
pygame.sprite.Sprite.__init__(self)
# 所有对象共享的属性
self.screem = screem
# 在游戏屏幕中显示当前游戏对象
def display(self):
if self.live:
self.image = self.images[self.direction] # 把图象赋值 设置坦克的图像
self.screem.blit(self.image,self.rect) # 画图像
# 坦克的公共父类
class Tank(BaseItem):
# 定义类属性,所有坦克对象高和宽都是一样的(类属性:所有对象可以共享)
width = 60
height = 60
def __init__(self,screem,left,top): # 表示坐标的意思 left:x top:y
super().__init__(screem)
#self.screem = screem # 坦克在移动或显示过程中需要用到当前游戏的屏幕
self.direction = "D" # 坦克的方向,默认方向向下(上下左右)
self.speed = 5 # 坦克移动的(默认)速度
self.stop = False # 坦克移动,停止的初始值
self.images = {} # 坦克的所有图片(key:方向 value:图片 surface)
self.images["L"] = pygame.image.load("images/enemy1L.gif")
self.images["R"] = pygame.image.load("images/enemy1R.gif")
self.images["U"] = pygame.image.load("images/enemy1U.gif")
self.images["D"] = pygame.image.load("images/enemy1D.gif")
self.image = self.images[self.direction] # 坦克的图片由方向决定 设置坦克的图像
self.rect = self.image.get_rect() #坦克的边界
self.rect.left =left
self.rect.top = top
self.live = True # 决定坦克是否消灭了
# 把坦克对应的图片显示在游戏窗口上
# def display(self):
# if self.live:
# self.image = self.images[self.direction] # 把图象赋值 设置坦克的图像
# self.screem.blit(self.image,self.rect) # 画图像
def move(self):
if not self.stop: # 如果坦克不是停止状态:
if self.direction =="L": # 如果坦克方向向左,坦克的left减小就OK了
if self.rect.left > 0: # 判断坦克是否在屏幕左边的边界上
self.rect.left -= self.speed
else:
self.rect.left = 0
elif self.direction == "R": # 如果坦克方向向右,坦克的right增加就OK了
if self.rect.right < TankMain.width: #判断坦克是否在屏幕右边的边界上:
self.rect.right += self.speed
else:
self.rect.right = TankMain.width #假如坦克已经在屏幕的最右边,就不能再往右移动了
elif self.direction == "U": # 如果坦克方向向上,坦克的top减小就OK了
if self.rect.top > 0:
self.rect.top -= self.speed
else:
self.rect.top =0
elif self.direction == "D": # 如果坦克方向向下,坦克的bottom增加就OK了
if self.rect.bottom < TankMain.height:
self.rect.bottom += self.speed
else:
self.rect.bottom = TankMain.height
def fire(self):
# 生成一个子弹
m = Missile(self.screem, self)
return m
# 我方坦克的类
class My_Tank(Tank):
def __init__(self,screem):
super().__init__(screem,275,400) # 创建一个我方坦克,坦克显示在屏幕的中下部位置
self.stop = True # 按住某一个方向键不动, 坦克就一直沿着这个方向走;松开键的时候,坦克就停止移动 —— 我方坦克独有的属性 (默认:开始的时候是停止的)
# 敌方坦克的类
class Enemy_Tank(Tank):
def __init__(self,screem):
super().__init__(screem,randint(1,5)*100 ,200) # 敌方坦克出现的位置是随机的:假设y:100 x : 随机
self.speed = 3
self.step = 8 # 坦克按照某个方向连续移动的步数
self.get_random_direction()
def get_random_direction(self): # 初始的时候随机给个方向
r = randint(0, 4) # 得到一个坦克移动方向和停止的随机数
if r == 4:
self.stop = True # 敌方坦克开始的时候(停 走 )随机的
elif r == 1:
self.direction = "L"
self.stop = False
elif r == 2:
self.direction = "R"
self.stop = False
elif r == 3:
self.direction = "U"
self.stop = False
elif r == 0:
self.direction = "D"
self.stop = False
#敌方坦克随机移动的方法:按照一个确定的随机方向,连续移动6步,然后才能再次改变方向
def random_move(self):
if self.live:
#print(self.step) 测试
if self.step == 0: #坦克的6步已经移动完了,需要从新确定方向
self.get_random_direction() # 随机给个方向
self.step = 6
else:
self.move()
self.step -= 1
class Missile(BaseItem):
width = 15
height = 15
def __init__(self,screem,tank):
super().__init__(screem)
self.tank = tank
self.direction = tank.direction # 炮弹的方向由所发射的坦克方向决定
self.speed = 12 # 炮弹移动的(默认)速度
self.stop = False # 坦克移动,停止的初始值
self.images = {} # 炮弹的所有图片(key:方向 value:图片 surface)
self.images["L"] = pygame.image.load("images/enemymissile.gif")
self.images["R"] = pygame.image.load("images/enemymissile.gif")
self.images["U"] = pygame.image.load("images/enemymissile.gif")
self.images["D"] = pygame.image.load("images/enemymissile.gif")
self.image = self.images[self.direction] # 坦克的图片由方向决定 设置坦克的图像
self.rect = self.image.get_rect() # 炮弹的边界
self.rect.left = tank.rect.left + (tank.width - self.width)/2 # 假设炮弹是坦克的正中心发射的
self.rect.top = tank.rect.top + (tank.height - self.height)/2
self.live = True # 炮弹是否消灭了
def move(self):
if self.live: # 如果炮弹还存在
if self.direction =="L": # 如果坦克方向向左,坦克的left减小就OK了
if self.rect.left > 0: # 判断坦克是否在屏幕左边的边界上
self.rect.left -= self.speed
else:
self.live = False
elif self.direction == "R": # 如果坦克方向向右,坦克的right增加就OK了
if self.rect.right < TankMain.width: #判断坦克是否在屏幕右边的边界上:
self.rect.right += self.speed
else:
self.live = False # 假如坦克已经在屏幕的最右边,就不能再往右移动了
elif self.direction == "U": # 如果坦克方向向上,坦克的top减小就OK了
if self.rect.top > 0:
self.rect.top -= self.speed
else:
self.live = False
elif self.direction == "D": # 如果坦克方向向下,坦克的bottom增加就OK了
if self.rect.bottom < TankMain.height:
self.rect.bottom += self.speed
else:
self.live = False
if __name__ == '__main__':
game = TankMain()
game.startGame()
# coding:utf-8
import pygame, sys,time
from random import randint
from pygame.locals import *
"""坦克大战的主窗口"""
class TankMain(object):
width = 600
height= 500
my_tank_missile_list = []
my_tank = None
# enemy_list = []
wall = None
enemy_list = pygame.sprite.Group() # 敌方坦克的族群
explode_list = []
enemy_missile_list = pygame.sprite.Group()
# 开始游戏的方法
def startGame(self):
pygame.init() #模块初始化:加载系统的资源
# 创建一个屏幕,屏幕的大小((宽,高),窗口的特性[0,RESIZEBLE,FULLSCREEM],颜色位数)
screem = pygame.display.set_mode((TankMain.width,TankMain.height), 0, 32) # 0:窗口不可变
# 给窗口设置一个标题
pygame.display.set_caption("坦克大战")
# 创建一堵墙
TankMain.wall = Wall(screem, 65, 160, 30, 120)
# my_tank = Tank(screem,275,400) 创建一个我方坦克,坦克显示在屏幕的中下部位置
TankMain.my_tank = My_Tank(screem)
if len(TankMain.enemy_list) == 0:
for i in range(1, 6): # 游戏开始时候初始化5个敌方坦克
TankMain.enemy_list.add(Enemy_Tank(screem)) # 把敌方坦克放到组里面
while True:
if len(TankMain.enemy_list) < 5:
TankMain.enemy_list.add(Enemy_Tank(screem)) # 把敌方坦克放到组里面
# color RGB(0,0,0),(255,255,255)
# 设置屏幕的背景色为黑色
screem.fill((0, 0, 0))
# 显示左上角的文字
for i, text in enumerate(self.write_test(), 0):
screem.blit(text, (0, 5+(15*i)))
# 显示游戏中的墙,并且对墙和其它对象进行碰撞检测
TankMain.wall.display()
TankMain.wall.hit_other()
# screem.blit(self.write_test(),(0,5))
# 获取事件:根据获取的事件处理
self.get_event(TankMain.my_tank, screem)
if TankMain.my_tank:
TankMain.my_tank.hit_enemy_missile() # 我方的坦克和敌方的炮弹进行碰撞检测
if TankMain.my_tank and TankMain.my_tank.live:
TankMain.my_tank.display() # 在屏幕上显示我方坦克
TankMain.my_tank.move() # 在屏幕行移动我方坦克
else:
TankMain.my_tank = None
# 显示和随机移动 所有的敌方坦克
for enemy in TankMain.enemy_list:
enemy.display()
enemy.random_move()
enemy.random_fire()
# 显示所有的我方炮弹
for m in TankMain.my_tank_missile_list:
if m.live:
m.display()
m.hit_tank() # 炮弹打中敌方坦克
m.move()
else:
TankMain.my_tank_missile_list.remove(m)
# 显示所有的敌方炮弹
for m in TankMain.enemy_missile_list:
if m.live:
m.display()
m.move()
else:
TankMain.enemy_missile_list.remove(m)
# 显示爆炸效果
for explode in TankMain.explode_list:
explode.display()
# 显示重置
time.sleep(0.05) # 多少秒画一帧 —— 每次休眠0.05秒
pygame.display.update()
# 获取所有的事件:敲击键盘,鼠标点击
def get_event(self,my_tank, screem):
for event in pygame.event.get():
if event.type == QUIT:
self.stopGame() # 程序退出
if event.type == KEYDOWN and (not my_tank) and event.key == K_n: # n 键
TankMain.my_tank = My_Tank(screem) # 重新生成一个我方坦克
if event.type == KEYDOWN and my_tank: # 键盘事件
if event.key == K_LEFT or event.key == K_a:
my_tank.direction ="L" # 仅仅改变坦克的方向:左
my_tank.stop = False
# my_tank.move()
if event.key == K_RIGHT or event.key == K_d:
my_tank.direction = "R"
my_tank.stop = False
# my_tank.move()
if event.key == K_UP or event.key == K_w:
my_tank.direction = "U"
my_tank.stop = False
# my_tank.move()
if event.key == K_DOWN or event.key == K_s:
my_tank.direction = "D"
my_tank.stop = False
# my_tank.move()
if event.key == K_ESCAPE: # 敲击键盘的Esc键
self.stopGame() # 程序退出
if event.key == K_SPACE: # 敲击键盘的空格键,发射炮弹
m = my_tank.fire()
m.good = True # 我方坦克发射的炮弹,好炮弹
TankMain.my_tank_missile_list.append(m)
if event.type == KEYUP and my_tank:
if event.key == K_LEFT or event.key == K_RIGHT or event.key == K_UP or event.key == K_DOWN:
my_tank.stop = True
if event.type == MOUSEBUTTONUP: # 鼠标事件
pass
# 关闭游戏
def stopGame(self):
sys.exit()
# 在屏幕的左上角显示文字内容
def write_test(self):
font = pygame.font.SysFont("simsunnsimsun",20) # 定义一个字体
text_sf1 = font.render("敌方坦克数量为:%d"%len(TankMain.enemy_list),True,(255,0,0)) # 根据字体创建一个文字的图像
text_sf2 = font.render("我方坦克炮弹的数量为:%d"%len(TankMain.my_tank_missile_list), True, (255, 0, 0))
return text_sf1, text_sf2
# 设计游戏窗口的标题
def set_title(self):
pass
# 坦克大战游戏中所有对象的父类
class BaseItem(pygame.sprite.Sprite):
def __init__(self,screem):
pygame.sprite.Sprite.__init__(self)
# 所有对象共享的属性
self.screem = screem
# 在游戏屏幕中显示当前游戏对象:即把坦克对应的图片显示在游戏窗口上
def display(self):
if self.live:
self.image = self.images[self.direction] # 把图象赋值 设置坦克的图像
self.screem.blit(self.image,self.rect) # 画图像
# 坦克的公共父类
class Tank(BaseItem):
# 定义类属性,所有坦克对象高和宽都是一样的(类属性:所有对象可以共享)
width = 60
height = 60
def __init__(self,screem,left,top): # 表示坐标的意思 left:x top:y
super().__init__(screem)
#self.screem = screem # 坦克在移动或显示过程中需要用到当前游戏的屏幕
self.direction = "D" # 坦克的方向,默认方向向下(上下左右)
self.speed = 5 # 坦克移动的(默认)速度
self.stop = False # 坦克移动,停止的初始值
self.images = {} # 坦克的所有图片(key:方向 value:图片 surface)
self.images["L"] = pygame.image.load("images/enemy1L.gif")
self.images["R"] = pygame.image.load("images/enemy1R.gif")
self.images["U"] = pygame.image.load("images/enemy1U.gif")
self.images["D"] = pygame.image.load("images/enemy1D.gif")
self.image = self.images[self.direction] # 坦克的图片由方向决定 设置坦克的图像
self.rect = self.image.get_rect() #坦克的边界
self.rect.left =left
self.rect.top = top
self.live = True # 决定坦克是否消灭了
self.oldtop = self.rect.top
self.oldleft = self.rect.left
def stay(self):
self.rect.top = self.oldtop
self.rect.left = self.oldleft
def move(self):
if not self.stop: # 如果坦克不是停止状态:
self.oldleft = self.rect.left
self.oldtop = self.rect.top
if self.direction =="L": # 如果坦克方向向左,坦克的left减小就OK了
if self.rect.left > 0: # 判断坦克是否在屏幕左边的边界上
self.rect.left -= self.speed
else:
self.rect.left = 0
elif self.direction == "R": # 如果坦克方向向右,坦克的right增加就OK了
if self.rect.right < TankMain.width: #判断坦克是否在屏幕右边的边界上:
self.rect.right += self.speed
else:
self.rect.right = TankMain.width #假如坦克已经在屏幕的最右边,就不能再往右移动了
elif self.direction == "U": # 如果坦克方向向上,坦克的top减小就OK了
if self.rect.top > 0:
self.rect.top -= self.speed
else:
self.rect.top =0
elif self.direction == "D": # 如果坦克方向向下,坦克的bottom增加就OK了
if self.rect.bottom < TankMain.height:
self.rect.bottom += self.speed
else:
self.rect.bottom = TankMain.height
def fire(self):
# 生成一个子弹
m = Missile(self.screem, self)
return m
# 我方坦克的类
class My_Tank(Tank):
def __init__(self,screem):
super().__init__(screem,275,400) # 创建一个我方坦克,坦克显示在屏幕的中下部位置
self.stop = True # 按住某一个方向键不动, 坦克就一直沿着这个方向走;松开键的时候,坦克就停止移动 —— 我方坦克独有的属性 (默认:开始的时候是停止的)
self.live = True
def hit_enemy_missile(self):
hit_list = pygame.sprite.spritecollide(self, TankMain.enemy_missile_list, False) # 碰撞检测
for m in hit_list: # 我方坦克中弹了
m.live = False
TankMain.enemy_missile_list.remove(m)
self.live = False
explode = Explode(self.screem, self.rect)
TankMain.explode_list.append(explode)
# 敌方坦克的类
class Enemy_Tank(Tank):
def __init__(self,screem):
super().__init__(screem,randint(1,5)*100 ,200) # 敌方坦克出现的位置是随机的:假设y:100 x : 随机
self.speed = 3
self.step = 8 # 坦克按照某个方向连续移动的步数
self.get_random_direction()
def get_random_direction(self): # 初始的时候随机给个方向
r = randint(0, 4) # 得到一个坦克移动方向和停止的随机数
if r == 4:
self.stop = True # 敌方坦克开始的时候(停 走 )随机的
elif r == 1:
self.direction = "L"
self.stop = False
elif r == 2:
self.direction = "R"
self.stop = False
elif r == 3:
self.direction = "U"
self.stop = False
elif r == 0:
self.direction = "D"
self.stop = False
# 敌方坦克随机移动的方法:按照一个确定的随机方向,连续移动6步,然后才能再次改变方向
def random_move(self):
if self.live:
#print(self.step) 测试
if self.step == 0: #坦克的6步已经移动完了,需要从新确定方向
self.get_random_direction() # 随机给个方向
self.step = 6
else:
self.move()
self.step -= 1
def random_fire(self):
r = randint(0, 50)
if r == 10:
m = self.fire()
TankMain.enemy_missile_list.add(m)
else:
return
class Missile(BaseItem):
width = 15
height = 15
def __init__(self,screem,tank):
super().__init__(screem)
self.tank = tank
self.direction = tank.direction # 炮弹的方向由所发射的坦克方向决定
self.speed = 12 # 炮弹移动的(默认)速度
self.stop = False # 坦克移动,停止的初始值
self.images = {} # 炮弹的所有图片(key:方向 value:图片 surface)
self.images["L"] = pygame.image.load("images/enemymissile.gif")
self.images["R"] = pygame.image.load("images/enemymissile.gif")
self.images["U"] = pygame.image.load("images/enemymissile.gif")
self.images["D"] = pygame.image.load("images/enemymissile.gif")
self.image = self.images[self.direction] # 坦克的图片由方向决定 设置坦克的图像
self.rect = self.image.get_rect() # 炮弹的边界
self.rect.left = tank.rect.left + (tank.width - self.width)/2 # 假设炮弹是坦克的正中心发射的
self.rect.top = tank.rect.top + (tank.height - self.height)/2
self.live = True # 炮弹是否消灭了
self.good = False
def move(self):
if self.live: # 如果炮弹还存在
if self.direction =="L": # 如果坦克方向向左,坦克的left减小就OK了
if self.rect.left > 0: # 判断坦克是否在屏幕左边的边界上
self.rect.left -= self.speed
else:
self.live = False
elif self.direction == "R": # 如果坦克方向向右,坦克的right增加就OK了
if self.rect.right < TankMain.width: #判断坦克是否在屏幕右边的边界上:
self.rect.right += self.speed
else:
self.live = False # 假如坦克已经在屏幕的最右边,就不能再往右移动了
elif self.direction == "U": # 如果坦克方向向上,坦克的top减小就OK了
if self.rect.top > 0:
self.rect.top -= self.speed
else:
self.live = False
elif self.direction == "D": # 如果坦克方向向下,坦克的bottom增加就OK了
if self.rect.bottom < TankMain.height:
self.rect.bottom += self.speed
else:
self.live = False
# 炮弹击中坦克:
# 情况一:我方炮弹击中敌方坦克,敌方炮弹击中我方坦克
# 情况二:
def hit_tank(self):
if self.good: # 如果炮弹是我方的炮弹
hit_list = pygame.sprite.spritecollide(self, TankMain.enemy_list, False)
for e in hit_list:
e.live = False
TankMain.enemy_list.remove(e) # 如果敌方坦克被击中,从列表中删除敌方坦克
self.live = False
explode = Explode(self.screem, e.rect) # 产生一个爆炸对象
TankMain.explode_list.append(explode)
# 爆炸类
class Explode(BaseItem):
def __init__(self, screem, rect):
super().__init__(screem)
self.live = True
self.images = [pygame.image.load("images/blast1.gif"), \
pygame.image.load("images/blast2.gif"), \
pygame.image.load("images/blast3.gif"), \
pygame.image.load("images/blast4.gif"), \
pygame.image.load("images/blast5.gif"), \
pygame.image.load("images/blast6.gif"), \
pygame.image.load("images/blast7.gif"), \
pygame.image.load("images/blast8.gif")]
self.step = 0
self.rect = rect # 爆炸的位置和发生爆炸前,炮弹碰到坦克的位置一样。在构建爆炸的时候,把坦克的 rect 传递进来
# display 方法在整个游戏运行过程中,循环调用,每隔 0.05 秒调用一次
def display(self):
if self.live:
if self.step == len(self.images) : # 最后一张爆炸图片已经显示了
self.live = False
else:
self.images = self.images[self.step]
self.screem.blit(self.image, self.rect)
self.step += 1
else:
# 删除该对象
pass
# 游戏中的墙
class Wall(BaseItem):
def __init__(self, screem, left, top, width, height):
super().__init__(screem)
self.rect = Rect(left, top, width, height)
self.color = (255, 0,0)
def display(self):
self.screem.fill(self.color, self.rect)
# 针对墙和其它坦克或者炮弹的碰撞检测
def hit_other(self):
if TankMain.my_tank:
is_hit = pygame.sprite.collide_rect(self, TankMain.my_tank)
if is_hit:
TankMain.my_tank.stop = True
TankMain.my_tank.stay()
if len(TankMain.enemy_list) != 0:
hit_list = pygame.sprite.spritecollide(self, TankMain.enemy_list, False)
for e in hit_list:
e.stop = True
e.stay()
if __name__ == '__main__':
game = TankMain()
game.startGame()
- 子弹碰到坦克闪退问题 ?????