1

次の単純化されたデータ型は、ゲームのすべてのオブジェクトのベースです。

data Object = Object { logic :: Logic, picture :: Picture }
data Logic = Logic { geometry :: Geometry, someAttributes :: SomeAttributes }
data Geometry = Geometry { coords :: Point, size :: Point }
data SomeAttributes = SomeAttributes { life :: Int, hasGravity :: Bool }

オブジェクトは次の関数によって作成されます。

hero position = Object
    (Logic
        (Geometry position (Point 25 55))
        (SomeAttributes 100 True))
    PictureConstructor1

enemy position = Object
    (Logic
        (Geometry position (Point 25 25))
        (SomeAttributes 3 True))
    PictureConstructor2

bullet position = Object
    (Logic
        (Geometry position (Point 5 5))
        (SomeAttributes 0 False))
    PictureConstructor3

--etc. for blocks and everything else

ゲーム構造の例:

[hero (Point 0 0), enemy (Point 50 0), enemy (Point 100 0), block (Point 0 (negate 30)), block (Point 50 (negate 30)), block (Point 100 (negate 30))]

次に、advance関数がこのリストを受け取り、重力、衝突などを適用し、オブジェクトを動かしたり、死に至らしめたりし[Object] -> [Object]ますObject...たとえば、whileとは常に一定のままで、そのままです。coordslifesizehasGravity

この定数データは、ある種の「特殊な属性」またはクラス属性を表しますが、「インスタンス」はそれらを持ち歩きます。これは、安全ではなくメモリが重く、シリアライゼーションには実用的ではありません。


型クラスを作成することを考えました。すべてのインスタンスは、変更可能なフィールドの「定数」とコンストラクターを提供します。私はより良いものを考えることはできません:

class Object a where
    size :: Point
    baseLife :: Point
    hasGravity :: Bool
    picture :: Picture

data Hero = Hero { coords :: Point, currentLife :: Int }

instance Object Hero where
    size = Point 25 55
    baseLife = 100
    hasGravity = True
    picture = PictureConstructor1

setHero a@(Hero xy _) = Hero xy (baseLife a)

より軽量で安全ですが、構造が失われているため、かなり醜いです (ロジック、ジオメトリなどはもうありません)。ラムダ型が存在する場合は使用すると思います:p。

これらの問題を解決する方法や、考えられる代替モデルについてのアイデアを共有してください。

4

1 に答える 1

1

問題は、これらすべての種固有のフィールドが他の関数によって変更される可能性があることですが、ゲーム中に変更できるのは、たとえば位置とライフ ポイントだけです。

Haskell のすべてのデータ構造は不変であるため、変更と言うときは、他の関数がデータ コンストラクターを使用して新しい (場合によっては異なる) オブジェクトを構築できることを意味していると思います。

それが起こらないようにしたい場合は、データ型をそれらを構築する関数 ( heroenemyおよびbullet) と一緒に、フィールドにアクセスするための関数と構築関数と共にデータ型の型コンストラクターのみをエクスポートする追加のモジュールに入れることができます。ただし、データ コンストラクターは除きます。

module GameData (Object, Logic, Geometry, SomeAttributes, logic, picture, geometry, someAttributes, coords, size, life, hasGravity, hero, enemy, bullet)

data Object = CreateObject { logic :: Logic, picture :: Picture }
data Logic = CreateLogic { geometry :: Geometry, someAttributes :: SomeAttributes }
data Geometry = CreateGeometry { coords :: Point, size :: Point }
data SomeAttributes = CreateSomeAttributes { life :: Int, hasGravity :: Bool }

hero position = ...
enemy position = ...
bullet position = ...

次に、公開するデータ コンストラクターを選択できます。おそらく、すべての「変更可能な」データを独自のデータ型に入れるのが理にかなっているので、そのデータ型のデータ コンストラクターをエクスポートできますが、他のデータ型のデータ コンストラクターはエクスポートできません。

このようにすべてを整理すると、オブジェクトの構築方法を非常に厳密に制御できます。この構築を行うことができるのはそのモジュールだけであり、他のモジュールはhero enemyおよびbullet関数にしかアクセスできないためです。

于 2012-07-24T20:37:02.540 に答える