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ゲームエンジンを使用して)このコードを実行すると、構造体Shakeが正しい値をログに記録しません。

完了率は、これらの値(フレームごと)をログに記録します。a0 b 0.001(または、ここでは、そのTime.deltaTime、前のフレームの処理にかかった時間の長さ)c 0

何が得られますか?なぜpercentageCompleteがフレームごとに0にリセットされるのですか?

Shakeを構造体ではなくクラスに変更すると、正常に機能します。

4

3 に答える 3

1

C#では、プロパティアクセスで読み取りと書き込みを組み合わせることができません。つまり、構造体タイプのプロパティへのアクセスは、読み取り専用アクセスと見なされます。残念ながら、C#は、structメソッドが変更するかどうかを示す手段を提供していません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);
}

コンパイラは、次のようなことを試みた場合、正しくスクォークすることができます。whenは、のShake.Update(ref shakes[i]);ようshakesなコンストラクトList<Shake>var temp = shakes[i]; Shake.Update(ref temp); shakes[i] = temp;許可するか、最初のコンストラクトを許可します(。shakesShake[]List<Shake>

値型は、参照型とは異なるセマンティクスを持っています。これらの異なるセマンティクスが役立つ場合があります。意味の違いは、便利な区分的突然変異を可能にする値型の方がそうでない値型よりも明白であり、すべての型が同じように動作する必要があると信じている人の中には、その理由でそれらを悪として非難する人もいますが、私はそのような考え方に同意しません。すべてのフィールドを公開し、変異するメソッドを持たない構造体thisは、その説明を満たす他のすべての構造体と同じように動作します(フィールドの正確な名前とタイプを保存してください)。このような動作は、他の参照型の動作とは異なりますが、それが便利な理由です。対照的に、プライベートフィールドを持つ構造体は、不変であると「ふり」し、値型の意味上の利点を排除するようにコーディングできますが、重要な構造体型の可変の格納場所は、かどうかに関係なく、常に可変の構造体インスタンスを保持します。タイプは不変のふりをします。私見ですが、値型は、そうでないものとして振る舞うふりをするよりも、自分自身を自分のものとして宣伝する方が良いです。

于 2012-10-23T22:57:39.333 に答える
1

[evil mutable struct] http://stackoverflow.com/questions/441309/why-are-mutable-structs-evil)を使用しています。

リストから(または厳密に型指定されたフィールドまたはローカル変数以外の任意のヒットから)構造体のメソッドを呼び出すと、元の構造体に影響を与えることなく、構造体の新しいコピーでメソッドが呼び出されます。

于 2012-10-23T20:22:20.203 に答える
1

構造体が値型であるためか、Shakeオブジェクトをリストにコピーすると、参照ではなく値でコピーされます。

于 2012-10-23T18:26:36.953 に答える