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:只有coords并且life被改变,例如,而size和始终保持不变,不受影响。hasGravity

这个常量数据代表了某种“特定属性”,或者类属性,但是“实例”携带它们,不安全内存大,序列化不实用


我想创建一个类型类,每个实例都会提供它们的“常量”和可以更改的字段的构造函数。我想不出比这更好的了:

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)

它更轻、更安全,但相当丑陋,因为它失去了结构(不再有逻辑、几何......)。我想如果它们存在的话我会使用 lambda 类型:p。

请分享您对如何解决这些问题或您可以考虑的替代模型的想法。

4

1 回答 1

1

问题是所有这些特定于物种的字段都可以通过其他功能进行修改,但在游戏过程中唯一可以更改的是位置和生命值。

由于 haskell 中的所有数据结构都是不可变的,我假设当您说修改时,您的意思是其他函数可以使用数据构造函数构造新的(可能不同的)对象。

如果您想防止这种情况发生,您可以将数据类型与构造它们的函数(heroenemybullet放在一个额外的模块中,该模块仅导出数据类型的类型构造函数以及用于访问字段和构造函数的函数,但不是数据构造函数。

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 enemyandbullet函数。

于 2012-07-24T20:37:02.540 回答