【Unity/2D】スイカゲーム風の落ち物ゲームを作ってみる話 #2 ポインターを動かす

記事をご覧いただき、誠にありがとうございます。

投稿主の無能です。

前回は、果物を受け止める容器と果物を落下させるポインターを作成しました。

今回はポインターを動かしてみようと思います。

ポインターを動かす

ポインターを動かすのですが、縦横無尽に動いてほしいわけではなく、左右に動いてくれればポインターの役割は十分です。
それでいて、移動範囲は容器の範囲内だけに留めたいです。

ではそのように動くためのスクリプトを書いていきましょう。

スクリプトを準備する

ではスクリプトを準備しましょう。

Projectビューの中がごちゃつくといけないので、「Scripts」フォルダを作成して今後作成するスクリプトはこのフォルダにまとめるようにします。

ProjectビューのAssetsフォルダを選択した状態でメニュー > Folderでフォルダを作成し、名前を「Scripts」にします。

ProjectビューのAssetsフォルダを選択

Folderを選択

名前を「Scripts」にする

そしてScriptsフォルダの中に入ってメニュー > MonoBehaviour Scriptでスクリプトを作成し、名前を「PointerController」にします。

Unity 6以前のバージョンではC# Scriptになっています。
呼称の変更は地味に戸惑うから止めてほしい…w

一つ注意しなければいけないのは、スクリプト作成後にすぐに名前を入力して、スクリプトの名前とクラス名が完全一致するようにします。
スクリプト作成直後に名前を入力しますが、そこで入力した名前がそのままクラス名になります。

例えばスクリプトを作成して、間違って何処かをクリックしたり別ウィンドウに表示を切り替えたりした場合は、デフォルト名の「NewMonoBehaviourScript」というスクリプトの名前になり、クラス名も「NewMonoBehaviourScript」になります。

スクリプト作成直後の名前入力状態

誤操作によりスクリプト名が確定してしまった状態
クラス名が「NewMonoBehaviourScript」に確定される

クラス名が確定

後から修正も可能ですが、Unity 6以前のUnityの仕様上、スクリプト名とクラス名が完全一致していない場合は、そのスクリプトはアタッチが外れたりアタッチ出来なくなります。

スクリプト名とクラス名が完全一致していない状態

Unity 6では解消されたようですが、基本は完全一致が正常に動作する条件となります。

Unity 6ではクラス名が登録される

スクリプト名とクラス名が一致していない

修正する時は、Projectビューのスクリプト名とVisual Stadio内で開いたスクリプトのクラス名が半角英数の大・小文字を含め完全一致するように修正してください。
他の修正方法としては、Visual Stadioでクラス名を右クリックして「名前の変更」で変更を行うとスクリプト名も一緒に変更されます。

また、何も書いていないスクリプトであれば削除して再度新規作成しても問題ありません。

Unity 6以前のバージョンではスクリプト名とクラス名の完全一致が正常な動作の条件ですので、スクリプトの名前入力の際は注意してください。

PointerControllerスクリプトが作成できたら、Pointerにアタッチします。

PointerにPointerControllerスクリプトをアタッチ

あともう一つスクリプトを作成して、名前を「Variables」にします。

Variablesスクリプトを作成

このVariablesスクリプトは何処にもアタッチせず、スクリプト全体の変数(定数)の倉庫の役割をさせるためのものです。

スクリプトの書き方は個々人で千差万別ですが、無能はこの書き方をしています。

ではVariablesスクリプトを開き編集します。
ダブルクリックやEnterでVisual Stadioが開き、その対象のスクリプトが開きます。

Visual StadioでVariablesスクリプトを開いた状態

ではVariablesスクリプトから見ていきます。

スクリプトの編集

Variables

Variables.cs

using UnityEngine;

public class Variables : MonoBehaviour
{
    public const float zero = 0f;                               // floatの0
}
0はよく使うので、倉庫の役目をするVariablesに定数として定義しておきます。

これで他のスクリプトで小数の0を使う時は「Variables.zero」で呼べるようになります。

また、整数の0を使う時は「(int)Variables.zero」とすることで、キャスト(型変換)を行い整数の0になります。

次にPointerControllerを見ていきます。

PointerController

PointerController.cs

using UnityEngine;

public class PointerController : MonoBehaviour
{
    #region Var-Container
    [Header("容器の壁:左")]
    [SerializeField] GameObject container_Left;
    [Header("容器の壁:右")]
    [SerializeField] GameObject container_Right;
    [Header("容器の壁との余白")]
    [SerializeField] float marginX = 0.1f;
    #endregion

    #region Var-Pointer
    [Header("ポインターの移動速度")]
    [SerializeField] float moveSpeed = 1f;
    #endregion

    #region Var-Internal
    Rigidbody2D pointerRB;                                                  // ポインターのRigidbody2D
    Vector2 moveDirection;                                                  // ポインターの移動ベクトル
    float movableRange_Left, movableRange_Right;                            // ポインターの移動可能範囲
    #endregion

