经常肚子疼是什么原因| 保家卫国是什么生肖| 移动电源和充电宝有什么区别| 述说是什么意思| 邪教是什么| 人流是什么| 到是什么意思| tnt是什么| 什么的仪式| 绿色的鸟是什么鸟| 为什么十五的月亮十六圆| 拍手腕中间有什么好处| 粉刺是什么东西| 什么是我的| 水仙是什么| 微五行属什么| 羸弱什么意思| 宝宝打嗝是什么原因引起的| 发菜是什么菜| 津津有味的意思是什么| 手指长痣代表什么| 毛囊炎是什么症状| 警告处分有什么影响| 抵税是什么意思| 小个子适合什么发型| 广东人吃什么| 甲状腺饱满是什么意思| 潍坊有什么好玩的| kappa是什么牌子| 一毛三是什么军衔| 凋零是什么意思| 618是什么星座| 脚底出汗是什么原因| 束缚什么意思| 什么是高血脂| 二月十号是什么星座| 什么是肺磨玻璃结节| 甲状腺4a类什么意思| 有什么好吃的家常菜| 白芷泡水喝有什么功效| mc是什么| 区级以上医院是什么意思| 记性不好吃什么药| 大便干燥一粒一粒的是什么原因| 荔枝适合什么地方种植| 雌蕊由什么组成| 白兰地是什么酒| 10月21日什么星座| 蜜蜂吃什么食物| 牛肉配什么菜好吃| 补办医保卡需要什么资料| 若无其事的若是什么意思| 溃疡用什么药| 大便检查能查出什么病| 有因必有果什么意思| 守望先锋是什么类型的游戏| 尿素酶阳性什么意思| 双肺纹理粗重什么意思| 男人额头凹陷预示什么| 什么的马| 肠胃不好喝什么茶| 尿特别多是什么原因| 对象是什么意思| 奶酪是什么做的| 瓶颈期什么意思| 腰痛去医院挂什么科| 漂头发是什么意思| 孔雀翎是什么东西| 口干舌燥喝水也不解渴是什么原因| 肝气犯胃吃什么中成药| 大姨的女儿叫什么| 血糖高的人吃什么| 奔走相告的走是什么意思| 三七植物长什么样子| 薏米和什么一起煮粥最好| 脸上长痣是什么原因| 右乳导管扩张什么意思| 出痧的颜色代表什么| 潜血阳性是什么意思| 口腔医学学什么课程| 衣禄是什么意思| 兔和什么生肖最配| 什么血型容易被蚊子咬| 什么是肾阴虚和肾阳虚| 奉子成婚是什么意思| 女大一抱金鸡是什么意思| 瞌睡是什么意思| 什么高什么长| 小麻雀吃什么| 男人胡子长得快是什么原因| 更是什么结构的字| 天丝是什么材质| 晚上看见蛇有什么预兆| 什么的流着| zw是什么意思| 指甲变厚是什么原因| 便潜血阳性什么意思| 成家是什么意思| original是什么牌子| 艾滋病通过什么传染| 女中指戴戒指什么意思| nba打铁是什么意思| 对策是什么意思| 工会主席是什么级别| 痤疮用什么药| 为什么叫太平间| 十月初三是什么星座| 古代广东叫什么| 梦见赢钱了是什么预兆| 干可以加什么偏旁| 远香近臭是什么意思| 妾是什么意思| 游离甲状腺素是什么| 什么是结扎| 南无阿弥陀佛是什么意思| 痔疮什么情况下需要做手术| 什么叫修辞手法| 头皮上长疣是什么原因造成的| 水鸭跟什么煲汤最佳| 自愈什么意思| george是什么牌子| 客厅沙发后面墙上挂什么画好| 开宠物医院需要什么条件| 小腿疼痛挂什么科| 什么食物去湿气效果好| giuseppe是什么牌子| 除了胃镜还有什么检查胃的方法吗| 抽烟肺疼是什么原因| 头发湿着睡觉有什么害处| 究竟涅盘是什么意思| 生蚝有什么营养价值| 6月1日是什么星座| 一什么草坪| 宫外孕是什么导致的| 一直吐是什么原因| 混油皮是什么意思| 吃生红枣有什么好处| 全距是什么意思| 什么植物吸收甲醛| 全组副鼻窦炎什么意思| 17楼五行属什么| 一什么毛驴| 大便羊屎粒是什么原因| 做梦笑出声是什么预兆| 液体变固体叫什么| hpv52高危阳性是什么意思| 矢气是什么意思| 水痘疫苗什么时候打| 绿色是什么意思| 世界上最大的海洋是什么| 焦虑会引起什么症状| 外阴裂口用什么药| 鲨鱼用什么呼吸| 甜菜根在中国叫什么| 哨兵是什么意思| 天门冬氨酸氨基转移酶是什么| 非农业户口是什么意思| 中国劲酒有什么功效| 为什么长湿疹| 六十天打一字是什么字| ige高是什么意思| 跑水是什么意思| 呲牙咧嘴是什么意思| 小叶增生吃什么药| 身骑白马是什么方言| 下聘是什么意思| 什么时候打胎对身体伤害最小| 脚后跟疼挂什么科| 饱和脂肪是什么| 看书有什么好处| 什么如什么| 动员是什么意思| 家蛇是什么蛇| 可可是什么饮料| 什么叫痤疮| 扇子骨是什么肉| 西洋参什么时候吃效果最好| 芒果不能和什么水果一起吃| 不劳而获是什么意思| 轻食是什么| 一个木一个舌读什么| 口臭用什么牙膏| 耳膜炎是什么症状| 周海媚什么病| 尿酸高注意什么| 晚上睡不着是什么原因| 倒斗是什么意思| 鹿茸有什么功效| 水泻拉肚子吃什么药| ex是什么| 足字旁的字与什么有关| 泡黄芪水喝有什么好处| 嘴唇起小水泡是什么原因| 冬虫夏草有什么作用| 拔完牙能吃什么| 流清口水是什么原因| 咳嗽脑袋疼是什么原因| 事物是什么意思| 亚麻籽有什么功效| 百田森的鞋什么档次| 火旺是什么意思| 势利眼是什么意思| 退化是什么意思| 熊猫长什么样| 过氧化氢阳性什么意思| 多汗症是什么原因引起的| 海之蓝是什么香型| 什么是超标电动车| 什么是传染病| 剁椒鱼头属于什么菜系| 什么属相不能带狗牙| 免疫球蛋白g是什么意思| 排卵期一般在什么时候| 安睡裤是什么| 什么是虚无主义| 丙字五行属什么| 气虚是什么原因造成的| 指甲有竖纹是什么病| 下面有异味用什么药| 外阴红肿瘙痒用什么药| 耵聍是什么| 过度纵欲的后果是什么| 市公安局政委是什么级别| 茄子与什么食物相克| 什么时间立秋| 磕头虫吃什么| 肌肉代偿是什么意思| 小肚右边疼是什么原因| s925是什么| 墨西哥人是什么人种| 泛性恋什么意思| 四月初七是什么星座| 尿道口流脓什么病| 得了子宫肌瘤注意什么| 中将是什么级别| 吃什么水果可以通便| 阿胶糕适合什么人吃| 长痣是什么原因| 什么是肺部腺性肿瘤| 农村做什么致富| 溯溪是什么意思| camouflage什么意思| exm是什么意思| 合肥有什么好吃的| 肝癌是什么原因引起的| 咬牙切齿什么意思| ca医学代表什么意思| 违心的话是什么意思| 毛囊炎什么症状| 东四命是什么意思| 吃什么利尿最快| 固执己见是什么意思| 大腿肌肉酸痛是什么病| 敷设是什么意思| 抗角蛋白抗体阳性是什么意思| 眼睛出血是什么原因| 胃泌素偏低是什么原因| 口炎读什么| 马齿苋不能和什么一起吃| 沐雨栉风是什么生肖| 小腿肿胀是什么原因引起的| 6月13号是什么星座| cva医学上是什么意思| 后背痒是什么原因| 百度

