2012-01-18 26 views
5

Tôi đang tạo trò chơi. Trò chơi bao gồm một mặt phẳng vô hạn. Các đơn vị phải nằm trên một hình vuông riêng biệt, vì vậy chúng có thể được đặt với một đơn giản Location { x :: Int, y :: Int }Cách tạo mô hình thế giới 2D trong Haskell

Có thể có nhiều loại Unit s. Một số có thể là sinh vật, và một số chỉ là vật thể, giống như một khối đá, hoặc gỗ (nghĩ rằng 2d minecraft đó). Nhiều người sẽ trống rỗng (chỉ cỏ hoặc bất cứ thứ gì).

Bạn sẽ mô hình hóa điều này trong Haskell như thế nào? Tôi đã xem xét việc làm dưới đây, nhưng những gì về Object vs Creature? họ có thể có các lĩnh vực khác nhau? Bình thường hóa tất cả chúng trên Đơn vị?

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

Tôi cũng đã xem xét việc có một loại vị trí

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

Bạn có bất cứ ý tưởng? Trong một ngôn ngữ OO, tôi có thể đã có Location hoặc Unit kế thừa từ khác, và làm cho các loại đơn vị cụ thể kế thừa từ mỗi khác.

Một lưu ý khác là sẽ gửi rất nhiều đối tượng này qua dây, vì vậy tôi cần serialize chúng vào JSON để sử dụng trên máy khách và không muốn viết tấn bản mẫu soạn thảo.

+1

Sử dụng 'Data.Map.Map' làm lưới của bạn. –

+0

Vì vậy, có x y là không nhiều hơn một phím trong Bản đồ, và các đơn vị chỉ có các lĩnh vực khác nhau của họ? Còn về thời điểm gửi chúng xuống cho khách hàng, tôi có nên gửi bản đồ/băm xuống không? –

Trả lời

7

Location chỉ đơn giản là loại hai chiều Point.

Tôi khuyên bạn không nên đánh cắp Unit giây cho vị trí họ đang ở; chỉ cần sử dụng một Map Location Unit để xử lý bản đồ giữa các vị trí trên lưới và những gì (nếu có) có mặt ở đó.

Theo như các loại cụ thể của Unit đi, tôi sẽ, ít nhất, đề nghị Sacombank lĩnh vực phổ biến ra thành một kiểu dữ liệu:

data UnitInfo = UnitInfo { ... } 

data BlockType = Grass | Wood | ... 

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

hoặc tương đương.

Nói chung, yếu tố phổ biến vào dữ liệu của riêng chúng và giữ dữ liệu đơn giản và "cách ly" càng tốt (ví dụ: di chuyển những thứ như "đơn vị này ở vị trí nào?" Thành các cấu trúc riêng biệt liên kết , để các kiểu dữ liệu riêng lẻ là "vô tận", có thể tái sử dụng và trừu tượng nhất có thể).

Có một số String cho "loại" của một Unit là mẫu antipattern mạnh trong Haskell; nó thường chỉ ra rằng bạn đang cố gắng để thực hiện gõ động hoặc OOP cấu trúc với các loại dữ liệu, đó là một phù hợp xấu.

Yêu cầu JSON của bạn làm phức tạp mọi thứ, nhưng this FAQ entry cho thấy một ví dụ tốt về cách tự nhiên đạt được loại tính tổng quát này trong Haskell không có loại nào. . Tất nhiên, nguyên nhân trước đây khiến bạn gặp vấn đề ở đây; thật khó để nối tiếp các hàm như JSON. Tuy nhiên, bạn có thể duy trì một bản đồ từ một ADT đại diện cho một "loại" của sinh vật hoặc khối, vv, và thực hiện thực tế của nó:

-- 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 

này cho phép bạn có tất cả các khả năng mở rộng và đừng-lặp-mình bản chất của cấu trúc OOP điển hình, đồng thời giữ tính đơn giản chức năng và cho phép chuyển giao mạng đơn giản của các trạng thái trò chơi.

Nói chung, bạn nên tránh suy nghĩ về mặt thừa kế và các khái niệm OOP khác; thay vào đó, hãy thử nghĩ về hành vi năng động về mặt chức năng và thành phần của các cấu trúc đơn giản hơn. Một hàm là công cụ mạnh mẽ nhất trong lập trình hàm, do đó tên, và có thể biểu diễn bất kỳ kiểu hành vi phức tạp nào. Nó cũng tốt nhất là không để cho các yêu cầu như chơi mạng ảnh hưởng đến thiết kế cơ bản của bạn; giống như ví dụ trên, hầu như luôn có thể xếp những thứ này trên trên cùng của thiết kế được xây dựng cho tính biểu cảm và đơn giản, thay vì các ràng buộc như định dạng truyền thông.

+0

Vẫn đang tiêu hóa, nhưng sooo hữu ích. Cảm ơn bạn! –

+0

Một điều đang ném tôi vào vòng lặp là trường id. Tôi đang lên kế hoạch lưu trữ trạng thái trong redis và JSON api sẽ yêu cầu một số thông tin liên lạc về id. Tôi có nên thêm một trường id vào các đơn vị của tôi không, hoặc liên kết nó bằng cách nào đó? Ví dụ: một khách hàng mới có thể muốn nói "Tôi mới! Hãy trả lại cho tôi đối tượng trình phát của tôi!" Họ sẽ muốn có id riêng của họ, nhưng họ sẽ gửi một vài lĩnh vực để chỉ định về người chơi của họ. Máy chủ tạo ra nó và trả về nó. Vì vậy, đối tượng của họ không có, cái tôi quay trở lại. –

+0

@SeanClarkHess: Có, một 'IntMap Unit' hoặc một cái gì đó sắp xếp để liên kết các định danh với các đơn vị có lẽ là sự lựa chọn tốt nhất ở đó; bao gồm cả số nhận dạng chính nó trong 'Đơn vị' là hợp lý. Tôi sẽ xem xét việc bao thanh toán các trường được khách hàng chỉ định vào cấu trúc riêng của họ, và bao gồm nó trong 'Creature', để các bit" vô hại "mà khách hàng có thể quyết định được phân lập từ những thứ mà họ không thể chạm vào (ví dụ: điểm sức khỏe); nói 'CreatureTemplate'. – ehird

Các vấn đề liên quan