    #region Start
    void Start()
    {
        // ポインターのRigidbody2Dを取得
        pointerRB = GetComponent<Rigidbody2D>();
        // 移動可能範囲を取得
        movableRange_Left = container_Left.transform.position.x + marginX;         // 左
        movableRange_Right = container_Right.transform.position.x - marginX;       // 右
    }
    #endregion

    #region Update
    void Update()
    {
        // 移動の受付処理
        InputProcess();
        // ポインターの移動
        PointerMove();
    }
    #endregion

    #region InputProcess
    // 移動の受付処理
    void InputProcess()
    {
        // 水平の入力を取得
        float horizontalInput = Input.GetAxis("Horizontal");
        // ポインターの移動ベクトルを作成
        moveDirection = new Vector2(horizontalInput, Variables.zero);
    }
    #endregion

    #region PointerMove
    // ポインターの移動
    void PointerMove()
    {
        // ポインターの移動範囲を制限
        MoveClamp();
        // ポインターを移動
        pointerRB.linearVelocity = moveDirection * moveSpeed;
    }
    #endregion

    #region MoveClamp
    // 移動範囲の制限
    void MoveClamp()
    {
        // 横の移動範囲を制限
        float pointerX = Mathf.Clamp(gameObject.transform.position.x, movableRange_Left, movableRange_Right);
        // ポインターの位置を取得した位置にする
        gameObject.transform.position = new Vector2(pointerX, gameObject.transform.position.y);
    }
    #endregion

}

それではメンバ変数から見ていきましょう。

メンバ変数

まずGameObjectで容器の壁の壁の左右のcontainer_Left・Rightを取得しています。
それから左右の壁との余白でfloatのmarginXになります。

次にポインターの移動速度としてfloatのmoveSpeedになります。

最後に内部処理用として、ポインターのRigidbody2DのpointerRB、移動ベクトルとなるmoveDirection、ポインターの移動可能範囲となるmovableRange_Left・Rightになります。

次に処理を見ていきます。

Start関数

Start関数では、pointerRBにポインターのRigidbody2Dを取得します。

次にmovableRange_Left・Rightに移動可能範囲となる最小値(movableRange_Left)と最大値(movableRange_Right)を代入します。
この時、marginXを最小値に足し合わせ、最大値に引き合わせることで余白を作ります。

何故余白を持たせるのかというと、オブジェクトの本体はそのオブジェクトの中心部分に存在しているからです。

例えると容器の壁は長方形のハリボテを着ていて、そのハリボテの分を余白として取ることで帳尻合わせをしています。

オブジェクトと図形のイメージ

Update関数

Update関数内では、移動の受付処理をするInputProcess関数と、ポインターの移動をする PointerMove関数を呼んでいます。

InputProcess関数

InputProcess関数では、まずInput.GetAxisで水平の入力を取得します。 
取得した値をhorizotalInputというローカル変数に代入します。

次に新しいベクトルとしてhorizotalInput(X方向)と0(Y方向)のベクトルを作成し、moveDirectionに代入します。

PointerMove関数

PointerMove関数では、移動可能範囲を作成するMoveClamp関数を呼んでいます。

次にポインターのlinearVelocityに、移動ベクトルのmoveDirectionとポインターの移動速度のmoveSpeedを掛けた値を代入します。

Unity 6ではvelocityは旧形式となったため、Unity 6以前のバージョンであればlinearVelocityではなくvelocityで問題ありません。

MoveClamp関数

MoveClamp関数では、移動を制限するためにMathf.Clampで計算した値をpointerXというローカル変数に代入します。

Mathf.Clampの使い方はドキュメントを参考にしてください。


Mathf.Clampで範囲の対象となるポインター自身のX座標、最小値にStart関数で取得したmovableRange_Leftを、最大値に同じくStart関数で取得したmovableRange_Rightにします。

そしてポインターの移動の横方向をpointerX、縦方向をポインター自身のY座標にします。

これでポインターが移動できるようになったので、Unityに戻って細かい設定をします。
あ、スクリプトはCtrl+sキーで上書き保存を忘れずに。

Unityでの作業

ポインターにアタッチしたPointerControllerに項目が追加されていますので、各項目を設定します。

追加された各項目を設定

容器の壁の左右は作成したContainer_Left・RightをHierarchyビューからドロップします。

容器の壁との余白、ポインターの移動速度は各自のPC環境で調整してください。

動作確認

では動作確認をします。

確認事項は
  • ポインターが動くか
  • 移動速度を変更するとポインターの動く速さが変わるか
  • 容器の壁の外にはみ出してポインターが移動しないか
になります。

ではUnityの上部の再生ボタン(▶ボタン)でゲームを再生して確認しましょう。

ポインターが動いた

速度を変更

ポインターの移動速度が変わった

左はこれ以上いけない(移動範囲の最小値)

右はこれ以上いけない(移動範囲の最大値)

どうやらポインターに想定通りの移動の機能を持たせられました。

まとめ

今回は
  • スクリプトファイルを作成した
  • スクリプトをポインターにアタッチした
  • アタッチしたスクリプトを編集してポインターに想定通りの機能を実装した
という事をやりました。

次回は容器の中に落下させる果物を作っていきたいと思います。

では、また次回!

コメント