280 likes | 436 Views
プロジェクト演習 Ⅱ インタラクティブゲーム 制作 イントロダクション 2. 第 11 回 プログラミングサプリ グラフィック素材編. 今日の内容. 2 次元画像の扱い方 画像を読み込んで表示 文字表示 3 次元モデルデータの扱い方 関数 ( メソッド ) の扱い方 関数の作り方・使い方 値の渡し方・ 受け取り方. 今週 のプロジェクト. 授業資料ページからダウンロードします 落とした Zip ファイルを解凍して、 出てきたフォルダを好きなところに配置 今週の FKUT 更新情報 ゲームパッド対応を強化
E N D
プロジェクト演習Ⅱインタラクティブゲーム制作イントロダクション2プロジェクト演習Ⅱインタラクティブゲーム制作イントロダクション2 第11回 プログラミングサプリグラフィック素材編
今日の内容 • 2次元画像の扱い方 • 画像を読み込んで表示 • 文字表示 • 3次元モデルデータの扱い方 • 関数(メソッド)の扱い方 • 関数の作り方・使い方 • 値の渡し方・受け取り方
今週のプロジェクト • 授業資料ページからダウンロードします • 落としたZipファイルを解凍して、出てきたフォルダを好きなところに配置 • 今週のFKUT更新情報 • ゲームパッド対応を強化 • fk_Sceneクラスのオブジェクトを使い分けることで画面切り替えが容易に
やっぱり2次元もいいよね! 画像素材との付き合い方
画像データとは • 言うまでもないですが、色のついた点の集まり • FKで扱える画像形式 • ビットマップ(BMP) • きれいだがでかい • PNG • きれいでコンパクト • 透過処理もできる • JPEG(JPG) • きちゃないけど超コンパクト
表示するには • fkut_SpriteModel • 色々お節介焼きな便利変数です • 画像の表示を絶望的に簡単にできます • 詳しくはお品書きを読んでね • FKUT/SpriteModel.h を参照 • できることが書いてあります • それに加えてModel系の命令も使えるよ
基本手順 • fkut_SpriteModel型の変数を作る • fkut_SpriteModel spr; • 表示させたい画像を読み込む • spr.readPNG(“hoehoe.png”); • readBMP/PNG/JPGを形式に合わせて使う • ウィンドウにエントリーする • window.entry(spr); • 先にカメラの設定を済ませておくこと • カメラモデルを変更したら再エントリー
位置やサイズの調整 • glMoveTo()やglTranslate()などが利用可能 • 画像の中心点がどこにくるかを指定 • ただし、有効なのはX,Y座標値のみ • 座標の軸の取り方にも注意(次スライド参照) • setPositionLT()で、画像の左上がどこにくるか基準での位置指定が可能 • 表示サイズは基本的に画像自体のサイズがそのまま適用される • 変更したい場合はsetSpriteSize()を使う
座標系の注意 • ウィンドウが800x600の場合 (-400,300) (0,0) (400,-300)
文字表示の手順 • 文字データ(フォント)を読み込む • initFont()を使う • Vista,7の場合は「メイリオ」をおすすめ • C:/Windows/fonts/Meiryo.ttc • 表示させたい文字をdrawText()で指定 • drawText()を呼ぶたびに文字が付け足される • 改行したい場合は”\n”と書く • 後で書き直すこともできる • 再度drawText()を呼んだり、clearText()で消したり • 数値の表示についてはサンプル参照 • 色の変更や細かい装飾はWeb上の資料を参照
3次元空間中に表示したい場合 • SpriteModelは画面上に貼り付ける専門の変数なので、別の変数を用意する • サンプル中に「背景に画像を敷く」コードがあるので、それを参考に • エリアコメントを解除してみよう
単なる手順の話でしかないですが 形状モデルデータの扱い方
FKにおける「形状」と「モデル」 • ポリゴンがどんな形をしているのか、画像がどう張り込まれているのか、をFKでは「形状」と呼ぶ • 球、ブロック、モデリングデータは「形状」 • 「形状」が乗っかった台座に相当して、位置や向きを保持するのが「モデル」 • 「形状」を「モデル」にセットして使う • SphereModelやBlockModelはこれらをミックスさせていたもの
MQOやXを単純に読む場合 • fk_IFSTextureクラスのオブジェクトを用意 • ifsとする • ifsに対してテクスチャ画像を読み込む • 画像形式に応じてreadXXX関数を使う • ifsに対して形状データを読み込む • readMQO()かreadD3DX()を使う • ModelのオブジェクトにsetShape(&ifs) • さらにモデルにマテリアルを設定し、ウィンドウにエントリーしてようやく表示
モーションを手軽に付けたモデルを扱いたい場合モーションを手軽に付けたモデルを扱いたい場合 • FK Performerを使ってみる • MQO形式のデータに対応 • 作ったモデルとモーションをfkut_Performerクラスで扱う • 形状とモデルとモーションをセットにしたクラス • 詳細はサンプル参照
当たり判定は球かブロックで近似 • MQOやXを読み込んだ場合でも、FK Performerを利用する場合でも、当たり判定用にBlockModelかSphereModelを用意しておく • create()はするが、entry()はしない • 形状をセットしたモデルを親子関係にして、移動処理などは当たり判定モデルをベースに行う
使えてる人、そうでない人いるでしょうが 関数を使ってスマートに書こう
関数とは • 以下の3つの特徴を持ちます。 • いくつかの処理を1つのカタマリにしておき、必要に応じて呼び出せる。呼び出した処理が終わったら元の場所に戻ってくる。 • 呼び出す際に必要な値を引き渡せる。要らなければ渡さなくてもいい。 • これを利用すると大幅に処理が効率化できる。 • 戻ってくる際に計算結果を返すことができる。要らなければ返さなくてもいい。
このコードを見て、無駄だと思わないかい? // se0のキー操作(a)による再生 if(window.getKeyStatus('a') == FKUT_SW_DOWN) { se0_play = true; se0.seek(0.0); } if(se0_play == true) { se0_play = se0.play(); } // se1のキー操作(s)による再生 if(window.getKeyStatus('s') == FKUT_SW_DOWN) { se1_play = true; se1.seek(0.0); } if(se1_play == true) { se1_play = se1.play(); }
赤くしたところが違うだけで、処理の流れや構造は一緒だ赤くしたところが違うだけで、処理の流れや構造は一緒だ // se0のキー操作(a)による再生 if(window.getKeyStatus('a') == FKUT_SW_DOWN) { se0_play = true; se0.seek(0.0); } if(se0_play == true) { se0_play = se0.play(); } // se1のキー操作(s)による再生 if(window.getKeyStatus('s') == FKUT_SW_DOWN) { se1_play = true; se1.seek(0.0); } if(se1_play == true) { se1_play = se1.play(); }
こういう感じで差し替え効くように書けると素敵こういう感じで差し替え効くように書けると素敵 // key, flag, seの所は状況に応じて差し替えたい if(window.getKeyStatus(key) == FKUT_SW_DOWN) { flag= true; se.seek(0.0); } if(flag== true) { flag= se.play(); } • playSoundByKey()関数 • 判定するキーの種類、鳴らしたいSEの変数、再生フラグ変数を引数として渡している
お品書きと本体 • 関数を作る時の返値の種類 関数名(引数リスト);の部分をこの授業ではお品書きと呼ぶ • 正確には「プロトタイプ宣言」と呼ぶ • お品書きはヘッダー(.h)に書く • 本体を書く.cppファイルと、その関数を利用したい.cppファイルでインクルードする • 本体はC++ファイル(.cpp)に書く
インクルードとは • 使いたい関数(やその他もろもろ)のヘッダーファイル(お品書き)を取り込む命令 • FKUTの機能もインクルードすることで使えるようになっている • 動作としては、ファイルに書かれている内容をその場にコピペするのと大差ない • なので、プロトタイプ宣言を直書きしても、ヘッダーをインクルードしても動作は一緒
ゲームでよく使う関数の作り方 • 返値は要らない場合が多い • 座標や数値の計算をしたい場合は返値を返すように作るとよい • int, doubleの他に、bool, fk_Vectorなどが返値としてよく用いられる • 引数は「参照渡し」にした方がよい • 引数で受け取る変数名の前に「&」を付ける • 値を参照するためだけに渡すものは型名の前に「const」を付ける • 付けないと’a’やFK_ENTERなどの定数が渡せない • fkut系の変数は必須 • fk系も基本的に参照渡しの方が問題が起きない
その他注意点 • 配列を渡したい場合の引数リスト • int *iArray や fk_Model *mArrayなど • *で渡した先で、[0]や[i]で要素を参照できる • SpecialKeyのコード • const fk_SpecialKey &spKey • 普通のキーコード • const char &key • 文字列を渡したい • string &text • (関数内でいじらないならconst string &text)
より詳しい人のために • 構造体やクラスの利用は推奨します • ただし、ある程度独学で頑張れるチームのみ • 分かってる人だけが使うのではなく、チーム全体で出来るだけ理解レベルを統一して開発にあたりましょう • グローバル変数の利用は極力避けるべし • トラブルのもとです • ゲームを通じて必要な変数はmain関数に作り、面倒でも引数でしっかり渡すように
値渡しと参照渡しの違い 値渡し(通常)の関数 参照渡しの関数 void func(int &iA) { iA *= 2; } // 以下main内だとする int iValue = 10; func(iValue); // ここでのiValueの値は? void func(int iA) { iA *= 2; } // 以下main内だとする int iValue = 10; func(iValue); // ここでのiValueの値は?
違いのまとめ • 値渡しだと、引数として「同じ値がコピーされる」ので、関数側でいじってもコピー元には影響がない • 参照渡しだと、引数として「その変数の箱自体が渡される」ので、関数側でいじった結果が反映される • 多くの場合はこっちの挙動の方がうれしい • だが、変数ではなく値を直書きしているものは受け取れない • キーの種類が参照渡しじゃないのはそのため • 引数を意図せずにいじって混乱することもある