繁体   English   中英

如果方法中的某些内容要求该参数使用“ ref”关键字,是否可以使用动态方法参数?

[英]Is it possible to have a dynamic method parameter if something in the method requires the parameter to use the “ref” keyword?

我一直在使用Unity开发平台游戏,并且有很多不同类型的水平移动,所有这些都通过Mathf.SmoothDamp函数执行。 我游戏中的所有内容均按预期工作,但今晚尝试清除一些混乱的代码后,我遇到了Smoothdamp功能的某些问题,特别是使用ref关键字的要求。

Mathf.SmoothDamp(float current, float target, ref float currentVelocity, float smoothTime)

数周以来,代码的结构方式是,我有一个函数可以根据不同的if语句及其关联的布尔值设置水平速度,但是这导致我不得不非常相似地重写许多代码块,只有很小的一部分差异通常是ref float currentVelocity平稳时间变量。

public void SetHorizontalForce(float x)
{
    if (State.IsJumpBoosted && xForce != 0) //Smooths out horizontal movement force when jump boosted left or right (also defines air control when horizontally jump boosted)
    {
        velocity.x = Mathf.SmoothDamp(velocity.x, x + xForce, ref velocityXSmoothingLeft, Parameters.xForceJumpSmoothing);
    }

    else if (State.Launch)
    {
        velocity.x = Mathf.SmoothDamp(velocity.x, Abilities.LaunchVelocity, ref launchVelocitySmoothing, Abilities.LaunchSmoothing);
    }

    else
    {
        if (smoothXForceMovement) //Smooths out horizontal boost movement when landing, so the character doesn't stop abruptly
        {
            velocity.x = Mathf.SmoothDamp(velocity.x, x, ref velocityXSmoothing, Parameters.xForceLandSmoothing);
        }

        if (PlayerInput.DirectionalInput.x != 0) //Otherwise move as normal
        {
            if (PlayerInput.DirectionalInput.x > 0)
            {
                velocity.x = Mathf.SmoothDamp(velocity.x, x, ref velocityXSmoothingLeft,
                    (State.IsCollidingBelow) ? Parameters.accelerationTimeGrounded : Parameters.accelerationTimeAirborne);
            }

            else if (PlayerInput.DirectionalInput.x < 0)
            {
                velocity.x = Mathf.SmoothDamp(velocity.x, x, ref velocityXSmoothingRight,
                    (State.IsCollidingBelow) ? Parameters.accelerationTimeGrounded : Parameters.accelerationTimeAirborne);
            }
        }
    }
}

这似乎不必要地多余,因此我想更改函数以接受参数:

public void SetHorizontalForce(float x, float velocityXSmoothing, float smoothTime)
{
velocity.x = Mathf.SmoothDamp(velocity.x, x, ref velocityXSmoothing, smoothTime);
}

然后,我将在代码的其他部分中根据需要调用此方法,并添加必要的变量以使所有内容再次正常运行。

public void Launch() 
{
    CharacterController2D.SetHorizontalForce(airplaneVelocity, launchVelocityXSmoothing, launchSmoothTime);

    StartCoroutine(LaunchResetTimer());
}

看起来应该可以,但是无论我尝试重写代码有多少种不同的方式,都再也无法实现。 实际上,我的角色几乎无法移动。 直到我删除了float velocityXSmoothing参数并在SetHorizo​​ntalForce函数中对其进行了硬设置,情况才开始好起来。

但是,如果每种独特的运动都没有自己的ref float currentVelocity值,则SmoothDamp似乎“作弊”,并且不会响应您期望的平滑时间。 (为澄清起见,我发现在左右移动时具有单独的平滑时间会导致这些值在平滑时间之前几乎完全平滑;使用单个平滑浮点会使这些值更快地平滑,并且感觉不到对输入的响应。 )

我使用的ref错误吗? 是否有可能像这样使用它作为参数? 我也尝试在SetHorizo​​ntalForce的平滑参数中添加ref ,但这没有用。

编辑:简短答案

private float _velocityXSmoothing = 10f; // You will need to set that to a value that suits you, I used 10f arbitrarily

public void SetHorizontalForce(float x, float smoothTime)
{
    velocity.x = Mathf.SmoothDamp(velocity.x, x, ref _velocityXSmoothing, smoothTime);
}

长答案

这将需要对c#语言的一些理解。

ref关键字表示该值是通过reference传递的 默认情况下,c#中的引用类型对象是通过引用传递的,这意味着如果将它们作为参数传递并进行编辑,则函数返回时,编辑不会消失。 另一方面,默认情况下按值传递值类型对象(例如struct和基本类型(例如float)),这意味着将复制值。 ref关键字用于强制通过引用传递基本类型。 看下面的例子:

private void Start()  
{
    float val = 1f;
    Debug.Log("start with: " + val)
    FuncByValue(val); // This will print val + 3, but not change val in the Start method
    Debug.Log("after FuncByValue: " + val)
    FuncByRef(val); // This will print val + 10, and the change affects val also in this Start method
    Debug.Log("after FuncByRef: " + val)
}

private void FuncByValue(float val) // here, val is a COPY of the argument. like another variable with the same value
{
    val = val + 3;
    Debug.Log("by value: " + val)
}

private void FuncByRef(ref float val) // Here, val is exactly the same variable as the argument
{
    val = val + 10;
    Debug.Log("by ref: " + val)
}

在此示例中,FuncByRef函数将更改vall的值,因此输出将为

开始于:1

按值:4

在FuncByValue之后:1

由ref:11

在FuncByRef之后:11

回到您的代码,然后执行以下操作:

public void SetHorizontalForce(float x, float velocityXSmoothing, float smoothTime)
{
    velocity.x = Mathf.SmoothDamp(velocity.x, x, ref velocityXSmoothing, smoothTime);
}

您通过ref传递速度,这意味着SmoothDamp函数将修改 is。 这在SmoothDamp文档中有所说明

currentVelocity当前速度,此值在每次调用时都会由函数修改。

这样做的原因是SmoothDamp希望您保留修改后的值,以便下次调用SmoothDamp时可以将其退还给您,以使效果继续。 在您的代码中,由于您的函数按值获取速度,因此您不会保留由SmoothDamp修改的值。 要使它起作用,而不是使用ref,可以做的就是将velocityXSmoothing保存为类变量,以便在每次调用之间保留它:

private float _velocityXSmoothing = 10f; // You will need to set that to a value that suits you, I used 10f arbitrarily

public void SetHorizontalForce(float x, float smoothTime)
{
    velocity.x = Mathf.SmoothDamp(velocity.x, x, ref _velocityXSmoothing, smoothTime);
}

现在, _velocityXSmoothing将在每次调用之间保留,并将由SmoothDamp函数正确更新

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM