プログラム編

ゲーム製作日誌 プログラム編 No.7 「Direct3Dのはじめのはじめ」

こんにちは。
前回までは、プレイヤーが操作するキーボードやマウスの状態をプログラム側で検知する手段として、DirectInputを扱ってきました。

no1-2
以前まで作成していた部分は、ゲームライブラリでいう入力を受け付けるところの「部門1」でした。今回から制作を始めていく機能は、出力の大部分を担う画面への描画機能であります。Direct3D 9という機能を使って描画を実現していこうと思います。


1、SharpDXの準備+ウィンドウの表示

 描画編からは、ウィンドウフォームを扱っていく必要が有るためにプロジェクトに若干の変更を加える必要があります。
 具体的には、「No.3」のプロジェクトの作成を「Windowsフォームアプリケーション」にするだけなのですが、今回はプロジェクトごと配布してしまおうと思います。

  • DirectX 9をインストールしていないPCの場合は、「DirectX End-User Runtimes (June 2010) 」をMicrosoftのページからダウンロードしてインストールしてください。
    ※「DirectX SDK」は、必要に応じてインストールすればよいです
  • SharpDXをダウンロードしたことがない場合は、「SharpDXのページ:http://sharpdx.org/」の「Download」ページの中ほどにある「SharpDX-Full-2.5.0.exe」をダウンロードしてインストールしてください。インストール中のオプションで必ず「SharpDX Runtime Assemblies」は選ぶようにしてください。
  1. VS(Visual Studio)側で「Windows フォームアプリケーション」プロジェクトを作成する
  2. VSのメニューバー中の「プロジェクト」→「参照の追加」をクリックする
  3. 「参照の追加」ダイアログ中の「参照」タブをクリックする
  4. SharpDXの「DirectX11-net40」というフォルダまで行き着く
    ※ 多くの場合、「DirectX11-net40」フォルダは「C:\Program Files (x86)\SharpDX\Bin」にインストールされます。また、スタートメニュー中の「SharpDX」→「SharpDX Runtime Assemblies」→「Bin」と進んでいくことでも見つけられます
  5. 「参照の追加」ダイアログで、そのフォルダ中の「SharpDX.dll」「SharpDX.DirectInput.dll」「SharpDX.Direct3D9.dll」「SharpDX.DirectSound.dll」の4つを選んで「OK」ボタンを押します。
 これでC#でSharpDXを扱えるようになりましたし、フォーム表示についてもできるようになっているはずです。しかし、そのままのコードではフォームが普通に出てなんにも手が出せないので、サンプルを参考にしながらProgram.csの中身を変えてみてください。


2、Direct3D 9の流れ

 これからは、Direct3D 9を利用して画面にいろいろ書いていくわけですが、その前に描画するために必要な流れを説明していきます。
  1. 描画用のウィンドウを用意する
     描画した内容を画面に出す領域が必要です。当面は、System.Windows.Forms名前空間にあるFormクラスを使ってウィンドウを用意していきます。

  2. 描画デバイス(SharpDX.Direct3D9.Device)を作成する
     描画デバイスというのは、Direct3D 9の中核を司るクラスでこれを通じて画面に描画したり画像を読み込んだりしていきます。今後は単にDeviceと書いていきます。

  3. 描画するために必要なリソースを読み込み・作成する
     Deviceを通して、描画したい絵や写真をファイルから読み込んだり、CGモデルを読み込んだりします。

  4. 描画開始をDeviceに通知する
     描画を始める前にDeviceに知らせておく必要があります。Device.BeginScene()メソッドを使います。

  5. 描画をしていく
     Deviceに描画命令を送って画面に描画をしていきます。ところでDirect3D 9は、三角ポリゴン(頂点を3つつないで作った三角面)しか描画単位を持たないため、すべての描画命令は「このポリゴンを描け!」といったものになります。

  6. 描画終了をDeviceに通知して画面に反映させる
     「5.」で描いていたポリゴンたちを、画面に反映させます。その際には、Device.EndScene()とDevice.Present()を順に呼びます。

  7. 今までに取得したリソースすべてとDeviceを開放する
     「3.」で読み込んだリソースの多くは、グラフィックボードのメモリに格納されるため必要がなくなった時点で開放してあげる必要があります。

 ざっとこんなものでしょうか。これらがマスターできれば、画面に色んな物を書いていくことができます。

 
 今回はこんなかんじで終わりにします。次回以降で、一つ一つの詳しい説明をしていきます。実践編は、もうちょっとあとになるかもね。

ゲーム製作日誌 プログラム編 No.6-1 「マウスの入力検知の実装」

こんにちは。お久しぶりです。
前回は、プログラムでプレイヤーが操作するマウスの状態を検知する方法を解説しました。今回はそれをどのようにライブラリに組み込むかを模索していきます。


1、組み込み方について考える要素

 キーボード回と同様、まずはマウスの入力検知機能にどんな特徴が必要かを考えます。
 1点を除いて、前回と全く同じです。
 
  • 判定はある周期のタイミングで一気に行い、ライブラリ使用者にはその周期内の判定記録を教えてあげればよい

     マウスをものすごく短い時間内にカチカチ出来る人はいません。ですからマウス状態を調べる作業を頻繁に行う必要はないです。決められた一定の周期に沿って取得しておけば十分です。


  • ゲームライブラリはひとつでよい、ふたつもいらない

      判定をする人は、一人でよいです。そんな時に便利なのがシングルトンパターンであることは前回説明しました。

  • クラスと関わるのは、更新タイミングとキーの状態取得時のみ

     このキー判定クラスが、利用者と関わる必要があるのは大きく分けて二回です。更新タイミングとキーの状態取得時のみです。しかし、ここではクリック状態とカーソル位置を別々に受け取れるようにして3つの関数を用意することにします。
     希望に応じて、カーソルが範囲内にあるか判定する関数を用意してみるのも良いかもしれません。
    ///<summary>
    一定周期が経過しキーボード状態を取得するタイミング
    </summary>
    void Update();

    ///<summary>
    マウスカーソルを取得。
    </summary>
    void GetCursor(out int x, out int y);

    ///<summary>
    ボタンがクリックされているか取得。(返り値:ボタンが押されているか)
    </summary>
    bool IsPressed(int button);

2、絶対座標ではなくフォーム座標

 Windows APIで入手できたマウスカーソル座標とは、画面全体の中での座標でした。実際ゲームを作ってみるとその画面座標というものがいかに意味を成さないわかります。
 ゲームは、絵が表示されるウィンドウの上をポチポチクリックして進めていくものなので、画面全体での座標だけ知ってても全く使えないのです。その絵が表示されてるウィンドウから見たカーソル位置を知る必要があります。
 画面全体のカーソル座標からウィンドウ上のカーソル座標を計算するには、ウィンドウフォームのPointToClient()メソッドを使ってあげます。チョー簡単ですね。ここのところは、サンプルにも入れておいたので気になる方はそちらを参照ください。

ClientPosition



3、サンプルプログラム

 今回の内容を元にサンプルプログラムを作ってみました。詳細はこちらを御覧ください。

 次回からは、ゲームライブラリの描画部にいよいよ入っていこうかなと思っています。(予定)


ゲーム製作日誌 プログラム編 No.6-2 サンプルプログラム

こんにちは。
 この記事では、ゲーム製作日誌 プログラム編 No.6「マウスの入力検知部分の実装」で考えたマウス判定処理のゲームライブラリへの組み込み方法を実現したソースコード例を紹介します。No.3で扱った、SharpDXの導入が前提になっています。
 今回のプログラムは、No.4のサンプルプログラムの状態更新部分を少し書き換えただけです。

/////////////////////////////////////////////////
//
// マウス入力判定機能クラス
//
// Author. ウマモサク
/////////////////////////////////////////////////

using SharpDX.DirectInput;
using System.Runtime.InteropServices;

class MouseInterface{
#region API連携
//GetCursorPosで現在座標を取得
[DllImport("user32.dll")]
private static extern void GetCursorPos(
ref tagPOINT lpPoint
);

//現在座標が入る構造体
public struct tagPOINT
{
public UInt32 x;
public UInt32 y;
}
#endregion

//シングルトン
private static MouseInterface instance;
public static MouseInterface Instance
{
get
{
return instance;
}
}
private static bool initialized=false;
public static void Initialize()
{
if (initialized)
return;

initialized = true;
instance = new MouseInterface();
}
public static void Dispose()
{
if (initialized)
{
instance.DisposeDevice();
instance = null;
initialized = false;
}
}

protected MouseInterface()
{
this.InitializeDevice();
}

private DirectInput directInput;
private Mouse device;

private MouseState buttonState;
private tagPOINT cursorState;

//描画フォーム
private System.Windows.Forms.Form screenForm;
public void SetScreenForm(System.Windows.Forms.Form form)
{
screenForm = form;
}

public void InitializeDevice()
{
directInput = new DirectInput();

//マウスが存在しない場合への対処
Guid keyboardGuid = Guid.Empty;
foreach (var g in directInput.GetDevices(DeviceType.Mouse, DeviceEnumerationFlags.AllDevices))
{
keyboardGuid = g.InstanceGuid;
}

if (keyboardGuid == Guid.Empty)
{
throw new Exception("マウスが見つかりません");
}

//デバイスを生成してマウス状態の取得を開始
device = new Mouse(directInput);
device.Acquire();

buttonState = device.GetCurrentState();
}

public void DisposeDevice()
{
device.Dispose();
directInput.Dispose();
}

public void Update()
{
buttonState = device.GetCurrentState();
cursorState = new tagPOINT();
GetCursorPos(ref cursorState);

//カーソル位置をフォーム座標に変換する
if (screenForm != null)
{
System.Drawing.Point p = new System.Drawing.Point((int)cursorState.x,(int)cursorState.y);
p = screenForm.PointToClient(p);
cursorState.x = (uint)p.X; cursorState.y = (uint)p.Y;
}
}

public bool IsPressed(int button)
{
return buttonState.Buttons[button];
}

public void GetCursor(out int x, out int y)
{
x = (int)cursorState.x;
y = (int)cursorState.y;
}
}


 以上が、ライブラリ部分です。このライブラリは、ゲーム起動時に以下のコードで初期化します。MouseInterfaceクラスの実体を作成するのです。

