2012-01-18 93 views
5

模式,我正在做一個遊戲。遊戲由一架無限的飛機組成。單元必須位於離散正方形中,因此它們可以用簡單的方式定位Location { x :: Int, y :: Int }如何在2D世界哈斯克爾

Unit s可能有多種。有些可能是生物,有些可能只是物體,就像一塊石頭或木頭(想想那裏有二維的我的世界)。許多人將是空的(只是草或其他)。

你將如何在Haskell模型呢?我考慮過在下面做,但Object vs Creature呢?他們可能有不同的領域?規範化他們所有單位?

data Unit = Unit { x :: Int, y :: Int, type :: String, ... many shared properties... } 

我也認爲具有位置類型

data Location = Location { x :: Int, y :: Int, unit :: Unit } 
-- or this 
data Location = Location { x :: Int, y :: Int } 
data Unit = Unit { unitFields... , location :: Location } 

你有什麼想法?在OO語言中,我可能會有LocationUnit從另一個繼承,並使單元的具體類型相互繼承。

另一個考慮因素是這會發送大量的這些對象通過線路的,所以我需要他們序列化JSON在客戶端上使用,並且不希望寫噸解析樣板。

+1

使用'Data.Map.Map'作爲您的網格。 – 2012-01-18 01:38:07

+0

那麼x和y只不過是地圖中的一個關鍵字,而單位只是各自的領域?什麼時候把它們發送給客戶,我是否也應該發送一個地圖/散列呢? – 2012-01-18 01:44:49

回答

7

Location只是一個簡單的二維Point類型。

我建議不要綁Unit s到他們所在的位置;只需使用Map Location Unit即可處理網格上各個位置之間的地圖以及其中存在的內容(如果有的話)。

至於特定類型的Unit走了,我會在最起碼,建議融通共同領域伸到數據類型:

data UnitInfo = UnitInfo { ... } 

data BlockType = Grass | Wood | ... 

data Unit 
    = NPC UnitInfo AgentID 
    | Player UnitInfo PlayerID 
    | Block UnitInfo BlockType 

或相似。

一般因素共同的東西出來爲自己的數據類型,並保持數據的簡單和「孤立」地(即移動的東西,如「什麼地方是這個單位的?」成獨立的結構關聯兩個,這樣個別的數據類型就像「永恆」的,可重用的和抽象的)。

Unit的「類型」擁有String是Haskell中的一個強反模式;它通常表明你正在嘗試使用數據類型實現動態類型或OOP結構,這是不合適的。

你的JSON要求複雜的事情,但this FAQ entry顯示如何慣用實現這種泛型Haskell中沒有String打字或花哨的類型級的黑客,使用功能和數據類型作爲抽象的基本單位一個很好的例子。當然,前者在這裏引起你的問題;很難將函數作爲JSON串行化。但是,你能保持從ADT代表生物或塊等的「類型」的地圖,其實際執行情況:

-- records containing functions to describe arbitrary behaviour; see FAQ entry 
data BlockOps = BlockOps { ... } 
data CreatureOps = CreatureOps { ... } 
data Block = Block { ... } 
data Creature = Creature { ... } 
data Unit = BlockUnit Block | CreatureUnit Creature 
newtype GameField = GameField (Map Point Unit) 

-- these types are sent over the network, and mapped *back* to the "rich" but 
-- non-transferable structures describing their behaviour; of course, this means 
-- that BlockOps and CreatureOps must contain a BlockType/CreatureType to map 
-- them back to this representation 
data BlockType = Grass | Wood | ... 
data CreatureType = ... 
blockTypes :: Map BlockType BlockOps 
creatureTypes :: Map CreatureType CreatureOps 

這讓你擁有所有的可擴展性和不 - 重複自己動手典型的OOP結構的本質,同時保持功能簡單並允許簡單的網絡傳輸遊戲狀態。

通常,您應該避免考慮繼承和其他OOP概念;相反,試圖從功能和簡單結構的組成方面考慮動態行爲。函數是函數式編程中最強大的工具,因此它的名稱可以表示任何複雜的行爲模式。最好不要讓網絡遊戲等要求影響你的基本設計;就像上面的例子一樣,幾乎總是可以將這些東西分層設計在頂部的設計上,這些設計都是爲表現力和簡單性而構建的,而不是像通信格式那樣的限制。

+0

仍在消化,但非常有幫助。謝謝! – 2012-01-18 02:06:39

+0

引發我循環的一件事是一個id字段。我正計劃在redis中存儲狀態,而JSON API將需要通過ID進行一些溝通。我應該爲我的單位添加一個ID字段,還是以某種方式關聯它?例如,一個新客戶可能想說「我是新手!把我的玩家對象給回去!」他們會想要自己的ID,但他們會發送幾個字段來指定他們的球員。服務器生成並返回它。所以他們的對象沒有一個,我返回的對象沒有。 – 2012-01-18 02:46:03

+0

@SeanClarkHess:是的,一個「IntMap單元」或類似的標識符與單位關聯可能是最好的選擇;包括「Unit」中的標識符本身也是合理的。我會考慮將客戶指定的字段分解爲它們自己的結構,並將其包含在「Creature」中,以便客戶可以決定的「無害」位與他們不應觸及的事物隔離(例如健康點);說'CreatureTemplate'。 – ehird 2012-01-18 13:28:44