CodeZine(コードジン)

特集ページ一覧

速習 Unity 2Dゲーム開発
~第14回 コントローラーでゲームをする

速習 Unity 2Dゲーム開発 第14回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2015/03/24 14:00
目次

コントローラーの操作でジャンプする

Aボタンの判定の追加

 コントローラーとUnityの対応が分かったところで「Aボタンを押せばキャラクターがジャンプする」ようにしましょう。対応表を見るとAボタンに対応するのは「joystick button 0」です。GameManager.csのスペースキーでジャンプ処理を行っていた部分を以下のように変更します。

コントローラーのAボタンでジャンプする
// スペースキーでジャンプ
// ジャンプ中はスペースキーが押されてもさらに上昇しない
// XBox 360コントローラー対応
if ((Input.GetKeyDown("space") || Input.GetKey(KeyCode.Joystick1Button0)) && this._charactorScript.isJumping == false)
{
    this._moveCharactor(Vector2.up * _upForce);
}

動作を確認する

 実行して動作を確認すると、Aボタンを押すとキャラクターが想定した以上にジャンプを行い画面の上端を飛び越えてしまいました。キーボードからコントローラーに変えたことで発生した不具合です。今回はその流れを確認しながら解決していきます。

 ジャンプの判定文をもう一度見直してみます。

ジャンプの判定
if ((Input.GetKeyDown("space") || Input.GetKey(KeyCode.Joystick1Button0)) && this._charactorScript.isJumping == false)

 この判定は以下の条件を満たすとジャンプを行います。

  • スペースキーまたはAボタン(Joystick1Button0)が押された
  • キャラクターのisJumpingの値がfalseである

 isJumpingはジャンプ中かどうかを判定するフラグで、これが正常に動作しているならキャラクターは大きくジャンプしないはずです。このフラグが怪しいので以下のようにログを書き出してみます。

デバッグを仕込む
if ((Input.GetKeyDown("space") || Input.GetKey(KeyCode.Joystick1Button0)) && this._charactorScript.isJumping == false)
{
    this._moveCharactor(Vector2.up * _upForce);
    Debug.Log("jump");
}

 予想通り一度のAボタン押下で複数回「jump」というログが出力されました。ではisJumpingの値はどのタイミングで変更されるのでしょうか?

ジャンプ判定の見直し

 isJumpingはCharactorManager.csのプライベート変数_isJumpingの値を取得するgetter的な変数でした。_isJumpingが書き替えられるタイミングは以下です。

_isJumpingが書き替えられるタイミング
/// <summary>
/// 接触状態から離れた
/// </summary>
/// <param name="col"></param>
public void OnCollisionExit2D(Collision2D col)
{
    if (col.gameObject.name == "ground" || col.gameObject.name == "floor")
    {
        this._collisionList.Remove(col.gameObject);

        // 接触しているGameObjectが0の場合はジャンプしていると判定してアニメーションを開始する
        if (this._collisionList.Count == 0)
        {
            this._isJumping = true;
        }
    }
}

 OnCollisionExit2Dというキャラクターが接地状態から離れた場合に発生するイベント内で_isJumpingが書き替えられています。GameManager.csのUpdateメソッドがOnCollisionExit2Dの処理が終わる前に複数回呼ばれるために、今回のバグが発生していると考えられます。

 試しにAボタンを押された直前に_isJumpingを書き替えてみます。_isJumpingはパブリックな状態ではgetterしか提供していないので、以下のように値を変更できるようにsetterを追加します。

CharactorManagerの_isJumpingにsetterを追加
public bool isJumping
{
    get { return _isJumping; }
    set { this._isJumping = value; }
}

 GameManager.csのUpdateメソッドに戻り、以下のようにisJumpingを操作します。

ジャンプ判定のフラグを変更するタイミングを早める
// スペースキーでジャンプ
// ジャンプ中はスペースキーが押されてもさらに上昇しない
// XBox 360コントローラー対応
if ((Input.GetKeyDown("space") || Input.GetKey(KeyCode.Joystick1Button0)) && this._charactorScript.isJumping == false)
{
    this._moveCharactor(Vector2.up * _upForce);
    this._charactorScript.isJumping = true;
}

 実行してみると、大きくジャンプする問題は解決していることが確認できます。

 setterを追加した点や、プログラミングの設計には改善の余地があるものの、今回の件で2つのことが分かりました。

  • OnCollisionExit2D発生までにUpdateメソッドが複数回呼ばれる(イベント開始にわずかながら時間がかかっている)
  • Input.GetKeyは複数回処理発生への注意が必要。

ボタン操作に対するもう一つの対応

 Input.GetKeyではボタンを押している間は複数回処理を実行してしまいましたが、「ボタンを押したタイミングで一度だけ」イベントが取得できればよりスマートに解決できそうです。すでにコードには答えが出ているのですが、スペースキーの判定同様にInput.GetKeyDownを利用すれば、押したタイミングで一度イベントを取得できます。

 コードを以下のように書き替えます。

Input.GetKeyDownに書き替え
if ((Input.GetKeyDown("space") || Input.GetKeyDown(KeyCode.Joystick1Button0)) && this._charactorScript.isJumping == false)
{
    this._moveCharactor(Vector2.up * _upForce);
}

 これでもキャラクターの想定外の高いジャンプは発生しなくなりました。isJumpingへの操作がなくなるので、setterも必要なくなりました。

 少し回りくどくなりましたが、OnCollisionExit2DイベントのタイミングとInput.GetKey、Input.GetKeyDownが分かったと思います。

まとめ

 ゲームにおけるコントローラーの対応について紹介しました。これからXBox OneやPlayStation 4のコントローラーがPCゲームの標準になっていくと、また別の操作への対応が必要になってくるかもしれませんが、今のところ、コントローラーはXBox 360をターゲットにするのが主流です。

 当たり前ですが、iPhoneやAndroid(Windows Phoneも)といったスマートフォンではコントローラーではなくタッチ操作への対応が必要になります。この辺は次回以降で紹介していければと思います。



  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:速習 Unity 2Dゲーム開発

もっと読む

著者プロフィール

  • 西村 誠(ニシムラ マコト)

     Microsoft MVP Windows Platform Development。  Flash、PHPの開発経験もあり国産ECサイト構築フレームワーク「EC-CUBE」の公式エバンジェリストでもある。  ブログ:眠るシーラカンスと水底のプログラマー  著書:基礎から学ぶ Windows...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5