MouseInterface.Initialize();


 その後、一定周期で以下のコードを呼び出します。ゲームでは通常、メインループという一定周期で処理をする仕組みを持っているため、その中に記述すればOKです。

MouseInterface.Update();


 実際にボタン押下状況を取得するときは、以下の関数呼び出しの返り値から判断します。左ボダンの判定を例に挙げます。

MouseInterface.IsPressed(0)

 
 マウスカーソルの座標を取得するには、以下の関数呼び出しの引数郡から判断します。

int cursorX,cursorY;
MouseInterface.GetCursor(out cursorX,out cursorY);

 ゲーム終了時には、作成した実体を消去してデバイスを開放する必要があります。

ゲーム製作日誌 プログラム編 No.5 「マウスの入力検知」

こんにちは。
今回は、プログラムでプレイヤーが操作するマウスの状態を検知する方法を解説していきます。

1,マウスの状態

 マウスは、キーボードとは異なり様々な種類の状態を持っています。

 1つ目にマウスのボタンです。一般のマウスには左・右・中央の3つのボタンがあります。左のボタンは何かを選択したり決定したりするときに使用しますね。右のボタンはキャンセルしたりメニューを開くときにしばしば使います。中央のボタンはあまり使う機会が無いですね。

 2つ目にはマウス自体の移動があり、画面上のカーソル位置とも言い換えられます。マウスを移動させることで画面上の矢印を移動させて目的の位置に持ってきたり、ゲームでは視点をずらすために動かすこともありますね。

 今回は、この2つの種類の状態を、プログラム側で把握できるようにしましょう。


2,ボタン状態と”マウス移動”の取得

 マウスボタンが押されているかどうか、またはマウスが動かされたかの確認は、DirectInputを通じて行うことができます。以下のソースを御覧ください。
 
using SharpDX.DirectInput;


DirectInput directInput = new DirectInput();

//接続されているマウスを探す
Guid mouseGuid = Guid.Empty;
foreach (var g in directInput.GetDevices(DeviceType.Mouse, DeviceEnumerationFlags.AllDevices))
{
mouseGuid = g.InstanceGuid;
}
if (mouseGuid == Guid.Empty)
{
throw new Exception("マウスが見つかりません");
}

//デバイスを初期化
Mouse device = new Mouse(directInput);

//マウス状態の取得開始
device.Acquire();

//マウスの状態を取得する
MouseState state = device.GetCurrentState()

 この一連のコードでマウスの状態を取得することができます。
 気づいた方がいるかもわかりませんが、このコードは前々回の記事のキーボード状態の取得のコードと非常によく似ています。具体的には、キーボードの文字がマウスに変わっただけです。マウスもキーボードもやるべきことは大体同じなのです。

 コードの一番最後の行では念願の”マウスの状態”らしきMouseStateクラスを取得できています。このMouseStateクラスには、マウスのボタン状態とマウスの移動量が含まれています。再び下のコードを御覧ください。
//左ボタンがおされているか
bool buttonL = state.Buttons[0];

//右ボタンが押されているか
bool buttonR = state.Buttons[1];

//中央のボタンが押されているか
bool buttonCenter = state.Buttons[2];

//マウスの移動量(x:横 y:縦)
int mouseMoveX = state.X;
int mouseMoveY = state.Y;
 MouseStateクラスのButtonsプロパティは、bool配列になっており左ボタンの場合は1番めに、右ボタンは2番めに押されているかどうかの真偽値が格納されています。
 また、MouseStateクラスのX,Yプロパティにはそれぞれマウス自体の移動量が格納されているわけです。
 一度Mouseクラスを作ってしまえばいつでもGetCurrentState()メソッドによってマウスの情報を得ることができます。



