这两个代码中的哪个“更好”?制作局部变量还是类变量?


11

我制作了更多游戏,问了更多愚蠢的问题。

希望这一段很简短。我正在创建一个非常基本的类,该类通过向刚体施加力来移动Player对象,但这让我想知道,我应该对rb进行类引用还是对Update每帧进行局部引用?(请记住,它已经存在于Monobehaviour.GameObject统一父类中)。

我想知道是否做很多局部变量会减慢整个循环的速度(通过局部变量,我的意思是在函数本身内部,而不是在类的顶部,希望我使用正确的术语)。

这就是我想做的两种方式:

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的问题。
Orphevs

1
您还可以使float va类属性。
乍得

最终我可能会实际使用Chad,因为我将在类中的两个方法中使用它。这实际上是简单的代码,可以解决有关局部变量和类变量的问题,而无需花费大量代码来解决。我真的很喜欢将变量保存在局部(并且在任何地方都保持“顺畅”!),但是当然,我必须确保不要开始复制事物,而不是每个变量都有一个类变量。
Big T Larrity

代码片段不是“代码”。询问“哪种代码更好”会让您看起来像个业余爱好者。
Miles Rout

1
我是一名业余选手,所以对我来说还不错,谢谢Miles
Big T Larrity

Answers:


25

总的来说,我发现您应该尽可能缩小范围的数据范围,从头开始并根据需要扩展范围。这意味着,如果您可以使其成为局部变量而不是成员,则应从此处开始。

这是因为范围较窄会减少代码中您必须推理出该数据的位置数,从而减少了您可以错误地推理出该数据的位置数(这会导致错误)。

实际上,仅声明局部变量几乎不会引起性能问题:它们很便宜,现代编译器甚至可以优化“扩展”。

初始化它们可能是一个问题。在您的情况下,每次通过都会查询您的刚体GetComponent,这会带来一些非零的费用。如果您知道该特定游戏对象的刚体组件不会改变,则可以查找一次并将结果存储在成员变量中,从而避免每次调用的开销。

在这种情况下,每次呼叫的开销不太可能会很大,但是随着时间的流逝,许多组件的开销可能会增加。您需要确定使用探查器。

因此,总结一下:通常,默认情况下,使事情尽可能地本地化,但是在这种情况下,使rb成员成为可能是合理的,这样您就可以一次执行查找,Awake而不必每次FixedUpdate调用都进行查找。


1
谢谢Josh,我确实认为将rb初始化一次会更好,并且非常感谢您清楚地解释了原因。很高兴知道,您不是100%肯定每次将GetComponent都计为初始化它,或者只是从Monobehaviour中“查找”它。但是,现在我对超级快速的有用答案非常感谢
Big T Larrity

1
@SuperMegaBroBro GetComponent 相当快-你会很难做的任何类型的具有可比性的速度查找。除非您有表明存在问题的性能数据,否则请坚持“保持本地化”的方法。您以后可以随时对其进行优化。见answers.unity.com/questions/185164/...不要忘记,缓存也不是免费的-如果缓存每一个GetComponent在你的游戏,这将可能是一个净损失。测量。确定哪些地方值得优化。专注于制作出色的游戏:)
六安'18

1
您应该从此答案中获得的主要要领(非常不错)是:如果要获取最容易推理,测试并确保没有错误的代码,请使用局部变量。但是,和往常一样,出于性能原因,有时我们有时需要牺牲一些代码来完善代码,因此类成员可能是合适的(但首先要进行概要分析,不要简单地进行过早优化)。
Polygnome

非常感谢大家,尤其是Luaan,因为我在写原始问题时一直在想这个“缓存”问题(但我真的不知道该怎么说)。我当然会尽可能采用“本地”方法。像往常一样感谢所有的帮助。
Big T Larrity

2

乔什·皮特里(Josh Petrie)的回答非常好-这是一个互补的观点。

当您使用相当了解领域的代码时,可以将变量的作用域限定在有意义的范围内。

例如,如果我有一个Person带有waveGoodbye方法的类,则我的类以前可能没有hand对象,因此可以在中本地声明它waveGoodbye。现在在这里很明显一个人有帮助,您可以自然地将其声明为的成员,Person而无需考虑它,但是同样的问题也适用。

如果在hand本地声明,则稍后可能会添加一个karateChop也需要帮助的方法。在这种情况下,在本地声明变量可能会引起问题-因为初级开发人员经常回退到从那里复制/粘贴声明waveGoodbye,现在您在两个地方都拥有相同的概念。hand然后需要在这两个地方都修改对的任何更改,从而开始了一个蚂蚁爬坡。

总而言之,

  1. 如果您对声明的位置有信心,请将其范围限定在合理的范围内。

  2. 如果您不确定,请从本地启动,并确保在听到一些代码重用时进行重构。

编辑:哦,不要犯同样的错误,我花了太多时间弄清楚声明的范围。预先了解数据的结构很困难,并且在编写代码时,结构可以显示自身。


2
也有东西自然有序,像每一个Person应该有成员hand 如果相关的应用程序,经常帮助其他开发者(大多数时候 6个月后),以便更好地理解代码。在这种情况下,Rigidbody在您的成员中拥有一个逻辑上似乎是合乎逻辑的Player,我要说的更多,即使这意味着性能较差。在视频游戏中,需要考虑的一个相关问题,但我认为在代码中,保持清晰通常更为重要
参见

1
优秀的答案,谢谢大家。我并不是想听起来像个万事通,但是所有这些答案都再次重申了我已经在想的事情,所以有一次我很高兴并且在游戏中取得了不错的进步。现在,我正在制作具有适当动画和所有内容的3D足球游戏,并取得了长足的进步:D很快,我将在这里需要有关如何使其成为2人游戏的帮助,我敢说在线mulitplayer:D大家开心,再次感谢!
Big T Larrity
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.