2012-01-16 35 views
2

我正在开发一个Java游戏,我遇到了一个问题,它决定了如何从我使用的框架中抽象出我的游戏世界。Java游戏开发:试图分离世界和渲染器

因为我现在有一个叫做World的课程,它可以跟踪世界上所有不同的物体,并根据游戏规则更新它们。然后我有三个基本对象类Person,ObstacleItem。每个对象都有不同的“类型”,它们由成员变量表示。所有对象类都从类GameObject扩展而来。

就像我现在使用的World和对象类与呈现游戏等的框架是分开的。类Game都告诉世界更新和呈现世界和世界上的物体。

问题是,我使用三种方法drawPersons()drawObstacles()drawItems()呈现对象,这很好,因为我已经编写了代码,我不会再添加任何对象类。真正的问题是渲染每个对象类的不同“类型”。就像我现在的绘图方法通过检查变量object.type来绘制项目,然后有一个switch语句选择适当的位图进行绘制。

我想简化它,所以我不必在每次给Item类添加一个新的“类型”时都添加到switch语句中。我认为这样做的唯一方法是让对象存储它们应该呈现的位图,因为它们在构建时具有其item.type变量集。这样我可以从drawItems()方法中删除开关语句。此外,我还可以给每个对象类一个draw()方法等等等等等等,但是我不想这样做的原因是因为它破坏了我与渲染器/框架和虚构游戏世界的分离。

我不确定该怎么做,一方面我知道使用switch语句是个不错的主意,就像我现在在使用switch语句,但另一方面,我知道这是更好的设计,让我的World和object类独立于框架,所以如果我想我可以把它打入一个新的框架或任何事情。

我有两种方法吗?

+2

正如旁注:你可能会得到更具体的帮助:http://gamedev.stackexchange.com/ – Thomas 2012-01-16 07:57:50

+0

谢谢你的建议,有没有办法移动这个问题,或者我只是转发问题? – 2012-01-17 03:29:02

+0

我不确定您是否可以提出更多问题,但我确定版主可以。如果您愿意,我们可以将其标记为主持人的注意力,让他们移动它。 – Thomas 2012-01-17 06:38:54

回答

2

您可以做的是使用组合,即您的实体包含多个具有不同用途的组件。例如,可能有一个渲染组件,一个物理组件,一个AI组件等。

世界通常会管理实体,然后子系统会查询实体以查找正确的组件。因此,如果渲染器想渲染一个实体,它将查询它的渲染组件,并可能是一个位置组件,并使用它们提供的数据来渲染实体。

在这种情况下呈现组件中可能包含纹理/位图,形状,材料等

欲了解更多信息的数据你可能想看看entity systems

+0

您的链接将我带到了[本文](http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/),我很好奇我将如何专门用Java解决这个问题。 – 2012-01-17 03:26:46

+0

@StickFigs查看我发布的链接的开源实现部分。作者在那里有一个Java实现的例子(实际上有两个:ES Alpha和ES Beta)。为方便起见,以下是ES Beta回购的链接:https://github.com/adamgit/Entity-System-RDBMS-Beta--Java- – Thomas 2012-01-17 06:35:15

+0

由于我无法再编辑我的评论,下面是一个更正:看一看在文章第一部分的“ES方法”链接中我链接了:) – Thomas 2012-01-17 06:42:20

2

将图像对象存储在每个可绘制对象中应该不是问题。存储图像不会中断渲染循环的功能。有时,如果不需要,过度抽象会很麻烦。我发现将图像存储在对象中没有任何问题。一旦开始向游戏添加更多可绘制对象,切换语句很快变得非常低效。想想有数百个可绘制对象的游戏。从长远来看,指针只需要很小的空间并加快代码的速度。

+1

我真的很感谢你牺牲抽象的简单性和性能的观点。如果我无法找到替代解决方案,我很可能会采取这种做法。 – 2012-01-17 03:24:09

+0

在高度面向对象的环境中,抽象可能最适合您,并且有很多数据重叠。还要考虑代码模块化。抽象可以有多种形式。通过从drawable对象中抽象draw()方法,您牺牲了World渲染循环的灵活性。对此可能有更多可行的解决方案,但switch()语句绝对不是解决这个问题的方法。祝你好运。 – collinjsimpson 2012-01-17 03:35:01

2

