唐氏综合症是什么原因| 水痘长什么样| 厚子鱼是什么鱼| 什么是肠胃炎| 鳞状上皮是什么意思| 肝功能查什么| 惊蛰什么意思| 银手镯为什么会变黑| 初一的月亮是什么形状| 窦房结内游走性心律是什么意思| 荞麦枕头有什么好处| 爱情是什么颜色的| 开宠物医院需要什么条件| 警犬都是什么品种| 意志力什么意思| 湿气重挂什么科| 棍子鱼又叫什么鱼| 喝酒后吃什么解酒最快| 左腹部是什么器官| zara是什么牌子| 信必可为什么轻微哮喘不能用| 蛇生肖和什么生肖相配| 总胆固醇偏高是什么原因| 什么年什么月| 哺乳期吃辣椒对宝宝有什么影响| 尿隐血3十是什么病| 梦见死猪是什么意思| 什么的礼物| 天台是什么意思| 木驴是什么| 梦到男朋友出轨了预示什么意思| flour什么意思| 贫血严重会导致什么后果| 94属什么生肖| 电器火灾用什么灭火器| 什么玉最值钱| 睾丸皮痒用什么药膏| 撑台脚是什么意思| 唐僧是什么佛| 胃胀吃什么中成药| 梦见红薯是什么意思| 孙子兵法到底说什么| 巨蟹什么象星座| 12月24是什么星座| 出火是什么意思| 雌二醇测定是什么检查| 小孩肚脐眼上面疼是什么原因| ykk是什么牌子| 肾炎吃什么药好| 一个永一个日念什么| 一个火一个宣念什么| 小翅膀车标是什么车| ckd医学上是什么意思| 小孩急性肠胃炎吃什么药| 释迦牟尼是什么意思| innisfree是什么牌子的化妆品| 妇科检查清洁度3度什么意思| 头皮一阵一阵发麻是什么原因| 怀孕分泌物是什么样的| 悬是什么意思| aoc是什么牌子| 马蜂蛰了用什么药| 查激素水平挂什么科| 06年属什么| 狗狗身上有皮肤病用什么药| 榴莲的寓意是什么意思| 固本培元是什么意思| hpv是指什么| 一什么而入| 是什么有什么| 弹力棉是什么面料| am和pm是什么意思| 月字旁的字与什么有关| nacl是什么| 好老公的标准是什么| 甲胄是什么意思| 胎位lop是什么意思| 尿胆原norm是什么意思| 往返是什么意思| 五月23是什么星座| 尿里带血是什么原因女性| 80岁是什么之年| 有点想吐是什么原因| 96年属什么命| 湿疹和荨麻疹有什么区别| 世界第一大河是什么河| 肠镜什么情况下取活检| 荣辱与共是什么意思| 为什么会脱发| 手指肿胀什么原因| 忍者神龟是什么意思| 情人什么意思| 摩羯是什么星座| 平身是什么意思| 射精出血吃什么药最好| 唱歌有什么好处| 前列腺素是什么| 黑道日为什么还是吉日| 火水是什么| 微信中抱拳是什么意思| 近亲结婚生的孩子会得什么病| 骨折吃什么补品| 女性甲状腺挂什么科| 力不到不为财是什么意思| 肝看什么科| 得令是什么意思| 海柳什么颜色最贵的| 厨子什么意思| 团委书记是什么级别| 缘故的故是什么意思| 牙周康又叫什么名字| 高三学生吃什么补脑抗疲劳| 胃肠感冒可以吃什么水果| 渗透压是什么| 鱼泡是鱼的什么器官| 月经期肚子疼是什么原因| 白带清洁度lv是什么意思| 常青藤是什么意思| 男性尿分叉是什么原因| 7大营养素是什么| 霉菌阳性是什么意思| 脂肪疝是什么病| 脾虚湿蕴证是什么意思| 深圳副市长什么级别| 什么是质子| 梦到吃螃蟹是什么意思| 草单斤是什么字| 宫颈肥大是什么原因| 腊月初四是什么星座| 心悸心慌吃什么药最好| 上校是什么级别| 魏大勋什么星座| 肝脏钙化灶什么意思| 孩子肚子疼挂什么科| 荷花鱼是什么鱼| 糖尿病人吃什么水果好| 脱臼是什么感觉| 榴莲和什么食物相克| 十全十美指什么生肖| 痱子是什么样的图片| 心脏支架不能吃什么| menu是什么意思| 促排卵是什么意思| 黑裙配什么颜色的上衣| 过什么意思| 乳头瘤病毒是什么意思| 地球是什么形状的| 包二奶是什么意思| 传说中的狮身人面像叫什么名字| 肾结石吃什么比较好| 什么牌子的指甲油好| 124是什么意思| 一个金字旁一个各念什么| 菊花什么颜色| 咽喉炎吃什么药好| 邮政编码有什么用| 1973年是什么命| 蛊虫是什么| 阳气最强的树是什么树| 摩羯座是什么动物| 氯雷他定有什么副作用| 肺肿瘤有什么症状| 慢性盆腔炎吃什么药效果好| 嗓子疼吃什么水果好| 猛虎下山是什么生肖| 尿酸520属于什么水平| 不孕不育有什么症状女| 号外是什么意思| 淋巴结节挂什么科| 总是很困想睡觉是什么原因| 喝茶喝多了有什么坏处| 炖大骨头放什么调料| 结甲是什么病| 胰岛素有什么副作用| 什么是干咳| 女人脾虚吃什么最好| 医生停诊是什么意思| 为什么老是肚子疼| 车前草治什么病最好| 脾虚湿盛吃什么药| 7月17日是什么日子| 临终关怀的目的是什么| 努力的意义是什么| 排斥一个人什么意思| pid是什么| 佰草集属于什么档次| 子宫形态不规则是什么意思| 什么一刻值千金花有清香月有阴| 康复治疗学是做什么的| 裸贷是什么意思| 全身冰凉是什么原因| b型血和o型血生的孩子是什么血型| 恩师是什么意思| 不打紧是什么意思| sid是什么| 凌晨3点多是什么时辰| 天天想睡觉没精神是什么原因| 胆固醇高是什么引起的| 意气用事是什么意思| 嗔恨是什么意思| 寝不言食不语什么意思| 白月光是什么意思| 闫和阎有什么区别| 补气吃什么| 攒局什么意思| 门第是什么意思| 口干口苦挂什么科| 包皮脱皮是什么原因| 42属什么| 上军校需要什么条件| 国药准字h代表什么| 脖子肿了是什么原因| 脸书是什么| 高兴的什么| 葡萄胎有什么症状反应| 吃鹅蛋对孕妇有什么好处| 什么叫语言障碍| 湿热吃什么食物好| 日语一个一个是什么意思| 萝卜喝醉了会变成什么| 左脸颊长痘是什么原因| 为什么要拔掉智齿| 本能反应是什么意思| 什么是法西斯主义| 女生生日送什么礼物好| 八月份是什么季节| 白细胞少了会得什么病| 缺镁吃什么食物补充最快| 缺少维生素有什么症状| 六级什么时候考| 鼻塞吃什么药| 男人都是大猪蹄子是什么意思| 这个季节吃什么水果| 重度肠化是什么意思| 腰肌劳损是什么原因引起的| 肝的作用和功能是什么| 隐情是什么意思| 舌苔白厚腻吃什么药| 脚底板脱皮是什么原因| 疯狂动物城狐狸叫什么| 血压低头疼是什么原因| 忘乎所以是什么意思| 褪黑素有什么作用| 长结节是什么原因造成的| 订盟是什么意思| 碱性磷酸酶偏高是什么原因| 森达属于什么档次的鞋| 走路快的人是什么性格| 盆腔炎吃什么药最有效| 师长是什么军衔| 什么邮箱最好用最安全| 征兵初检检查什么| 血压高查什么项目| 2015年属什么| 血小板计数偏高是什么原因| 小气道病变是什么意思| 脑梗吃什么食物| 马拉松起源与什么有关| 黄精泡水喝有什么功效| 什么是比| 牙医靠什么吃饭| 喝什么茶对肾好| 鱼腥草有什么作用| 纯棉是什么面料| 百度

