简短而简单,我只是不明白为什么它的工作方式如下:
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
是什么给出的?为什么百分比完成每帧重置为0?
如果我将Shake更改为类而不是结构,它可以正常工作。
答案 0 :(得分:1)
也许是因为结构是值类型,因此将Shake对象复制到列表中会按值复制,而不是通过引用复制。
答案 1 :(得分:1)
你正在使用[邪恶的可变结构] http://stackoverflow.com/questions/441309/why-are-mutable-structs-evil)。
当您从列表(或来自强类型字段或局部变量之外的任何其他)调用结构上的方法时,它将在结构的新副本上调用该方法,而不会影响原始结构。
答案 2 :(得分:1)
C#不允许属性访问组合读取和写入,这意味着对结构类型的属性的访问将被视为只读访问。不幸的是,C#没有提供指示struct方法是否会修改this
的方法。因此,尝试调用在只读结构上修改this
的struct方法将编译正常,但它实际上不起作用。
为了避免这个问题,如果你的struct需要定义一个像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]);
是shakes
时尝试类似List<Shake>
的话,编译器就能正确地发出尖叫声,但是会允许{{1}这样的构造如果var temp = shakes[i]; Shake.Update(ref temp); shakes[i] = temp;
是shakes
而不是Shake[]
,则会允许第一个构造(并且它会起作用)。
值类型与引用类型具有不同的语义。有时这些不同的语义可能很有用。对于那些允许方便的分段变异的价值类型而言,语义上的差异更明显,而那些相信所有类型的人应该表现得同样谴责它们是邪恶的,但我不同意这种看法。暴露其所有字段并且没有变异List<Shake>
的方法的结构体将像满足该描述的每个其他结构一样(除了其字段的精确名称和类型)。这种行为与任何引用类型不同,但这就是使它有用的原因。相比之下,虽然可以对具有私有字段的结构进行编码以“假装”为不可变的,并消除值类型的语义优势,但是非平凡结构类型的可变存储位置将始终包含可变结构实例,无论类型是否假装是不可变的。恕我直言,价值类型最好将自己宣传为自己的东西,而不是假装表现为他们不是的东西。