使用公共静态字段,良好的编程习惯/快速?

时间:2010-07-17 17:20:07

标签: java performance

我正在用Java编写一个大型游戏,我正在尝试优化代码,但也要保持代码整洁有序。现在我不确定是否应该使用具有许多实例使用的几个变量的单个类的公共静态字段。

例如,类摄像机具有x和y位置,用于定义用户正在查看的地图的哪个部分以及需要绘制到屏幕的内容。目前我正在使用5万个单位进行基准测试,我有以下选项来绘制它们。

1:在每个单元中存储对摄像机实例的引用,并在绘制时调用getX()和getY():

public void paint()   
{   
   paint(x - camera.getX(), y - camera.getY());  
}  

2:在绘制时,将摄像机的坐标作为参数提供给每个单元:

public void paint(int cameraX, int cameraY)  
{   
   paint(x - cameraX, y - cameraY);  
}

3:使摄像机类的x和y变量保持静态:

public void paint()   
{   
   paint(x - Camera.x, y - Camera.y);  
}

我感兴趣的是通常被视为最佳解决方案,如果它影响性能。也许有更多方法可以做到这一点我还没有想到呢?

谢谢!

8 个答案:

答案 0 :(得分:3)

我建议您创建一个Painter类并执行以下操作:

public void paint(Painter painter)  
{   
   painter.draw(x, y, unit_sprite);
}

这样单位不必担心相机的存在。这不是该单位的业务如何运作。该单位只需要知道如何在全球统筹方案上绘制自己,画家将了解这与实际的屏幕坐标有什么关系。

为什么这是一个好主意?

  • 减少代码,每个单位不必担心翻译到正确的坐标框架。所有代码都存在于一个位置。
  • 易于改变。例如,假设您决定实施缩放功能。如果每个单位都有自己的翻译,这将是一个痛苦。但是,如果所有这些逻辑都在画家中,您可以修改画家以处理重新缩放图像并确定正确的偏移。
  • 依赖性降低,单位不知道相机是什么,它们更简单,因为他们不担心。

关于您提出的解决方案:

  1. 在对象上存储对相机的引用,假定只有一个相机。如果你实现像拆分视图这样的东西怎么办?这可能不太可能,但是通过存储引用,您可以不必要地将自己锁定在一个视角中。
  2. 拆分变量的问题在于逻辑上这两个部分是一个项目。这使得弄清楚发生了什么有点困难,如果你有一天需要更多的参数会导致问题,并且还会向单位提供它真正不需要的信息。
  3. 这会遇到与#1相同的问题,它会把你锁定在一个整个地方使用的单个相机中。该单元不应负责定义相机的使用方式。
  4. 关于表现:

    差别几乎没有。我不确定在一场表演大战中会有什么方法可以获胜,但我可以告诉你,如果你有性能问题,他们会在其他地方(我猜实际上是blitting功能)。通过组合与偏移相关的所有代码是单个位置,我提出的方法将使实现优化更容易。例如,常见的优化不是绘制屏幕外的东西。如果您有20个函数计算偏移量并调用绘图函数,则必须转到每个函数并更改它们。如果您使用画家,那么您可以简单地更改画家类以忽略在可见区域之外绘制的请求,并且您已完成。

    关于一般的静态变量:

    我认为静态变量(和单例)是全局变量,因此几乎从不使用它们。让它们保持静态可以将我与特定的决定联我不够聪明,无法做出正确的决定,所以我需要我的代码灵活。

    一些指南:

    1. 如果您发现自己需要访问对象内的数据,即x,y值,请考虑是否应该告诉该对象做某事调用方法。即告诉不要问。
    2. 如果对象(如Painter)仅被对象用于特定任务,则它应该是参数而不是成员变量。

答案 1 :(得分:2)

如果您一直只有一台相机,我会选择第三种方式。否则我会选择第二种方式。

我认为从性能的角度来看,使用公共静态字段是一个好主意。就代码可读性而言,如果很容易理解一直只有一台摄像机,那也应该没问题。

答案 2 :(得分:1)

你必须在你的背景下进行基准测试才能确定,但​​这是我的经验:

  • 如果您在内循环中使用少量参数,那么将参数传递给函数通常是最快的。这是因为JIT会将这些分配给寄存器
  • 访问公共静态成员变量也非常快,只有需要注意的问题是潜在的并发问题(例如,当您处于渲染帧的过程中引擎可能会改变相机位置吗?)
  • 通过实例引用访问速度最慢,但仍然足够快,可以在实时游戏中使用。如果您的课程是最终的,并且当然也会内联访问者方法,这会有所帮助。

答案 3 :(得分:1)

使用整数vaule枚举并计算毫秒到m.server。

这是客人而不看任何书籍。

答案 4 :(得分:0)

总的来说,第二个应该提供良好的平衡;它还可以确保您在预期时不会意外地保持对相机的引用,或者您不会遇到与有状态静态字段的冲突。

请记住,无论您选择何种解决方案,您都应该对性能进行分析 - 但在您有证据证明它是一个解决方案之前,不要预期这会成为瓶颈。

答案 5 :(得分:0)

在所有编程语言中,始终建议对静态和实例成员使用get / set方法。如果有必要,这允许透明地更改客户端代码的内部实现。但是,如果性能非常重要,有时这些规则会被打破。

答案 6 :(得分:0)

等一下,看看吧。

long startTime = System.currentTimeMillis();
for(int i=0; i<1000000; i++){
  // Call your code

}
System.out.println("Total time " + (System.currentTimeMillis() - startTime)  + " ms");

我的猜测是JIT将处理差异,它们都将大致相同。没有什么可以替代自己计时。此外,我建议在进行这些微观性能调整之前,分析应用程序并查看在运行应用程序时花费的时间。

答案 7 :(得分:0)

出于同样的原因我有同样的问题(一个大型的java游戏)。

我已经测试了两种表示自上一帧以来时间的变量的方法,它在每一帧的每个对象的每个实例中使用。

一种方式是静态,另一种方式是将变量作为参数从主循环传递到每个对象的每个子类。

以下是我的结果:http://i.stack.imgur.com/WtSue.png

我已经每次测试3次。正如你所看到的结果非常相似,除了在130和210之间,我无法解释原因。