基于untiy实现的Google小恐龙游戏3---第二个Boss

本文记录了一位大学生开发者在Unity中设计第二个游戏BOSS克眼和新敌人小眼的过程,包括BOSS的移动机制、追踪玩家和爆炸效果,以及一个小弟敌人的设计和代码实现。
摘要由CSDN通过智能技术生成

前言

大家好,上一篇文章我设计了一个简单的第一个BOSS,以及二个新敌人。然后这个文章准备设计第二个BOSS,虽然感觉做这些挺水的,但是作为一个的大学生,也就只可以这样的,毕竟难的我也确实不会,先写着练练手吧。然后,今天的代码比之前少了一点,但是写的时候还是吃了些力,可能还是因为技术不够熟练的原因。不管了,下面开始本次练习记录。

BOSS选择2

既然上一次选择了史莱姆王作为游戏的第一个BOSS,而且也算是比较容易实现的,这次不妨直接用泰拉瑞亚的第二个BOSS作为小恐龙游戏的第二个boss吧。泰拉瑞亚中一个比较出名的存在--克眼。这一个boss其实有两个阶段,但是我在游戏里只写了一个,感觉第二阶段可以作为别的再写一次。

新敌人:小眼

这次也想之前一样设计了一个新的敌人,因为我发现泰拉瑞亚里面的很多BOSS都会召唤小弟,所以感觉每写一个boss都可以把小弟的内容给写进去,而且把小弟的脚本和BOSS的脚本分开,还可以让小弟作为新的敌人在游戏里生成。

然后就是这个小弟的设计,在原本的游戏里,这个小弟的技能也就一种,朝着玩家冲过去。这个没啥意思,因为我们之前编写的翼龙也会朝玩家冲去。所以我自己把这个小弟设计为,一个阻挠玩家的存在,他不会直接冲向玩家,而是盘绕在玩家周围,在玩家身前或者身后形成一堵墙一样的东西,然后到达位置之后就会自毁,产生爆炸,阻挠玩家躲避BOSS技能的存在。

基本思路是获取玩家的position然后随机获得y轴坐标以及x轴坐标,赋予速度。

关于这个速度,untiy里面的刚体自带了一个velocity的对象,他是一个Vector3类型,可以给对象赋予速度,然后同时在unity里面还存在其他让对象运动的函数,比如Addforce之类的,还有一些特殊的存在比如:MovePosition(),translate()等,后者需要放在update里面每一帧执行,而velocity只需要执行一次,对象就会获得一个恒定的速度。在我安排小弟移动的时候,不小心把rig.velocity = vel*speed;这样的方法放在了update里面使得每一帧都有一个速度,再加上不断判定玩家的位置,导致速度不断叠加,然后使得速度变成无限了。其实主要是speed指数上升了,希望下次不要犯这样的错误。

这是使用的小弟和爆炸图片;

