2012-01-16 60 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