0

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

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 不会记录正确的值。

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

是什么赋予了?为什么percentageComplete 每帧都重置为0?

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

4

3 回答 3

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]);when shakesis a List<Shake>,但允许构造 like var temp = shakes[i]; Shake.Update(ref temp); shakes[i] = temp;,或者允许第一个构造(并且它会工作),如果shakes是 aShake[]而不是 a List<Shake>.

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

于 2012-10-23T22:57:39.333 回答
1

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

于 2012-10-23T18:26:36.953 回答
1

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

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

于 2012-10-23T20:22:20.203 回答