私はハスケルを使ってゲームを作っています(これは割り当てなので、私を判断しないでください)が、データ型に関する問題に直面しています。抽象レコードまたはレコードインターフェイス?
私が望むのは、位置、速度、角度と回転速度を持つデータ型エンティティです。この考えでは、レコードは非常にうまく機能します。
data Entity = Entity {
location :: Vector,
velocity :: Vector,
angle :: Float,
rotation :: Float
}
ここで、エンティティのインスタンス、つまりPlayer Rock PickupとBulletが必要です。しかし、Players RocksとBulletsは余分なフィールド、すなわちhealth :: Intを持たなければならず、Pickupは別のフィールド、すなわちpickupType :: PickupTypeを持っていなければなりません。
しかし、どのエンティティタイプでも作業したい特定の方法があります。例:
move :: Entity -> Entity
move [email protected](Entity {location, velocity, angle, rotation}) = e {location = location + velocity, angle = angle + rotation}
これを行う方法やこれが可能であるかどうかはわかりません。私はなぜこれが不可能なのか理解できません。他の言語でも可能です。
いくつかの試みとなぜ彼らは私が望むかなり何ではありません。
試み1:
type Player = Player {
e :: Entity,
health :: Int
}
これは動作しますが、それは本当に醜いです。これは、たとえば、プレーヤーを移動する方法です。
movePlayer :: Player -> Player
movePlayer [email protected](e) = p {e = move e}
これはちょうど実際には醜いです。
陽性: 抽象クラスを簡単に作成できます。 簡単にインスタンスを作成できます。 簡単な抽象メソッド。
ネガティブ: インスタンスのエンティティ実装フィールドを取得または設定することは難しいです。
試み2:
class Entity e where
getLocation :: e -> Vector
getVelocity :: e -> Vector
...
setLocation :: Vector -> e -> e
setVelocity :: Vector -> e -> e
...
data Player = Player {
playerLocation :: Vector,
playerVelocity :: Vector,
...
playerHealth :: Int
}
instance Entity Player where
getLocation = location
getVelocity = velocity
...
setLocation l e = e {location = l}
setVelocity v e = e {playerVelocity = v}
...
move :: (Entity e) => e -> e
move e = (setLocation (getLocation e + getVelocity e) . setAngle (getAngle e + getRotation e)) e
まあ、それは動作しますが、私たちはそれらの定義は今、本当に醜いしていることすべてに同意することができます願っています。どのエンティティでも動作する抽象メソッドは、邪悪になります。唯一の良いことは、movePlayerのようなメソッドがとても簡単になることです。
movePlayer :: Player -> Player
movePlayer = move
私はmoveを使うことができるので、movePlayerをもう定義する必要はありません。
陽性: インスタンスのエンティティ実装フィールドを簡単に取得または設定できます。
ネガティブ: 抽象クラスを作成するのは難しいです。 インスタンスを作成するのがさらに難しくなります。 難解な抽象メソッド。
試行3:
インスタンスに必要なすべてのフィールドをEntityに与えます。
data Entity = Entity {
location :: Vector,
velocity :: Vector,
angle :: Float,
rotation :: Float,
health :: Int,
pickupType :: PickupType
}
このように、インスタンスを定義する必要はなく、エンティティを使用することもできます。唯一の問題は、余分なデータが大量にあることです。これは現在私が使用しているものであり、IMOは私の問題のための最良の解決策ですが、私はまだそれを好きではありません。
陽性: 抽象クラスを作成するのは簡単ですが、それはもはや抽象クラスではありません。 インスタンスを定義する必要はありません。 簡単な抽象メソッド。 インスタンスのエンティティ実装フィールドを簡単に取得または設定できます。
ネガティブ: 多くの未使用データ。 エンティティを作成するたびに多くのナンセンスフィールドを定義する必要があります。
だから私は非常に単純な理由のために、あなたの最初の試みとなるだろう、私はこれらの3以上良くする方法を見つけることができません:(
あまりにも多くのフィールドが常に不整合な状態を意味するため、最後の方法は本質的に悪いことです。 – ThreeFx
その他:ゲームを書くのにHaskellを使うのに間違ったことはありません:) – duplode