回归正题,按照这样设计之后,获得的代码为:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class littleEyeMove : MonoBehaviour
{
    [Header("Set in Inspector")]
    public GameObject dino;
    public Vector3 dinoPos;
    public Rigidbody rig;//刚体对象
    public float liveTime;//存活时间
    public GameObject explode;//记录一个爆炸的对象
    //设计成一个在某个地方爆破的敌人
    public Vector3 pos;//记录一个位置
    public float timeSummon;//生成时间
    public Vector3 vel;
    // Start is called before the first frame update
    void Start()
    {
        dino = GameObject.Find("dino");//找到恐龙对象
        dinoPos = dino.transform.position;//获取恐龙的基本坐标
        pos= dinoPos;//获取第一个位置
        liveTime = 3f;//存活时间为三秒
        rig = GetComponent<Rigidbody>();//获取刚体对象
        timeSummon = Time.time;//获取初始时间
        int num = Random.Range(0, 2);
        switch (num)//这里是想随机分配位置
        {
            case 0:
                pos.x -= 1f;
                break;
            case 1:
                pos.x += 1f;
                break;
        }
        pos.y += (float)Random.Range(0,2);//获取一个随机y轴位置
        vel = pos - gameObject.transform.position;//获取速度
        vel.Normalize();
        rig.velocity = vel*2f;//给予一个速度
    }

    // Update is called once per frame
    void Update()
    {
        TrackPlayer();//注视玩家
        if (Time.time - timeSummon>=liveTime)//靠近了位置
        {
            rig.velocity = Vector3.zero;//停止移动
            GameObject sm = Instantiate(explode);//生成爆炸的对象
            sm.transform.position = gameObject.transform.position;
            Invoke("Dest", 0.1f);
        }
    }
    //这个代码是在BOSS那里复制过来的,毕竟也是眼珠子
    void TrackPlayer()//眼睛紧跟着玩家
    {
        Vector3 eyePos = gameObject.transform.position;//获取眼睛当前位置
        dinoPos = dino.transform.position;//获取玩家坐标
        float length = (dinoPos - eyePos).magnitude;//获得长度
        float Ang = Mathf.Abs((dinoPos.y - eyePos.y) / length);//获得一个sin值
        float A2 = (Mathf.Asin(Ang) * Mathf.Rad2Deg);//反sin函数加上弧度制获得角度
        if (eyePos.y <= dinoPos.y)//假如在下方
        {
            A2 += 90f;//加上九十度
        }
        //在左边       
        //计算确切角度;
        if (eyePos.y >= dinoPos.y)//在上方需要修改
        {
            A2 = 90f - A2;
        }
        if (eyePos.x <= dinoPos.x)//在左边
        {
            gameObject.transform.rotation = Quaternion.Euler(0, 0, A2);
        }
        else
        {
            gameObject.transform.rotation = Quaternion.Euler(0, 0, -A2);
        }

    }
    void Dest()
    {
        Destroy(gameObject);
    }
}
 

上面那个注视玩家的代码在BOSS设计的时候再解释。 

Boss--克眼

设计这一个boss,我决定给他添加一些有意思的机制,不然也就老三样。这个BOSS在原游戏里面,是一直注释着玩家的,那我也可以通过untiy自带的transform进行旋转。

unity自带的2D其实也是具有z轴的,指向电脑屏幕,因此可以通过绕z轴旋转,达成效果。

下载得到的图片,transform在(0,0,0)状态下,眼睛往下看,那么根据观察得到:

旋转的参考为:当眼在玩家左边时,需要对角度进行加法,在右边则进行减法。然后眼在上边需要对旋转的角加上90度。根据这一个可以直接利用unity自带的反三角函数获得角度,首先可以得到一个sin值,用对边比斜边得到。但是现在又存在一个问题就是,实际上,通过y轴/magitude的绝对值,假如眼在上方,得到的并非为我们所需要的那个角的sin值,因此我们需要用九十度减去这一个角。还有就是Unity的反三角函数计算出来的是弧度制的值需要乘以57.3才可以得到角度。

自此,这一个思路已经完全可以成立

对于看着玩家的代码为:

 void TrackPlayer()//眼睛紧跟着玩家
 {
     Vector3 eyePos = gameObject.transform.position;//获取眼睛当前位置
     dinoPos=dino.transform.position;//获取玩家坐标
     float length = (dinoPos - eyePos).magnitude;//获得长度
     float Ang = Mathf.Abs((dinoPos.y - eyePos.y) / length);//获得一个sin值
     float A2 = (Mathf.Asin(Ang) * Mathf.Rad2Deg);//反sin函数加上弧度制获得角度
     if (eyePos.y <= dinoPos.y)//假如在下方
     {
         A2 += 90f;//加上九十度
     }
     //在左边       
         //计算确切角度;
     if (eyePos.y >= dinoPos.y)//在上方需要修改
     {
         A2 = 90f - A2;
     }
     if (eyePos.x <= dinoPos.x)//在左边
     {
         gameObject.transform.rotation = Quaternion.Euler(0,0,A2);
     }
     else
     {
         gameObject.transform.rotation = Quaternion.Euler(0, 0, -A2);
     }

 }

