# coding = utf-8
import pygame, sys, time
from pygame.locals import *
from random import randint
'''坦克大战主窗口'''
class TankMain(object):
width = 700
height = 600
wall_list = []
my_tank = None
home = None
lives = 3
# enemy_list = [] # 敌方坦克列表
enemy_list = pygame.sprite.Group() # 敌方坦克(精灵)族群
my_tank_missile = [] # 我方子弹列表
enemy_tank_missile = pygame.sprite.Group() # 敌方子弹(精灵)族群
explode_list = [] # 爆炸效果列表
# 开始游戏
def startGame(self): # 开始游戏
pygame.init() # pygame模块初始化,加载系统资源
# 设置一个窗口,第一个参数:(宽,高),第二个参数:窗口可变{0,RESIZABLE,FULLSCREEM,..},第三个参数:颜色位数{32,64,..}
# screem是一个Surface表面对象
screem = pygame.display.set_mode((TankMain.width, TankMain.height), 0, 32)
# 给窗口设置标题
pygame.display.set_caption("坦克大战")
# 生成我方坦克,敌方坦克,障碍物等
self.creat(screem)
# 循环显示屏幕内容,形成动态效果
while True:
screem.fill((0, 0, 0)) # 设置背景颜色 RGB (255,255,255):白色 (0,0,0):黑色
# 显示
self.show(screem)
# 事件处理
self.get_event(TankMain.my_tank, screem) # 获取事件进行处理
time.sleep(0.05) # 每次休息0.05秒跳到下一帧
pygame.display.update() # 显示重置
# 在屏幕上显示文字内容
def write_text(self):
font = pygame.font.SysFont('simhei', 13) # 定义一个字体 参数: 字体 大小 粗细
text_sf0 = font.render("我方坦克生命:%d"%TankMain.lives, True, (255, 0, 0)) # 根据字体创建一个文字的图像 参数:内容 抗锯齿 颜色 背景
text_sf1 = font.render("敌方坦克数量:%d"%len(TankMain.enemy_list), True, (255, 0, 0))
# 根据字体创建一个文字的图像 参数:内容 抗锯齿 颜色 背景
text_sf2 = font.render("我方坦克屏幕子弹数量:%d"%len(TankMain.my_tank_missile), True,
(255, 0, 0)) # 根据字体创建一个文字的图像 参数:内容 抗锯齿 颜色 背景
return text_sf0, text_sf1, text_sf2
# 生产,创建我方坦克,敌方坦克
def creat(self, screem):
# 生产墙列表
for i in range(1, 14):
if i % 3 == 0:
TankMain.wall_list.append(GrassBarrier(screem, i * Barrier.width, TankMain.height - 400))
TankMain.wall_list.append(CobWallBarrier(screem, i * Barrier.width, 300))
elif i % 4 == 0:
pass
elif i % 5 == 0:
TankMain.wall_list.append(GrassBarrier(screem, i * Barrier.width, TankMain.height-400))
TankMain.wall_list.append(IronWallBarrier(screem, i * Barrier.width, 300))
elif i % 7 == 0:
TankMain.wall_list.append(CobWallBarrier(screem, i * Barrier.width, 300))
else:
TankMain.wall_list.append(IronWallBarrier(screem, i * Barrier.width, 300))
TankMain.wall_list.append(WaterBarrier(screem, i * Barrier.width, TankMain.height - 400))
TankMain.wall_list.append(GrassBarrier(screem, i * Barrier.width, i*Barrier.height))
TankMain.wall_list.append(WaterBarrier(screem, TankMain.width-i * Barrier.width, i * Barrier.height))
# 生成我方坦克的家
for i in range(0, 3):
if i == 1:
TankMain.home = HomeBarrier(screem, TankMain.width/2-HomeBarrier.width/2,
TankMain.height-HomeBarrier.width)
TankMain.wall_list.append(CobWallBarrier(screem, (TankMain.width+(2*i-3)*HomeBarrier.width)/2,
TankMain.height-HomeBarrier.width*2))
else:
TankMain.wall_list.append(CobWallBarrier(screem, (TankMain.width+(2*i-3)*HomeBarrier.width)/2,
TankMain.height-HomeBarrier.width))
TankMain.wall_list.append(CobWallBarrier(screem, (TankMain.width+(2*i-3)*HomeBarrier.width)/2,
TankMain.height-HomeBarrier.width*2))
# 生产我方坦克
TankMain.my_tank = MyTank(screem)
# 生产敌方坦克
for i in range(1, 6):
if i % 3 == 0:
TankMain.enemy_list.add(EnemyTankQ(screem)) # 在族群中添加3个普通坦克,就会有一个强坦克
TankMain.enemy_list.add(EnemyTank(screem)) # 在族群中添加一个精灵sprite(坦克)
# 在屏幕上显示(矩形rect, sprite, image,等)
def show(self, screem):
# 显示文字
for i, text in enumerate(self.write_text(), 0):
screem.blit(text, (0, 5 + (13 * i))) # 在左上角显示文字 参数:源 位置(x,y)
# 显示我方坦克的家
if TankMain.home and TankMain.home.live:
TankMain.home.display()
TankMain.home.hit_other()
else:
TankMain.home = None
TankMain.lives = 0
TankMain.my_tank = None
# 显示敌方坦克
for enemy_tank in TankMain.enemy_list:
if enemy_tank.live:
enemy_tank.display()
# enemy_tank.hit_ourself()
enemy_tank.random_move()
enemy_tank.random_fire()
else:
TankMain.enemy_list.remove(enemy_tank)
# 显示我方坦克
if TankMain.my_tank and TankMain.my_tank.live:
TankMain.my_tank.enemy_hit_mytank()
TankMain.my_tank.display()
TankMain.my_tank.move()
elif TankMain.lives:
TankMain.my_tank = MyTank(screem)
TankMain.my_tank.live = True
TankMain.lives -= 1
else:
TankMain.my_tank = None
pass
# 显示我方炮弹
for mm in TankMain.my_tank_missile:
if mm.live:
mm.display()
mm.hit_tank() # 检测是否命中敌方坦克
mm.move()
else:
TankMain.my_tank_missile.remove(mm)
# 显示敌方炮弹
for em in TankMain.enemy_tank_missile:
if em.live:
em.display()
em.move()
else:
TankMain.enemy_tank_missile.remove(em)
# 显示墙
for wall in TankMain.wall_list:
if wall.live:
wall.display()
wall.hit_other()
else:
TankMain.wall_list.remove(wall)
# 显示爆炸效果
for explode in TankMain.explode_list:
if explode.live:
explode.display()
else:
TankMain.explode_list.remove(explode)
# 显示胜利
if not TankMain.enemy_list:
finall_text = pygame.font.SysFont('simhei', 50).render("YOU WIN", True, (255, 0, 0), (0, 255, 0))
screem.blit(finall_text, (TankMain.width / 2 - 70, TankMain.height / 2 - 25))
# 显示失败
if (TankMain.lives == 0 and not TankMain.my_tank) or not TankMain.home :
finall_text = pygame.font.SysFont('simhei', 50).render("YOU LOSE", True, (127, 127, 127), (255, 0, 0))
screem.blit(finall_text, (TankMain.width / 2 - 80, TankMain.height / 2 - 25))
# 获取所有事件(敲击键盘,点击鼠标等)
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 TankMain.lives and event.key == K_RETURN:
# TankMain.lives -= 1
# TankMain.my_tank = MyTank(screem)
if event.type == KEYDOWN and my_tank: # 敲击键盘事件
if event.key == K_ESCAPE: # 敲击键盘ESC
self.stopGame() # 退出
if event.key == K_LEFT or event.key == K_a: # 敲击键盘方向键向左
my_tank.direction = 'L'
my_tank.stop = False
if event.key == K_RIGHT or event.key == K_d: # 敲击键盘方向键向右
my_tank.direction = 'R'
my_tank.stop = False
if event.key == K_UP or event.key == K_w: # 敲击键盘方向键向上
my_tank.direction = 'U'
my_tank.stop = False
if event.key == K_DOWN or event.key == K_s: # 敲击键盘方向键向下
my_tank.direction = 'D'
my_tank.stop = False
if event.key == K_SPACE:
mm = my_tank.fire()
TankMain.my_tank_missile.append(mm)
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 \
or event.key == K_a or event.key == K_d or event.key == K_w or event.key == K_s:
my_tank.stop = True
if TankMain.my_tank and event.type == MOUSEBUTTONDOWN: # 鼠标事件
mm = my_tank.fire()
TankMain.my_tank_missile.append(mm)
# 关闭游戏
def stopGame(self): # 停止游戏
sys.exit()
# 坦克大战游戏中的基础父类
class BaseIetm(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(BaseIetm):
# 定义属性,所有坦克的宽高都是一样的
width = 47
height = 47
def __init__(self, screem, left, top):
super().__init__(screem)
self.direction = 'D' # 表示坦克方向,默认向下(U,D,L,R)
self.speed = 5 # 坦克默认速度
self.stop = False
self.images = {} # 表示坦克图片字典,key:方向,value:图片(surface)
self.images['L'] = pygame.image.load("image/T_L.png") # 我方坦克
self.images['R'] = pygame.image.load("image/T_R.png")
self.images['U'] = pygame.image.load("image/T_U.png")
self.images['D'] = pygame.image.load("image/T_D.png")
self.image = self.images[self.direction] # 坦克的图片由坦克的方向决定
self.rect = self.image.get_rect() # 获得图片的边界
self.rect.left = left # 设置图片位置x
self.rect.top = top # 设置图片位置y
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.oldtop = self.rect.top
self.oldleft = self.rect.left
if self.direction == 'L':
if self.rect.left > 0:
self.rect.left -= self.speed
else:
self.rect.left = 0
elif self.direction == 'R':
if self.rect.right < TankMain.width:
self.rect.right += self.speed
else:
self.rect.right = TankMain.width
elif self.direction == 'U':
if self.rect.top > 0:
self.rect.top -= self.speed
else:
self.rect.top = 0
elif self.direction == 'D':
if self.rect.bottom < TankMain.height:
self.rect.bottom += self.speed
else:
self.rect.bottom = TankMain.height
# 坦克开火,发射炮弹
def fire(self):
pass
# 我方坦克
class MyTank(Tank):
def __init__(self, screem):
super().__init__(screem, TankMain.width/2-MyTank.width/2, TankMain.height-150) # 我方坦克初始化位置
self.direction = 'U' # 我方坦克默认朝上
self.stop = True
def enemy_hit_mytank(self):
if TankMain.enemy_tank_missile:
em_list = pygame.sprite.spritecollide(self, TankMain.enemy_tank_missile, False)
for em in em_list:
em.live = False
self.live = False
explode = Explode(self.screem, self.rect)
TankMain.explode_list.append(explode)
# if TankMain.enemy_list:
# tank_list = pygame.sprite.spritecollide(self, TankMain.enemy_list, False)
# for tank in tank_list:
# tank.stop = True
# tank.stay()
# 坦克开火,发射炮弹
def fire(self):
mm = MyMissile(self.screem, self)
return mm
# 敌方坦克
class EnemyTank(Tank):
def __init__(self, screem):
super().__init__(screem, randint(0, TankMain.width), randint(0, TankMain.height-350))
self.images['L'] = pygame.image.load("image/tan_l.png") # 敌方坦克
self.images['R'] = pygame.image.load("image/tan_r.png")
self.images['U'] = pygame.image.load("image/tan_u.png")
self.images['D'] = pygame.image.load("image/tan_d.png")
self.speed = 4 # 敌方坦克速度
self.step = 8 # 敌方坦克按照一个方向移动6步
self.get_random_direction()
# 获得一个随机方向
def get_random_direction(self):
r = randint(0, 4)
if r == 0:
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 == 4:
self.direction = 'D'
self.stop = False
# 敌方坦克确定一个随机方向移动8步,然后再次改变方向移动
def random_move(self):
if self.live:
if self.step == 0: # 如果已经移动了8步,则又随机获得一个方向
self.get_random_direction()
self.step = 8
else:
self.move()
self.step -= 1
# 坦克开火,发射炮弹
def random_fire(self):
if randint(1, 100) > 95:
em = EnemyMissile(self.screem, self)
TankMain.enemy_tank_missile.add(em)
else:
return
# 敌方坦克
class EnemyTankQ(EnemyTank):
def __init__(self, screem):
super().__init__(screem)
self.images['L'] = pygame.image.load("image/tank_l.png") # 敌方坦克
self.images['R'] = pygame.image.load("image/tank_r.png")
self.images['U'] = pygame.image.load("image/tank_u.png")
self.images['D'] = pygame.image.load("image/tank_d.png")
# 炮弹父类
class Missile(BaseIetm):
width = 12
height = 12
def __init__(self, screem, tank):
super().__init__(screem)
self.tank = tank
self.direction = tank.direction # 表示炮弹方向,由坦克方向决定
self.speed = 12 # 炮弹默认速度
self.images = {} # 表示炮弹图片字典,key:方向,value:图片(surface)
self.images['L'] = pygame.image.load("image/pao2.png") # 我方炮弹
self.images['R'] = pygame.image.load("image/pao2.png")
self.images['U'] = pygame.image.load("image/pao2.png")
self.images['D'] = pygame.image.load("image/pao2.png")
self.image = self.images[self.direction] # 炮弹的图片由炮弹的方向决定
self.rect = self.image.get_rect() # 获得炮弹的边界
self.rect.left = tank.rect.left + (tank.width - self.width)/2 # 设置炮弹位置x
self.rect.top = tank.rect.top + (tank.height - self.height)/2 # 设置炮弹位置y
self.live = True # 决定炮弹生死
# 炮弹移动
def move(self):
if self.live:
if self.direction == 'L':
if self.rect.left > 0:
self.rect.left -= self.speed
else:
self.live = False
elif self.direction == 'R':
if self.rect.right < TankMain.width:
self.rect.right += self.speed
else:
self.live = False
elif self.direction == 'U':
if self.rect.top > 0:
self.rect.top -= self.speed
else:
self.live = False
elif self.direction == 'D':
if self.rect.bottom < TankMain.height:
self.rect.bottom += self.speed
else:
self.live = False
# 炮弹击中坦克,第一种:我方炮弹击中敌方坦克,需要我方炮弹的边界和所有敌方坦克边界比对,看是否重叠,返回重叠位置
# 第二种:敌方炮弹击中我方坦克,需要敌方炮弹和我方坦克位置比对,若重叠,返回位置
def hit_tank(self):
if TankMain.enemy_list: # 我方炮弹击中敌方坦克
# 在与另一个精灵相交的组中查找精灵,检测是否碰撞 参数:本精灵 目标精灵组 是否删除组中所有碰撞的(Sprite)精灵
em_list = pygame.sprite.spritecollide(self, TankMain.enemy_list, False)
for em in em_list:
self.live = False
em.live = False
explode = Explode(self.screem, em.rect) # 产生一个爆炸对象
TankMain.explode_list.append(explode)
# 我方炮弹
class MyMissile(Missile):
def __init__(self, screem, tank):
super().__init__(screem, tank)
# 敌方炮弹
class EnemyMissile(Missile):
def __init__(self, screem, tank):
super().__init__(screem, tank)
self.images['L'] = pygame.image.load("image/pao3.png") # 我方炮弹
self.images['R'] = pygame.image.load("image/pao3.png")
self.images['U'] = pygame.image.load("image/pao3.png")
self.images['D'] = pygame.image.load("image/pao3.png")
# 爆炸类
class Explode(BaseIetm):
def __init__(self, screem, rect):
super().__init__(screem)
self.live = True
self.images = [pygame.image.load("image/bao1.png"),
pygame.image.load("image/bao2.png"),
pygame.image.load("image/bao3.png"),
pygame.image.load("image/bao4.png"),
pygame.image.load("image/bao5.png"),
pygame.image.load("image/bao6.png")]
self.step = 0
self.image = self.images[self.step] # 初始化第一张爆炸效果图
self.rect = rect
def display(self):
if self.live:
if self.step == len(self.images) : # 显示最后一张
self.live = False
else:
self.image = self.images[self.step]
self.screem.blit(self.image, self.rect) # 爆炸位置由坦克的rect位置决定
self.step += 1
else:
pass # 删除该爆炸效果对象
# 游戏中的静态障碍物(建筑,草,水等)
class Barrier(BaseIetm):
width = 47
height = 47
def __init__(self, screem, left, top):
super().__init__(screem)
# self.rect = Rect(left, top, width, height) # 构建一个rect(一个物体在屏幕的位置及大小 )
self.image = pygame.transform.scale(pygame.Surface((40, 40)), (40, 40))
self.rect = self.image.get_rect()
self.rect.left = left
self.rect.top = top
self.live = True
def display(self):
if self.live:
self.screem.blit(self.image, self.rect)
# 碰撞检测
def hit_other(self):
pass
# 障碍物--铁墙
class IronWallBarrier(Barrier):
def __init__(self, screem, left, top):
super().__init__(screem, left, top)
self.image = pygame.transform.scale(pygame.image.load("image/zhuan.gif"),
(Barrier.width, Barrier.height))
# 铁墙碰撞检测
def hit_other(self):
if TankMain.my_tank:
if pygame.sprite.collide_rect(self, TankMain.my_tank):
TankMain.my_tank.stop = True
TankMain.my_tank.stay()
if TankMain.enemy_list:
et_list = pygame.sprite.spritecollide(self, TankMain.enemy_list, False)
for et in et_list:
et.stop = True
et.stay()
if TankMain.my_tank_missile:
mm_list = pygame.sprite.spritecollide(self, TankMain.my_tank_missile, False)
for mm in mm_list:
mm.live = False
if TankMain.enemy_tank_missile:
em_list = pygame.sprite.spritecollide(self, TankMain.enemy_tank_missile, False)
for em in em_list:
em.live = False
# 障碍物--土墙
class CobWallBarrier(Barrier):
def __init__(self, screem, left, top):
super().__init__(screem, left, top)
self.image = pygame.transform.scale(pygame.image.load("image/tu.gif"),
(Barrier.width, Barrier.height))
# 土墙碰撞检测
def hit_other(self):
if TankMain.my_tank:
if pygame.sprite.collide_rect(self, TankMain.my_tank):
TankMain.my_tank.stop = True
TankMain.my_tank.stay()
if TankMain.enemy_list:
et_list = pygame.sprite.spritecollide(self, TankMain.enemy_list, False)
for et in et_list:
et.stop = True
et.stay()
if TankMain.my_tank_missile:
mm_list = pygame.sprite.spritecollide(self, TankMain.my_tank_missile, False)
for mm in mm_list:
mm.live = False
self.live = False
explode = Explode(self.screem, self.rect)
TankMain.explode_list.append(explode)
if TankMain.enemy_tank_missile:
em_list = pygame.sprite.spritecollide(self, TankMain.enemy_tank_missile, False)
for em in em_list:
em.live = False
self.live = False
explode = Explode(self.screem, self.rect)
TankMain.explode_list.append(explode)
# 障碍物--草
class GrassBarrier(Barrier):
def __init__(self, screem, left, top):
super().__init__(screem, left, top)
self.image = pygame.transform.scale(pygame.image.load("image/cao.gif"),
(Barrier.width, Barrier.height))
# 草碰撞检测
def hit_other(self):
pass
# 障碍物--水
class WaterBarrier(Barrier):
def __init__(self, screem, left, top):
super().__init__(screem, left, top)
self.image = pygame.transform.scale(pygame.image.load("image/shui.gif"),
(Barrier.width, Barrier.height))
# 水碰撞检测
def hit_other(self):
pass
# 我方坦克的家
class HomeBarrier(Barrier):
def __init__(self, screem, left, top):
super().__init__(screem, left, top)
self.image = pygame.transform.scale(pygame.image.load("image/home.gif"),
(Barrier.width, Barrier.height))
# 家碰撞检测
def hit_other(self):
if TankMain.my_tank:
if pygame.sprite.collide_rect(self, TankMain.my_tank):
TankMain.my_tank.stop = True
TankMain.my_tank.stay()
if TankMain.enemy_list:
et_list = pygame.sprite.spritecollide(self, TankMain.enemy_list, False)
for et in et_list:
et.stop = True
et.stay()
if TankMain.my_tank_missile:
mm_list = pygame.sprite.spritecollide(self, TankMain.my_tank_missile, False)
for mm in mm_list:
mm.live = False
self.live = False
explode = Explode(self.screem, self.rect)
TankMain.explode_list.append(explode)
if TankMain.enemy_tank_missile:
em_list = pygame.sprite.spritecollide(self, TankMain.enemy_tank_missile, False)
for em in em_list:
em.live = False
self.live = False
explode = Explode(self.screem, self.rect)
TankMain.explode_list.append(explode)
# 测试运行
if __name__=='__main__':
game = TankMain()
game.startGame()
图片链接:http://www.aigei.com/view/63180.html#items 自己下
运行效果图:
主要用到pygame模块
官方文档:http://www.pygame.org/docs/