eaglesakuraの技術ブログ

技術的な話題とか、メモとか。

Unity学習 よくあるJoystickの移動系を再現する

よくある入力系とは

  • 左スティックで移動する
    1. スティックを上(奥)に倒すと画面奥方向に移動
    2. スティックを下(手前)に倒すと画面手前方向に移動
    3. スティックを左に倒すと画面左方向に移動
    4. スティックを右に倒すと画面右方向に移動
  • よくある入力系なので、アセットも充実している
    • だが、久々に自分で実装してみよう
    • 実に8年ぶりの実装である

移動方向を計算する

  • カメラからみた自キャラの方向を計算する
  • 自キャラの方向に、ジョイスティックの方向を加算する
    • カメラがグローバル座標に対して45度のとき、ジョイスティックを上(0度)に倒すと、グローバル座標45度方向に移動する
    • カメラがグローバル座標に対して45度のとき、ジョイスティックを下(180度)に倒すと、グローバル座標225度方向に移動する
    • XZ平面上で動作する場合に有効な制御
      • 人間はXZ平面で概ね生きているので、だいたい問題ない
  • キャラを移動方向に向ける
    • つまり、キャラの向きと移動方向は独立している
    • アクションゲームでよく見る
      • FF13は急旋回すると、キャラが一度立ち止まるモーションが入る
        • リアルだけど、好みが分かれると思う
  • カメラがキャラ真上にあると死ぬ
    • atan2の限界である

カメラ設定

  • カメラもジョイスティックで移動できるようにする
  • データとして プレイヤーからの距離 Global Yaw Global Pitch をもたせる
  • プレイヤーを囲む球面上をカメラ位置が移動し、LookAtはプレイヤーの周辺に固定することになる
    • AtはEmpty Objectをターゲットにする
  • 右JoystickはコントローラーによってUnity側のバインドが異なる
    • 一つのコントローラーだけ使ってると、別なコントローラーで痛い目を見る

Animator追加

  • 歩く 止まる でモーション制御が必要である
  • 単純な遷移制御のみで良いため、 Animator.CrossFadeInFixedTime(StateName, Duration) で遷移させる
    • 名前指定できる、遷移時間設定できるので、多くの場面で事足りそう
    • 参考URL
    • 毎フレーム、必要なStateをSubjectに流し続けて、変化したらObserverがハンドリングする
private Subject<string> _stateName = new Subject<string>();
protected override void Awake()
{
    base.Awake();
    _stateName.DistinctUntilChanged()
        .Subscribe(state => Animator.CrossFadeInFixedTime(state, AnimationTransitionDurationSec));
}    

private void WalkByUserInput(Vector2 beforeInputAxis, Vector2 currentInputAxis)
{
    // Move User
    if (!currentInputAxis.IsZero())
    {
        _stateName.OnNext("Run");
    }
    else
    {
        _stateName.OnNext("Idle");
    }
}

移動速度とフレームレート

  • FixedUpdate で位置更新を行う
  • フレームレート固定でいどうするので、システムから値を取得する
    • 参考URL
    • 前フレームから経過時間取得 Time.deltaTime
    • ターゲットフレームレート取得 Application.targetFramerate でSet/Get

所感

  • ターゲットロックなしだと、 カメラ移動 + ジョイスティック上 で好きな方向に移動できてしまう
    • ちょっと気持ち悪い
    • アホの子っぽい
  • カメラと移動を独立させる
    • ある程度緩和されるけど、カメラを移動させすぎるとやっぱり気持ち悪い動きになる
  • カメラロックオンは偉大である