您可以调查Visitor pattern。你的游戏世界中的对象需要通过他们执行一些操作来识别的访问者:在这种情况下,操作正在绘制。用于根据游戏对象的不同实现选择的逻辑被保留在访问者一侧。

2

我相信你可以使用Decorator Pattern来包装你的课程。

修饰器包含一个GameObject实例,并将通过调用原始实例上的方法实现GameObject函数。

当您以这种方式继承GameObject时,还可以使装饰器使用draw()方法实现Renderable接口。

1

我建议你是使用位图在一个大的图像atlasing即你的图像,然后在您的游戏对象类的抽象方法,返回的是一个游戏的对象在册的区域。

这样

public abstract class GameObject{ 

... 
... 
.. 

public abstract TextureRegion getGameObjectTextureRegion(); 
... 
.. 
} 

,并在每个扩展游戏对象存储实例变量,这样

public class Person extends GameObject{ 
.... 
.... 
... 
public static final TextureRegion person_region = new TextureRegion(top,left,height,width); 
... 
... 
public TextureRegion getGameObjectTextureRegion(){ 
return person_region; 
} 

然后存储在阵列或所有的游戏对象ArrayList 这样

ArrayList<GameObject> game_objects = new ArrayList<GameObject>(); 
//add items to it 
game_objects.add(new Person()); 
gmae_objects.add(...); 

并在你的绘制方法循环t他game_objects列表和电话getGameObjectTextureRegion

for(GameObject item : game_objects) 
{ 
TextureRegion region = item.getGameObjectTextureRegion(); 
// then pass them with the game object position to your rendering method 
... 


} 

注:TextureRegion看起来像这样

public class TextureRegion{ 

float top; 
float left; 
float width; 
float height; 
} 
+0

我理论上喜欢这个想法,但不幸的是我很容易经常更改图形资源,而且我的工作流程不够复杂,无法自动处理所有移动我需要处理地图集 – 2012-01-17 03:22:05

0

我喜欢托马斯的 “实体系统” 的答案。但我自己正在考虑一种不同的方法。我会尽可能抽象地介绍它,因为我对Java不太熟悉。

您可能有某种'resources'变量存储了object_type:data对,其中包含您打算在世界中插入的每种类型对象所需的资源。 '资源'变量可以是动画列表或任何其他公共资源。

更具体一点,让我给你一个Python的例子(因为这是我所知道的最好的)。在Java或几乎任何其他语言中应用相同的问题都不应该成为问题。在Python中,我将创建一个字典变量,看起来像这样:

{ 
Person1:["person1.bmp", "person1_alternative1.bmp", "person1_whatever.wmv"], 
Person2:["person2.bmp", "person2_alternative1.bmp", "person2_whatever.wmv"], 
Obstacle1:["Obstacle1.bmp", "Obstacle1_alternative1.bmp", "Obstacle1_whatever.xyz"], 
Obstacle1:["Item1.bmp", "Item1_alternative1.bmp", "Item1_whatever.xyz"] 
} 

...等等

您认为合适你可以延长该还;添加其他类型的资源,可能是对象坐标,尺寸或其他。例如

{ 
person1:{basic_animation:"person1.bmp", alt_animation:"person1_alternative1.bmp", sfx1:"person1_whatever.wmv"}, 
person2:{basic_animation:"person2.bmp", alt_animation:"person2_alternative1.bmp", sfx1:"person2_whatever.wmv"}, 
obstacle1:{basic_animation:"obstacle1.bmp", alt_animation:"obstacle1_alternative1.bmp", res1:"obstacle1_whatever.xyz"}, 
item1:{basic_animation:"item1.bmp", alt_animation:"item1_alternative1.bmp", sfx1:"item1_whatever.wmv"} 
} 

Java的语法和可能不同,但您会得到一般想法。我不确定Java如何处理关键:值类型的变量,我认为它有一些类。如果没有,你总是可以自己做。

这个大的'资源'变量可以是你的游戏类的一部分,当你实例化游戏类时,可以初始化并填充相关数据。它甚至可以存储在别的地方,如果你喜欢把所有的常量分组在一个单独的地方/模块/任何(我这样做!)。然后,您可以将drawPersons(),drawObstacles()和drawItems()统一为一个draw()函数,为每个“对象”检查“object.type”并在“资源”中查找以获取其相关数据。

现在我不知道性能和其他因素,可能它需要一些聪明人的一些优化!

+0

哇!我刚刚意识到问题的年龄:| – 2014-01-22 09:39:52