3,”カーソル移動”の取得


 さて、ここまででマウスボタンと移動量を取得することが出来ました。これにより、画面上のボタンをクリックするインターフェースや、マウスの移動によって視点の向きを変える操作が可能になりました。しかし、そのようなインターフェースを扱う上で重要な画面上のカーソル位置がまだ判明していません。
 DirectInputとは、そもそもマウスやキーボードといった装置自体の状態を把握するための機能です。そのため、OS上で管理しているようなカーソルの位置は専門外であるため取得することができません。ですから今回は、DirectInputではなくOSに直接カーソルの位置を尋ねなければいけません。
 下のコードを御覧ください。

using System.Runtime.InteropServices;
//クラス内に記述
[DllImport("user32.dll")]
private static extern void GetCursorPos(ref POINT lpPoint);

private struct POINT
{
public UInt32 x;
public UInt32 y;
}

public void GetCursor(out int x, out int y)
{
POINT p = new POINT();
GetCursorPos(ref p);

x = p.x;
y = p.y;
}
 カーソル位置取得の場合は特に準備は必要なくて、単にAPIと関連付けた関数(上の例ではapiGetCursorPos)を呼び出せば大丈夫です。その点では、他の取得処理よりも楽ですね。



4,まとめ


 今回の内容をまとめると大きく2つです。
  • マウスのボタンや移動量をチェックするには、予め作成しておいたMouseクラスのGetCurrentState()メソッドを呼び出す。その返り値の、Buttonsメンバには[0]:左ボタン,[1]:右ボタン,[2]:中央ボタンの順で状態が格納されている。マウスの移動量は、XとYのメンバから取得する。

  • 画面上のカーソルの位置を取得するには、user32.dllのGetCursorPos()関数を呼ぶ。

 次回は、マウス状態をゲームライブラリに組み込む方法について模索したいと思います。おそらくキーボードの時と似たようなものになるでしょうが。

ゲーム製作日誌 プログラム編 No.4-2 「キーボードの入力検知部分の実装」 サンプルソース

こんにちは。
 この記事では、ゲーム製作日誌 プログラム編 No.4「キーボードの入力検知部分の実装」で考えたキーボード判定処理のゲームライブラリへの組み込み方法を実現したソースコード例を紹介します。No.3で扱った、SharpDXの導入が前提になっています。

/////////////////////////////////////////////////
//
// キーボード入力判定機能クラス
//
// Author. ウマモサク
/////////////////////////////////////////////////

using SharpDX.DirectInput;

class KeyboardInterface{
//シングルトン
private static KeyboardInterface instance;
public static KeyboardInterface Instance
{
get
{
return instance;
}
}
private static bool initialized=false;
public static void Initialize()
{
if (initialized)
return;

initialized = true;
instance = new KeyboardInterface();
}
public static void Dispose()
{
if (initialized)
{
instance.DisposeDevice();
instance = null;
initialized = false;
}
}

protected KeyboardInterface()
{
this.InitializeDevice();
}

private DirectInput directInput;
private Keyboard device;

private KeyboardState keystate;

public bool this[Key key]
{
get
{
return keystate.IsPressed(key);
}
}

public void InitializeDevice()
{
directInput = new DirectInput();

//キーボードが存在しない場合への対処
Guid keyboardGuid = Guid.Empty;
foreach (var g in directInput.GetDevices(DeviceType.Keyboard, DeviceEnumerationFlags.AllDevices))
{
keyboardGuid = g.InstanceGuid;
}

if (keyboardGuid == Guid.Empty)
{
throw new Exception("キーボードが見つかりません");
}

//デバイスを生成してキーの取得を開始
device = new Keyboard(directInput);
device.Acquire();

keystate = device.GetCurrentState();
}

public void DisposeDevice()
{
device.Dispose();
directInput.Dispose();
}

public void Update()
{
keystate = device.GetCurrentState();
}
}


 以上が、ライブラリ部分です。このライブラリは、ゲーム起動時に以下のコードで初期化します。KeyboardInterfaceクラスの実体を作成するのです。

KeyboardInterface.Initialize();


 その後、一定周期で以下のコードを呼び出します。ゲームでは通常、メインループという一定周期で処理をする仕組みを持っているため、その中に記述すればOKです。

KeyboardInterface.Update();


 実際にキー押下状況を取得するときは、以下の関数呼び出しの返り値から判断します。Enterキーの判定を例に挙げます。

KeyboardInterface.IsPressed(Key.Return)

 ゲーム終了時には、作成した実体を消去してデバイスを開放する必要があります。

KeyboardInterface.Dispose();


 
twitterはこちら
ニコ生放送します
ギャラリー
  • ウマモサク
  • ウマモサク
  • ウマモサク
  • 3/17 制作記録
  • 3/17 制作記録
  • C91告知
  • C91告知
  • C91告知
  • C91告知
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

  • ライブドアブログ