自动锁定系统

自动锁定系统文档

概述

百度 习近平引用的这句古语,化用了中国古代“慎微”和“节欲”两种思想,意在告诫人们不要被蝇头小利诱惑,因此失去操守,坏了大事,忘了大义。

允许玩家通过鼠标中键快速锁定和切换敌人目标,实现精确的第三人称战斗体验。

参数配置

自动锁定参数

[Header("自动锁定参数")]
public float lockDetectionRadius = 30f;    // 锁定检测半径
public LayerMask enemyLayerMask = -1;      // 敌人层级遮罩
参数 类型 默认值 说明
lockDetectionRadius float 30f 检测敌人目标的最大半径(米)
enemyLayerMask LayerMask -1 指定检测的层级,-1表示所有层级

锁定转向参数

[Header("锁定转向参数")]
public float lockRotationSpeed = 10f;      // 锁定时的旋转速度
public float minLockDistance = 1f;         // 最小锁定距离
public float maxLockDistance = 20f;        // 最大锁定距离
参数 类型 默认值 说明
lockRotationSpeed float 10f 锁定模式下角色转向目标的速度
minLockDistance float 1f 最小锁定距离,防止锁定过近目标
maxLockDistance float 20f 最大锁定距离,超出范围自动取消锁定

目标要求

  • 命名规范: 目标对象名称必须包含"Enemy"(不区分大小写)
  • 距离限制: 目标必须在 minLockDistancemaxLockDistance 之间
  • 后面记得改为敌人设置专门的层级以提高性能,用名字区分太蠢了

