实现距离50米内,怪物自动追踪人物

知识点

  • 向量减法及其应用

  • 向量归一化原理

  • 向量点乘的几何意义

  • 向量叉乘的特性

  • 向量距离计算

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class MonsterAI : MonoBehaviour
{
    // 复习一下向量的减法,实现怪物朝向人移动
    //【触发】人物距离怪物50米内  【执行】怪物朝向人的方向移动

    public Transform PlayerTran;      // 存储游戏主角的Transform组件
    public Transform MosnsterTran;    // 存储单个怪物的Transform组件(可能是用于测试或特定怪物)

    GameObject[] MonsterTran;         // 存储所有带有"Monster"标签的怪物对象数组

    public float MoveDirSeed = 10f;   // 怪物的移动速度

    private void Start()
    {
        // 在游戏开始时,查找场景中所有带有"Monster"标签的游戏对象
        MonsterTran = GameObject.FindGameObjectsWithTag("Monster");
    }

    // Update is called once per frame
    void Update()
    {
        // 每帧更新怪物移动逻辑
        MonsterMove();

        // 计算并显示怪物与玩家之间的距离
        VectorDistance();
       
        // 计算法线向量并绘制调试射线
        // 法线向量垂直于怪物到玩家的向量和玩家前方向量的平面
        Vector3 Normal = NormalLine(MosnsterTran.position - PlayerTran.position, PlayerTran.forward);
        // 绘制红色射线表示法线方向
        Debug.DrawRay(PlayerTran.position, Normal * 100, Color.red);
        // 绘制玩家前方方向的射线
        Debug.DrawRay(PlayerTran.position, PlayerTran.forward * 100);
    }

    /// <summary>
    /// 这个函数实现怪物追踪人去移动,且判断怪物在人的方位,用到了向量的减法和点乘
    /// 功能:控制所有怪物向玩家移动,并判断怪物相对于玩家的方位
    /// </summary>
    void MonsterMove()
    {
        #region 怪物移动和方位判断区域
        // 遍历所有怪物对象
        for (int i = 0; i < MonsterTran.Length; i++)
        {
            // 检查怪物对象是否存在
            if (MonsterTran[i] != null)
            {
                // 计算从怪物指向玩家的方向向量(向量减法:终点-起点)
                Vector3 MoveDir = PlayerTran.position - MonsterTran[i].transform.position;
                // 计算从玩家指向怪物的方向向量
                Vector3 ForwordDir = MonsterTran[i].transform.position - PlayerTran.position;

                // 检查怪物与玩家之间的距离是否在50单位内
                if (MoveDir.magnitude <= 50)
                {
                    // 如果距离在范围内,让怪物向玩家方向移动
                    // Vector3.Normalize将方向向量转换为单位向量,保持方向但长度为1
                    // Time.deltaTime使移动与帧率无关
                    MonsterTran[i].transform.Translate(Vector3.Normalize(MoveDir) * MoveDirSeed * Time.deltaTime);
                }

                // ============= 下面是判断怪物是否在人物前后方 =============
                // 使用点乘判断两个向量的方向关系:
                // 点乘 > 0: 两个向量方向基本相同(夹角小于90度)
                // 点乘 = 0: 两个向量垂直(夹角等于90度)
                // 点乘 < 0: 两个向量方向基本相反(夹角大于90度)

                // 计算玩家前方方向与指向怪物方向的点乘值
                if (Vector3.Dot(PlayerTran.forward, ForwordDir.normalized) > 0)
                {
                    // 点乘大于0,说明怪物在玩家前方
                    Debug.Log("怪物在你的前方,他叫+" + MonsterTran[i]);
                }
                else if (Vector3.Dot(PlayerTran.forward, ForwordDir.normalized) == 0)
                {
                    // 点乘等于0,说明怪物在玩家正侧面
                    Debug.Log("怪物在你的正侧面,他叫+" + MonsterTran[i]);
                }
                else
                {
                    // 点乘小于0,说明怪物在玩家后方
                    Debug.Log("怪物在你的后方,他叫+" + MonsterTran[i]);
                }
            }
        }
        #endregion
    }

    /// <summary>
    /// 计算并显示单个怪物与玩家之间的距离
    /// 功能:计算MosnsterTran指向的怪物与玩家之间的距离,并绘制连线
    /// </summary>
    void VectorDistance()
    {
        // 计算两个点之间的直线距离
        float distan = Vector3.Distance(MosnsterTran.position, PlayerTran.position);
        // 在场景中绘制从怪物位置到玩家位置的连线(在Scene视图中可见)
        Debug.DrawLine(MosnsterTran.position, PlayerTran.position);
        // 在控制台输出距离信息
        Debug.Log("距离是" + distan);
    }

    /// <summary>
    /// 计算两个向量的叉积,得到垂直于这两个向量的法线向量
    /// 功能:计算向量A和向量B的叉积,返回法线向量
    /// </summary>
    /// <param name="A">第一个输入向量</param>
    /// <param name="B">第二个输入向量</param>
    /// <returns>返回垂直于A和B的法线向量</returns>
    public Vector3 NormalLine(Vector3 A, Vector3 B)
    {
        // Vector3.Cross计算两个向量的叉积
        // 结果向量同时垂直于输入的两个向量
        return Vector3.Cross(A, B);
    }
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Unity青子

难题的解决使成本节约,求打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值