2010-02-11 53 views
8

我正在爲Android手機制作Java射擊遊戲。我在遊戲中有20個奇怪的敵人,每個敵人都有一些獨特的行爲,但某些行爲被大多數人重複使用。我需要塑造子彈,爆炸物,小行星等等,以及其他所有的行爲都像敵人一樣的東西。我目前的設計有利於在組成繼承和代表遊戲對象有點像這樣:如何以模塊化的方式建模遊戲對象渲染和行爲?

// Generic game object 
class Entity 
{ 
    // Current position 
    Vector2d position; 

    // Regular frame updates behaviour 
    Behaviour updateBehaviour; 
    // Collision behaviour 
    Behaviour collideBehaviour; 

    // What the entity looks like 
    Image image; 
    // How to display the entity 
    Renderer renderer; 

    // If the entity is dead and should be deleted 
    int dead; 
} 

abstract class Renderer { abstract void draw(Canvas c); } 

abstract class Behaviour { abstract void update(Entity e); } 

要只畫無論是存儲實體的圖像,你可以如附加一個簡單的渲染器

class SimpleRenderer extends Renderer 
{ 
    void draw(Canvas c) 
    { 
    // just draw the image 
    } 
} 

爲了使實體飛行約隨機每一幀,他們只是在像這樣的行爲:

class RandomlyMoveBehaviour extends Behaviour 
{ 
    void update(Entity e) 
    { 
    // Add random direction vector to e.position 
    } 
} 

或者添加像等待,直到玩家在尋之前關閉更復雜的行爲:

class SleepAndHomeBehaviour extends Behaviour 
{ 
    Entity target; 
    boolean homing; 

    void init(Entity t) { target = t; } 

    void update(Entity e) 
    { 
    if (/* distance between t and e < 50 pixels */) 
    { 
     homing = true; 
     // move towards t... 
    } 
    else 
    { 
     homing = false; 
    } 
    } 
} 

到目前爲止,我對這個設計非常滿意。這是很好的和靈活的,你可以例如模塊化後一類,所以你可以提供「睡眠」行爲和「清醒」行爲,所以你可以說新的WaitUntilCloseBehaviour(播放器,50/像素 /,新的MoveRandomlyBehaviour(),新的HomingBehaviour())。這使得新的敵人很容易。

困擾我的唯一部分是行爲和渲染器如何進行通信。目前,實體包含一個圖像對象,行爲可以修改它,如果它選擇這樣做。例如,一種行爲可能會改變睡眠和清醒圖像之間的對象,渲染器只會繪製圖像。我不知道這是怎麼回事例如:

  • 那麼面對某個方向的炮塔般的敵人呢?我想我可以添加一個旋轉字段到行爲和渲染器都可以修改/讀取的實體。

    • 那麼坦克的身體和坦克的槍有不同的方向坦克呢?現在,渲染器需要從某個地方訪問兩個旋轉以及要使用的兩個圖像。如果只有一個坦克,你不會真的想用這個膨脹實體類。

    • 敵人在槍中充電時發光呢?您真的想將充值時間存儲在Behavior對象中,但是Renderer類無法看到它。

我有辦法的上方,從而渲染和行爲,可以保持一定程度上獨立於模型的麻煩思考。我能想到的最佳方法是讓行爲對象包含渲染器對象的額外狀態,然後行爲對象調用渲染器的繪製方法,並在需要時傳遞額外狀態(例如旋轉)。

然後你可以有一個坦克般的行爲對象,想要一個坦克般的渲染器,後者要求兩個圖像和兩個旋轉進行繪製。如果你想讓你的坦克只是一個普通的圖像,你只需編寫一個忽略旋轉的子類渲染器。

任何人都可以想到任何替代品?我真的很想要簡單。因爲它是一種遊戲,所以效率也可能是一個問題,例如,繪製一張5x5的敵人圖像,當我有50個敵人以60fps的速度飛行時,會涉及到很多層次的函數調用。

回答

1

組合設計是一個有效的設計,因爲它允許混合和匹配行爲和渲染。我們添加了一個「數據包」,它包含基本信息(在您的情況下位置和死/活狀態)以及由行爲設置/取消設置的變量數據和衝突子系統。渲染器可以使用這些數據(如果不需要,也可以不使用)。這樣做很好,並且可以帶來整潔的效果,例如爲給定的圖形效果設置「目標」。

的幾個問題:

  • 如果渲染請求數據,該行爲沒有設置。在我們的例子中,事件被記錄下來,並使用默認值(在渲染器中定義)。
  • 事先檢查所需的信息有點難(例如,渲染器A的數據庫中應該包含哪些數據?由行爲B設置了哪些數據?)。我們試圖保持doc是最新的,但我們正在考慮通過類記錄set/get,並生成doc頁面...

當前我們使用HashMap數據包,但這是在PC上,而不是在iPhone上。我不知道perfomance是否足夠,在這種情況下,另一個結構可能會更好。

同樣在我們的案例中,我們已經決定了一組專門的渲染器。例如,如果實體擁有非空屏蔽的數據,該ShieldRenderer顯示錶示......在你的情況下,連坦克都具有兩個渲染器連接到兩個(初始化定義)DATAS:

Renderer renderer1 = new RotatedImage("Tank.png", "TankRotation"); 
Renderer enderer2 = new RotatedImage("Turret.png", "TurretRotation"); 

與「 TankRotation「和」TurretRotation「所設定的行爲。渲染器只是在顯示圖像之前旋轉圖像。

image.rotate (entity.databag.getData(variable)); 

希望這有助於

問候
紀堯姆

+0

謝謝。我還沒有對它進行分析,但是如果我想要大量物體(例如子彈)飛行,我可能想要避免使用hashmaps來更新Android上的所有行爲。我注意到將變量存儲保存在行爲對象本地的一個優點是它使得系統更加健壯並且更容易測試,因爲您不必擔心與相同變量混淆的組合行爲。 – BobbyJim 2010-02-19 18:12:35

+0

同意。正如我所說,我們在PC上,並沒有太多的對象。另外,它的樂趣:) – 2010-02-19 20:33:10

1

你與去設計看起來不錯。本章有關components可能會對您有所幫助。

+0

謝謝。我已經實施了上面的方法,這太棒了!有一件事我從來沒有看到人們所建議的是排序行爲(例如,按順序調用兩個行爲的行爲)和條件行爲(例如,一個行爲有條件地調用另一行爲)。感覺現在我已經有了一點腳本語言,它的重量非常輕。例如,通過使用多個對象的組合,我可以說「如果(您距玩家300像素)(玩家在家),否則(在玩家處拍攝)」。我可以編碼新的例如現在只需幾分鐘,遊戲中的敵人就可以開始遊戲。 – BobbyJim 2010-02-19 18:17:04

+0

這很酷。你基本上有一個腳本語言:這是一個教科書[解釋器模式](http://en.wikipedia.org/wiki/Interpreter_pattern)。 – munificent 2010-02-19 23:42:41