思路

1. 目标检测

开始检测 → 获取检测半径内的碰撞体 → 筛选包含"Enemy"的对象 → 验证距离范围 → 按距离排序 → 更新可用目标列表

2. 锁定切流程

按中键 → 检查当前状态 → 开始锁定/切换目标/退出锁定 → 更新锁定状态 → 验证目标有效性

3. 实时验证

每帧检查 → 验证目标存在性 → 验证距离有效性 → 无效时自动退出锁定

性能优化以及后续更新

1. 层级设置

// 为敌人设置专门的层级
enemyLayerMask = LayerMask.GetMask("Enemy");

2. 检测半径优化

  • 根据游戏场景大小调整 lockDetectionRadius
  • 避免设置过大的检测半径影响性能

3. 目标命名规范

  • 统一使用包含"Enemy"的命名规范
  • 避免在非敌人对象中使用"Enemy"关键词

4. 添加锁定UI指示器

// 在锁定目标时显示UI指示器
public void ShowLockIndicator(Transform target)
{
    // 显示锁定UI逻辑
}

效果

后面记得录GIF

完整的第三人称移动代码:

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

public class ThirdPersonMove : MonoBehaviour
{
    //锁定目标
    public Transform LockTarget;

    [Header("输入参数")]
    public float dashSpeed = 1.5f;
    public bool inputEnabled = true;
  
    // 混合树参数
    [Header("混合树参数")]
    public float blendTreeTransitionTime = 0.2f;          // 混合树切换时间
  
    // 状态机控制参数
    [Header("状态机控制参数")]
    public string moveStateParameter = "IsLockMode";      // 控制移动状态混合树的参数名
  
    // 锁定转向参数
    [Header("锁定转向参数")]
    public float lockRotationSpeed = 10f;      // 锁定时的旋转速度
    public float minLockDistance = 1f;         // 最小锁定距离
    public float maxLockDistance = 20f;        // 最大锁定距离

    // 自动锁定参数
    [Header("自动锁定参数")]
    public float lockDetectionRadius = 30f;    // 锁定检测半径
    public LayerMask enemyLayerMask = -1;      // 敌人层级遮罩

    GameObject mainCamera;
    Animator animator;
    CharacterController characterController;
  
    // 状态机相关变量
    private bool isLockMode = false;
  
    // 自动锁定相关变量
    private List<Transform> availableTargets = new List<Transform>();
    private int currentTargetIndex = -1;
    private bool isLocking = false;

    void Start()
    {
        //获取当前场景的主相机
        if (mainCamera == null)
        {
            mainCamera = GameObject.FindGameObjectWithTag("MainCamera");
        }
    }


    void Awake()
    {
        animator = GetComponent<Animator>();
        characterController = GetComponent<CharacterController>();
        //速度控制
        animator.speed /= animator.humanScale;
    }


    // 目标旋转角度
    float targetRotation = 0.0f;
    // 平滑旋转时间
    public float RotationSmoothTime = 0.1f;
    // 平滑旋转速度
    float rotationVelocity;
    void Update()
    {
        if (!inputEnabled) return;

        // 检测鼠标中键输入
        if (Input.GetMouseButtonDown(2)) // 鼠标中键
        {
            ToggleAutoLock();
        }

        // 验证当前锁定目标是否仍然有效
        if (isLocking)
        {
            ValidateCurrentTarget();
        }

        if (Input.GetKey(KeyCode.LeftShift))
        {
            //animator.speed = moveSpeed * 1.5f / animator.humanScale;
            //只改变走路的速度,在混合树上乘这个SprintSpeed参数
            animator.SetFloat("SprintSpeed", dashSpeed / animator.humanScale);
        }
        else
        {
            animator.SetFloat("SprintSpeed", 1 / animator.humanScale);
        }
      
        // 检查是否进入或退出锁定模式
        bool shouldBeLockMode = LockTarget != null;
        if (shouldBeLockMode != isLockMode)
        {
            isLockMode = shouldBeLockMode;
        }
      
        // 更新混合树权重
        UpdateBlendTreeWeight();
      
        #region 水平方向
        if (LockTarget == null)
            FreeMove();
        else
            LockMove();
        #endregion

    }