这样眼珠子就会一直看着玩家了。

下一个设计:

Boss会在不释放技能时盘绕在玩家周围,但是我没有写随机盘绕,我设计为,Boss会在以玩家2x2的范围内的角处停留,玩家移动则跟着移动。 然后释放一次技能之后就会换一个选点继续盘旋。

然后逛完四个点之后重置,同时超出边界自动回到停留点:

大概图示时这样:

差不多就这样然后基本的代码是:

dinoPos = dino.transform.position;//获取主角位置
if (canMove == true)
{
    pos = gameObject.transform.position;
    standNext = dinoPos;
    standNext.x += stanroll[standNum].x; standNext.y += stanroll[standNum].y;
    if ((pos - standNext).magnitude <= 0.1f)//假设两者距离小于0.1
    {
        rig.velocity = Vector3.zero;
        gameObject.transform.position = standNext;
    }
    else
    {
        Vector3 vel = standNext - gameObject.transform.position;
        vel.Normalize();
        rig.velocity = vel * 2f;
    }

}

 private Vector2[] stanroll = new Vector2[]
{
    new Vector2(3f,3f),new Vector2(-3f,3f),new Vector2(-3f,-1f),new Vector2(3f,-1f)
};

上面这个就是四个角的坐标记录,方便使用。

