これらの2つのコードのどちらが「より良い」ですか?ローカル変数またはクラス変数を作成しますか?


11

私はより多くのゲームを作り、より愚かな質問をしています。

うまくいけば、これは非常に簡単です。剛体に力を加えてPlayerオブジェクトを移動するだけの非常に基本的なクラスを作成していますが、rbへのクラス参照を作成するのか、Update every frame内のローカル変数を作成するだけなのでしょうか?(これは、Monobehaviour.GameObject unity親クラスにすでに存在していることを念頭に置いてください)。

多くのローカル変数を実行するとループ全体の速度が低下するのではないかと思います(ローカルとは、クラスの先頭ではなく、関数自体の内部を意味します。正しい用語を使用してください)。

これが私が言いたいことです、私がそれをすることを考えていた2つの方法:

public class Player : MonoBehaviour {

private void FixedUpdate()
{
    Rigidbody rb = GetComponent<Rigidbody>();

    float v = Input.GetAxis("Vertical");

    rb.AddForce(v * rb.transform.forward * Const.walkForce);
}
}

または...

public class Player : MonoBehaviour {
Rigidbody rb;

private void Awake()
{
    rb = GetComponent<Rigidbody>();
}

private void FixedUpdate()
{
    float v = Input.GetAxis("Vertical");

    rb.AddForce(v * rb.transform.forward * Const.walkForce);
}
}

4
これはコードレビューSEの質問のようです。
オルフェフ2018年

1
float vaクラスプロパティを作成することもできます。
チャド

クラス内の2つのメソッドで使用するため、実際にはおそらくチャドになります。大量のコードで肥大化することなく、ローカル変数とクラス変数についての質問をするのは、本当に単純なコードでした。私は変数をローカルに維持することを本当に好みます(そして、その場所で「邪魔にならない」!)もちろん、それぞれにクラス変数を1つ持つのではなく、複製を開始しないようにする必要があります。
Big T Larrity 2018年

コードスニペットは「コード」ではありません。「どちらのコードが良いか」について尋ねると、アマチュアのように見えます。
Miles Rout 2018年

1
私はアマチュアですので、おかげでいいですMiles
Big T Larrity

回答:


25

一般的に、最初にデータの範囲をできるだけ狭くし、必要に応じて範囲を広げる必要があることがわかりました。つまり、メンバーではなくローカル変数にできる場合は、そこから開始する必要があります。

これは、スコープが狭くなると、そのデータについて推論する必要があるコード内の場所の数が減り、そのため、データについて誤って推論できる場所の数が減るためです(バグにつながります)。

実際にローカル変数を宣言するだけでは、実際にパフォーマンスの問題になることは決してありません。それらは安価であり、最新のコンパイラは「エクストラ」を最適化することさえできます。

それらを初期化することは問題になるかもしれません。あなたの場合、剛体はを介して毎回検索されGetComponentますが、コストはゼロではありません。この特定のゲームオブジェクトでリジッドボディコンポーネントが変更さないことがわかっている場合は、リジッドボディコンポーネントを1回検索して結果をメンバー変数に格納し、呼び出しごとのわずかなオーバーヘッドを回避できます。

この1つのインスタンスでコールごとのオーバーヘッドが大きくなる可能性は低いですが、時間の経過とともに、多くのコンポーネントでこれを行うと、合計が増える可能性があります。確かにプロファイラーを適用したいと思うでしょう。

要約すると、一般的に、デフォルトはできるだけローカルにすることですが、この場合rbはメンバーを作成して、一度ルックアップを実行し、呼び出しAwakeごとに実行する必要がないようにするのがおそらく妥当FixedUpdateです。


1
Joshに感謝します。rbを1回だけ初期化するほうがよいと思いました。その理由を明確に説明してくれてありがとう。GetComponentが毎回それを初期化するか、単にMonobehaviourから「ルックアップ」するとカウントしたことは100%確かではありませんでした。しかし、今、私は非常に迅速で役立つ回答
Big T Larrityを

1
@SuperMegaBroBro GetComponent かなり高速です-同等の速度を持つあらゆる種類のルックアップを行うのは難しいでしょう。問題があることを示唆するパフォーマンスデータがない場合は、「物事をローカルに保つ」アプローチを使用してください。後でいつでも最適化できます。answer.unity.com/questions/185164/…を参照してください。キャッシュも無料ではないことを忘れないGetComponentでください。ゲーム内のすべてのキャッシュをキャッシュすると、おそらく正味の損失になります。測定。最適化の価値がある場所を特定します。素晴らしいゲームを作ることに集中し
ましょう

1
この答え(かなり良い)から取り除くべき主な要点は次のとおりです。最も簡単に推論し、テストし、バグがないことを確認するには、ローカル変数を使用します。ただし、いつものように、パフォーマンス上の理由からコードを完璧にするために犠牲を払う必要がある場合があるため、クラスメンバーが適切な場合があります(ただし、最初にプロファイルし、時期尚早な最適化をしないでください)。
Polygnome

元の質問を書いているときに「キャッシュ」の問題について疑問に思っていたので、特にLuaanに感謝します(ただし、どうすればいいかわからなかった)。私は確かに可能な限り「ローカル」アプローチを採用します。いつものようにすべての素晴らしい助けに感謝します。
Big T Larrity 2018年

2

ジョシュ・ペトリーの答えはとても良いです-これは補足的な見方です。

ドメインをかなりよく理解しているコードで作業するとき、変数を意味のある場所にスコープすることができます。

たとえばPersonwaveGoodbyeメソッドを持つクラスがある場合、クラスにhandオブジェクトがなかった可能性があるため、でローカルに宣言できwaveGoodbyeます。さて、ここに人が手を持っているのは明らかなので、あなたはそれをPerson何も考えずにのメンバーとして自然に宣言するかもしれませんが、同じ問題が当てはまります。

handローカルで宣言する場合は、後でkarateChop手作業も必要とするメソッドを追加する可能性があります。これは、変数をローカルで宣言することが問題になる可能性があるときです-ジュニア開発者はしばしば宣言のコピー/貼り付けにフォールバックしwaveGoodbye、今では同じ概念が2つの場所にあります。handその後のすべての変更は、両方の場所で変更する必要があるため、アリバグの丘が始まります。

結局のところ、

  1. 宣言の配置に自信がある場合は、意味のある場所にスコープを設定してください。

  2. 自信がない場合は、ローカルで起動し、コードの再利用のヒントを得たときに必ずリファクタリングしてください。

編集:ああ、私があなたの宣言をどこにスコープするかを理解するのにあまりにも多くの時間を費やすのと同じ間違いをしないでください。データの構造を前もって理解することは困難であり、コードを記述すると、構造にはそれ自体を明らかにする方法があります。


2
また、アプリケーションに関連する場合Personはすべてにメンバーが必要であるように、自然に順序付けされたものがあると、他の開発者(多くの場合 6か月後)がコードをよりよく理解するのに役立ちます。この場合、のメンバーとしてを使用するのは論理的であり、パフォーマンスが低下することを意味するとしても、ビデオゲームで考慮すべき関連するポイントですが、私は思うのコードでは、明確にすることが多い方が重要であるhand RigidbodyPlayer
alseether

1
素晴らしい答えはみんなに感謝します。私は万能薬のように聞こえるようにしようとはしていませんが、これらのすべての答えは、私がすでに考えていたことを再確認しただけなので、一度は非常に満足し、ゲームでいくつかの素晴らしい進歩を遂げています。今私は適切なアニメーションとすべてを備えた3Dフットボールゲームを作成しています。実際の進歩を遂げています。
Big T Larrity 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.