現在作成進行中のマップエディタで、実行速度が遅い箇所がありました。
それが以下のプログラム部分です。
それが以下のプログラム部分です。
for (int x = 0; x < w; ++x) { for (int y = 0; y < h; ++y) { var id = rscGrd.Areas[x + rcChr.X, y + rcChr.Y]; var chip = RscGround.GetChip(id); if (chip?.Image == null) continue; ContColorArea[x, y] = (int)chip?.Image.Tag; } }
これは以下のような動作を行っています。
- 配置されたBGチップの id を取得
- その id に対応するチップを取得
- チップがない、またはチップのイメージが無ければ次の座標に
- チップイメージの Tag に隠された色番号を色連続マップに設定
実行速度は 1190ms でした。

- 考察
id が配置されているという事は、チップは必ず存在します。そのため、本来はチップが無いという状態はあり得ません。ですが、この判定を外すと null アクセスで停止します。その理由ですが、配置マップ rscGrd.Areas が全てチップで埋め尽くされているわけではないためです。存在しない id ではチップは取得できません。
では、存在していない初期状態は何かというと id = 0 の状態です。そこで最初に id が 0 だったら何もしないという判定を加えてみます。
for (int x = 0; x < w; ++x) { for (int y = 0; y < h; ++y) { var id = rscGrd.Areas[x + rcChr.X, y + rcChr.Y]; if (id == 0) continue; var chip = RscGround.GetChip(id); ContColorArea[x, y] = (int)chip.Image.Tag; } }

実行速度は 963ms です。
ソニー(SONY)
2022-07-09
- もっと速くならないか?
これで確かに速くなりましたが、それでも少し遅いです。追跡していくと、GetChip でチップを取得する際に、画像の存在確認をしているため遅いのだと分かりました。そのため、今度は一度取得した chip 情報は二度と取得しないようにしたらどうかと考えました。
それを実現する方法が Dictionaryです。要は id から色番号が欲しいだけですから、id から即座に色番号を取得する辞書を作れば良いと考えた訳です。最終的なコードが下記です。
Dictionary<ulong, int> colorIdxs = new(); for (int x = 0; x < w; ++x) { for (int y = 0; y < h; ++y) { var id = rscGrd.Areas[x + rcChr.X, y + rcChr.Y]; if (id == 0) continue; if (!colorIdxs.ContainsKey(id)) { colorIdxs.Add(id, (int)RscGround.GetChip(id).Image.Tag); } ContColorArea[x, y] = colorIdxs[id]; } }
Dictionary<ulong, int> は、id の型である ulong を与えると、色番号の型である int の値を受け取る指定となります。ただ、未登録のキーを与えると例外が起きるので、そのキーがあるかどうかを ContainsKey で判定して、未登録なら新規に辞書に登録しています。これでかなりの高速化になりました。
高速化で有効なのは何度も同じ取得を呼び出さないという事です。今回は GetChip が遅かったので効果てきめんでした。この考え方は C# ではかなり効きますが、基本的にはどの言語でも同じように組めば高速化すると思います。
簡単な内容ですが、参考になれば幸いです。
※ 一軒家でリビングに配置するならこちら。以前、このスペックなら50万円とかしてたと思うんですが、頑張れば手が出せる範囲の値付けに落ちてきてる。これはかなり良さそうですが、やっぱりソニータイm
ソニー(SONY)
2022-08-13



コメント