Simplestar Game

How do I create a 3D game ?
http://simplestar.syuriken.jp/
since 17/01/2009
  • BACK
  • HOME
  • NEXT
  • |

:::::::::::029話 Blender独自フォーマット出力B:::::::::::

どうも星姫です。
前回はBlenderより独自フォーマットの中間ファイルを出力しました。
形式はXMLでしたが、始めてXMLという単語を耳にした方などは、その扱い方に困っていると思います。
今回は、XMLファイルを読み込んで、描画に用いるモデルデータに変換するコンバーターを作ります。

最近、デモンズソウルで遊んでいたので更新が止まっていました…申し訳ない。
え、まだプレイしていない!?おススメしますが、ハマり過ぎに注意してください。

さて、本題に入ります。
今回はC#を使って、頂点リストとインデックスリストを出力するコンバータを作成します。
C#アプリのもっとも基本的なことを初めに勉強し、残りはコンバータ作成について説明していこうと思います。

以下の記事は Blender 2.49b のものなので、最新の Blender 2.55(2010/12現在)の情報は載ってません。
誰でも簡単に解析できるXML形式で Blender 2.55 からモデルデータを手に入れたい方はダウンロードへお越しください。
今回はC#アプリのユーザーコントロールの入門講座としては、かなり役立つ記事ですので、ツールを作ってみたいとか思う方は読むべし!

新規プロジェクトを立ち上げますよ。VisualStudioを起動してください。

赤枠で示したように、C#のフォームアプリケーションを土台として作成します。
プロジェクト名は"SimpleConverter"としました。

赤枠で示した部分を自分の好きな名前に変えておきましょう。(その他はいじりません)

プロジェクトを右クリックして、ユーザコントロールの追加を選択してください。
これから作るのはメニューコントロールなので、コントロール名は"MenuFrame"としましょう。

ツールボックスの場所は見つかります?そこの「メニューとツールバー」項目から「MenuStrip」を選んで
ユーザコントロール内をクリックしてください、以下のように追加されると思います。

これより、必ず作らなくてはならない項目を作成します。
次のように、「ファイル」メニューを追加しましょう。
ファイル(&F)と枠内に打ち込みます。

同じ要領でヘルプ[ヘルプ(&H)]を追加します。
次に、ファイルの下に「開く(&O)」と「終了(&X)」を打って項目を追加しましょう。

さて、ショートカットキーも設定しましょう
「開く」の項目を選んでプロパティを見ると「Shortcutkeys」の項目があると思います。
以下のように「Ctrl + O」となるように設定してください。
(プロパティが見つからない人はさすがにいないよね…)

「終了」のショートカットキーはおなじみ「Alt + F4」です。
ヘルプの下には「バージョン情報(&A)」を追加しておいてください。

ここまでの作業結果は以下のとおりです。

さて、ここで一度プロジェクトをビルドしてください。
次にFormMain.csのフォームデザインを開いてください。
すると、ツールボックスに先ほど作成したユーザコントロールが追加されていると思います。
ユーザコントロールが追加されない(表示されない)という方は 「ツール」>「オプション」>「Windows フォーム デザイナ」>「全般」にある「ツールボックス」の項の[AutoToolboxPopulate] を「False」から「True」にしてもう一度ビルドしてください。(以下の図参照)

これは入門者がひっかかりやすい罠です、気をつけて!

ツールボックスにユーザコントロール「MenuFrame」が追加されたなら
ツールボックス内で選択し、フォーム内クリックで追加してください。

次に、この画像にならい、フォーム内に追加された「MenuFrame」コントロールのプロパティの
「AutoSize」をTrueに、「Dock」をTopに設定してください。
これでメニューコントロールの配置完了です。試しに「F5」を押してデバッグ実行をしてみてください。

メニューの動作はするけど、終了を押してもアプリケーションが閉じないと思います。
それもそのはず、終了項目を押したときのイベント処理をコーディングしていないからです。
では、ひとまず終了してください。

アプリケーションを終了するには、メインフォーム内でClose()関数を呼ぶ必要があります。
そこら辺のC#入門サイトでは、ユーザコントロールを使わないので
同じファイル内でClose関数を呼べば良いです、と説明して終わっていると思います。

