忍者ブログ
  • 2024.04
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 2024.06
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

【2024/05/04 06:13 】 |
アクションのいい感じのキャラ移動を作る
アクションゲームの主人公の移動について作ってみた。

iPhoneのアクションゲームの移動操作については、いろいろな方法がある。


たとえば左右キーのバーチャルボタンがあって、キーを押すとそっちに主人公が歩くタイプがある。キーじゃなくてレバーになってる場合もある。
でもこれは、正確にキーやレバーの場所をタッチしないといけない。これは結構難しい。
普通ボタンの位置は見ずにゲームプレイするから、だんだんずれていっちゃう。
特に、右へ行きたいときはつい右の方をタッチするようになるから、ずれは思いのほかすぐ起きる。
タッチしたときに感触もないから、ずれてしまうのは防ぐのが難しい。


キーの位置から指がずれてしまう欠点を克服する方法として、スライド方式で移動するタイプもある。
左右キーの位置とかは決まってなくて、画面のどこをタッチしてもよく、タッチした場所から左右にスライドすると、その量に応じて主人公が左右に移動する、というものだ。


iPhoneのパックマンにこの方式の操作が両方入っている。
やってみると分かるが、スライド方式(パックマンではフリックと呼んでいる)がずっとやりやすい。


というわけで、この方式で実装してみる。

ただしパックマンと違うのは、移動量がアナログに変化することだ。
パックマンは、右入力か左入力かを検知したら、その向きにパックマンが方向転換するだけ、移動速度はいつも一定だ。
対してこれから作ろうとしているアクションゲームは、ちょっとだけスライドしたらちょっとだけ主人公が歩く。そういう違いはつけないといけない。

また、プレイヤーに、スライド方式であると一目で分からせるインターフェース、移動量最大に達したかどうか分からせる見た目にすることも必要。
これについては考えていることがあるが、後日。



スライド量に比例して主人公を動かす。
それはいい。
指を離すと途端に主人公が止まってしまう。
これはよくない。

慣性力を働かせよう。
常に前フレームの移動量の0.8倍の慣性力が働くようにしてみた。
60フレームで動いているから、結構キツメに慣性がかかるはずだ。
すると、指を離してもある程度スーッと歩き続けるようになった。ここはいい感じ。
ただしこうすると、前フレームの速度が加算されるので、トップスピードがすごくあがってしまう。
具体的には、元のトップスピードが6.0だったとすると、0.8の慣性がつくと30.0まで跳ね上がる。(30.0 * 0.8 + 6.0 = 30.0…が終端速度になるというわけ。)
(元の速度v, 慣性k, とすると、新しい速度v' は v' = v / (1 - k) ということ)

というわけで、トップスピードをさっきまでの5分の1に落とした。
これで、最高速は変わらず、指を離したときの慣性力がつくようになった。

次に、ジャンプ中の横移動について。
空中にいるときは、地面にいるときよりも慣性力が強く働かなければおかしい。
空中で、地上のようにクイッとターンできては不自然だ。物理学的にも、空中では本来横移動の速度は着地まで変わらないはずだ(空気抵抗除く。ジェットを装備でもしてない限り)

というわけで、ジャンプ中のみ慣性力を強くしてみた。0.99。
でもこれだと、さっきの計算式から言って、ジャンプ中の最高速が元の100倍になってしまう…ジャンプすると速度があがるという不思議現象になっちゃう。

ちょっと違う方法にしよう。
慣性力0.8というのは同じで、これを乗じる間隔を広げる(回数を少なくする)というのはどうか。
これなら最高速があがることはなく、しかも速度が落ちるのもゆっくりになる。
10フレームに1回だけ慣性力0.8掛けをするようにしてみた。
わりといい感じになった。

あとは慣性力とジャンプ中の間引きをいい感じに調整すれば、ひとまず平地を歩いてジャンプするぶんに関してはいい感じにできるだろう。


しかし、まだ気になることがある。
右に走っていて、左に方向転換したくなったとき、
左にちょっとスライドしても、右へ走る速度が下がるだけで、左向きに移動するようにはならない。
左へ移動するためには、タッチ始点よりも左にスライドしないといけない。または、一度指を離してから改めて左スライドする必要がある。

これはちょっと不便だ。
タッチ始点がどの位置だったかなんて覚えている分けないし、
一度指を離すというのも余計な操作が入ってしまってよくない。
右へ走っている状態でも、ちょっとでも左スライドしたら、主人公が左に動き始める。移動までしなくとも、主人公に左向きの移動の力を加えてブレーキがかかるくらいのことはしたい。(後者の方が良さそう)