【类刺客信条跑酷系统】新增_跳跃机制

输入控制

百度 坚持以“科学、公正、客观、权威”为工作原则,坚持以科学的方法、公正的立场、客观的态度,对房地产企业进行研究,最后得出权威的结果。

PlayerController

    //是否跳跃
    public bool jump;

重构输入控制

        #region 角色输入控制
        #region 水平方向
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        //把moveAmount限制在0-1之间(混合树的区间)
        float moveAmount = Mathf.Clamp01(Mathf.Abs(h) + Mathf.Abs(v));
  
        //标准化 moveInput 向量
        var moveInput = new Vector3(h, 0, v).normalized;
        if(inputEnabled == false){
            h = 0;
            v = 0;
        }

        //让人物期望移动方向关联相机的水平旋转朝向
        //  这样角色就只能在水平方向移动,而不是相机在竖直方向的旋转量也会改变角色的移动方向
        desireMoveDir = cameraController.PlanarRotation * moveInput;
        //让当前角色的移动方向等于期望方向
        moveDir = desireMoveDir;

        planarVelocity = Vector3.zero;
        #endregion
        #region 竖直方向——Jump
        if(!InAction)
            jump = Input.GetButton("Jump");

添加动画

        if(jump && isGrounded){
            animator.SetTrigger("jump");
        }

