python simple tank war 简单坦克大战 used turtle module by lixingqiu

坦克是用海龟画图画出来的,不是很漂亮,呵呵,只显示一个封面吧。
python turtle坦克大战tank war by lixingqiu李兴球

"""坦克大战,小坦克被一群大坦克包围,情况十分危急。
  小坦克的优势在于速度快,能连续发射。制作日期:2018年10月。
  这是一个用python的海龟画图模块制作的射击小游戏,需要用鼠标指针操作小坦克突围!
  制作日期:2018年10月,作者:李兴球。

"""
#从海龟模块导入所有命令

from turtle import *
import math
from random import randint

def load_sound():
    """加载声音与播放背景音乐"""
    sound_normal = True
    explode_sound= None
    shoot_sound = None
    try:
        import pygame
        pygame.mixer.init()
        pygame.mixer.music.load("音效/newgrounds.wav")
        pygame.mixer.music.play(-1,0)
        explode_sound = pygame.mixer.Sound("音效/Boom.wav")
        shoot_sound = pygame.mixer.Sound("音效/榴弹炮.wav")
    except:
        print("播放背景音乐或加载音频出现错误.")
        sound_normal = False
        
    """返回声音是否正常,爆炸声,射击声三个对象"""
    return sound_normal,explode_sound,shoot_sound
        
def init_screen():
    """初始化屏幕,注册坦克形状"""
    screen = Screen()
    screen.setup(width,height)
    p = ((0,0),(50,0),(50,80),(10,80),(10,150),(-10,150),(-10,80),(-50,80),(-50,0))
    screen.addshape("tank",p)        # 注册tank形状
    screen.bgcolor("blue")           # 屏幕背景色
    screen.title(gametitle)          # 设定屏幕标题
    screen.colormode(255)            # 设定颜色模式
    screen.delay(0)                  # 屏幕延时为0
    screen.bgpic("封面设计.png")     # 封面加载
    """添加爆炸造型图片列表到形状列表"""
    explosion_images = ["explosion-" + str(i) + ".gif"  for i in range(17)]
    [screen.addshape(image) for image in explosion_images ]  # 注册爆炸造型到形状列表
    return screen,explosion_images


class Bullet(Turtle):
    """炮弹类,炮弹生成后会自己移动,直到碰到边缘。"""
    def __init__(self,x,y,h):
        Turtle.__init__(self,visible=False,shape="circle")
        self.penup()
        self.dead = False
        self.goto(x,y)
        self.setheading(h)
        self.showturtle()
        self.move()
        
    def move(self):
        """炮弹移动,碰到边缘就‘死亡’"""
        self.fd(10)
        if self.bumpedge():self.dead = True
        if self.dead:
            self.hideturtle()
            del self            
        else:
            screen.ontimer(self.move,10)

    def bumpedge(self):
        """碰到边缘返回True,否则False"""
        return abs(self.xcor())>width/2 or abs(self.ycor())>height/2
        
class NPCtank(Turtle):
    deadcount = 0                         #统计数量的类变量
    def __init__(self,mytank,my_bullet):
        """敌方坦克的敌人就是mytank,my_bullet是我方炮弹列表"""
        Turtle.__init__(self,shape='tank',visible=False)
         
        self.shapesize(0.3,0.3)
        color1 = randint(0,255),randint(0,255),randint(0,255)
        self.color("black",color1)
        self.penup()
        self.setheading(randint(1,360))
        self.fd(randint(200,height*0.4))   # 配合随机方向让npc随机移到一个地方    
        self.enemy = mytank
        self.enemy_bullet = my_bullet         
        self.face_enemy()                  # 一出生就面向mytank
        self.dead = False
        self.move()
        
    def move(self):
        """移动npc坦克,有时会面向mytank"""
        self.fd(1)
        self.shoot()      # 设置一定的机率发射炮弹
        self.bumpedge()   # 碰到屏幕边缘就向后转
        self.bumpenemy()  # 碰到敌人(mytank)后会爆炸,mytank当然也会爆炸,游戏结束
        self.bumpbullet() # 碰到我方炮弹就爆炸
        if  self.dead:            
            self.hideturtle()              # 死了后,显示爆炸效果
            bomb = Bomb(self.xcor(),self.ycor(),explosion_images)
            NPCtank.deadcount = NPCtank.deadcount + 1
            info ="当前击毁敌方坦克数:" + str(NPCtank.deadcount)
            top_turtle.print(info)
            if NPCtank.deadcount == tanksamount:
                bottom_turtle.print("游戏成功结束,作者:李兴球")
        else:
            screen.ontimer(self.move,10)
    def bumpenemy(self):
        """碰到敌人就两方都死亡,npc的敌人就是mytank"""
        r = self.distance(self.enemy)
        if r <20 and not self.enemy.dead:
            self.hideturtle()
            self.dead = True
            self.enemy.hideturtle()
            self.enemy.dead = True
            # mytank爆炸,我方坦克阵亡,在死的位置上显示爆炸效果          
            x = self.enemy.xcor()
            y = self.enemy.ycor()
            Bomb(x,y,explosion_images)
            bottom_turtle.print("突围失败! 作者:李兴球")
            
            
    def bumpbullet(self):
        """碰到我方炮弹就死亡"""
        for b in self.enemy_bullet:
            r = self.distance(b)
            if r <20:
               self.hideturtle()
               self.dead = True
               break
             
    def bumpedge(self):
        """bumpedge就掉头"""
        faraway = abs(self.xcor())>width/2 or abs(self.ycor())>height/2  
        if faraway:self.right(180) # 掉转头
    def face_enemy(self):
        """面向敌人,NPC的敌人就是mytank,可以增加代码让转向更平滑"""
        self.setheading(self.towards(self.enemy.position()))
        
    def shoot(self):
        """敌坦克的发射方法,同时把‘死了’的炮弹移去"""
        if randint(0,100) == 1:            # 有时间会面向mytank
            self.face_enemy()
            if randint(0,20) ==1 :  
                b = Bullet(self.xcor(),self.ycor(),self.heading()) # 生成炮弹
                enemybullet.append(b)      # 添加到敌方炮弹列表
                # 移去dead为True的敌方炮弹
                for b in enemybullet:
                    if b.dead :enemybullet.remove(b)
             
 
        
