方法忽略 class 范围变量值更改

Method ignores class scope variable value change

问题出在布尔值 isDodging 上。它在 Dodge() 方法中设置为 true。这应该触发 Movement() 方法中的 if 语句(在 FixedUpdate() 中调用),但该块总是被跳过。我附上了所有 class' 代码,因为这里一定有我遗漏的东西:

using UnityEngine;

public class MovementController
{
    /* COMPONENTS */
    public Rigidbody2D Rigidbody { private get; set; }

    /* VARIABLES */
    private bool isDodging = false;
    private Vector2 dodgeDirection = Vector2.right;
    private float dodgeDuration = 1f;
    private float dodgeSpeed = 20f;
    private float timer = 0f;

    /* METHODS */
    
    // Called in fixed update (since it's dealing with physics)
    public void Movement(Vector2 currentPosition, Vector2 velocity)
    {
        Debug.Log("In movement: " + isDodging);
        if (isDodging)
        {
            Debug.Log("Dodge 3");
            Move(currentPosition, dodgeDirection * dodgeSpeed);

            timer += Time.fixedDeltaTime;
            if (timer >= dodgeDuration)
            {
                Debug.Log("Stopped dodging " + Time.fixedTime);
                isDodging = false;
            }
        }
        else
        {
            Move(currentPosition, velocity);
        }
    }

    private void Move(Vector2 currentPosition, Vector2 velocity)
    {
        if (Rigidbody == null)
        {
            Debug.LogWarning("No rigidbody to move!");
            return;
        }

        Rigidbody.MovePosition(currentPosition + (velocity * Time.fixedDeltaTime));
    }

    // Must be called while Movement is being called
    public void Dodge(Vector2 direction, float maxSpeed, float speedMultiplier = 2f, float duration = 1f)
    {
        if (direction == Vector2.zero) { return; }
        Debug.Log("Dodge 1 " + isDodging);

        dodgeDirection = direction;
        dodgeDuration = duration;
        dodgeSpeed = maxSpeed * speedMultiplier;

        isDodging = true;
        Debug.Log("Dodge 2" + isDodging + Time.fixedTime);
        
        timer = 0f;
    }
}

事实是,“运动中:”日志始终显示 isDodging 为 false,并且它下面的 if 块永远不会运行。同时,“Dodge 2”将显示 true(因为 isDodging 在其正上方发生了变化)。最奇怪的是:“Dodge 1”在第一次调用 Dodge() 时显示 false,但之后每次调用时都显示 true - 就好像 isDodging 在class 范围,并且 Movement() 出于某种原因无法识别。

这两个函数都在单独的 MonoBehaviour 中调用:

public class CreatureMovement : MonoBehaviour
{
    [Header("Movement")]
    [SerializeField] protected Vector2Reference moveDirection;
    [SerializeField] protected FloatReference maxSpeed;

    [Header("Dodge")]
    [SerializeField] private FloatReference dodgeDuration;
    [SerializeField] private FloatReference dodgeSpeedMultiplier;

    [Header("References")]
    [SerializeField] private new Rigidbody2D rigidbody;

    private readonly MovementController movement = new MovementController();

    public float MaxSpeed { get => maxSpeed; }

    private float speed;
    private float Speed { get => speed; set => speed = Mathf.Clamp(value, 0, maxSpeed); }

    public virtual Vector2 Velocity
    {
        get => moveDirection.Value * Speed;
        set
        {
            moveDirection.SetValue(value.normalized);
            Speed = value.magnitude;
        }
    }

    private void Start() => movement.Rigidbody = rigidbody;
    private void FixedUpdate() => movement.Movement(transform.position, Velocity);

    public void Dodge() => movement.Dodge(moveDirection, maxSpeed, dodgeSpeedMultiplier, dodgeDuration);
}

其中 Dodge() 从玩家输入调用。

除了闪避之外,移动完全符合预期。问题可能不在 Move() 方法中,因为其中没有 isDodging

我完全不知道为什么会这样,代码对我来说似乎很简单,但就是行不通。请帮忙解决这个问题。

您在预制件上调用 Dodge 而不是该预制件的场景实例 运行 CreatureMovement.FixedUpdate.

我相信您可以通过将此代码放入 Dodge(来源:Max-Pixel)来验证这一点:

if (gameObject.scene.name == null) Debug.Log("It's a prefab!");

您需要更改输入处理以在场景中的实例而不是预制件上调用 Dodge

您可以通过将场景中的实例拖到按钮的 onclick 事件中,然后选择 Dodge 来实现。或者,如果您动态生成对象,您可以在 Start 中找到对按钮的引用,并将 Dodge 添加到它的 onClick 侦听器中:

private void Start()
{
    movement.Rigidbody = rigidbody;  
    // something along the lines of this...
    Button buttonRef = GameObject.Find("ButtonName").GetComponent<Button>();

    buttonRef.onClick.AddListener(Dodge);
}