天天看點

Unity(3)-“英雄無敵”敵人+敵人生成器子產品

B站Unity學習筆記

連結:https://www.bilibili.com/video/BV12s411g7gU

Unity(3)-“英雄無敵”敵人+敵人生成器子產品

敵人

策劃
Unity(3)-“英雄無敵”敵人+敵人生成器子產品
需求分析
Unity(3)-“英雄無敵”敵人+敵人生成器子產品

代碼實作

  1. 敵人馬達EnemyMotorEnemyMotor類

    -定義朝向目标點旋轉的方法

    -定義尋路的方法

    -定義向前移動的方法

/// <summary>
/// 敵人馬達類
/// 提供移動、旋轉、尋路功能
/// </summary>
public class EnemyMotor : MonoBehaviour
{
    public WayLine line;
    //目前路點的索引預設是0
    private int currentPointIndex;
    public float moveSpeed = 5;
   /// <summary>
   /// 向前移動
   /// </summary>
   public void MovementForward()
    {
        this.transform.Translate(0,0,moveSpeed*Time.deltaTime);
    }

   /// <summary>
   /// 注視旋轉
   /// </summary>
   /// <param name="point">需要注視的目标點</param>
    public void LookRotation(Vector3 targetPoint)
    {
        //目前物體注視目标點旋轉
        this.transform.LookAt(targetPoint);
    }

    /// <summary>
    /// 尋路,沿路線(Vector3[])移動
    /// </summary>
    /// <returns>傳回尋路結果</returns>
    public bool Pathfinding()
    {
        //return false; 到達終點,無需尋路
        //return true;  需要尋路

        if (line.WayPoints == null ||currentPointIndex>= line.WayPoints.Length) return false;

        //如果到達目标點(判斷 目前位置 和 目标點之間的距離(Vector3.Distance))
        //更新目标點(向下一個路點移動)

        //朝向目标點
        LookRotation(line.WayPoints[currentPointIndex]);
        //向前移動
        MovementForward();
        if (Vector3.Distance(this.transform.position, line.WayPoints[currentPointIndex])<0.1f)
        {
            currentPointIndex++;
        }
        return true;
}

           

2.敵人狀态資訊EnemyStatusInfo類

  • 定義變量:目前生命值,目前生命值
  • 定義方法:受傷,死亡。
/// <summary>
/// 敵人狀态資訊
/// 定義敵人資訊,提供受傷、死亡功能;
/// </summary>
public class EnemyStatusInfo : MonoBehaviour
{
    public EnemySpawn spawn;
    //目前血量
    public float enemyHP = 200;
    //最大血量
    public float maxHP = 200;

    /// <summary>
    /// 受傷
    /// </summary>
    /// <param name="amount">需要扣除的血量</param>
    public void Damage(float amount)
    {
        //扣血
        enemyHP -= amount;
        //血量為0時,調用死亡方法
        if (enemyHP <= 0)
        {
            Deadth();
        }
    }

    //延遲銷毀時間
    public float deathDelay = 5;

    /// <summary>
    /// 死亡
    /// </summary>
    public void Deadth()
    {
        //播放死亡動畫
        var anim = GetComponent<EnemyAnimation>();
        anim.action.Playing(anim.deathAnimName);

        //銷毀目前物體
        Destroy(this.gameObject,deathDelay);
        Debug.Log("我死了");

        //設定路線狀态
        GetComponent<EnemyMotor>().line.IsUsable = true;

        //産生下一個敵人
        spawn.GenerateEnemy();
    }
    
}

           

3.敵人動畫EnemyAnimation類

  • 定義各種動畫名稱的變量,如跑步、閑置、攻擊。
  • 定義AnimationAction類,提供有關動畫的行為。
/// <summary>
/// 敵人動畫
/// 定義需要播放的動畫名稱
/// </summary>
public class EnemyAnimation : MonoBehaviour
{
    //跑步動畫名稱
    public string runAnimName;
    //攻擊動畫名稱
    public string attackAnimName;
    //閑置動畫名稱
    public string idleAnimName;
    //死亡動畫名稱
    public string deathAnimName;

    //行為類
    public AnimationAction action;

    public void Awake()
    {
        action = new AnimationAction(GetComponentInChildren<Animation>());
    }
}
           

4.動畫行為類 AnimationAction

/// <summary>
/// 動畫行為類
/// 提供有關動畫的行為
/// </summary>
public class AnimationAction
{

    //附加在敵人模型上的動畫元件引用
    private Animation anim;

    /// <summary>
    /// 建立動畫行為類
    /// </summary>
    /// <param name="anim">附加在敵人模型上的動畫元件引用</param>
    public AnimationAction(Animation anim)
    {
        this.anim = anim;
    }

   /// <summary>
   /// 播放動畫
   /// </summary>
   /// <param name="animName">需要播放動畫的名稱</param>
    public void Playing(string animName)
    {
        anim.CrossFade(animName);
    }

    /// <summary>
    /// 判斷指定動畫是否在播放
    /// </summary>
    /// <param name="animName">動畫名稱</param>
    /// <returns></returns>
    public bool IsPlaying(string animName)
    {
        return anim.IsPlaying(animName);
    }

}

           

5.敵人人工智能EnemyAI

  • 擷取[敵人馬達、敵人動畫]腳本對象引用。
  • 定義枚舉:敵人狀态State
  • 每幀根據狀态,執行尋路或攻擊
/// <summary>
/// 敵人AI
/// </summary>
[RequireComponent(typeof(EnemyAnimation))]
[RequireComponent(typeof(EnemyMotor))]
[RequireComponent(typeof(EnemyStatusInfo))]

public class EnemyAI : MonoBehaviour
{
    //定義敵人狀态的枚舉類型
    public enum State
    {
        Attack,   //攻擊狀态
        Pathfinding  //尋路狀态
    }