1753885554766

1753885587187

重置signal——解决信号一直叠加导致的连跳

1753778342286

脚本加在状态机地面行走的locomotion上面

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

public class FSMClearSignals : StateMachineBehaviour
{
    public string[] clearAtEnter;
    public string[] clearAtExit;

    // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
    override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        foreach (var signal in clearAtEnter)
        {
            animator.ResetTrigger(signal);
        }
    }

    // OnStateUpdate is called on each Update frame between OnStateEnter and OnStateExit callbacks
    //override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //  
    //}

    // OnStateExit is called when a transition ends and the state machine finishes evaluating this state
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        foreach (var signal in clearAtEnter)
        {
            animator.ResetTrigger(signal);
        }
    }

    // OnStateMove is called right after Animator.OnAnimatorMove()
    //override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    // Implement code that processes and affects root motion
    //}

    // OnStateIK is called right after Animator.OnAnimatorIK()
    //override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    //{
    //    // Implement code that sets up animation IK (inverse kinematics)
    //}
}

套接出FSM On Enter&Exit方法

加在状态机的Jump上

1753781956492

    public string[] onEnterMessages;
    // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
    override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        foreach (string message in onEnterMessages)
        {
            animator.SendMessageUpwards(message);
        }
    }
    public string[] onExitMessages;
    // OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
    override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
    {
        foreach (string message in onExitMessages)
        {
            animator.SendMessageUpwards(message);
        }
    }

这样就可以在PlayerJumpController.cs中写起跳时的人物移动逻辑

会传到Jump下的两个StateMachineBehaviour脚本中

    public void OnJumpEnter(){
        Debug.Log("起跳");
    }
    public void OnJumpExit(){
        Debug.Log("落地"); 
    }

锁死平面移动——限制空中转向

PlayerController

//输入控制
public bool inputEnabled = true;
public bool lockPlannar;
    public void OnJumpEnter(){
        Debug.Log("起跳");
        playerController.inputEnabled = false;
        lockPlannar = true;
    }
    public void OnJumpExit(){
        Debug.Log("落地"); 
        playerController.inputEnabled = true ;
        lockPlannar = false;
    }
        #region 角色输入控制
        #region 水平方向
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        //把moveAmount限制在0-1之间(混合树的区间)
        float moveAmount = Mathf.Clamp01(Mathf.Abs(h) + Mathf.Abs(v));
  
        //标准化 moveInput 向量
        var moveInput = new Vector3(h, 0, v).normalized;
        if(inputEnabled == false){
            h = 0;
            v = 0;
        }

        //让人物期望移动方向关联相机的水平旋转朝向
        //  这样角色就只能在水平方向移动,而不是相机在竖直方向的旋转量也会改变角色的移动方向
        desireMoveDir = cameraController.PlanarRotation * moveInput;
        //让当前角色的移动方向等于期望方向
        if (lockPlannar == false)
            moveDir = desireMoveDir;

关于最后的跳跃锁死,也可以不用

        if (lockPlannar == false)
            moveDir = desireMoveDir;

