07 (难)敌人逻辑/马达、动画、状态、AI

需求分析:
创建脚本--敌人马达 EnemyMotor,提供移动、旋转、寻路功能
创建脚本--敌人状态信息 EnemyStatusInfo,定义血量,提供受伤、死亡功能
创建脚本-敌人动画 EnemyAnimation,定义各种动画名称,提供播放动画的功能
创建脚本--敌人AI EnemyAI ,通过判断状态,执行寻路或攻击
创建脚本--敌人生成器EnemySpawn,附加到根路线中,提供生成敌人的功能。
创建类--路线 WayLine,包含路点坐标Vector3[] Points,是否可用bool IsUseable
动画行为控制类AnimationAction负责控制动画行为
最终实现,自动生成敌人,敌人沿着指定路线运动并播放动画
EnemyMotor    敌人马达
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///<summary>
///敌人马达、提供移动、旋转、寻路功能
///</summary>
public class EnemyMotor : MonoBehaviour
{
    public WayLine line;
    private int currentPointIndex;
    public float moveSpeed = 5;
    public void MovementForward()
    {
        this.transform.Translate(0, 0, moveSpeed*Time.deltaTime);
    }
    public void LookRotation(Vector3 targetPoint)
    {
        //面朝目标点
        this.transform.LookAt(targetPoint); 
    }
    public bool PathFinding()
    {
        if (line.WayPoints==null||currentPointIndex >= line.WayPoints.Length) return false;
        //return false;到达终点
        //如果到达目标点 更新目标点(向下一个路点移动) 判断间距Vector3.Distance
        //朝向目标点移动
        LookRotation(line.WayPoints[currentPointIndex]);
        MovementForward();
        //如果到达目标,index++
        if (Vector3.Distance(this.transform.position, line.WayPoints[currentPointIndex]) < 0.5f)
        {
            currentPointIndex++;
        }
        return true;//可以继续寻路
    }
}
EnemyStatusInfo  敌人状态信息类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///<summary>
///
///</summary>
public class EnemyStatusInfo : MonoBehaviour
{
    public float HP = 200;
    public float maxHP = 200;
    //受伤减血amount
    public void Damage(float amount)
    {
        //血量为0时调用死亡方法
        HP -= amount;
        if (HP <= 0) Death();
    }
    public void Death()
    {
        //播放死亡动画
        //销毁物体
        Debug.Log("挂了");
        Destroy(this.gameObject);
    }
}
EnemyAnimation   动画入口信息
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///<summary>
///动画入口动画名Model+Action实例
///</summary>
public class EnemyAnimation : MonoBehaviour
{
    public string runAnimName;
    public string attackAnimName;
    public string idleAnimName;
    public string deathAnimName;

    //行为类
    public AnimationAction action;

    private void Awake()
    {
       action = new AnimationAction(GetComponent<Animation>());
    }
}
AnimationAction 动画行为控制类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///<summary>
///创建动画行为类Controller
///</summary>
public class AnimationAction
{
    //附加在敌人模型上的动画组件引用
    private Animation anim;
    public AnimationAction(Animation anim)
    {
        this.anim = anim;
    }
    //播放动画
    public void Play(string animName)
    {
        anim.CrossFade(animName);
    }
    public bool IsPlaying(string animName)
    {
        return anim.IsPlaying(animName);
    }
}
EnemyAI 敌人AI,核心处理器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///<summary>
///
///</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;
    public float atkInterval = 1;
    private void Update()
    {
        //判断
        //执行寻路
        //执行攻击
        switch (currentState)
        {
            case State.PathFinding:
                PathFinding();
                break;
            case State.Attack:
                Attack();
                break;
        }
    }

    private void PathFinding()
    {
        //执行寻路 调用motor中寻路方法 播放跑步动画
        //如果寻路结束,修改状态为攻击
        if (motor.PathFinding() == false)
        {
            currentState = State.Attack;
        }
        anim.action.Play(anim.runAnimName);
    }

    private void Attack()
    {
        if (!anim.action.IsPlaying(anim.attackAnimName))
        {
            Debug.Log("闲置中");
        }
        if (atkTimer <= Time.time)
        {
            anim.action.Play(anim.attackAnimName);
            atkTimer = Time.time + atkInterval;
        }
        //发起攻击 执行攻击动画
    }
}
WayLine 路线类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///<summary>
///路线Model类
///</summary>
public class WayLine
{
    public Vector3[] WayPoints { get; set;}
    //路线是否可用
    public bool IsUsable { get; set; }
    public WayLine(int wayPoingCount)
    {
        WayPoints = new Vector3[wayPoingCount];
        IsUsable = true;
    }
}
EnemySpawn 敌人生成器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///<summary>
///
///</summary>
public class EnemySpawn : MonoBehaviour
{
    public GameObject[] enemyType;
    //创建敌人最大数目
    public int maxCount = 5;
    //开始同时创建的敌人数目
    public int startCount = 1;
    //已经创建敌人数目
    private int spawnedCount;
    private WayLine[] lines;

    private void Start()
    {
        CalculateWayLines();
        for(int i = 0; i < startCount; i++)
        {
            GenerateEnemy();
        }

    }
    private void CalculateWayLines()
    {
        lines = new WayLine[this.transform.childCount];
        for (int i = 0; i < lines.Length; i++)
        {
            //每一个路线
            //路线变换组件引用 
            Transform wayLineTF = this.transform.GetChild(i);
            lines[i] = new WayLine(wayLineTF.childCount);
            for (int pointIndex = 0; pointIndex < wayLineTF.childCount; pointIndex++)
            {
                lines[i].WayPoints[pointIndex] = wayLineTF.GetChild(pointIndex).position;
            }
        }
    }
    public void GenerateEnemy()
    {        //延迟时间随机?
        Invoke("CreateEnemy",3);
    }

    private void CreateEnemy()
    {
        //选择一条可以使用的路线?
        WayLine[] usableWayLines = SelectUsableWayLine();
        WayLine line = usableWayLines[Random.Range(0, usableWayLines.Length)];
        //Instantiate(敌人预制件、位置、旋转角度);
        int randomIndex = Random.Range(0, enemyType.Length);
        //创建随机的敌人,位置为路线的第一个路点,不旋转
        GameObject go = Instantiate(enemyType[0], line.WayPoints[0], Quaternion.identity) as GameObject;
        //配置信息
        EnemyMotor motor = go.GetComponent<EnemyMotor>();
        motor.line = line;
        line.IsUsable = false;
    }

    //得到所有可用的路线
    private WayLine[] SelectUsableWayLine()
    {
        List<WayLine> result = new List<WayLine>();
        foreach (var item in lines)
        {
            if (item.IsUsable) result.Add(item);
        }
        return result.ToArray();
    }
}