python3少儿编程学习之_坦克大战射击游戏_turtle版源码

版权声明:所有文章皆为李兴球先生原创,转载请注明出处,否则保留权利,追究责任。 https://blog.csdn.net/avskya/article/details/82960347

"""坦克大战,小坦克被一群大坦克包围,情况十分危急。小坦克的优势在于速度快,能连续发射。

"""


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

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()                         #进入主循环   
   """需要本作品素材请联系风火轮少儿编程李兴球先生"""

猜你喜欢

转载自blog.csdn.net/avskya/article/details/82960347
今日推荐