操作の仕方は変わらないが、移動の仕方を変える必要がある。
今までは、タッチ始点から現タッチ点までの距離に応じて、主人公に(その瞬間に置ける)速度を毎フレーム与えていた。
今回は、直前のタッチ点から現タッチ点までの距離に応じて、主人公に速度を与えることになるわけだ。
というわけで実装してみたんだけど、いまいち。というか何も変わらなかった。

別の策。
デバイスタッチとしての方向転換を検知したら、タッチ始点をその座標に更新するようにしてみた。
方向転換の検知のために、スライドをどっち方向に行っていたかを保持しておく。また、方向転換の瞬間は多くの場合(必ず?)一度タッチ移動量が0になる瞬間があるようなので、それも考慮して、直前のスライドタッチの方向を記憶しておく。で、それが反転したら、方向転換したと判断。
方向転換したら、タッチ始点をその座標に変更する。
すると、次のフレームから、新しいタッチ始点を基点として主人公速度の計算を行うようになる。

これで、クイックターンができるようになった。


記録のため、コードを貼っておく

//////////////
// キャラ操作
fdInputDataSizedButton button = fdInputGetData().getButton(BUTTON_MOVE);


fdf moveX = 0.f;

//タッチ始点を保持
if (button.hasPressed()) {
posTouched_ = button.getPoint();
}
//入力に応じて移動量を計算
else if (button.isOn()) {
fdPoint2 curPoint = button.getPoint();
fdPoint2 moveTouched = curPoint - posTouched_;

static const bool QUICKTURN = true;
if (QUICKTURN) {

//方向転換していたときの処理
FD_DEBUG_PRINTF("buttonMovedSize = %f\n", button.getMovedSize().w);
if (button.getMovedSize().w * prevTouchMovedX_ < 0) {
//タッチ始点を現座標に更新
posTouched_ = curPoint;
moveTouched = curPoint - posTouched_; //実質0
FD_DEBUG_PRINTF("方向転換\n");
}
if (button.getMovedSize().w != 0) {
prevTouchMovedX_ = button.getMovedSize().w;
}
}

const fdf MOVE_RATE = 0.08f;
const fdf MOVE_X_ABS = 1.2f;//6.f;
const fdf MOVE_X_MIN = 1.f;


//速度計算
moveX = moveTouched.x * MOVE_RATE;
if (moveX < MOVE_X_MIN && moveX > -MOVE_X_MIN) {
moveX = 0;
}
else if (moveX < -MOVE_X_ABS) {
moveX = -MOVE_X_ABS;
}
else if (moveX > MOVE_X_ABS){
moveX = MOVE_X_ABS;
}

}

//慣性力を与える
static bool INERTIA = true;
static float rateInertia = 0.8f;

if (INERTIA) {
moveX += fPrevMoveX_;// * rateInertia;
}

posChara_.x += moveX;
//FD_DEBUG_PRINTF("size=%f\n", moveX);

if (INERTIA){
if (isJumping()) {
if (gameCounter_ % 10 == 0)
fPrevMoveX_ = moveX * rateInertia;
}
else{
fPrevMoveX_ = moveX * rateInertia;
}
}


//ジャンプ
static const int JUMP_COUNT = 48;
static fdf s_jumpDh[JUMP_COUNT/2] = { //delta height
1.f, 1.f, .9f, .9f, .8f, .8f, .7f, .7f, .6f, .6f,
.5f, .5f, .4f, .4f, .3f, .3f, .2f, .2f, .15f, .15f,
.1f, .1f, .05f, .05f,
};
static fdf s_jumpHeight = 6.f;

fdInputDataSizedButton jumpButton = fdInputGetData().getButton(BUTTON_JUMP);
if (!isJumping() && jumpButton.hasPressed()){
nJumpCount_ = JUMP_COUNT;
}
if (nJumpCount_ > 0) {
if (nJumpCount_ > JUMP_COUNT/2 - 1) {
int index = JUMP_COUNT - nJumpCount_ - 1 - 1;
posChara_.y -= s_jumpDh[index] * s_jumpHeight;
}
else{
int index = nJumpCount_ - 1;
posChara_.y += s_jumpDh[index] * s_jumpHeight;
}
nJumpCount_--;
}



PR
【2011/08/11 14:15 】 | 開発日記 | 有り難いご意見(0) | トラックバック()
<<ライト、ついてますか―問題発見の人間学 | ホーム | タッチ点の取得の方法>>
有り難いご意見
貴重なご意見の投稿














虎カムバック
トラックバックURL

<<前ページ | ホーム | 次ページ>>