    /// <summary>
    /// 更新混合树权重
    /// </summary>
    private void UpdateBlendTreeWeight()
    {
        // 状态机参数控制
        animator.SetBool(moveStateParameter, isLockMode);
    }

    /// <summary>
    /// 新版Input输入系统————移动
    /// </summary>
    Vector2 moveAmount;
    void OnMove(InputValue value)
    {
        moveAmount = value.Get<Vector2>();

    }

    /// <summary>
    /// 自由移动,方向
    /// </summary>
    private void FreeMove()
    {
        if (moveAmount != Vector2.zero)
        {
            // 计算水平方向输入方向,将其转换为世界空间坐标系——x和z是水平坐标轴
            Vector3 inputDir = new Vector3(moveAmount.x, 0.0f, moveAmount.y).normalized;
            // 计算目标朝向
            targetRotation = Mathf.Atan2(inputDir.x, inputDir.z) * Mathf.Rad2Deg +
                                  mainCamera.transform.eulerAngles.y;
            // 平稳地旋转玩家,使其面向他们移动的方向。
            float rotation = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetRotation, ref rotationVelocity, RotationSmoothTime);
            // 旋转玩家
            transform.rotation = Quaternion.Euler(0.0f, rotation, 0.0f);
        }
        //Y轴输入值——只影响前进的速度控制,朝向由上面的if中的语句决定
        var axisY = animator.GetFloat("AxisY");
        //平滑过渡到Y轴目标值
        axisY = Mathf.MoveTowards(axisY, moveAmount.magnitude, Time.deltaTime * 5f);
        animator.SetFloat("AxisY", axisY);
    }

    /// <summary>
    /// 锁定目标时的移动——八向移动
    /// </summary>
    private void LockMove()
    {
        if (LockTarget == null) return;
      
        //角色位置到目标的向量
        var dir = LockTarget.position - transform.position;
        float distance = dir.magnitude;
      
        // 检查距离是否在有效范围内
        if (distance < minLockDistance || distance > maxLockDistance)
        {
            // 距离太近或太远时,不进行锁定转向
            return;
        }
      
        //去除y轴的影响
        dir.y = 0;
      
        // 确保方向向量不为零
        if (dir.magnitude > 0.1f)
        {
            //目标朝向
            var targetRotation = Quaternion.LookRotation(dir);
            //从 当前朝向到目标朝向 平滑旋转
            // 使用lockRotationSpeed作为旋转速度
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, lockRotationSpeed * Time.deltaTime);
        }
      
        // 锁定移动混合树参数
        var AxisX = animator.GetFloat("AxisX");
        var AxisY = animator.GetFloat("AxisY");
        //平滑改变轴向
        AxisX = Mathf.MoveTowards(AxisX, moveAmount.x, Time.deltaTime * 5f);
        AxisY = Mathf.MoveTowards(AxisY, moveAmount.y, Time.deltaTime * 5f);
        //更新锁定移动动画参数
        animator.SetFloat("AxisX", AxisX);
        animator.SetFloat("AxisY", AxisY);
    }

    /// <summary>
    /// 切换自动锁定状态
    /// </summary>
    private void ToggleAutoLock()
    {
        if (!isLocking)
        {
            // 开始锁定模式
            FindAvailableTargets();
            if (availableTargets.Count > 0)
            {
                currentTargetIndex = 0;
                LockTarget = availableTargets[currentTargetIndex];
                isLocking = true;
                Debug.Log($"锁定目标: {LockTarget.name}");
            }
        }
        else
        {
            // 切换到下一个目标
            if (availableTargets.Count > 1)
            {
                currentTargetIndex = (currentTargetIndex + 1) % availableTargets.Count;
                LockTarget = availableTargets[currentTargetIndex];
                Debug.Log($"切换到目标: {LockTarget.name}");
            }
            else
            {
                // 只有一个目标或没有目标,退出锁定模式
                ExitLockMode();
            }
        }
    }

    /// <summary>
    /// 查找可用的锁定目标
    /// </summary>
    private void FindAvailableTargets()
    {
        availableTargets.Clear();
      
        // 获取检测半径内的所有碰撞体
        Collider[] colliders = Physics.OverlapSphere(transform.position, lockDetectionRadius, enemyLayerMask);
      
        foreach (Collider col in colliders)
        {
            // 检查对象名称是否包含"Enemy"
            if (col.name.ToLower().Contains("enemy"))
            {
                // 检查距离是否在有效范围内
                float distance = Vector3.Distance(transform.position, col.transform.position);
                if (distance >= minLockDistance && distance <= maxLockDistance)
                {
                    availableTargets.Add(col.transform);
                }
            }
        }
      
        // 按距离排序,最近的优先
        availableTargets.Sort((a, b) => 
            Vector3.Distance(transform.position, a.position).CompareTo(
                Vector3.Distance(transform.position, b.position)));
    }

    /// <summary>
    /// 退出锁定模式
    /// </summary>
    private void ExitLockMode()
    {
        LockTarget = null;
        isLocking = false;
        currentTargetIndex = -1;
        availableTargets.Clear();
        Debug.Log("退出锁定模式");
    }

    /// <summary>
    /// 检查当前锁定目标是否仍然有效
    /// </summary>
    private void ValidateCurrentTarget()
    {
        if (LockTarget == null)
        {
            ExitLockMode();
            return;
        }
      
        // 检查目标是否仍然存在
        if (LockTarget.gameObject == null)
        {
            ExitLockMode();
            return;
        }
      
        // 检查距离是否仍然有效
        float distance = Vector3.Distance(transform.position, LockTarget.position);
        if (distance < minLockDistance || distance > maxLockDistance)
        {
            ExitLockMode();
            return;
        }
    }

    /// <summary>
    /// 手动设置锁定目标
    /// </summary>
    /// <param name="target">要锁定的目标</param>
    public void SetLockTarget(Transform target)
    {
        if (target != null)
        {
            LockTarget = target;
            isLocking = true;
            currentTargetIndex = -1; // 手动设置时不使用索引
            Debug.Log($"手动锁定目标: {target.name}");
        }
    }

    /// <summary>
    /// 手动清除锁定目标
    /// </summary>
    public void ClearLockTarget()
    {
        ExitLockMode();
    }

    /// <summary>
    /// 获取当前是否处于锁定模式
    /// </summary>
    /// <returns>是否锁定中</returns>
    public bool IsLocking()
    {
        return isLocking;
    }

    /// <summary>
    /// 获取当前可用目标数量
    /// </summary>
    /// <returns>可用目标数量</returns>
    public int GetAvailableTargetCount()
    {
        return availableTargets.Count;
    }


}

