开发者

Discriminated unions and inheritance

开发者 https://www.devze.com 2023-01-14 02:27 出处:网络
I\'m looking to create a scene-graph for my F# project somthing like: root ->player_bob -->torch ->enemy_1

I'm looking to create a scene-graph for my F# project somthing like:

root
->player_bob
-->torch
->enemy_1
-->extravagant_hat
-->enemies_cat_jess 
--->fleas
--->fur_ball
->loot

etc,etc.

Each item needs to hold a collection of game objects to represent it's children.

e.g e开发者_StackOverflow社区nemy1's list contains a cat and a hat and the cats list contains fleas and a fur ball

So I plan to make them all inherit from a class that contains a collection that describes that objects children.

Now to my question: Should I down-cast child objects to GameObject's and store them in a list of the "GameObject" base class OR create a discriminating union e.g

type SceneObject = 
        |Character of Character //e.g player, enemy, cat
        |Item of Item //e.g hat, torch, furball

And store objects as a list of "SceneObjects" to avoid any problems/overheads with up-casting them, etc. As well as allowing me to describe special cases where the object isn't rendered and/or not used in collision detection e.g: sound emitters, trap triggers, etc.

The discriminated union + inheritance combo is my initial thought; though, as I'm new to FP, I thought it wise to ask the pro's for the best, functional, way of approaching this.

Thanks,

JD


You can use the discriminated union recursively.

type SceneObject = 
    | Character of <characterData> * (SceneObject list) 
    | Item      of <itemData>      * (SceneObject list)

And use it like this

let root = [Character("Bob", [Item("Torch", []); ...]); ...]


An alternative to what Dario suggest is to declare a separate type for actual objects in the game (such as items and characters) and wrap it in another object that adds a list of child objects. This would look like this:

type SceneObject =
  | Character of <characterData>
  | Item of <itemData>

type ObjectWithChildren = 
  { Object : SceneObject
    Children : ObjectWithChildren list }

Both of the options are correct functional design, but I would prefer this version, because it makes certain kinds of processing easier. For example, if you wanted to traverse all objects in the game tree, you can write something like:

let rec traverse tree = 
  // Do something with tree.Object
  for child in tree.Children do traverse child

In this version, you don't need to pattern match on SceneObject at all, so you don't need to include all the cases (such as Item and Character).

0

精彩评论

暂无评论...
验证码 换一张
取 消