初音ミク冒険記、足場に向かってジャンプすると勝手に更にジャンプすることがある問題の解決
実は、リファクタリング祭りをしている最中に
先日の記事に書いた
・足場に向かってジャンプすると勝手に更にジャンプすることがある
特に坂に向かってジャンプする時に発生する
どうやら坂にぶつかる時に
左右への移動キーを押していると起きるみたい
というバグの原因が判明した。
が、対処方法が中々思いつけなくて、かなりの苦戦を強いられた。
何度も
14歳からはじめるC言語わくわくゲームプログラミング教室Visual Studio 2008編―Windows XP/Vista対応
を読み返して、本に書いてあることは実装できていることを確認。
いくら読み返しても問題が分からない。
そう、本に書いていない部分でかげさんが追加した機能やバグ修正が問題だったのだ。
具体的には、追加した機能では空中制御
バグ修正では、上り坂大ジャンプ/下り坂小ジャンプ
こいつらが、非常に状況をわかりづらくしていたのだ。
初音ミク冒険記で解決策に困ったやっかいなバグのいくつかは
「空中にいる、かつ、地面にいる」時に起こる。
それ日本語おかしくね?
と思うかもしれないが、そこはゲームプログラムの世界である。
起こりえるんだなコレが。
要するに「ジャンプした先に地面があるパターン」だ。
具体的には「ジャンプ上昇中に地面にいる」という状況である。
上述の本にも書かれているんだけど図解しよう。
上の図は、試練の洞窟 エリア3の上の方にある
連続ジャンプで上っていく地面だ。
ミクは上に向かってジャンプしている。
地面の当たり判定は、地面の一番上の線。
ミクの当たり判定は、灰色の丸の部分。
大きいのはダメージを受ける判定円で足元が着地の判定円だ。
地面の線に対してミクの足元は接触しているので
この状態が「空中にいる、かつ、地面にいる」という状態だ。
実際に空中にいるというのが解除されるのは
ちゃんとミクが着地したタイミングである。
ミクが着地するというの説明しよう。
上の図で説明すると、今度は飛び降りている最中だと思って欲しい。
飛び降りの時は、飛び降りコマンドを受け付けた時にいる足場は、
着地判定の対象外となる。
なので対象となるのは、現在の足元の判定円の下にある足場だ。
ここに、上から下向きに下りると着地と扱う。
さっきはジャンプだったので上昇中は、足場の接触判定は無視する
というパターンに該当していた。
ここに「初音ミク冒険記」の坂移動中のジャンプについて考えてみる
で書いていた解決策が加わるとどうなるか?
さっきの例は平らな足場でのジャンプや飛び降りだったが
今度は斜めの足場である。
ミクのいる場所から坂に向かってジャンプする
先のジャンプの例に当てはめると「上昇中は足場の接触判定は無視する」に該当する。
ココで問題になるのは、ジャンプ上昇中に坂に接触した場合だ。
「上昇中は足場の接触判定は無視する」ので着地扱いにならない。
そして坂移動中のジャンプの対処は、該当記事の通りである。
つまり、対処する条件は、
上り坂、もしくは下り坂で「空中にいる、かつ、地面にいる」だ。
当然、上り坂大ジャンプや下り坂小ジャンプの対策で
ミクの移動ベクトルを通常ジャンプ分、足しているわけだから
見た目は坂に着地しているのにもう1回ジャンプしたような動きになる。
これが、「足場に向かってジャンプすると勝手に更にジャンプすることがある」原因だ。
どうなって欲しいか文章にすると以下の通りだ。
1.上り坂大ジャンプや下り坂小ジャンプの対策は、
ミクがこれからジャンプする時だけ動いて欲しい。
2.ジャンプして一度「空中にいる、かつ、地面にいない」状態になってから
上り坂大ジャンプや下り坂小ジャンプの対策が動かないで欲しい
単純に考えると
ジャンプボタンを押した瞬間だけ
上り坂大ジャンプや下り坂小ジャンプの対策が動けば良い
のだが、これだとミクが坂にいる関係で
ジャンプした直後で完全に空中に浮くまでのフレーム数が
1だと良いかもしれないけど2以上だと2フレーム目以降で
大ジャンプもしくは小ジャンプしてしまう・・・
2を実現しようとしても「空中にいる、かつ、地面にいない」状態になってから
というのが難しい気がする・・・
それに厄介なのが空中制御ができることで
上昇中、下降中だけじゃなく、ジャンプしつつ
ジャンプ頂点(上昇中でも下降中でもないタイミング)で
水平移動ができるタイミングがあるところ。
そうなるとジャンプで上昇中とか下降中とかの判定をしても
上手くいかないパターンがあるわけで・・・
・
・
・
ちょっと考えれば分かりそうなものだけど
思いつくのに1時間半くらいかかった。
接地状態から「空中にいる、かつ、地面にいない」状態になるまで
どのくらいのフレーム数があるのか分からないけど
1秒間60フレームだとして大体10フレーム(1/6秒)もあれば
その状態になるんじゃないかと。
この仮定に基づいて、ジャンプした瞬間から
上り坂大ジャンプや下り坂小ジャンプの対策は動くのだけど
その効果を10フレームを超えたらなくしてしまう。
という案を考えてみた。
ジャンプした瞬間から「空中にいる」という状態になるので
「空中にいる」間は「ジャンプ中のフレーム数」をカウントアップしていき
「空中にいない」状態になったら「ジャンプ中のフレーム数」を0にする。
2013/02/10追記
ソースプログラム載せるの忘れてた。
jumpFrameCounterはmyGame.hに追加
2013/02/10追記
■jumpFrameCounter変数の初期化
int initGame(){
AppLogAdd("initGame stageNo=[%d] mapNo=[%d]\n", playerInfo.stageNo, playerInfo.mapNo);
usedLineNum = 0;
memset((char *)landLine, 0x00, sizeof(Line2D)*128);
// 接地中フラグ
onTheGround = FALSE;
// ジャンプ中フラグ
nowJumping = FALSE;
// ジャンプフレームカウンタ
jumpFrameCounter = 0;
// エアリアルステップフラグ初期化
aerialStepFlg = FALSE;
2013/02/10追記
■playGame関数の最初の方
//***************************************************************
// オートコレクト関連
//***************************************************************
autoCollectAnime++;
autoCollectAnime = autoCollectAnime % 60;
//***************************************************************
// ジャンプ関連
// (坂道に向かってジャンプした時、勝手にもう1回ジャンプする対策)
//***************************************************************
if(nowJumping == TRUE){
jumpFrameCounter++;
}else{
jumpFrameCounter = 0;
}
//***************************************************************
// マップレイヤー1の地形描画の呼び出し(背景)
//***************************************************************
drawMap_Layer1();
2013/02/10追記
■playGame関数の坂道ジャンプの箇所の修正前
// 接地中だが、上り坂または下り坂でジャンプ中の場合
// プレイヤーベクトルのy座標を通常ジャンプのy座標にベクトル補正する
if(((debugUpSlope == 1) || (debugDownSlope == 1)) && (nowJumping == TRUE)){
//printfDx("currentVector1.y=[%f]\n", currentVector1.y);
//printfDx("y=[%f]\n", playerInfo.playerVector.y);
playerInfo.playerVector.y = JUMP_MOVE.y;
}
2013/02/10追記
■playGame関数の坂道ジャンプの箇所の修正後
// 接地中だが、上り坂または下り坂でジャンプ中の場合
// プレイヤーベクトルのy座標を通常ジャンプのy座標にベクトル補正する
if(((debugUpSlope == 1) || (debugDownSlope == 1)) && (nowJumping == TRUE)){
//printfDx("currentVector1.y=[%f]\n", currentVector1.y);
//printfDx("y=[%f]\n", playerInfo.playerVector.y);
// ★この処理って
// ・上り坂を上りながらこれからジャンプ
// ・下り坂を下りながらのこれからジャンプ
// には対応できても、ジャンプ中に坂に接地した時の考慮が無いんじゃないか?
playerInfo.playerVector.y = JUMP_MOVE.y;
// ジャンプしてから10フレーム後には、この処理をしないようにすれば
// 一度ジャンプして(地面を離れて)からのジャンプ上昇中に
// 坂に接地した時にonTheGround = TRUE、かつ、nowJumping = TRUEになったとしても
// (試練の洞窟のエリア2の一番上の坂に向かってジャンプし、
// ジャンプの頂点に達する前に坂に当たってしまうとか
// 坂に向かってクイックステップやクイックムーブしながらのジャンプで
// ジャンプの頂点に達する前に坂に当たってしまうといった状況でも)
// 上述の坂ジャンプによるジャンプ力の増減対策が効かないようにできると思う。
if(jumpFrameCounter > 10){
playerInfo.playerVector.y = 0;
}
}
コレでいけると思ってやってみたら上手くいきました!
数フレームだけミクの画像が微妙になる瞬間もあるみたいけど
意図しないジャンプを勝手にするよりは、ずっと良いと思う。
きっと、もっとスマートなやり方はあるんだろうけど
やり方が思いつかない以上、プログラムすることはできないしねぇ。
実は、このやり方、試練の洞窟 エリア2の下の方の上り坂で
ジャンプする方向がその坂とほぼ同じ角度の時
つまりクイックムーブで上り坂を移動中にジャンプってすると
ジャンプしているのか微妙な状況なのにジャンプの効果音がするんだよね。
もっとも、このやり方をする前と後とで同じ動きだったんだけど・・・
同じ動きだから気にしないで良いよねってことにする。
同じ場所でも通常移動やクイックステップだと上手く動くし。
適度に妥協も必要じゃないか?
そういうことにしときましょう。(笑)
| 【固定リンク】 | 【コメント (0)】 | 【トラックバック (0)】
このエントリーへのリンク
トラックバック
この記事へのトラックバックの一覧です: 初音ミク冒険記、足場に向かってジャンプすると勝手に更にジャンプすることがある問題の解決:
コメント
このブログの新着コメントをRSSリーダに登録する為のxml