プロジェクト演習Ⅱ インタラクティブゲーム制作 イントロダクション2 第6回 はじめての3Dプログラミング ジャンプ(色んな意味で)編 今日の内容 • 跳びたい! – 状態による条件分岐 – 速度と加速度 – 衝突判定の効率化 • そろそろmain()が膨らむのがつらい… – クラスと関数を導入したプログラム • こちらも結構な「ジャンプ」かも…… 今週のプロジェクト • 授業資料ページからダウンロードします – 落としたZipファイルを解凍して、出てきた フォルダを好きなところに配置 ちょびっとProcessingチックに書いてみようか プログラムの構造を整理しよう そろそろ行数辛くないですか? • main()がどんどん 伸びるよ! – やったね!…ではない int main(int argc, char *argv[]) { // 準備処理がごちゃー! … // ここからループ! while(update() ==true) { // 条件分岐がごちゃー! … } return 0; • 100行超えた関数を うじうじいじるのは ちょっとイケてない – と言いつつ私も顔を 背ける…… } なので、関数化したい • 準備でやることは setup() • 毎フレーム処理する ことはdraw() • あれあれ、これって Processingチック? void setup() { // ここで準備 }; void draw() { // ここでループ while(update() == true) { // 処理本体 } }; setup()やdraw()の中身も 用途に応じて関数に分ける • やることが増えると 結局setup()やdraw() が爆発する • 処理のカタマリごとで 関数に分けると見通し が良くなる • 関数の基本 – 名前を呼ばれたらそこへ ジャンプ – 終わったらもどの場所へ ジャンプ void draw() { while(update() == true) { are(); sore(); } }; void are() { // 超複雑なアレに関する処理 }; void sore() { // 超難解なソレに関する処理 }; そんなプログラミングを 実現するために • 「クラス」を導入 – privateのところに プログラムで使いたい オブジェクトや変数を 用意する • 関数内で使い捨てるもの は関数内でもいい – publicのところに関数を 書く • 準備はsetup() • ループはdraw() • それ以外にも関数は 作ってよい • main()関数から、 きちんとsetup()と draw()を呼んでいる のを確認しておこう – ゲームがオブジェクトに なってる?と思った人は なかなか鋭い • 今のやり方だと結局 1ファイルは長くなるが、 これを分割する方法は いずれまた 前回の課題でやりたかった人もいるでしょう キーを押したら勝手に動く、は どーやるの? 以前に教えた条件分岐で できたこと • キーを「押してる間」こうしろ • キーを「押した瞬間」こうしてね だけど • キーを押したら「こう動き始めてね」 – で、一定時間過ぎたら動作終了するような フラグ、立ってますか? 1. キーが押された!フラグが立った! if(キー押された) { フラグON } 2. フラグ立ってる間はこうしなさい! アクションが終了したら、 フラグをベキッ!と折りなさい if(フラグON) { アクション1コマ分の処理 if(アクション終わり?) { フラグOFF } } 飛べないアクションはただのアクションだ お前ちょっと跳んでみろよ ジャンプはアクションの命 • ジャンプもフラグに よって管理できる アクションのひとつ – 右図は驚異的な 跳躍力でお馴染みの 配管工Mさん フラグ(モード)管理の流れ • • • • 普通の状態を0とする キーを押されたら上昇モード(1)とする 頂点に達したら下降モード(2)とする 着地したら0に戻す 上昇と下降ってどういう処理? • 単純に一定距離ぶん上下移動させる – glTranslate()で動かせばいいのだが… – ずっと一定値だと単調で気持ち悪い • 速度と加速度の関係を思いだそう – 速度をいじってやることで動きに緩急が付く – 重力加速度とかに則ってもいいけど、 そのままだとあんまり面白くない – 気持ちいい動きを探してみよう モードの境目 • 通常→上昇 – キーが押された瞬間 • 上昇→下降 – y方向の速度がマイナスになった時 • 下降→着地 – 地面とぶつかった時 • 先週覚えた「衝突判定」が使えそう! • 通常→下降 – 足元に地面が無くなったとき! 今回の当たり判定 • 障害物はfkut_BlockModel • プレイヤーはfkut_SphereModel • 当たり判定には、fkut_BlockModelの変数に対し てcheckToMovingSphere()を使う – block.checkToMovingSphere(other, spd, back); • otherの部分に操作しているSphereModelを、 spdに動かす予定の速度を、backには空のfk_Vectorを渡す – if(命令 == true)でYesなら衝突している • backの部分に渡したfk_Vectorには、spdをどれだけ 減算すれば衝突寸前まで戻せるかを表すベクトルが入る 真の衝突判定とは • ある瞬間にぶつかってるかどうか、を 調べるだけでは「干渉判定」でしかない • 「これくらい動く予定なんだけど、 どこかでぶつかっちゃう?」を調べる !!!! ! ? ! spdが非常に重要な変数になる • まずは次のフレームでどれだけ動かした いかをspdに蓄積し、当たり判定で修正 • 修正が済んだspdをモデルにglTranslate() で適用する • Block対Blockなら checkToMovingBlock()で同じように 判定できる 用途に応じて使い分け • キャラクターは球 – 見た目はゴージャスに 作った形状でもいい – それらを覆うような球 を当たり判定用に用意 して、親子関係を結べ ばいい • entry()しなければ表示 されない • マップはブロック – 球だとつるつるすべっ て操作性に難がある その他もろもろ カメラを一緒に動かす • 自分で用意したfk_Modelの変数をカメラ としてセットすると、物体同様に動きを コントロールすることが可能 • キャラクターの動きと同期すれば、 FPS的な画面も作れる Modelシリーズの回転制御命令 • 今のところ「方向」を指定するやり方し か教えていないが、他にも色々あります – XYZ軸それぞれについてこのくらいの角度 で!などといった姿勢の指定が可能 • glAngle() – 現在位置からここを中心に回転しろ、なんて 命令も • glRotateWithVec() • リファレンスを見て実験して確かめよう ぶつかるためじゃない当たり判定 • ゲームでは「ある地点に到達したら何か がおきる」という処理も必要 • fkut_BlockModelを配置して、そこに接 触したらイベント発生、という使い方も できる – entryしなければ表示はされない 今日の課題 • BASIC – Xキーを押すと、5秒間(300フレーム)球が赤くなり、 3倍の速さで走るようにしてみよう • フラグとして秒数をカウントする変数を用意 • フラグが立っているかいないかで処理を分岐 • フラグが立っている場合の処理で、残り時間を減算していく • ADVANCED – 2段ジャンプをできるようにしてみよう • EXTREME – ジャンプで上っていけるフィールドを作り、 ゴールに到達したらクリアを褒めるメッセージを 出して終了するゲームを作ってみよう 複雑なフィールドを作ってしまった人へ 当たった場合の戻し方 戻し方の罠 • 動物体の次フレームでの位置を仮定する • その動きを阻害する可能性のある物体全 てと衝突判定を行う • 戻しベクトルが発生したら動物体に適用 する • 全物体と判定を終えたら終了… ではない 以下のようなシチュを考える • 右図のような状況の 場合、Aに衝突して発 生した戻しベクトル によって、Bに衝突す る危険性がある • A→Bの順に判定でき ればいいが、そうな らなかったらどうす る? 真上から見た図 解決案 • 全部の物体と判定して、 do { 「戻しベクトルが発生 戻しベクトル初期化 しなかったら」判定終 for(障害物全部) { 了とする 当たり判定する • 色々効率化の余地はあ 戻しベクトル加算 るだろうが、とりあえ } ずはこうしておこう 動物体に適用 } while(適用したベクト ルがゼロじゃなかった らもう1回ループ); 重力の扱い • 基本的には常時下向 きの力を働かせる • そうすると、同じ高 さで並べたブロック でつっかかる – 足下のブロックから先 に判定できればいいが、 そうもいかない • 速度をXZ方向とY方 向に分解して2回判定 真横から見た図 A B 物体を押せるようにした場合 • 押されて動いた物体vs全物体での 判定も必要 – 判定回数が爆発的に増加する • 押して動かせるのは限定的にするべき – でも関数を上手く作れば処理はコンパクトに 書けるはず
© Copyright 2024 ExpyDoc