- - PR -
【C#】マルチスレッドによる処理が重い(ゲーム作成)
1
投稿者 | 投稿内容 | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2007-03-26 00:36
現在C#にてブロック崩しのようなゲーム制作をしています。
C#とマルチスレッドが初挑戦なので手探りで進めていますが、動作がカクカクしたりするので、どこかおかしければアドバイスお願いします。 現在背景画像とボールのアニメーションのみ実装済みです。 -------------------------------------------------------------------- [フォームクラス] ・FPSの管理スレッド:60FPSになるようにフォームの再描画を管理(whileループ) private void thd_Paint() { frame = 0; int before = Environment.TickCount; while (!IsDisposed) { int now = Environment.TickCount; int progress = now - before; int ideal = (int)(frame * (1000.0F / FPS)); if (ideal > progress) Thread.Sleep(ideal - progress); Invalidate(); frame++; if (progress >= 1000) { framer = frame; before = now; frame = 0; } } } ・OnPaint:背景画の描画とボールの描画 protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); //背景の描画 e.Graphics.DrawImage(m_cImgLst.imgFBack, 0, 0); e.Graphics.DrawImage(m_cImgLst.imgBBack, CConst.DF_RECT_BBACK, CConst.DF_RECT_BBACK, GraphicsUnit.Pixel); //ボールの描画 e.Graphics.DrawImage(m_cImgLst.imgYBall, cBall.Pos.X, cBall.Pos.Y); } [ボールクラス] ・ボールの移動スレッド:whileループで座標を変更(10msのスリープあり) private void thd_Move() { while (true) { if (m_Pos.X + m_Speed.X < 250) { m_Speed.X = m_Speed.X * -1; } if (m_Pos.X + m_Speed.X > 774 - 11 / 2) { m_Speed.X = m_Speed.X * -1; } if (m_Pos.Y + m_Speed.Y < 40) { m_Speed.Y = m_Speed.Y * -1; } if (m_Pos.Y + m_Speed.Y > 700 - 11 / 2) { m_Speed.Y = m_Speed.Y * -1; } m_Pos.X+=m_Speed.X; m_Pos.Y+=m_Speed.Y; Thread.Sleep(10); } } -------------------------------------------------------------------- ちなみにフォームの描画設定は以下のようにしています。 SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer, true); [開発環境] WindowsXP Pro SP2 Microsoft Visual C# 2005 Express Edition _________________ うちうせん [ メッセージ編集済み 編集者: うちうせん 編集日時 2007-03-26 00:50 ] [ メッセージ編集済み 編集者: うちうせん 編集日時 2007-03-26 02:06 ] | ||||||||||||||||
|
投稿日時: 2007-03-26 11:39
無意味に高FPSを目指したりしない。人間に知覚できる限界を超えても意味が無い。 また画面のリフレッシュレートに近い周期で画面を更新をするなら、リフレッシュレートとの同期を取る必要がある。同期を取らないとブラウン管だと画面がちらついて見えたりする(液晶なら目立たない)。リフレッシュレートと同期を取るためには・・・DirectXを使ってください。
Sleepの使い方を間違っている。Sleepの分解能はシステム構成にもよるが10ms程度しかない。したがってそれ以上に細かな時間を指定しても10msのn倍に丸められてしまう。この例だと"Thread.Sleep(10);"と指定しているのと大差ない。 演算があっているか否かまでは確認していないけど、期待したとおりにちゃんと動いていますか?カクカクした動作をする(フレーム抜けが発生する)のであれば、このループの処理に時間がかかっている(例えば100ms以上かかったりしている)と思うのですけど。
画面に描画する命令は非同期に動作するので注意。DrawImageから戻った時点では、まだ画面上に表示されていない事もある。また命令をためて置くバッファがいっぱいになると、応答が帰ってくるまでしばらく待たされることもある。
描画と同じ程度の周期で演算させるなら、きちんと同期を取らないとまずい。微妙なタイミングのずれで、一回描画している間に2回移動させていたり、あるいは1回だけだったりするだろう。これもがくがくした動作の原因となりうる。 | ||||||||||||||||
|
投稿日時: 2007-03-26 15:26
返答ありがとうございます。
思ってた以上に難易度が高そうですね・・・。 完全に知識外なので勉強しなおして再チャレンジしてみます。 アドバイスありがとうございました。 | ||||||||||||||||
|
投稿日時: 2007-03-26 23:24
まず、小言から。
よく、「プログラム コードが仕様書だ」とおっしゃる方がいますが、私はそうは思いません。コードは計算式でしかないからです。数学に「証明問題」というものがあります。証明自体は計算式で示しますが、計算式だけ示しても、正解とはしてもらえません。計算式を補足するための文が必要です。コードに対するあなたの意図を付けていただけないですか?それがあって初めて、「コードが仕様書だ」といえると思います。 そして本題。 上のような理由で、書いてあることを理解できているかどうか怪しいですが、コード上の怪しいところはここです。
初めて実行されるとき、frame が 0 なので、ideal も 0 となります。 次の回では、frame が 1 なので、ideal は 17 です。前回実行時との Tick 差が 17 以下の時、たとえば 8 の時、9 マイクロ秒スリープします。 その次。frame が 2 なので、ideal は 33 です。1回目を実行したときと、今回の実行時との Tick 差が 33 以下の時…この先、とても無駄な処理になることはわかりますか?何のためにこの処理が必要なのかわかりません。 ボールの位置計算もおかしいですよね?この計算式だと、ボールが速いとき、壁につく前にバウンドしてしまいます。また、計算回数を多くして対応しないといけないのに、移動距離を大きくしています。これではすり抜けを起こしてしまいます。 私だったら、、、 1.描画する 2.次に描画するタイミングを計算する 3.描画する絵を作る 4.次に描画するタイミングまで時間があるなら待つ のように作るかな。 _________________ | ||||||||||||||||
|
投稿日時: 2007-03-26 23:46
タイトル
「シューティングゲーム プログラミング 」 http://www.amazon.co.jp/%E3%82%B7%E3%83%A5%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%B2%E3%83%BC%E3%83%A0-%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E6%9D%BE%E6%B5%A6-%E5%81%A5%E4%B8%80%E9%83%8E/dp/4797337214/ref=sr_1_2/249-0239508-3445934?ie=UTF8&s=books&qid=1174920000&sr=1-2 こんな感じの本でもよんでから始めたほうがいいかも 基本的なアルゴリズムや考え方が列挙されています。 ブロック崩し系は入門には最適だと思います。 |
1