跳起速度

    [SerializeField] float jumpSpeed;
        #region 地面检测
        GroundCheck();
        animator.SetBool("isGrounded", IsGrounded);
        if (IsGrounded)
        {
            //设置一个较小的负值,让角色在地上的时候被地面吸住
            //只有在没有跳跃的情况下才重置ySpeed,避免跳跃被覆盖
            if (!jump)
            {
                ySpeed = -0.5f;
            }
            else
            {
                animator.SetBool("jump", jump);
                ySpeed = jumpSpeed;
                jump = false;
            }

            //在地上的速度只需要初始化角色期望方向的速度就行,只有水平分量
            planarVelocity = desireMoveDir * moveSpeed;

效果如下:

1753861822705

最后记得把ParkourController里的JumpDown对应按键修改了,不然冲突

            //只有高度大于autoJumpHeight 且 玩家按下Drop键才会跳下悬崖
            if (playerController.LedgeHitData.height > autoJumpDownHeight && !Input.GetButtonDown("Drop")){
                shouldJump = false;
            }

该部分完整代码:

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

public class PlayerController : MonoBehaviour
{
    [Header("玩家属性")]
    [SerializeField] float moveSpeed = 7f;
    [SerializeField] float rotationSpeed = 500f;
    [SerializeField] float jumpSpeed;

    [Header("Ground Check")]
    [SerializeField] float groundCheckRadius = 0.5f;
    //检测射线偏移量
    [SerializeField] Vector3 groundCheckOffset;
    [SerializeField] LayerMask groundLayer;

    //是否在地面
    public bool IsGrounded { get; set; }
    //是否拥有控制权:默认拥有控制权,否则角色初始就不受控
    bool hasControl = true;
    //输入控制
    public bool inputEnabled = true;
    //是否在动作中
    public bool InAction { get; private set; }
    //是否在攀岩中
    public bool IsHanging { get; set; }
    //是否跳跃
    public bool jump;
    public bool lockPlannar;

    //moveDir、velocity改成全局变量
    //当前角色的移动方向,这是实时移动方向,只要输入方向键就会更新
    Vector3 moveDir;
    //角色期望的移动方向,这个期望方向是和相机水平转动方向挂钩的,与鼠标或者手柄右摇杆一致
    Vector3 desireMoveDir;
    //水平方向的速度
    Vector3 planarVelocity;
    //竖直方向的跳跃冲量
    Vector3 thrustVelocity;

    //是否在悬崖边沿上
    public bool IsOnLedge { get; set; }
    //悬崖边沿击中相关数据
    public LedgeHitData LedgeHitData { get; set; }

    float ySpeed;

    Quaternion targetRotation;

    CameraController cameraController;
    Animator animator;
    CharacterController charactercontroller;
    EnvironmentScanner environmentScanner;
    Rigidbody rigid;
    MeleeFighter meleeFighter;

    private void Awake()
    {
        //相机控制器设置为main camera
        cameraController = Camera.main.GetComponent<CameraController>();
        //角色动画
        animator = GetComponent<Animator>();
        //角色控制器
        charactercontroller = GetComponent<CharacterController>();
        //环境扫描器
        environmentScanner = GetComponent<EnvironmentScanner>();
        //
        rigid = GetComponent<Rigidbody>();
        //近战
        meleeFighter = GetComponent<MeleeFighter>();
    }
    private void Update()
    {
        //如果没有控制权,后面的就不执行了
        if (!hasControl)
        {
            return;
        }
        //如果在动作中,不执行后面的运动逻辑并且不播放走路动画
        if (IsHanging || InAction || meleeFighter.InAtkAction)
        {
            animator.SetFloat("moveAmount", 0);
            return;
        }

        #region 角色输入控制
        #region 水平方向
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        //把moveAmount限制在0-1之间(混合树的区间)
        float moveAmount = Mathf.Clamp01(Mathf.Abs(h) + Mathf.Abs(v));
  
        //标准化 moveInput 向量
        var moveInput = new Vector3(h, 0, v).normalized;
        if(inputEnabled == false){
            h = 0;
            v = 0;
        }

        //让人物期望移动方向关联相机的水平旋转朝向
        //  这样角色就只能在水平方向移动,而不是相机在竖直方向的旋转量也会改变角色的移动方向
        desireMoveDir = cameraController.PlanarRotation * moveInput;
        //让当前角色的移动方向等于期望方向
        //if (lockPlannar == false)
        moveDir = desireMoveDir;

        planarVelocity = Vector3.zero;
        #endregion
        #region 竖直方向——Jump
        jump = Input.GetButton("Jump");
        #endregion
        #endregion

        #region 地面检测
        GroundCheck();
        animator.SetBool("isGrounded", IsGrounded);
        if (IsGrounded)
        {
            //设置一个较小的负值,让角色在地上的时候被地面吸住
            //只有在没有跳跃的情况下才重置ySpeed,避免跳跃被覆盖
            if (!jump)
            {
                ySpeed = -0.5f;
            }
            else
            {
                animator.SetBool("jump", jump);
                ySpeed = jumpSpeed;
                jump = false;
            }

            //在地上的速度只需要初始化角色期望方向的速度就行,只有水平分量
            planarVelocity = desireMoveDir * moveSpeed;


            #region 悬崖检测
            //在地上的时候进行悬崖检测,传给isOnLedge变量
            IsOnLedge = environmentScanner.ObstacleLedgeCheck(desireMoveDir, out LedgeHitData ledgeHitData);
            //如果在悬崖边沿,就把击中数据传给LedgeHitData变量,用来在ParkourController里面调用
            if (IsOnLedge)
            {
                LedgeHitData = ledgeHitData;
                //调用悬崖边沿移动限制
                LedgeMovement();
                //  Debug.Log("On Ledge");
            }
            #endregion

            //在地面上,速度只有水平分量
            #region 角色动画控制
            //  dampTime是阻尼系数,用来平滑动画
            //这里不应该根据输入值赋值给BlendTree动画用的moveAmount参数
            //因为动画用的moveAmount参数只需要水平方向的移动量就行了,不需要考虑y轴
            //那么也就不需要方向,只需要值
            //所以传入归一化的 velocity.magnitude / moveSpeed就行了
            animator.SetFloat("moveAmount", planarVelocity.magnitude / moveSpeed, 0.2f, Time.deltaTime);
            #endregion
        }
        else
        {
            //在空中时,ySpeed受重力控制
            ySpeed += Physics.gravity.y * Time.deltaTime;
            //简单模拟有空气阻力的平抛运动:空中时的速度设置为角色朝向速度的一半
            planarVelocity = transform.forward * moveSpeed / 2;
        }
        #endregion

        #region 角色控制器控制
        //更新y轴方向的速度
        planarVelocity.y = ySpeed;

        //先检查角色控制器是否激活
        if (charactercontroller.gameObject.activeSelf && charactercontroller.enabled && hasControl)
        {
            //帧同步移动
            //通过CharacterController.Move()来控制角色的移动,通过碰撞限制运动
            charactercontroller.Move(planarVelocity* Time.deltaTime);
        }

        //每次判断moveAmount的时候,确保只有在玩家实际移动时才会更新转向
        //没有输入并且移动方向角度小于0.2度就不更新转向,也就不会回到初始朝向
        //moveDir.magnitude > 0.2f 避免了太小的旋转角度也会更新
        if (moveAmount > 0 && moveDir.magnitude > 0.2f)
        {
            //人物模型转起来:让目标朝向与当前移动方向一致
            targetRotation = Quaternion.LookRotation(moveDir);

        }
        //更新transform.rotation:让人物从当前朝向到目标朝向慢慢转向
        transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation,
                         rotationSpeed * Time.deltaTime);
        #endregion
    }


    /// <summary>
    /// 起跳和落地角色控制权
    /// </summary>
    public void OnJumpEnter()
    {
        Debug.Log("起跳");
        inputEnabled = false;
        lockPlannar = true;
    }
    public void OnJumpExit()
    {
        Debug.Log("落地");
        inputEnabled = true;
        lockPlannar = false;
    }
posted @ 2025-08-04 15:52  EanoJiang  阅读(7)  评论(0)    收藏  举报
蓟类植物是什么 胃火重口臭吃什么药好 胆结石切除胆囊后有什么影响 蟑螂喜欢什么环境 婴儿拉肚子是什么原因造成的
错构瘤是什么意思 什么人不能吃黄精 病毒由什么组成 什么是子公司 做梦梦到很多蛇是什么意思
男性小便出血是什么原因 好强的女人是什么性格 羊肉和什么菜搭配最好 生的反义词是什么 二倍体是什么意思
灰菜有什么功效与作用 脚痛去医院挂什么科 m代表什么单位 猪肉炖什么好吃 临床是什么意思
4a是什么意思hcv8jop7ns0r.cn 什么病不能吃西洋参hcv7jop4ns8r.cn 低度鳞状上皮内病变是什么意思hcv9jop7ns4r.cn 乙肝e抗原阳性是什么意思hcv9jop0ns1r.cn 腱鞘囊肿挂什么科hcv9jop4ns2r.cn
蜜蜂吃什么cj623037.com dwi是什么检查hcv7jop5ns1r.cn 夸瓜读什么hcv8jop1ns8r.cn 高血压属于什么科hcv8jop5ns2r.cn 多囊卵巢是什么原因造成的hcv8jop9ns7r.cn
abi是什么意思tiangongnft.com 2001是什么年hcv9jop8ns3r.cn 碧字五行属什么hcv9jop6ns2r.cn bu是什么颜色hcv9jop7ns4r.cn 月经不来是什么原因导致的hcv8jop6ns1r.cn
晚餐吃什么好hcv8jop9ns6r.cn 首台套是什么意思hcv9jop7ns4r.cn 韩束适合什么年龄段的人用hcv7jop4ns6r.cn 豆工念什么hcv8jop3ns2r.cn 踏实是什么意思hcv9jop6ns3r.cn
百度