Unity3D 我的蹲伏行走动画抖动

问题描述 投票:0回答:2

我似乎无法让我的蹲下行走动画停止口吃,就像它不断被切断并重新开始一样。附件是我的动画代码:

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

public class Animation : MonoBehaviour
{

    public GameObject player;

    private float slowV = 0.3f;
    private float fastV = 1f;

    private float blendSpeed = .6f;

    private float time;
    private float timeX;

    private float timeY;

    private bool crouch;
    private bool crouch2;

    void Start()
    {
        time = 0;
        timeX = 0;
        timeY = 0;
        crouch = false;
        crouch2 = false;
    }

    void Update()
    {
        Debug.Log(crouch);

        if (Input.GetKey(KeyCode.LeftControl) && Input.GetKey(KeyCode.W))
        {
            player.GetComponent<Animator>().SetBool("crouchWalk", true);
            player.GetComponent<Animator>().SetBool("crouch", false);

        }
        else if (Input.GetKey(KeyCode.LeftControl))
        {
            player.GetComponent<Animator>().SetBool("crouch", true);
        }
        else
        {
            player.GetComponent<Animator>().SetBool("crouchWalk", false);
            player.GetComponent<Animator>().SetBool("crouch", false);

            if (Input.GetKey(KeyCode.W))
            {
                if (Input.GetKey(KeyCode.LeftShift))
                {
                    time = Mathf.Clamp(time + blendSpeed * Time.deltaTime, -fastV, fastV);
                    player.GetComponent<Animator>().SetFloat("y", time);
                }
                else
                {
                    if (time < slowV)
                    {
                        time = Mathf.Clamp(time + blendSpeed * Time.deltaTime, -fastV, slowV);
                        player.GetComponent<Animator>().SetFloat("y", time);
                    }
                    else
                    {
                        time = Mathf.Clamp(time - blendSpeed * Time.deltaTime, slowV, fastV);
                        player.GetComponent<Animator>().SetFloat("y", time);
                    }
                }
            }
            else if (Input.GetKey(KeyCode.S))
            {
                if (Input.GetKey(KeyCode.LeftShift))
                {
                    time = Mathf.Clamp(time - blendSpeed * 2 * Time.deltaTime, -fastV, fastV);
                    player.GetComponent<Animator>().SetFloat("y", time);
                }
                else
                {
                    if (time > -slowV)
                    {
                        time = Mathf.Clamp(time - blendSpeed * Time.deltaTime, -slowV, fastV);
                        player.GetComponent<Animator>().SetFloat("y", time);
                    }
                    else
                    {
                        time = Mathf.Clamp(time + blendSpeed * Time.deltaTime, -fastV, -slowV);
                        player.GetComponent<Animator>().SetFloat("y", time);
                    }
                }
            }
            else
            {
                if (time > 0f)
                {
                    time = Mathf.Clamp(time - blendSpeed * Time.deltaTime, 0f, 1f);
                }
                else
                {
                    time = Mathf.Clamp(time + blendSpeed * Time.deltaTime, -1f, 0f);
                }
                player.GetComponent<Animator>().SetFloat("y", time);
            }


            if (Input.GetKey(KeyCode.D))
            {
                if (Input.GetKey(KeyCode.LeftShift))
                {
                    timeX = Mathf.Clamp(timeX + blendSpeed * 2 * Time.deltaTime, -fastV, fastV);
                    player.GetComponent<Animator>().SetFloat("x", timeX);
                }
                else
                {
                    if (timeX < slowV)
                    {
                        timeX = Mathf.Clamp(timeX + blendSpeed * Time.deltaTime, -fastV, slowV);
                        player.GetComponent<Animator>().SetFloat("x", timeX);
                    }
                    else
                    {
                        timeX = Mathf.Clamp(timeX - blendSpeed * Time.deltaTime, slowV, fastV);
                        player.GetComponent<Animator>().SetFloat("x", timeX);
                    }
                }
            }
            else if (Input.GetKey(KeyCode.A))
            {
                if (Input.GetKey(KeyCode.LeftShift))
                {
                    timeX = Mathf.Clamp(timeX - blendSpeed * 2 * Time.deltaTime, -fastV, fastV);
                    player.GetComponent<Animator>().SetFloat("x", timeX);
                }
                else
                {
                    if (timeX > -slowV)
                    {
                        timeX = Mathf.Clamp(timeX - blendSpeed * Time.deltaTime, -slowV, fastV);
                        player.GetComponent<Animator>().SetFloat("x", timeX);
                    }
                    else
                    {
                        timeX = Mathf.Clamp(timeX + blendSpeed * Time.deltaTime, -fastV, -slowV);
                        player.GetComponent<Animator>().SetFloat("x", timeX);
                    }
                }
            }
            else
            {
                if (timeX > 0f)
                {
                    timeX = Mathf.Clamp(timeX - blendSpeed * Time.deltaTime, 0f, 1f);
                }
                else
                {
                    timeX = Mathf.Clamp(timeX + blendSpeed * Time.deltaTime, -1f, 0f);
                }

                player.GetComponent<Animator>().SetFloat("x", timeX);
            }

            if (Input.GetKey(KeyCode.Space))
            {
                player.GetComponent<Animator>().SetBool("jump", true);
            }
        }
    }
}

这是我的动画师的屏幕截图

enter image description here

我有一段关于游戏中问题的简短视频,但我不确定如何将其附加到这里

起初我以为它被另一个动画打断了,我试图通过分配隔离键和在动画窗口中尝试不同的节点连接来隔离它

我尝试通过将它放入 if else 语句中将它与所有其他动画分开

我已经在网上搜索了答案

