スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

ゲーム制作状況 - 2013/11/30 -

今日の報告!

更新遅くなって済みません(_ _;)

ちょっと怒涛の如く不具合が発生したので、
対策を色々と練っていました。


今日は、その不具合と対処した方法を順に記載していきます。


■主人公がブロックの正反対に移動する
不具合その1。

ちょっと、動くブロックを実装してみたのですが、
動くブロックのX座標移動がマイナス、主人公の移動速度が0などの時に、
主人公がブロックの左側から右側に瞬間移動する現象が発生しました。

【参考画像】
Sample_20131130_1.jpg

さて、一体何が起こったのでしょう?


これは、めり込み解消の方法が誤っていました。

今まで下記の様にしていたのですが、
//右側へ移動していれば
if( ( *it )->MoveX > 0 ){
//衝突した物体の左側方向へ押し戻す
( *it )->m_PosX -= ( ( t_RightA - t_LeftB ) + 1 );
}else{
//左側へ移動していれば
//衝突した物体の右側方向へ押し戻す
( *it )->m_PosX += ( ( t_RightB - t_LeftA ) + 1 );
}

※(*it)がプレイヤー。 Aと付いている変数が主人公の矩形、
 Bと付いている変数が衝突した物体の矩形。

これ、主人公主体の判定方法だったのです。
つまり、主人公が移動して何かにぶつかるのではなく、
"何かが移動して来て"主人公にぶつかった場合
正常な判定が行われません。

今回の、ブロックのX軸方向移動がマイナス、主人公の移動速度0の場合、
elseの方の判定が行われて、右側に押し出される、という理屈。


なので、衝突する対象との相対的な重なる方向を算出し、
めり込み解消の為の押し出す方向を決める様にしました。

if( ( *it )->m_MoveX - ( *it2 )->m_MoveX > 0 ){
//衝突した物体の左側方向へ押し戻す
( *it )->m_PosX -= ( ( t_RightA - t_LeftB ) + 1 );
}else if( ( *it )->m_MoveX - ( *it2 )->m_MoveX < 0 ){
//衝突した物体の右側方向へ押し戻す
( *it )->m_PosX += ( ( t_RightB - t_LeftA ) + 1 );
}


今回の例に当てはめると、
0 - -2 = 2となり、正常に物体の左側に押し戻される様になります。

その他の色んなパターンでも検証しましたが、
正常に判定されることを確認しています。

~色んな接触パターン~
主人公  物体
0 +1  //物体が左側から接触
0 -1  //物体が右側から接触
+1 0  //主人公が左側から物体に接触 
+1 -1  //主人公が左側から物体に、物体が右側から主人公に接触 
+2 +1  //主人公が左側から物体に追い付いて接触
-1 0  //主人公が右側から、物体に接触
-1 +1  //主人公が右側から物体に、物体が左側から主人公に接触 
-2 -1  //主人公が右側から物体に追い付いて接触



■左方向の移動速度が、右方向の移動速度より速い
不具合その2。

ちょっとMoveの値を細分化して起こった現象なのですが、
大体、下記の様にしていました。

m_DetailMove += 200;
m_Move = ( m_DetailMove >> 10);



今まで、m_Moveに直接1や2を加算とかしていましたが、
それだと移動速度の微調整が効かないので、

m_DetailMoveの値を200とか500とかで増やし、
10ビット右へシフト演算(1024で割るのと同義)した結果を
m_Moveに代入
する様にしました。
(つまりm_DetailMoveが1024になった際に、m_Moveが1になる。)

そしたらなんと、
左方向の移動の方が若干早い、という状態になりました。
一体何故なのか。

…調べてみたら、下記の様になっていました。
(780 >> 10) = 0
(-780 >> 10) = -1


絶対値が1024以下の負(マイナス)の値の場合、
10ビットシフト演算だと0にならない模様。
これにより、移動速度1の誤差が発生していました。

仕方がないので、
素直に m_Move = m_DetailMove / 1024として対処。


■主人公が、移動する物体に乗っている時にジャンプすると、
ジャンプしたその場に取り残される

不具合その3。

…。

これ根本から実装を見直そうと
思ったので苦労した。


【参考画像】
Sample_20131130_2.jpg

上記の様に、X軸方向に10ドットぐらいの速さで移動していても、
ジャンプすると、真上に飛んで落下します。

現実世界でならあり得ない動きです。

例えるならば、スキーでジャンプ台からジャンプしたら、
スキー板だけが前方に発射され、
自分はジャンプ台の真上にジャンプ、落下する様なものです。

【参考画像】
Sample_20131130_3.jpg


…こんな動きはあり得ない。
うーん、うーん…


Sample_20131130_4.jpg


で、色々と悩んでいたんですが、
原因及び対処法がようやく分かりました。

原因は、接触した場合に、リフトの移動方向の差分を、主人公の座標に加算
という手法を取っていたからです。

if( 接触していれば ){
( *it )->m_PosX += ( *it2 )->m_MoveX;
}


これだと、リフトと接触しなくなった時点で、
主人公の座標修正処理が働きません。

だから真上に飛んだのです。
(主人公のm_MoveXは0の為。)


「じゃあ移動速度(m_MoveX)を代入すれば良いじゃん」という事で、
下記の様にしたのですが、別の問題が発生しました。

if( 接触していれば ){
( *it )->m_MoveX = ( *it2 )->m_MoveX;
}

今度は、リフトの上で主人公が身動きを取れなくなりました。

