今天,又是充满希望的一天!

UnitySir - 00007-1_增加简陋的怪物控制器

Posted on By Zj

需要实现功能

//怪物控制必须要有以下几个条件 : //怪物需要实时计算与主角的距离: //1.主角进入了怪物的检测区 (范围 = (25)) //此时怪物会向主角移动,播放移动动画 //2.怪物的攻击区 (范围 = (1.8)) //当角色进入怪物的攻击区,怪物才会攻击,此时播放攻击动画 //3.怪兽死亡 //当怪物血量低于0时,播放死亡动画 //4.主角退出了怪物的检测区 (范围 = (25)) //此时怪物会回到生成区

首先完成 1,2,4 点,怪物死亡放在后面增加

知识点

CharacterController角色控制器组件的使用

public CollisionFlags Move (Vector3 motion);

移动该角色

public static float Distance (Vector3 a, Vector3 b);

返回 ab 之间的距离。


完整代码

MonsterCheckPlayer

using UnityEngine;

/// <summary>
/// 怪物检测玩家脚本
/// </summary>
public class MonsterCheckPlayer : MonoBehaviour
{
    //检测条件:
    //1.需要实时计算与主角的距离
    //2.需要用主角的位置 - 怪物的位置 ,此时怪物才能看向主角

    /// <summary>
    /// 主角实时位置
    /// </summary>
    [Header("主角位置")] [SerializeField] private Vector3 playerPos = Vector3.zero;

    [Header("怪物位置")] [SerializeField] private Vector3 monsterPos = Vector3.zero;

    [Header("主角与怪物的距离")] [SerializeField] private float distance;

    [Header("角色是否进入怪物检测区")] [SerializeField]
    private bool isInCheck;

    private void Awake()
    {
        monsterPos = transform.position;
    }

    private void Start()
    {
        SimpleMsgMechanism.ReceiveMsg("PlayerCurrentPos", objects =>
        {
            //实时获取主角位置
            playerPos = (Vector3) objects[0];
        });
    }

    private void Update()
    {
        //获取怪物的实时位置
        monsterPos = transform.position;
        //如果 distance 小于25 ,则进入检测区
        distance = Vector3.Distance(playerPos, monsterPos);
        isInCheck = distance < 25f;

        //是否进入检测区
        SimpleMsgMechanism.SendMsg("PlayerIsInMonsterCheck", isInCheck, playerPos,monsterPos);
    }
}

MonsterCtrl

using UnityEngine;

public class MonsterCtrl : MonoBehaviour
{
    [SerializeField] private CharacterController monsterController;

    [Header("是否进入怪物检测区")] [SerializeField] private bool isInCheck;

    [Header("怪物的出生点位置")] [SerializeField] private Vector3 monsterBronPointPos = Vector3.zero;

    [Header("怪物的位置")] [SerializeField] private Vector3 monsterPos = Vector3.zero;

    [Header("怪物是否移动")] [SerializeField] private bool isMove;
    [Header("怪物是否开始攻击")] [SerializeField] private bool isAttack;
    [Header("怪物是否死亡")] [SerializeField] private bool isDeath;

    [Header("主角当前的位置")] [SerializeField] private Vector3 playerPos = Vector3.zero;

    //怪物控制必须要有以下几个条件 :
        //怪物需要实时计算与主角的距离:
            //1.主角进入了怪物的检测区 (范围 = (25))
                //此时怪物会向主角移动,播放移动动画
            //2.怪物的攻击区 (范围 = (1.8))
                //当角色进入怪物的攻击区,怪物才会攻击,此时播放攻击动画
            //3.怪兽死亡
                //当怪物血量低于0时,播放死亡动画
            //4.主角退出了怪物的检测区 (范围 = (25))
                //此时怪物会回到生成区
    private void Awake()
    {
        monsterController = GetComponent<CharacterController>();
        monsterPos = transform.position;
    }

    private void Start()
    {
        monsterBronPointPos = transform.position; //获取出生点
        SimpleMsgMechanism.ReceiveMsg("PlayerIsInMonsterCheck", objects =>
        {
            isInCheck = (bool) objects[0]; //是否进入检测区
            playerPos = (Vector3) objects[1]; //主角实时位置
            monsterPos = (Vector3) objects[2]; //怪物的实时位置

            Debug.DrawLine(playerPos, monsterBronPointPos);
        });
    }

    private void Update()
    {
        if (isInCheck)
        {
            //如果角色进入检测区,怪物实时看着主角并向主角移动
            //实时看着主角
            transform.LookAt(playerPos);
            //获取主角与怪物之间的距离
            var distance = Vector3.Distance(playerPos, monsterPos);
            //获取主角和怪物之间的偏移
            var offset = (playerPos - monsterPos);
            //如果怪物没有接触地面
            if (!monsterController.isGrounded)
            {
                //应用重力。
                offset.y -= 20f * Time.deltaTime;
            }

            if (distance > 1.8f)
            {
                //当主角和怪物之间的的距离大于 0.1 时 ,怪物就向主角移动
                //获取到目标方向
                offset = offset.normalized * 1.2f;
                //移动到目标点
                monsterController.Move(offset * Time.deltaTime);
                isMove = true; //移动
            }
            else
            {
                //当检车到主角时,如果和主角的距离小于等于2,则开始攻击
                isMove = false;
            }
        }
        else
        {
            //如果主角退出检测区,怪物就回到出生点
            isAttack = false;
            //怪物要实时看着出生点
            transform.LookAt(monsterBronPointPos);
            //获取出生点与怪物之间的距离
            var distance = Vector3.Distance(monsterBronPointPos, monsterPos);
            //获取出生点和怪物之间的偏移
            var offset = (monsterBronPointPos - monsterPos);

            if (!monsterController.isGrounded)
            {
                //应用重力。
                offset.y -= 20f * Time.deltaTime;
            }

            if (distance > 1f)
            {
                //获取到目标方向
                offset = offset.normalized * 1.5f;
                //移动到目标点
                monsterController.Move(offset * Time.deltaTime);
                isMove = true; //移动
            }
            else
            {
                isMove = false;
            }
        }
        //发送当前怪物的移动状态,从而播放对应的动画
        SimpleMsgMechanism.SendMsg("MonsterIsMove", isMove);
    }
}

MonsterAni

using UnityEngine;

public class MonsterAni : MonoBehaviour
{
    [SerializeField] private Animator _animator;

    private void Awake()
    {
        _animator = GameObject.Find("Monster1/Monster1").GetComponent<Animator>();
    }

    private void Start()
    {
        SimpleMsgMechanism.ReceiveMsg("MonsterIsMove", objects =>
        {
            bool isMove = (bool) objects[0];
            _animator.SetInteger("move", isMove ? 1 : 0);
        });
    }
}

这里只实现了怪物的移动,攻击死亡还没有实现


参考链接

CharacterController平滑移动到某点


如果内容对你有所帮助:

UnitySir (bilibili)

B站ID:UnitySir