我目前正在用 Java 开发一个小平台,我为它编写了自己的游戏引擎 Bonsai .现在我在问自己“我是否过度使用静力学?”这个问题。
一方面,它非常方便,因为我不必在每个类(如 map 或玩家)中保留对游戏实例的引用。另一方面......我已经不得不去掉小程序支持,因为它有很多静态的东西。
所以我的问题是,既然你们可能是比我更有经验的 Java 程序员,我应该摆脱所有的静态因素吗?如果是的话,什么是达到这样的效果的有效方法:
public void draw(Graphics2D) {
if (this.game.time() > this.timer) {
this.game.image.draw(this.tiles[this.game.animation.get("tileAnim")], x, y, null)
}
}
代替:
public void draw(Graphics2D) {
if (Game.time() > this.timer) {
Image.draw(this.tiles[Animation.get("tileAnim")], x, y, null)
}
}
在 map 编辑器中甚至更糟:
public void control() {
if(this.map.game.input.keyPressed(...)) {
this.map.game.sound.play(...);
}
}
编辑
根据答案,我决定创建一个 GameObject 类,它为每个组件提供包装器方法。 map 、播放器等,然后从它继承子类,这样我所有的 this.game 调用都隐藏在幕后,它在前端看起来仍然不错:
public class GameObject {
private Game game;
public GameObject(Game g) {
game = g;
}
public Game Game() {
return game;
}
public GameAnimation Animation() {
return game.animation;
}
public GameInput Font() {
return game.input;
}
// ...
public long Time() {
return game.time();
}
}
现在代码看起来像这样:
public class Player() {
public Player(Game g, int xpos, int ypos) {
super(g);
// do other stuff
}
public void jump() {
// jump code
Sound().play("jump");
}
}
或者这是更糟糕的 Java?
EDIT2
好吧,我已经遇到了使用方法调用的问题,编译器给我错误,因为它无法在原始游戏中找到我的子类游戏的方法,我想我只是要在这里使用普通字段。
EDIT3
好的,我的 GameObject 类现在看起来像这样,一切正常,我可以重新实现小程序支持:)
public class GameObject {
protected Game game;
protected GameAnimation animation;
protected GameFont font;
protected GameInput input;
protected GameImage image;
protected GameSound sound;
public GameObject(Game g) {
game = g;
animation = game.animation;
font = game.font;
input = game.input;
image = game.image;
sound = game.sound;
}
}
最佳答案
首先。
您不必删除所有静态代码,只是因为这样会使它在“纸上”更好。
您真的必须了解实例代码(非静态)和类代码(静态)之间的区别
static 代码(类方法/属性)在方法/属性不需要类的实例工作时使用。一个很好的例子是图像绘制方法:Image.draw()
实例 方法/属性可用于保持给定对象的状态,该对象必须与其他对象中的数据分开。
例如,如果您的游戏中有 Player
类,并且您有两个实例 player1
和 player2
,那么它们中的每一个都有意义有自己的分数:
public class Player {
private int score;
private String name;
etc.....
}
Player one = new Player("Player 1");
display( one.score );
Player two = new Player("Player 2");
display( two.score );
而不是必须创建工件来保持每个玩家的分数(比如将它们放在数组中,其中每个索引都是一个属性并使该数组静态等)
其次
您可以通过为对象分配适当的属性并以正确的方式执行封装来减少您提到的构造object1.atr2.other.next.etc
。
如果对象 b
需要访问另一个 a
的第 N 个元素,则所述属性很可能属于对象 b
而不是 a
或者可能那个对象 a
应该提供一种方法来避免暴露它的内部结构。
它甚至使代码更易于阅读:
即。
public void draw(Graphics2D) {
if( this.game.needsDrawing() ) {
this.game.draw();
}
}
代替:
public void draw(Graphics2D) {
if (this.game.time() > this.timer) {
this.game.image.draw(this.tiles[this.game.animation.get("tileAnim")], x, y, null)
}
}
同样,这取决于情况,可能存在不需要实例的情况(同样,例如 Image 的 draw() 实用方法)
最后。
实例方法允许您使用多态性,而类方法则不允许(至少在 Java 和其他静态类型语言中)。
因此,如果您的代码是实例代码,您可能会受益于使用运行时委托(delegate)和多态性。以 State pattern 为例如果您的所有代码都是静态的,您将无法使用它,但您可以使用实例代码:
class Game {
GameState state = GameState.getInitialState( this );
void run() {
while( state.alive ) {
do X Y Z
state.updateState();
}
}
}
class GameState {
Game context;
static GameState getInitialState( Game g ) {
return new StartGameState(g);
}
void updateState();
}
class StartGameState {
void updateState() {
if( this.context.someCondition() ) {
this.context.state = new MidGameState();
}
}
}
class MidGameState {
void updateState() {
if( this.context.someOtherCondition() ) {
this.context.state = new EndGameState();
}
}
}
class EndGameState {
void updateState() {
Game over...
}
}
再一次,只有当这在面向对象方面有意义时,比如对象是否具有需要其数据的属性?如果不是,最好将该部分代码保持静态。
所有这些概念(封装、多态、抽象、继承等)都是 OO 技术的本质,涵盖在 OOA/D 中。虽然它们看起来像是语法糖(大多数情况下确实如此),但您的经验会告诉您何时应该将某些东西作为类 代码以及何时作为实例 代码。
关于java - 在我的 Java 游戏项目中过度使用静态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1561299/