我将不胜感激对这个问题的任何帮助或见解

谢谢

unity3d
2个回答
0
投票

Any State
过渡还包括您要过渡到的状态。您正在使用 bool 来确定蹲伏。当您将其设置为 true 时,动画开始从它所处的任何状态过渡到蹲伏动画。然而,下一帧 bool 很可能仍然为真。你再一次从
Any State
(现在是
Crouched Walk
)开始跳跃并开始过渡到
Crouched Walk
。结果听起来很愚蠢。你从动画中间的某处过渡到开始,蹲伏行走似乎在抖动。

为避免

Any State
转换出现问题,您应该使用 Trigger

player.GetComponent<Animator>().SetTrigger("CrouchStart");

在这种情况下,我称之为

CrouchStart
您必须创建这个新的动画触发器变量并将其绑定到从
Any State
Couched Walk
的过渡。

您的代码当前设置的方式会导致触发器在每一帧重新激活,如果您只进行简单的交换。解释如何让它与

GetButtonDown
一起工作并处理周围的所有东西会有点罗嗦,所以我冒昧地重写了你的代码。如果依赖地狱没有乐趣,则嵌套 else,所以我为您清理了它。它应该仍然完全一样,但我没有测试太多。

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

public class Animation : MonoBehaviour
{
    [SerializeField] Animator anim;//you never use the player gameobject anyway

    [SerializeField] float slowV = 0.3f;//made Serialized, so you can adjust in the editor
    [SerializeField] float fastV = 1f;
    [SerializeField] float blendSpeed = .6f;

    private float adjustedBlendSpeed;
    private Vector2 dir;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            anim.SetTrigger("Jump");
        }

        if (Input.GetKeyDown(KeyCode.LeftControl))
        {
            anim.SetTrigger("CrouchStart");
        }

        if (Input.GetKeyUp(KeyCode.LeftControl))
        {
            anim.SetTrigger("CrouchEnd");
        }

        //axis Horizontal AD, Vertical WS by default
        Vector2 dirTarget = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")).normalized;

        anim.SetBool("Walking", dirTarget.magnitude > 0.1f);

        //some creative liberty was taken to avoid else if condition hell
        //it *should* still function like before
        if (Input.GetKey(KeyCode.LeftShift))
        {
            dirTarget *= fastV;
            adjustedBlendSpeed = blendSpeed * 2;
        }
        else
        {
            dirTarget *= slowV;
            adjustedBlendSpeed = blendSpeed;
        }
        Vector2 accel = (dirTarget - dir).normalized * adjustedBlendSpeed * Time.deltaTime;
        dir += accel;
        anim.SetFloat("x", dir.x);
        anim.SetFloat("y", dir.y);
    }
}

动画师和以前基本一样。我添加了

Crouch
Crouch Walk
状态之间的转换,因此我不必在代码中执行此操作。我也只对
Crouch
Crouch Walk
使用一个蹲伏触发器。忽略状态和警告的奇怪名称,我只是懒得制作动画。

如您所见,从

Any State
Crouch
Crouch Walk
的过渡得到相同的
CrouchStart
触发器 and
Walking
布尔。必须满足这两个条件才能开始过渡。返回到混合树的转换使用
CrouchEnd
触发器。


0
投票

TLDR,确保你的参数是正确的

我让它工作了,我无法准确指出我的第一个版本有什么问题,但是在实现你的代码@Voidsay 之后,在播放场景时看着动画师,这是我发现的:

首先,我尝试完全按照您描述的方式实现代码和动画师,但仍然无法正常工作。然后我开始试验并将我的蹲伏和蹲伏动画状态更改为单个混合树,这也是我最初的意图。

我注意到我的蹲伏状态的动画条太快了,这让我注意到控制我的蹲伏混合树的参数太低,导致蹲伏在一个点混合,使它看起来像它口吃。(正是我第一次遇到这个问题时的样子)

我更改了代码以正确达到最大混合值,现在它可以工作了

它可能是逻辑和参数问题的结合,或者前者然后是后者,但我想我永远不会知道。

这是我第一次和动画师合作,所以我可能对它不够熟悉。

不管怎样,谢谢@Voidsay 的帮助,你的创作自由也比我的意大利面要好得多

这是我当前的代码和动画控制器:

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

public class Animation2 : MonoBehaviour
{
    [SerializeField] Animator anim;

    [SerializeField] float slowV = 0.3f;
    [SerializeField] float fastV = 1f;
    [SerializeField] float blendSpeed = .6f;

    private float adjustedBlendSpeed;
    private Vector2 dir;



    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            anim.SetTrigger("Jump");
        }

        if (Input.GetKeyDown(KeyCode.LeftControl))
        {
            anim.SetTrigger("CrouchStart");
        }

        if (Input.GetKeyUp(KeyCode.LeftControl))
        {
            anim.SetTrigger("CrouchEnd");
        }

        Vector2 dirTarget = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")).normalized;

        anim.SetBool("Walking", dirTarget.magnitude > 0.1f);

        if (Input.GetKey(KeyCode.LeftShift))
        {
            dirTarget *= fastV;
            adjustedBlendSpeed = blendSpeed * 2;
        }
        else
        {
            dirTarget *= slowV;
            adjustedBlendSpeed = blendSpeed;
        }
        Vector2 accel = (dirTarget - dir).normalized * adjustedBlendSpeed * Time.deltaTime;
        dir += accel;
        anim.SetFloat("x", dir.x);
        anim.SetFloat("y", dir.y);

        anim.SetFloat("crouchX", dir.x);
        anim.SetFloat("crouchY", dir.y);
    }
}

Animator

© www.soinside.com 2019 - 2024. All rights reserved.