最后攻击方式只写了两个:叫小弟和冲刺,没什么太大的问题,直接上代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class KEyeMove : MonoBehaviour
{
    [Header("Set in Inspector")]
    public GameObject smallEye;//保存小眼珠子的对象
    public Rigidbody rig;//刚体对象
    public GameObject dino;
    public Vector3 dinoPos;
    public Vector3 pos;
    public float timeNow;//记录当前时间
    public float liveTime;//存活时间
    public float timePast;//技能间隔
    public float summonTime;
    public Vector3 standNext;//设立一个位置记录下一个位置
    public Vector3 standPast;//记录上一个位置
    private int roll;//技能使用的色子
    public int standNum = 0;
    private Vector2[] stanroll = new Vector2[]
    {
        new Vector2(3f,3f),new Vector2(-3f,3f),new Vector2(-3f,-1f),new Vector2(3f,-1f)
    };
    public bool canMove;
    private bool isSkill;
    private bool isTrack;
    public Vector3 vel = Vector3.zero;

    // Start is called before the first frame update
    void Start()
    {
        dino = GameObject.Find("dino");
        rig = GetComponent<Rigidbody>();
        timeNow = Time.time;
        summonTime = Time.time;
        liveTime=60f;
        timePast = 3f;//技能间隔为三秒
        standPast = new Vector3(32.25f, 8.17f, 0);
        gameObject.transform.localPosition = standPast;
        standNext = Vector3.zero;
        pos = gameObject.transform.position;//初始化自身位置
        standNum = 0;
        canMove = true;
        isSkill = false;
        isTrack = false;
    }

    // Update is called once per frame
    void Update()
    {
        if (Time.time - summonTime >= liveTime)
        {
            Destroy(gameObject);
        }
        TrackPlayer();
        dinoPos = dino.transform.position;//获取主角位置
        if (canMove == true)
        {
            pos = gameObject.transform.position;
            standNext = dinoPos;
            standNext.x += stanroll[standNum].x; standNext.y += stanroll[standNum].y;
            if ((pos - standNext).magnitude <= 0.1f)//假设两者距离小于0.1
            {
                rig.velocity = Vector3.zero;
                gameObject.transform.position = standNext;
            }
            else
            {
                Vector3 vel = standNext - gameObject.transform.position;
                vel.Normalize();
                rig.velocity = vel * 2f;
            }

        }
        if(Time.time - timeNow >= timePast)//达到了技能释放的时间
        {
            canMove = false;//停止围绕运动
            IsSkill();//更改isskill属性
            //重置时间
            switch(roll)//根据roll进行移动
            {
            case 0:
                    for(int i=0;i<5;i++)//随机生成小弟
                    {
                        GameObject le = Instantiate(smallEye);//实例化小眼珠子
                        Vector3 smPos = gameObject.transform.position;
                        smPos.y += (float)i * 0.2f;//存在间隔
                        le.transform.position = smPos;//生成小眼珠子
                    }
                    canMove = true;//可以移动
                    StandNumplus();//切换跟随地点
                    timeNow = Time.time;
                    roll = Random.Range(0, 2);//随机抽取
                    break;
            case 1:
                    if (isTrack == false)
                    {
                        dinoPos = dino.transform.position;//获取玩家位置
                        standNext = dino.transform.position;
                        vel = dinoPos - gameObject.transform.position;//获取速度位置
                        
                        int num = Random.Range(0,2);
                        switch (num)
                        {
                                case 0:
                                vel.x += 1f;
                                standNext.x += 1f;
                                break;
                                case 1:
                                vel.x -= 1f;
                                standNext.y -= 1f;
                                break;
                                //随机寻找一个坐标,前一点或者后一点
                        }
                        vel.x *= 2f; vel.y *= 2f;//加速
                        rig.velocity = vel;//进行加速
                        isTrack = true;
                    }
                    if(isTrack == true)//假如正在跟踪
                    {
                        Vector3 PPos = gameObject.transform.position;//获取位置
                        if ((gameObject.transform.position - standNext).magnitude <= 0.5f||PPos.x>=32.5f||PPos.x<=18.5f||PPos.y<=1.7f||PPos.y>=10.2f)//已经到达目的地附近
                        {//上面添加了一个判定,为了防止一飞冲天,导致没办法重设的问题
                            rig.velocity = Vector3.zero;//速度归零
                            isTrack = false;
                            StandNumplus();//换取选点
                            timeNow = Time.time;//重置时间
                            canMove = true;//允许移动
                            roll = Random.Range(0, 2);//随机选点
                        }
                       
                    }
                    break;
                    
            }
        }


    }
    void TrackPlayer()//眼睛紧跟着玩家
    {
        Vector3 eyePos = gameObject.transform.position;//获取眼睛当前位置
        dinoPos=dino.transform.position;//获取玩家坐标
        float length = (dinoPos - eyePos).magnitude;//获得长度
        float Ang = Mathf.Abs((dinoPos.y - eyePos.y) / length);//获得一个sin值
        float A2 = (Mathf.Asin(Ang) * Mathf.Rad2Deg);//反sin函数加上弧度制获得角度
        if (eyePos.y <= dinoPos.y)//假如在下方
        {
            A2 += 90f;//加上九十度
        }
        //在左边       
            //计算确切角度;
        if (eyePos.y >= dinoPos.y)//在上方需要修改
        {
            A2 = 90f - A2;
        }
        if (eyePos.x <= dinoPos.x)//在左边
        {
            gameObject.transform.rotation = Quaternion.Euler(0,0,A2);
        }
        else
        {
            gameObject.transform.rotation = Quaternion.Euler(0, 0, -A2);
        }

    }
    void IsSkill()
    {
        isSkill = !isSkill;//更改释放技能属性
    }
    void StandNumplus()
    {
        if (standNum >= 3)
        {
            standNum = 0;
        }
        else
        {
            standNum ++;
        }
    }
}
 

以上就是这一个BOSS的设计了,其实也是比较简单的设计,不过感觉还可以。

以下为添加之后的游戏实例图:

 

结语

这此这个练习就到此为此啦,我还会继续添加更多的内容,丰富自己的 代码经验,提高能力,谢谢大家!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值