【问题标题】:Weird struct behavior, explanation would be great奇怪的结构行为,解释会很好
【发布时间】:2012-10-23 18:18:30
【问题描述】:

简短而简单,我只是不明白为什么会这样:

using UnityEngine;
using System.Collections.Generic;

// this struct holds data for a single 'shake' source
public struct Shake
{
    public float AmountX;
    public float AmountY;
    public float Duration;

    private float percentageComplete;
    public float PercentageComplete { get { return percentageComplete; } }

    public Shake(float _amountX, float _amountY, float _duration)
    {
        AmountX = _amountX;
        AmountY = _amountY;
        Duration = _duration;
        percentageComplete = 0f;
        Debug.Log("wtf");
    }

    public void Update()
    {
        Debug.Log("a " + percentageComplete);
        percentageComplete += Time.deltaTime;
        Debug.Log("b " + percentageComplete);

        AmountX = Mathf.Lerp(AmountX, 0f, percentageComplete);
        AmountY = Mathf.Lerp(AmountY, 0f, percentageComplete);

    }
}

// This class uses that data to implement the shakes on a game camera
public class CameraShake : MonoBehaviour 
{
    // components
    private Transform myTransform;

    // vars
    private List<Shake> shakes;

    private float totalShakeX;
    private float totalShakeY;

    private void Awake()
    {
        myTransform = transform;

        shakes = new List<Shake>();
    }

    private void Update() 
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            AddShake(new Shake(.1f, .1f, 1f));
        }

        totalShakeX = 0f;
        totalShakeY = 0f;

        for (int i = 0; i < shakes.Count; i++)
        {
            shakes[i].Update();
            Debug.Log("c " + shakes[i].PercentageComplete);

            totalShakeX += shakes[i].AmountX;
            totalShakeY += shakes[i].AmountY;

            if (shakes[i].PercentageComplete >= 1f)
            {
                shakes.RemoveAt(i);
                i--;
            }
        }

        myTransform.position += new Vector3(totalShakeX, 0f, totalShakeY);
    }

    public void AddShake(Shake shake)
    {
        shakes.Add(shake);
    }
}

当我运行这段代码(使用 Unity3D 游戏引擎)时,struct Shake 没有记录正确的值。

完成百分比记录这些值(每帧): 一个 0 b 0.001(或附近,它的 Time.deltaTime,处理前一帧所花费的时间) c 0

什么给了?为什么percentageComplete 每帧都重置为0?

如果我将 Shake 更改为类而不是结构,它可以正常工作。

【问题讨论】:

  • 你怎么打电话给Update()
  • MonoBehaviors 中的Update() 被游戏引擎(Unity3D)自动调用

标签: c# class struct unity3d


【解决方案1】:

C# 不允许属性访问结合读取和写入,这意味着对结构类型属性的访问将被视为只读访问。不幸的是,C# 没有提供指示结构方法是否会修改this 的方法。因此,尝试调用修改只读结构上的this 的结构方法可以正常编译,但实际上不起作用。

为了避免这个问题,如果你的结构需要定义一个像Update这样的方法来修改一个结构,你应该把它改成这样:

public static void Update(ref Shake it)
{
    it.percentageComplete += it.Time.deltaTime;
    it.AmountX = Mathf.Lerp(it.AmountX, 0f, it.percentageComplete);
    it.AmountY = Mathf.Lerp(it.AmountY, 0f, it.percentageComplete);
}

如果您尝试类似以下操作,编译器将能够正确地发出警告:Shake.Update(ref shakes[i]);shakesList&lt;Shake&gt;,但将允许像var temp = shakes[i]; Shake.Update(ref temp); shakes[i] = temp; 这样的构造,或者允许第一个如果 shakesShake[] 而不是 List&lt;Shake&gt;,则构造(并且它会起作用)。

值类型与引用类型有不同的语义。有时这些不同的语义会很有用。允许方便的分段突变的值类型的语义差异比那些不允许方便的值类型更明显,并且一些认为所有类型都应该表现相同的人因此谴责它们是邪恶的,但我不同意这种想法。公开其所有字段并且没有改变this 的方法的结构将像满足该描述的所有其他结构一样表现(除了其字段的精确名称和类型)。这种行为不同于任何引用类型,但这正是它有用的原因。相比之下,虽然可以对具有私有字段的结构进行编码,以便“假装”为不可变,并消除值类型的语义优势,但非平凡结构类型的可变存储位置将始终保存可变结构实例,不管类型是否假装是不可变的。恕我直言,价值类型最好宣传自己是什么,而不是假装自己不是。

【讨论】:

    【解决方案2】:

    也许是因为结构体是值类型,所以将 Shake 对象复制到列表中是按值复制,而不是按引用复制。

    【讨论】:

    • 是的,一切正常 OP 应该了解结构和类实际上做了什么msdn.microsoft.com/en-us/library/ms173109.aspx
    • Hmmmm.. 我不这么认为,因为游戏引擎 (Unity3D) 包含一个名为 Vector3 的向量结构/值类型。当使用 Add 方法和关键字 new 将它们添加到 List 时,它们工作得很好......就像这样:listOfVector3s.Add(new Vector3(0f, 0f, 0f));
    • @Draknir 是的,我不太确定问题出在哪里,这就是我说“也许”的原因。但我看不出有任何其他原因将percentageComplete 重置为零。
    • @Draknir:不可变结构不是问题。
    【解决方案3】:

    您正在使用 [evil mutable struct]http://stackoverflow.com/questions/441309/why-are-mutable-structs-evil)。

    当您从列表(或从除强类型字段或局部变量之外的任何匹配项)调用结构上的方法时,它将在结构的新副本上调用该方法,而不会影响原始结构。

    【讨论】:

      猜你喜欢
      • 2017-04-06
      • 2017-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-28
      相关资源
      最近更新 更多