class Bomb(Turtle):
    """炸弹类,它实例化后,自己就会切换造型,从而“爆炸”"""
    def __init__(self,x,y,images):
        """x,y是爆炸的坐标,images是已注册到屏幕形状列表的造型图片"""
        Turtle.__init__(self,visible=False)
        self.penup()
        self.goto(x,y)
        self.index = 0                 # 造型索引编号从0开始
        self.amount  = len(images)     # 造型数量
        self.images = images           # 造型列表
        self.showturtle()              # 显示
        if snd_normal: explode_sound.play()
        self.next_costume()   # 利用屏幕的定时器功能使之循环一定的次数
        
    def next_costume(self):
        if self.index < self.amount:     # 小于总数量就换造型       
           self.shape(self.images[self.index]) # 从列表取指定索引的图片,设为海龟的形状
           self.index = self.index + 1
           screen.ontimer(self.next_costume,50)
        else:
           self.hideturtle()
           del self
                      
        
def make_mytank():
    """生成我方坦克对象,并返回到主程序"""
    blue= Turtle(shape='tank',visible=False)
    blue.shapesize(0.2,0.2)  # "亲生"的形状可以缩放
    blue.penup()
    blue.pencolor("black")
    blue.fillcolor("blue")
    blue.pensize(2)
    blue.dead = False        # 增加额外的dead属性
    return blue

def mytank_wait_bump_enemybullet():
    """我方坦克每隔10豪秒等待是否碰到敌方炮弹"""
    if not mytank.dead:
        for b in enemybullet:   # 对敌方阵营炮弹列表中的每颗炮弹进行检测
            if b.distance(mytank)<20:  # 如果炮弹到mytank的距离小于20,认为碰到了炮弹              
                mytank.hideturtle()    # 隐藏
                mytank.dead = True     # 标记为“死亡”
                Bomb(b.xcor(),b.ycor(),explosion_images) # 显示爆炸效果
                bottom_turtle.print("突围失败! 作者:李兴球")
                break
        screen.ontimer(mytank_wait_bump_enemybullet,10) # 10毫秒检测一次

    
def follow_mouse(event):
    """本函数让小海龟面朝鼠标指针移动"""
    if not mytank.dead:
        x = event.x - width/2              # 转换成海龟坐标系中的x坐标
        y = height/2 - event.y             # 转换成海龟坐标系中的y坐标
        dy = y - mytank.ycor()
        dx = x - mytank.xcor()
        angle = math.degrees(math.atan2(dy,dx))
        mytank.setheading(angle)
        if mytank.distance(x,y)>20 :mytank.fd(2)
    else:
        screen.cv.bind("<Motion>",None)   # 取消绑定鼠标移动事件
 
        
    
def shoot(x,y):
    """mytank发射函数,被绑定在screen.onclick事件上"""
    if not mytank.dead:
        if snd_normal : shoot_sound.play() # 如果声音加载正常,则播放发射声
        b = Bullet(mytank.xcor(),mytank.ycor(),mytank.heading())
        mybullet.append(b)
        # 移去dead属性为True的炮弹
        for b in mybullet:
            if b.dead :mybullet.remove(b)
    else:
        screen.onclick(None)              # 取消单击事件的函数绑定
     

class Writer(Turtle):
    """用来在屏幕上写字的海龟对象"""
    def __init__(self,y):
        Turtle.__init__(self,visible = False)
        self.penup()
        self.sety(y)
        self.color("cyan")
        self.font = ("黑体",20,"normal")
    def print(self,string):
        self.clear()        
        self.write(string,align='center',font=self.font)
        
    

def start_game():
    screen.bgpic("草地.png")
    screen.cv.bind("<Motion>",follow_mouse)   # 画布绑定鼠标移动事件
    screen.onclick(shoot)                     # 单击屏幕,绑定发射函数
    mytank.showturtle()
    """生成敌方坦克"""     
    npc = [NPCtank(mytank,mybullet) for i in range(tanksamount)] 
    [enemy.showturtle() for enemy in npc]     # 显示每个npc坦克
    screen.onkeypress(None,"space")           # 取消按键注册事件
     
    
if __name__ =="__main__":
    
    gametitle = "坦克大战_海龟画图版_作者:李兴球"
    tanksamount = 20                          # 坦克数量
    width,height=800,700                      # 屏幕宽度,高度
    enemybullet = []                          # 敌方炮弹列表
    mybullet = []                             # 我方炮弹列表
    """声音是否正常,爆炸声,射击声"""
    snd_normal,explode_sound,shoot_sound = load_sound()   # 加载声音
    screen,explosion_images = init_screen()   # 初始化屏幕,显示封面,返回screen和爆炸造型列表
    mytank = make_mytank()                    # 我方坦克
    top_turtle = Writer(310)                  # 顶部写字龟
    top_turtle.print("当前击毁敌方坦克数:0") # 在顶部写些字
    bottom_turtle = Writer(-330)              # 底部写字龟    
    screen.onkeypress(start_game,"space")     # 注册按空格事件,生成敌方坦克等等
    mytank_wait_bump_enemybullet()            # 等待碰到敌方炮弹 
    screen.listen()                           # 给屏幕设置焦点
    screen.mainloop()                         # 进入主循环