問題はそんな簡単なことじゃありませんよ!
今回のようにユーザコントロールをフォームに追加した場合
フォームとユーザコントロール間でやり取りが必要になります。

その方法を教えろ!というのがついこの前の私でした。
以下に解決方法を記しました。困っている方は読んでくれると嬉しいです。

コントロール間のやり取りに欠かせないのが「デリゲート」(delegate: 委託)というキーワードです。
説明の前にさっそく使ってみましょう。

まずは、次の画像を参考に、メニューコントロールのコードを表示して下さい。

そこに、次のコードを書き込みます

/**************************************************************************//**
* @file        MenuFrame.cs
* @brief    MenuFrameクラス
* @author    Simplestar
* @date        2010-09-19
*
* @par    [説明]
*        メニューコントロール定義・実装 ファイル
* Copyright © 2010  SimpleStar Game
* @ref        http://simplestar.syuriken.jp/
*/
/***************************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace SimpleConverter
{
    /// <summary>
    /// メニューコントロールクラス
    /// </summary>
    public partial class MenuFrame : UserControl
    {
        //------------------------------------------------------------------------
        // EventHandlers
        //------------------------------------------------------------------------

        /// <summary>
        /// メニューコントロール「終了」のイベントハンドラ
        /// </summary>
        /// <param name="sender">イベント発行元</param>
        /// <param name="e">イベント追加情報</param>
        public delegate void EventExitHandler(object sender, EventArgs e);

        //------------------------------------------------------------------------
        // Events
        //------------------------------------------------------------------------

        //! メニューコントロール「終了」イベント
        public event EventExitHandler eventExit;

        //------------------------------------------------------------------------
        // Public functions
        //------------------------------------------------------------------------

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public MenuFrame()
        {
            InitializeComponent();
        }
    }
}

続いて、メニューコントロールの「終了」項目をデザイン上で選択し、プロパティの「Name」を"Exit"にしてください。
さらに、赤枠で示した雷のマークをクリックし、イベント関連を設定するプロパティに移ってください。

そこに上図に示すように、「Click」の項目があります。
「Click」項目をダブルクリックして、クリックイベントハンドラを作成します。
自動で、コード表示に移ると思います。そこを以下のコードに書き換えて下さい。

        /// <summary>
        /// メニューコントロール「終了」のクリックイベント
        /// </summary>
        /// <param name="sender">イベント発行元</param>
        /// <param name="e">イベント追加情報</param>
        private void Exit_Click(object sender, EventArgs e)
        {
            //! イベントを投げる
            if ( null != eventExit)
            {
                eventExit(sender, e);
            }
        }

メニューのユーザコントロールの用意は、ひとまず完了しました。

ここまでの作業ですが
イベントのためにイベントハンドラを用意し、イベントを用意して
「終了」のクリック時に用意したイベントを投げるように設定しました

では、FormMainのデザインに戻ります。
フォームをダブルクリックすると、コードが自動生成されてロードイベントが作られると思います。
ここを次のコードに書き換えて下さい。
フォームを閉じる関数も追加します。(イベント登録で+=と書いたあたりでTabキーを2回押すと良いことあるかも!?)

        /// <summary>
        /// ロードイベント
        /// </summary>
        /// <param name="sender">イベント発行元</param>
        /// <param name="e">イベント追加情報</param>
        private void FormMain_Load(object sender, EventArgs e)
        {
            // メニュー「終了」イベントに、「フォームを閉じる」関数を登録
            menuFrame1.eventExit += new MenuFrame.EventExitHandler(CloseForm);
        }

        /// <summary>
        /// フォームを閉じる
        /// </summary>
        /// <param name="sender">イベント発行元</param>
        /// <param name="e">イベント追加情報</param>
        void CloseForm(object sender, EventArgs e)
        {
            // フォームを閉じる
            Close();
        }

さて、コード内にコメントをいくつか残しましたが
重ねて説明すると、ロード時、メニューの「終了」に対して、「フォームを閉じる」関数を登録します。
これで、もう一度ビルドしてデバッグ実行してみてください。
「終了」のクリックや「Alt + F4」でフォームが閉じるようになります。

ここまで、勉強したことをまとめます。
delegateというキーワードよりイベントハンドラを作成し、コントロール間でイベントのやり取りができるようになりました。
イベントに追加情報を渡したいという方は、次のリンクを読んでいただければと思います。

C#のイベント機能

続いて、「開く」の機能を実装してみましょう。

「開く」項目の名前を"Open"に設定し、クリック時に呼ばれる関数を自動生成します。(これまでの説明通り作業するだけ)
それを、次のコードに書き換えて下さい。

        /// <summary>
        /// メニューコントロール「開く」のクリックイベント
        /// </summary>
        /// <param name="sender">イベント発行元</param>
        /// <param name="e">イベント追加情報</param>
        /// <remarks>
        /// コードの参考元:「ファイルを開く」ダイアログボックスを表示する
        /// http://dobon.net/vb/dotnet/form/openfiledialog.html
        /// </remarks>
        private void Open_Click(object sender, EventArgs e)
        {
            // OpenFileDialogクラスのインスタンスを作成
            OpenFileDialog openFileDlg = new OpenFileDialog();

            // はじめに表示されるフォルダを指定す
            openFileDlg.InitialDirectory = @"C:\Users\simplestar\Documents";
            // [ファイルの種類]に表示される選択肢(フィルタ)を設定する
            openFileDlg.Filter = "XMLファイル(*.xml)|*.xml|すべてのファイル(*.*)|*.*";
            // [ファイルの種類]ではじめに[XMLファイル]が選択されているようにする
            openFileDlg.FilterIndex = 1;
            // タイトルを設定する
            openFileDlg.Title = "ファイルを選択してください";
            // ダイアログボックスを閉じる前に現在のディレクトリを復元するようにする
            openFileDlg.RestoreDirectory = true;

            //ダイアログを表示する
            if (DialogResult.OK == openFileDlg.ShowDialog())
            {
                //選択されたファイル名(フルパス)を取得
                // openFileDlg.FileName
            }

        }

初期フォルダの指定で私のドキュメントフォルダになってますが、ここは貴方のドキュメントフォルダに変えて下さい
OpenFileDialogクラスについては、次のページを参考にしました。

「ファイルを開く」ダイアログボックスを表示する

選択したファイルパスをどうするかはアプリケーションによりますので、ここまででとりあえずOKです。
これで「開く」項目の設定が完了しました。
続いてヘルプの「バージョン情報」を設定します。

これまで同様、「バージョン情報」項目名を"Version"に設定して、クリック時に呼ばれる関数を自動生成してください。
それを、次のコードに書き換えて下さい。

        /// <summary>
        /// メニューコントロール「バージョン情報」のクリックイベント
        /// </summary>
        /// <param name="sender">イベント発行元</param>
        /// <param name="e">イベント追加情報</param>
        private void Version_Click(object sender, EventArgs e)
        {
            // バージョンフォームの表示
        }

バージョンフォームの表示、の部分をこれから実装します。

プロジェクトを右クリックして、「追加」>「Windows フォーム」を選択します。
この画像を参考に、新しくプロジェクトにフォームを追加してください。
名前は"FormVersion"とします。

そして、フォームへ次に示すようにコントロールを追加・配置してください。
コントロール名を明記しましたので、これらをツールボックスから追加してください。
配置はフィーリングで何とかなります。

新しいコントロールが出てきました。PictureBoxとLabelとButtonです。
それぞれのプロパティのText項目をここで示すものと同じにしてください。(バージョン番号とビルド時刻は意味ないですが…)

PictureBoxに使う画像は、右クリック「イメージの選択」より
「プロジェクト リソースファイル」にチェックを入れて、「インポート」を押します。
画像ファイルを選択すれば、図のようにリソースに追加されます。

次は、バージョン番号とビルド時刻をラベルに設定する作業に入ります。
その際、忘れてはならない作業がAssemblyInfo.csファイルの次の行のコメントアウトを交換することです。

最初はこうなっていますが…

// アセンブリのバージョン情報は、以下の 4 つの値で構成されています:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// すべての値を指定するか、下のように '*' を使ってビルドおよびリビジョン番号を
// 既定値にすることができます:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

以下のように変更します。

[assembly: AssemblyVersion("1.0.*")]
// [assembly: AssemblyVersion("1.0.0.0")]

あとは、OKボタンのクリック時に呼ばれる関数とフォームのロードイベントを自動生成してから、FormVersion.csのコードを
次のコードにならい、書き換えます。

/**************************************************************************//**
* @file        FormVersion.cs
* @brief    FormVersionクラス
* @author    Simplestar
* @date        2010-09-19
*
* @par    [説明]
*        バージョン情報フォームクラス 定義・実装 ファイル
* Copyright &copy; 2010  SimpleStar Game
* @ref        http://simplestar.syuriken.jp/
*/
/***************************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;    // for Assembly
using System.Globalization; // for CultureInfo

namespace SimpleConverter
{   
    /// <summary>
    /// バージョン情報フォームクラス
    /// </summary>
    public partial class FormVersion : Form
    {
        /// <summary>
        /// コンストラクタ
        /// </summary>
        public FormVersion()
        {
            InitializeComponent();
        }

        /// <summary>
        /// ロードイベント
        /// </summary>
        /// <param name="sender">イベント発行元</param>
        /// <param name="e">イベント追加情報</param>
        private void FormVersion_Load(object sender, EventArgs e)
        {
            // バージョンの取得
            //@{
            Assembly assembly = Assembly.GetExecutingAssembly();
            Version version = assembly.GetName().Version;
            //}@

            // ラベルへバージョン番号を設定
            labelVersion.Text = "Version: " + version.ToString();
           
            // ラベルへビルドした時刻を設定
            {
                DateTime buildDate = new DateTime(2000, 1, 1).AddDays(version.Build).AddSeconds(2 * version.Revision);
                CultureInfo cultureInfo = new CultureInfo("en-US");
                labelBuildDate.Text = "BuildDate: " + buildDate.ToString("MMM d yyyy HH:mm:ss", cultureInfo);
            }
        }

        /// <summary>
        /// 「OK」ボタンが押された
        /// </summary>
        /// <param name="sender">イベント発行元</param>
        /// <param name="e">イベント追加情報</param>
        /// <remarks>フォームを閉じる</remarks>
        private void buttonOK_Click(object sender, EventArgs e)
        {
            // フォームを閉じる
            Close();
        }
    }
}

最後に、MenuFrame.csの「バージョン情報」がクリックされた時に呼ばれる関数の部分を次のように実装します。

        /// <summary>
        /// メニューコントロール「バージョン情報」のクリックイベント
        /// </summary>
        /// <param name="sender">イベント発行元</param>
        /// <param name="e">イベント追加情報</param>
        private void Version_Click(object sender, EventArgs e)
        {
            // バージョンフォームの表示
            {
                // フォームのインスタンス生成
                FormVersion formVersion = new FormVersion();
                // メインフォームの中央に配置
                formVersion.StartPosition = FormStartPosition.CenterParent;
                // フォームの表示
                formVersion.ShowDialog(this);
                // フォームの破棄
                formVersion.Dispose();
            }
        }

これで、C#アプリにおける基本的な機能の実装が完了しました。
ビルド実行をして、動作を確かめてみて下さい。

これから、アプリを作る時にこの作業は必ず行いますので
このページをブックマークするなり忘れないようにしましょう

ここまでの作業をまとめます。
メニューコントロールを作り、フォームに追加しました。
メニューコントロールにて、ファイルを開く動作、アプリを閉じる動作、バージョン情報を表示する動作を実装しました。
ここまでは、全てのアプリの土台となる基本的なものです。

次に、SimpleConverter特有の実装を行います。

ページが長くなったので、次回に続きをやりましょう。
GUIをサクッと作れる技術はゲーム作りには欠かせません。
ぜひ今回学んだことを活かしてみて下さい。

よかったらコメントもどうぞ

2010/09/05 初記。
2010/09/19 追加。

:::::::::::029話 Blender独自フォーマット出力B:::::::::::

  • BACK
  • HOME
  • NEXT
ホームページ制作 フリー素材 無料WEB素材
Copyright (C) Simplestar All Rights Reserved.