2011-12-09 6 views
3

ゲームでは、プールされたスプライトのうちのどれが使用中であるかを確認する必要があります。一度に複数のスプライトを「アクティブ」にすると、両方とも不変のHashSetであるpassivePoolからactivePoolに転送したいと思います(大丈夫、毎回新しいセットを作成します)。だから私の基本的な考え方は、の線に沿ってにある:ScalaのインスタンスをSetから別のものに移動

activePool ++= passivePool.take(5) 
passivePool = passivePool.drop(5) 

が、私は私が取る5 5が、私はそれからドロップすることを異なる可能性があります推測しているScalaのドキュメントを読みます。それは間違いなく私が望むものではありません。また、私は何かを言うことができます:

val moved = passivePool.take(5) 
activePool ++= moved 
passivePool --= moved 

をしかし、これは私が制限されたデバイス(Android携帯電話)にほとんどリアルタイムでフレームごとに行う必要がある何かであるように私は私が検索する必要があります、これはかなり遅いだろうと思いますpassivePoolからのmovedスプライトのそれぞれ1つずつ。

賢い解決策はありますか?あるいは、私は何か基本的なものを逃していますかここでの効率は第一に考慮する必要があります。また、スプライトがゲーム内で破壊されたときにアクティブプールからスプライトをランダムに削除する必要があるため、セットの代わりにリストを使用することはできません。

+1

1.なぜ、最初のバージョンが2番目のバージョンより効率的だと思いますか? 2.あなたの問題に変更可能なマップを使用することをお勧めします。これはただの感覚です。 – ziggystar

答えて

6

これらの質問に対する回答を得るためのベンチマークのようなものはありません。 100セットのサイズ1000を取り出し、空になるまで一度に5個ずつ落として、どれくらい時間がかかるかを見てみましょう。

passivePool.take(5); passivePool.drop(5)     // 2.5 s 
passivePool.splitAt(5)          // 2.4 s 
val a = passivePool.take(5); passivePool --= a    // 0.042 s 
repeat(5){ val a = passivePool.head; passivePool -= a }  // 0.020 s 

何が起こっているのですか?

immutable.HashSetが最適化された(事実上O(1))追加操作と削除操作でハッシュトライとして構築されていますが、他の多くのメソッドは再実装されません。代わりに、追加/削除をサポートしていないコレクションから継承されているため、効率的なメソッドを無料で取得することはできません。したがって、ほとんどの場合、ハッシュセット全体を最初から再構築します。あなたのハッシュセットに含まれる要素がほんの一握りでない限り、これは悪い考えです。 (サイズ1000のセットでは50〜100倍の減速とは対照的に、サイズ100のセットは「唯一の」6-10倍の減速を有する...)。

したがって、最終行:ライブラリが改善されるまで、それは "非効率的な"方法です。あなたはに大いに速くなります。

+0

ありがとう、これは非常に興味深く、驚くべきことでした!そして、はい、私はScalaのコレクションを特に思いますが、私は常識を使用しようとすべきではなく、代わりに測定してください。 – vertti

4

私は戻って移動するための5つのスプライトと単一のメソッド呼び出しでトリミングされたプールの両方あなたを与えるであろう、ここsplitAtを使用して、いくつかの走行距離があるかもしれないと思う:あなたが割り当てることができる場合

val (moved, newPassivePool) = passivePool.splitAt(5) 
activePool ++= moved 
passivePool = newPassivePool 

ボーナスポイントを最初の行のpassivePoolに直接戻っていますが、新しい変数movedを定義している簡単な例では可能ではありません。

+0

私はパーティションに似た何かがあったことを知っていました。ありがとう! – vertti

関連する問題