チュートリアル
チュートリアルでは、ここに書いている文章のほかに、6つのビデオもあります。
それぞれの項目をまとめて実演したものをビデオ化したものになります。
文章で分かりにくい時でもビデオを見ると理解できることもあると思います。(その逆もあるでしょう)
ビデオ1 3D物体
ビデオ2 Xファイルメッシュ
ビデオ3 2D物体
ビデオ4 サウンド(WAV、MIDI)
ビデオ5 2Dシューティングを3分で作る
ビデオ6 3Dシューティングを3分で作る
まず、3D物体のインスタンスを作成します。インスタンスの作成は非常に簡単です。C言語の変数宣言のように、
BOX box;
などと書けばいいだけです。 boxの部分(インスタンス名)はもちろん自由に決めることが出来ます。
次に、Load()関数を実行します。”ロード”という概念はNEGAAのその他のオブジェクトにも共通の概念です。この場合、ボックスのジオメトリを読み込む(頂点、ポリゴン等を読み込む)ことです。
box.Load();
次に、描画ですが、これも至極簡単です。インスタンスからメソッドを呼び出せばいいだけです。この場合では、
box.Draw();
これだけです。画面には、四角形が見えるでしょう!ボックスをZ手前方向から見ているので、単なる四角形に見えますが、方向を変えるとボックスと確認できます。
カメラを操作することによりオブジェクトを様々な角度から見ることができます。
いま試しに、ボックスを斜め上から見下ろすようなカメラアングルにしてみましょう。
まずはカメラをボックスの斜め上に移動します。それから、ボックスを見下ろす姿勢になるようにカメラを回転させます。
つまり移動と回転をするわけです。
まず、移動はSetPosition()関数で行います。書き方は次のようになります。
Camera.SetPosition(2,2,-2);
引数はx,y,z成分を意味します。この場合、xプラス方向に2、yプラス方向に2、zマイナス方向に2だけ移動しなさい、という意味になります。
つまり、横に2移動して上に2移動して、手前に2下がった位置に移動しなさいということです。
次に、回転です。
カメラもボックスなどと同じで、RotateYaw()、RotatePitch()、RotateRoll()関数で回転します。それぞれY軸周り、X軸周り、Z軸周りの回転です。
NEGAAでは、デフォルトでは、うっすらとしたアンビエントライトしかありません。
アンビエントライトはもっとも簡易なライトで、陰影や光沢が出ません。
陰影や光沢のでる、いわゆるちゃんとしたライトは、アプリケーションでインスタンスを作成します。
簡単です、たとえば平行ライトであれば、次のように書けばいいのです。
DISTANT_LIGHT light;
DISTANT_LIGHTは型名です。lightはインスタンス名なので任意に決めることが出来ます。
ライトを照らすには、そのインスタンスからIlluminate()関数を実行します。
なお、平行ライトのほかに、2種類のライトがあります。
点ライトの型は POINT_LIGHT です。
スポットライトの型は SPOT_LIGHT です。
RotateYaw()、RotatePitch()、RotateRoll()関数で回転を指定します。引数は360度単位の度数です。(ラジアン単位ではありません)
例) Y軸周りで毎フレーム1度ずつ回転させたい場合は次のように書きます。
box.RotateYaw(1);
RotatePitch()はX軸周り、RotateRoll()Z軸周りになります。
OOO.scaleメンバ変数を増減させることで拡大又は縮小します。
例えばboxというBOX型のインスタンスであれば、box.scale=2.0などと書きます。これは、その物体を2倍に拡大することを意味します。半分の大きさにしたいのなら、box.scale=0.5とします。
物体を配置あるいは移動させるには、OOO.vPos(その物体のvPosメンバ)を直接更新します。
vPosは位置を保持するメンバです。
例えば、ボックスを3次元上の位置(1,4,2)に配置したいときは、
box.vPos.x=1;
box.vPos.y=4;
box.vPos.z=2;
などと書きます。
また、次のように書くこともできます。
box.vPos = D3DXVECTOR3(1,4,2);
ゲームはもとより、一般のソフトにおいてもキー入力の検知は必ずといっていいほど必要でしょう。
キーボードを押したことをプログラムに知らせることが出来なければ、ゲーム内のキャラの操作などが一切できません。
NEGAAでは、キー入力の検知も非常に簡単に行えます。例えば、キーボードのスペースキーを押したら文字を表示するという動作は次のように書けます。
if(Key(DIK_SPACE))
{
RenderString("hello world",10,10);
}
Key()関数が、キーボードを検知する関数です。
Key()関数の引数には、DIK_から始まるキーボード定数を指定します。上の場合はスペースキーを検知したいのでDIK_SPACEとしました。
Key()関数は、指定したキーが押されれば、true(真)を返します。そのためif(Key())という書き方でいいことになります。
DIK_OOは、キーボード定数で、キーの数だけあります。例えば、リターンキーならDIK_RETURN、左矢印キーなら DIK_LEFT、aキーならDIK_A、F1キーならDIK_F1という具合です。
キー名称がそのまま定数になっているので、全てを知らなくとも、大抵の場合、その定数が分かるでしょう。
移動と配置は、本質的に同じことです。なぜから、”移動は連続的な再配置”だからです。
例えば、ボックスを横に移動させたいとき(横に動かしたいとき)は、
box.vPos.x+=0.1;
などと書きます。この場合、ボックスは毎フレーム0.1単位右に進むことになります。
ゲームではどちらかというと基本形状よりはxファイルを使うことがほとんどです。
xファイル用の型がNEGAAにはあります。
XMESHがそうです。インスタンスの作成は次のように書きます。
XMESH xm;
インスタンスを作成したら、3D物体と同じように、ロードします。ただし、3D物体と異なるのは、Load()関数が引数をとることです。
引数は、xファイルのファイル名です。たとえば次のように書きます。
xm.Load("car.x");
以上で、初期化は終わりです。
レンダリングは、これも3D物体と同じく、Draw()関数で、
xm.Draw();
と書きます。
移動、回転、スケーリング などの手順も3D物体と同様です。
3D物体と同様です。というよりも、そもそもNEGAAでは、xファイルメッシュは3D物体のひとつです。
当然、各種手順や挙動など、3D物体として振る舞います。
単なる3D物体(ボックスなどの基本形状)に無い動作が、このアニメーション関連です。これはXファイルメッシュ固有の属性になります。
m_fAnimSpeedメンバがアニメーションのスピードを意味します。
このメンバを増加すればアニメーションスピードは速くなりますし、減少させればアニメーションスピードは遅くなります。
アニメーションをストップさせたい場合、このメンバをゼロにします。
2DスプライトはSPRITE_2D型を使用します。例えば次のように宣言します。
SPRITE_2D sp;
これで sp というインスタンスが生成されました。
次にロードします。
sp.Load("たま.bmp",D3DXCOLOR(0,0,0,255));
D3DXCOLOR()の部分は”抜け色”の指定です。抜け色とは、透過させたい色の値であり、絵の周りの色のことです。左から順にR,G,B,Aの値を0〜255の値を指定します。例えば、抜け色が黒なら0,0,0,255と指定し、抜け色が青なら0,0,255,255、抜け色が黄緑なら0,255,255,255、白なら255,255,255,255という具合です。
描画はDraw()メソッドで行いますが、2DスプライトのDraw()はRECT型(矩形)の引数をとります。
RECTは矩形の型です。(矩形とは、四角形の領域です。) 矩形を指定することにより、”画像の一部のみ”を描画することができます。
次の例は、画像の左上から128x128の領域のみ描画するコードです。スプライト自体のサイズも、矩形で指定したサイズになります。
画像は1024x1024ピクセルだとしても、描画されるのは128x128の部分だけです。
RECT rect;
rect.top=0;
rect.left=0;
rect.right=128;
rect.bottom=128;
//一部を描画したい場合は、矩形範囲を指定
sp.Draw(&rect);
一部ではなく全体を描画したい場合は、引数にNULLを渡せば、全体を描画するようになります。同様にスプライト自体のサイズもその全体サイズになります。
1024x1024の画像ファイルをロードしたのであれば、スプライトも1024x1024のサイズになります。(非常に大きなスプライトになりますね)
sp.Draw(&NULL);
2D絵でも、移動や回転は3Dと同じです。ただし、2D絵は”ピクセル単位”で移動するので、たとえば、
sp.m_vPos.x+=0.1;とすると、遅すぎるかもしれません。3D物体であれば、0.1単位はけっこう大きな移動量ですが、ピクセル単位では違います。
回転は、Rotate()関数で行えます。
3D物体と異なり、回転軸はz軸周り1種類しかありません。したがって、Rotate()関数も1種類になります。
引数は、360度の度数です。(ラジアン単位ではありません)
Rotate(2)とすれば、2度回転します。
OOO.scaleメンバ変数を増減させることで拡大又は縮小します。
例えばspriteというSPRITE_2D型のインスタンスであれば、sprite.scale=2.0などと書きます。これは、その物体を2倍に拡大することを意味します。半分の大きさにしたいのなら、sprite.scale=0.5とします。
なお、2Dスプライトのサイズはデフォルトで100ピクセル×100ピクセルです。
WAVファイルは、主に効果音に使われます。
再生するにあたって、まず行わなければならないことは、サウンドソース(サウンドファイル)の”ロード”(読み込み)です。
”ロード”した後に、”再生”できます。この、”ロード” → ”再生” という手順はMIDIでも同様です。
次の例は、boon.wavというwavファイルを読み込み、そして再生するコードです。
DWORD dwIndex=0;
LoadSound(&dwIndex,"boon.wav",NULL,NULL,true);
Play(dwIndex,true);
Load()は一度だけ行えばいい処理です。というよりもLoad()の実行は一度である必要があります。なぜ、ロードを一度しか実行したくないかと言うと、(同じサウンドとして)ロードを何回も実行すると、無駄なメモリーを食いつぶすことになるからです。もちろん、異なるサウンドをロードする場合は、また新たにロードすることにはなります。
サウンド(WAV、MIDI両方)の停止は、それぞれのインスタンスのStop()メソッドにより停止します。
MIDIファイルはBGMに使われます。(SEには向きません)
再生するにあたって、まず行わなければならないことは、サウンドソース(サウンドファイル)の”ロード”(読み込み)です。
”ロード”した後に、”再生”できます。この、”ロード” → ”再生” という手順はWAVでも同様です。
次の例は、music.midというMIDIファイルを読み込み、そして再生するコードです。
DWORD dwIndex=0;
LoadMIDI(&dwIndex,"music.mid",true);
Play(dwIndex,true);
Load()は一度だけ行えばいい処理です。というよりもLoad()の実行は一度である必要があります。なぜ、ロードを一度しか実行したくないかと言うと、(同じサウンドとして)ロードを何回も実行すると、無駄なメモリーを食いつぶすことになるからです。もちろん、異なるサウンドをロードする場合は、また新たにロードすることにはなります。
サウンド(WAV、MIDI両方)の停止は、それぞれのインスタンスのStop()メソッドにより停止します。
ビデオのみとなります。ビデオを参照してください。
ビデオのみとなります。ビデオを参照してください。