posted @ 2025-08-04 03:57  EanoJiang  阅读(0)  评论(0)    收藏  举报
什么石头最值钱 水乳是什么 1比1是什么意思 女性去泰国要注意什么 肚子疼用什么药好
溜号是什么意思 鱼翅是什么鱼身上的 女性下面水少是什么原因 但爱鲈鱼美的但是什么意思 报仇是什么意思
什么叫酮症酸中毒 白头发有什么方法变黑 啤酒加生鸡蛋一起喝有什么效果 酵母提取物是什么 鼻子上长痘痘是什么原因
小叶增生和乳腺增生有什么区别 胖头鱼又叫什么鱼 什么的脚 血沉高意味着什么意思 平滑肌是什么
今年54岁属什么生肖hcv8jop5ns6r.cn 咳嗽挂什么科hcv8jop6ns2r.cn 八珍胶囊适合什么人吃hcv7jop5ns5r.cn 子宫粘连是什么原因引起的hcv8jop6ns2r.cn 老婆的妹妹叫什么clwhiglsz.com
卡尔文克莱恩是什么牌子hcv7jop7ns4r.cn 血糖高适合喝什么汤hcv8jop6ns8r.cn 女生是什么意思hcv9jop1ns8r.cn 肌酐偏高是什么意思hcv9jop6ns1r.cn 璠字取名寓意什么dayuxmw.com
什么水不能喝hcv9jop4ns9r.cn 钡餐检查能查出什么hcv9jop8ns1r.cn 便是什么意思hcv8jop6ns9r.cn 为什么手比脸白那么多hcv8jop9ns6r.cn 眼白出血是什么原因hcv7jop5ns3r.cn
心衰的症状是什么hcv8jop5ns7r.cn 谁也不知道下一秒会发生什么hcv9jop5ns1r.cn 补肾气吃什么药最好hcv9jop6ns9r.cn 水瓶座什么性格hcv8jop5ns2r.cn 口蜜腹剑是什么意思hcv7jop6ns5r.cn
百度