例:
リフトがX軸方向に2ドット、
主人公がリフトの上で、X軸方向に2ドット 動くとします。

すると、絶対座標としては、主人公はX軸方向に4ドット動かないといけません。
しかし、リフトの移動速度を代入している為、(2を代入)
左右移動が行えない状態になったのです。

なので、代入ではなく、
主人公の移動速度 + リフトの移動速度にする(加算する)必要があると思いました。

んで、「加算すれば、これで実装完了だ!」と思ったら、また別の問題が発生。


リフトに乗ると、
リフトの移動方向に主人公が発射される様になりました。

【参考画像】
Sample_20131130_5.jpg


同様に考えてみます。

例:
リフトがX軸方向に4ドット、
主人公がリフトの上で、X軸方向に2ドット 動くとする。

上記の場合、主人公の移動速度は下記の様になります。
2 + 4 = 6
6 + 4 = 10
10 + 4 = 14
 :


見ても分かりますが、速度がどんどん加算されていくので、
リフト以上の速さで右方向に移動
します。


もう対処不能なのではないかと思いましたが、何とか

摩擦で減衰した主人公の移動距離と
相対的な移動速度のズレを算出、
そのズレに(1 - 摩擦力)を乗算し、
その値を、主人公側の移動速度から引く


という方法で、実装完了しました。
けっこう疲れた…。

上記だけだと意味不明だと思うので解説をします。
まずリフトに乗った際、0.9の割合で移動速度が減少していくものとします。

■主人公の移動速度が5の場合。
5 → 4.5 → 4.05 → 3.645 …中略… 0

この場合、式は下記の様になります。
int t_DifX = ( ( *it )->m_MoveDetailX*m_Friction - ( *it2 )->m_MoveDetailX );
( *it )->m_MoveDetailX += - t_DifX*( 1- m_Friction );

分かり易いように、下記の様に書き直してみました。
int t_DifX = ( ( *it )->m_MoveDetailX*0.9 - ( *it2 )->m_MoveDetailX );
( *it )->m_MoveDetailX -= t_DifX*0.1;


で、次に、
リフトが右に10、
リフトに乗った主人公が右に5 移動するとします。

分かり易いように、1024倍せずに、
そのままの値で、小数点以下の値にして計算
してみます。

t_Dif = 5*0.9 - 10;   … -5.5
5 -= -5.5*0.1; … 5.55

t_Dif = 5.55*0.9 - 10;   … -5.005
5.55 -= -5.005*0.1; … 6.0505

t_Dif = 6.0505*0.9 - 10;   … -4.55455
6.0505 -= -4.55455*0.1; … 6.505955

t_Dif = 6.0505*0.9 - 10;   … -4.55455
6.0505 -= -4.55455*0.1; … 6.505955

長くなるので省略しますが、
主人公の移動速度が、最終的に
リフトの移動速度である10に収束
します。

あともう一つ、
移動速度5で、主人公が地面を歩いている状況でもシミュレートしてみます。

t_Dif = 5*0.9 - 0;   … 4.5
5 -= 4.5*0.1; … 4.55

t_Dif = 4.55*0.9 - 0;   … 4.095
4.55 -= 4.095*0.1; … 4.1405

t_Dif = 4.1405*0.9 - 0;   … 3.72645
4.1405 -= 3.72645*0.1; … 3.767855

t_Dif = 3.72645*0.9 - 0;   … 3.353805
3.72645 -= 3.353805*0.1; … 3.390645

こちらも見ていれば大体分かりますが、
主人公の移動速度は5 … 4 … 3と減少していき、
最終的に移動速度は0に収束します。

つまり、
リフトの上を歩いている場合は、歩くのを止めると、
リフトの移動速度に収束(リフトに乗っている状態)し、

地面を歩いている場合は、歩くのを止めると、
移動速度0に収束する(立ち止まる)のです…!!


この式を生み出すのに
時間がかかった。


全くもって手こずらされた。
実際の物理シミュレーションとは色々と違うとは思いますが、
これでひとまず良し、としましょう。

そもそもアクションゲームは、

何の支えも無く宙に浮いてるブロックとか、
下からジャンプしたらすり抜けられるけど、上から下にはすり抜けられない床とか、
ジャンプした後、更に滞空中にもう一度ジャンプとか、

実際の物理法則では、ありえない現象なんて
いっぱい起こっています。


正確な物理シミュレーションでなくとも、
ある一定の法則に基づき、アクションゲームの世界が構築されていれば
良いのではないかな
、と。


~今日のひとこと~

Twitterの方では既に紹介しましたが、こちらでも紹介。
「コンプレックス・エイジ」という作品が
大きな反響を受けている様です。

【参考画像】
Sample_20131130_6.jpg


"ゴスロリ"を着る事が趣味だった主人公が、
年を重ねるごとに趣味として続けられない事を悟り始める、と言った内容。
(永遠に"お姫様"では居られ…なかった。)


日頃、「終わり」というのは気にしないものですが、
目に見える形で「終わり」というものが訪れる瞬間があるという事を認識させられます。

特に"コスプレ"を趣味としている方には、
同様の心境になるかもしれない
ので、
現段階で一度見ておくと良いかもしれません。

ううむ…やだな…、終わりなんてやって来ないで欲し

【参考URL】コンプレックス・エイジ -第63回ちばてつや賞入選
スポンサーサイト

テーマ : ゲーム製作 関連 - ジャンル : ゲーム

コメント
コメントの投稿
管理者にだけ表示を許可する



上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。