    private State currentState = State.Pathfinding;
    private EnemyAnimation anim;
    private EnemyMotor motor;

    private void Start()
    {
        anim = GetComponent<EnemyAnimation>();
        motor = GetComponent<EnemyMotor>();
    }

    //攻擊計時器
    private float atkTimer;
    //攻擊間隔
    private float atkInterval = 2;

    private void Update()
    {
        //判斷
        switch (currentState)
        {
            case State.Pathfinding:
                Pathfinding();
                break;
            case State.Attack:
                Attack();
                break;
        }
        
        
    }

    private void Pathfinding()
    {
        //播放跑步動畫
        anim.action.Playing(anim.runAnimName);
        //執行尋路 調用motor類中的尋路方法 
        //如果尋路結束,修改狀态為攻擊
        if (motor.Pathfinding() == false) { currentState = State.Attack; };
    }

    private void Attack()
    {
        //如果攻擊動畫沒有播放
        if (anim.action.IsPlaying(anim.attackAnimName) == false)
        {
            //播放閑置動畫
            anim.action.Playing(anim.idleAnimName);
        }
           

        if (atkTimer <= Time.time)
        {
            //執行攻擊 
            //播放攻擊動畫
            anim.action.Playing(anim.attackAnimName);
            atkTimer = Time.time + atkInterval;
        }
    }
}
           

敵人生成器

策劃
Unity(3)-“英雄無敵”敵人+敵人生成器子產品
需求分析
Unity(3)-“英雄無敵”敵人+敵人生成器子產品

1.敵人生成器EnemySpawn類

  • 定義變量

    WayLine[] lines用于存儲所有路線

    GameObject[] enemyTyoes用于記錄敵人預制件

    int startCount 用于記錄開始時需要建立的敵人數量

    int spawnedCount 用于記錄已經産生的敵人數量

    int maxCount 用于記錄産生敵人數量的上限

    int maxDelay 用于記錄産生敵人的最大延遲時間

  • 定義方法

    CalculateWayLines() 用于計算所有路線及坐标

    GenerateEnemy(),用于生成一個敵人

/// <summary>
/// 敵人生成器
/// </summary>
public class EnemySpawn : MonoBehaviour
{
    public GameObject[] enemyType;
    //需要建立的敵人最大數目
    public int maxCount = 5;
    //開始同時建立的敵人數目
    public int startCount = 2;
    //已經建立的敵人數量
    private int spawnedCount;
    public int maxDelay = 10;

    /// <summary>
    /// 生成一個敵人
    /// </summary>
    public void GenerateEnemy()
    {
        spawnedCount++;
        if (spawnedCount>=maxCount)
        {
            return;
        }
        //延遲時間随機

        Invoke("CreateEnemy",Random.Range(1,maxDelay));

    }

    private void CreateEnemy()
    {
        //選擇一條可以使用的路線
        //選擇所有可以使用的路線
        WayLine[] usableWayLines = SelectUsableWayLine();
        //随機選擇一條
        WayLine line = usableWayLines[Random.Range(0, usableWayLines.Length)];

        int randomIndex = Random.Range(0, enemyType.Length);
        //建立敵人
        //Instantiate(敵人預制件,位置,旋轉角度);
        GameObject go = Instantiate(enemyType[randomIndex], line.WayPoints[0], Quaternion.identity) as GameObject;

        //配置資訊
        EnemyMotor motor = go.GetComponent<EnemyMotor>();
        motor.line = line;
        line.IsUsable = false;  //不可以使用
        //傳遞生成器對象引用[建議使用委托代替]
        go.GetComponent<EnemyStatusInfo>().spawn = this;
    }

    private void Start()
    {
        CalculateWaylines();
    }

    private  WayLine[] lines;

    private void CalculateWaylines()
    {
        //路線數組
        lines = new WayLine[this.transform.childCount];
        for (int i = 0; i < lines.Length; i++)
        {
            //每一個路線
            //路線變換元件的引用
            Transform wayLineTF = this.transform.GetChild(i);
            //路點數量
            int count = wayLineTF.childCount;
            //建立路線對象
            lines[i] = new WayLine(count);
            lines[i].IsUsable = true;
            //建立路點數組對象
            lines[i].WayPoints = new Vector3[count];
            for (int pointIndex = 0; pointIndex < count; pointIndex++)
            {
                lines[i].WayPoints[pointIndex] = wayLineTF.GetChild(pointIndex).position;
            }
        }
    }

    /// <summary>
    /// 選擇所有可以使用的路線
    /// </summary>
    /// <returns></returns>
    private WayLine[] SelectUsableWayLine()
    {
        List<WayLine> result = new List<WayLine>(lines.Length);
        //周遊所有路線
        foreach (var item in lines)
        {
            //如果可以使用,添加到result中
            if (item.IsUsable) result.Add(item);
        }
        return result.ToArray();
    }

}

           

2.Wayline類

public class WayLine
{
    /// <summary>
    /// 目前路線所有路點坐标
    /// </summary>
   public Vector3[] WayPoints { get; set; }

    /// <summary>
    /// 是否可用
    /// </summary>
   public bool IsUsable { get; set; }

   public WayLine(int wayPointCount)
    {
        WayPoints = new Vector3[wayPointCount];
        IsUsable = true;
    }

}