【雑記】C#のウィンドウプログラムを少々

仕事の関係で、見積もりとC#のウィンドウプログラムの学習をしていた。

C#でのウィンドウプログラムは、ちょうどjavaのSwingのように、イベントドリブンの設計になっているようだ。

そのため簡単なゲームループを作ろうと思っても、ウィンドウプログラムの作法から学ばなければならない。

そこで、また一から調べてたのでゲームループを備えたウィンドウを出すだけでも結構難儀した。

結論から言うと、ウィンドウを出すには出せた。

ググって見たり、サンプルコードを解析したりして、なんとかそれらしいゲームループのウィンドウスケルトンを作ることが出来たんだけれども、これがベストな実装かどうかは心もとない。

というのも、自作のゲームループで一定のフレームレートでコンポーネントをリフレッシュしているものの、実際に再描画しているのは、別のスレッドでやっているように思われる。

おそらく、ゲームループから呼び出したウィンドウの再描画要求はいったんキューに溜められて、ウィンドウが管理するイベント処理スレッドが実際の描画処理を呼び出しているのだと思われる。

ゲームループ側で一定のフレームレートで確実にコンポーネントを強制描画する方法があれば、それがベストだと思われる。

ゲームループ側のコードを貼り付けておく。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace XNA_STUDY
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            //ゲームの中身(System.Windows.Forms.Formを継承)
            XnaStudy mainForm = new XnaStudy();

            mainForm.Show();

            // フレームを処理する周期(1/60秒)
            float period = 1000f / 60f;

            //前回処理時間
            double lastTime = (double)System.Environment.TickCount;

            //フレームレート
            float fps = 60.0f;

            double fpsLimiter = 0.0f;

            //ゲームループ
            while (mainForm.Created)
            {
                //開始時間を取得
                double startTime = (double)System.Environment.TickCount;

                //前回の呼び出しからの経過時間
                double deltaTime = startTime - lastTime;

                mainForm.deltaTime = deltaTime;

                //フレームレートの計算
                fpsLimiter += deltaTime;

                if (fpsLimiter > 1000)
                {
                    fpsLimiter -= 1000;
                    mainForm.fps = fps;
                    fps = 0;
                }

                // ここで描画以外の計算処理を行う。
                mainForm.UpdateGame();

                //描画コンテキストを作成
                System.Drawing.Graphics g = mainForm.CreateGraphics();
                
                // ここで描画処理を行う。
                mainForm.RenderGame(g);

                //描画コンテキストを破棄
                g.Dispose();

                fps++;

                lastTime = startTime;

                // Windowsメッセージを処理させる
                Application.DoEvents();

                //処理全体の時間が最大フレーム時間に満たない場合、スリープする
                double procTime = (double)System.Environment.TickCount - startTime;

                // 1ms以上の間があるか?
                if (period - procTime > 1)
                {
                    // Sleepする
                    System.Threading.Thread.Sleep((int)(period - procTime));
                }
            }
        }
    }
}
4年前

コメントを残す

メールアドレスが公開されることはありません。