2016-03-20 5 views
5

ゲームをプログラミングしたいと思います。複数のエンティティにコンポーネントパターンを使用したいと思います。Nim - メソッドを実装するオブジェクトのシーケンスを作成します。

interfaces/type-classes/multiple inheritanceの言語では問題ありません。

いくつかのエンティティは更新可能ですがレンダリング可能ではないものが必要ですが、いくつかは両方とも必要です。


ハスケル:

class Updateable a where 
    update :: Float -> a -> a 

class Renderable a where 
    render :: a -> Picture 

class InputHandler a where 
    handleInput :: Event -> a -> a 

私は更新することが可能なもののリストを作成することができます。 Javaでは

updateAll :: Updateable a => Float -> [a] -> [a] 
updateAll delta objs = map (update delta) objs 

/D/...これは今、私はこれがマルチメソッドとNIMで実現することができるか疑問に思ってインタフェース

interface Updateable { 
    void update(float delta); 
} 

// somewhere in a method 
List<Updateable> objs = ...; 
for (Updateable o : objs) { 
    o.update(delta); 
} 

を経由して実施することができます。

フィッティングマルチメソッドの存在をタイプで表現できますか?

var objs: seq[???] = @[] 



編集:より多くのコードと固定間違ったHaskellの例明示的な interfaceキーワードの欠如が common question in the Nim communityある

+0

[コンセプト](http://nim-lang.org/docs/manual.html#generics-concepts)のように思えますが、まだWIPであり、私は 'seq [Updatable] '。 'updateable = concept x update(x)' – Karroffel

+0

あなたの例では、複数の継承をどの程度正確に使いたいかは不明です。たとえば、コンポーネントがrender()やupdate()を実装していない場合は、何もしないでください。一般的なエンジンのコンポーネントベースのアーキテクチャ(Unity3d、UE4)を見ると、ユーザが実装するコアクラス用のインタフェースは使用されません。実装する必要がある多くのインタフェースよりも単一の「コンポーネント」型について考える方が簡単です。 – endragor

答えて

3

これがあなたの質問に答えるかわかりませんが、言及する価値はあります。

ゲームオブジェクトをタイプに基づいて別々のリストに保存する場合、まだ多くの一般的なロジックを書くことができます。先読みと分岐予測のため、オブジェクトを型で格納する方がパフォーマンスが向上します。彼が話していることを知っている人から、この講義を参照してください:Multiprocessor Game Loops: Lessons from Uncharted 2: Among Thieves

たとえば、一部のオブジェクトタイプに対してtexture procを定義した場合は、それらのすべてに対して機能する汎用draw(t: T) = magicRenderToScreen(texture(t)) procを記述することができます。これは、リソースプールやその他の一般的な動作を実際に実装している場合にも便利です。

影響を受ける各オブジェクトタイプをレンダリングループと更新ループに含める必要がありますが、それは実際には大したことではありません。単純なマクロを使ってこれを冗長にすることもできるので、レンダリングループには次のような内容が含まれているだけです。renderAll(players, enemies, sprites, tiles)

一般的なリストはコンパイルされた言語では単純ではありません。ゲームに取り組んでいます。ジェネリックリストを作成するには、通常、ポインタと動的ディスパッチ、または何らかの種類のユニオンタイプを使用する必要があります。私はニムが親オブジェクトのrefから正しいマルチメソッドにディスパッチできることを覚えているようです(リストはいくつかの型を含み、実行時に動的にディスパッチできます)。完了...?

もっと知りたい方は、教えてください。

+0

答えをありがとう。共通のスーパークラスに基づく動的ディスパッチはまだ行えますが、インタフェース(存在しない)を介して複数の継承をシミュレートしようとしました。私は、さまざまな種類の複数のリストに行きます。 – Karroffel

+0

これ以上考えてみると、行動のリストもあり、それらのリストへの参照からゲームオブジェクトを構成することは可能でしょう。 – Jostein

3

を追加しました。あなたが他のアプローチのためのインターフェースがかもしれ必要正確に何に応じて、read in that forum threadすることができますように、しかし

import strutils # For formatFloat 

type 
    IUpdateable = 
    tuple[ 
     update: proc(v: float) {.closure.}, 
     show: proc(): string {.closure.} 
     ] 

    Rounded = ref object 
    internalValue: float 

    Real = ref object 
    a_real_value: float 

# Here goes our rounded type. 
proc `$`(x: Rounded): string = 
    result = "Rounded{" & $int(x.internalValue) & "}" 

proc updateRounded(x: Rounded, delta: float) = 
    x.internalValue += delta 

proc getUpdateable(x: Rounded): IUpdateable = 
    result = (
    update: proc(v: float) = x.updateRounded(v), 
    show: proc(): string = `$`(x) 
    ) 

converter toIUpdateable(x: Rounded): IUpdateable = 
    result = x.getUpdateable 

# Here goes our Real type. 
proc `$`(x: Real): string = 
    result = "Real{" & 
    x.a_real_value.format_float(precision = 3) & "}" 

proc update_real(x: Real, delta: float) = 
    x.a_real_value += delta 

proc getUpdateable(x: Real): IUpdateable = 
    result = (
    update: proc(v: float) = x.update_real(v), 
    show: proc(): string = `$`(x) 
    ) 

# Here goes the usage 
proc main() = 
    var objs: seq[IUpdateable] = @[] 
    var a = Rounded() 
    var b = Real() 
    a.internalValue = 3.5 
    b.a_real_value = 3.5 

    objs.add(a) # works because of toIUpdateable() 
    objs.add(b.getUpdateable) 

    for obj in objs: 
    echo "Going through one loop iteration" 
    echo "\t", obj.show() 
    obj.update(0.4) 
    echo "\t", obj.show() 
    obj.update(0.4) 
    echo "\t", obj.show() 

main() 
# -> Going through one loop iteration 
# -> Rounded{3} 
# -> Rounded{3} 
# -> Rounded{4} 
# -> Going through one loop iteration 
# -> Real{3.50} 
# -> Real{3.90} 
# -> Real{4.30} 

:Araqの答えを撮影し、Java/Dスニペットに基づいて仮想的なケースに適用する、私たちはこのような何かを書くことができより良い。また、おそらく将来の道のりはconceptsですが、通常はマニュアルが乾燥していてthe related unit tests are crypticなので、以前のタプルの例をコンセプトに変換することはできませんでした。

もしあなたが概念のために行くと思うのであれば、フォーラムで直接質問するべきですが、マニュアルには、concepts are still in developmentと書かれているように注意してください。

+0

コンセプトのアプローチは行き詰まっているようです。コンセプトにはランタイム表現はありません。 seq [Updateable]を作成することはできません。クロージャのタプルを使用することは正しく感じません。コンパイラができないので、独自のvtableを構築するようなものです。私はNimが1.0リリースの前にインタフェースを取得することを願っています – Karroffel

+1

一般的に、Nimのアイデアは、[そのような機能を実装する可能性を残す]というものです(https://bitbucket.org/fowlsoft/interfaces/wiki/Home)。公式のOOPマクロではありませんが、あなた自身で構築することができます(http://nim-by-example.github.io/oop_macro/)。 –

関連する問題