YKpages

ロボット分野で勉強したことのまとめ

Unity ゲーム開発日記:プレイヤーを動かす

はじめに

2Dシューティングゲーム「オシャレなロケット:Oshare-Na-Rocket」のシステムを作っていきます。

今回はプレイヤーを動かすシステムを作ります。

参考

主に公式のチュートリアルを参考にします。

チュートリアルでは2Dモードで作成していますが、 私は3Dモードで作成します(ゲーム自体は基本的に2Dです)。

unity3d.com

以下の記事はPlayerを進行方向へ向けるときに参考にさせていただきました

qiita.com

背景を黒に

Main Camera の "Clear Flag" を "Solid Color" にして色を黒にします

背景はとりあえずこれで良しとします

プレイヤーのオブジェクトを作成

Create > 2D Objects > Sprite を選択

名前は "Player" にします

Player の Sprite に "Knob" を選択すると、黒い背景に白い点が現れます

そしてPlayerに "Rigidbody" をアタッチ

Rigidbodyをアタッチすると、そのオブジェクトを物理的に制御できます

docs.unity3d.com

タッチ(マウス)でプレイヤーを操作

タッチ、またはマウスでプレイヤーを動かします

本来はスマートフォンのタッチ操作で動かすことになりますが、 Unityエディタ上ではマウスで動かします

方法

  • タッチを始めた座標(スクリーン座標)を取得
  • 指をスライドさせた後の座標を取得
  • 1と2からプレイヤーが移動する方向を計算
  • プレイヤー移動

タッチ操作のための関数を作成

// タッチを始めた座標
Vector2 TouchPositionFrist;
     void PlayerTouch ()
    {
        // タッチ数をカウント、0より大きい場合(つまりタッチがある場合)
        if (Input.touchCount > 0)
        {
            Touch touch = Input.GetTouch(0);

            // タッチを始めた時
            if (touch.phase == TouchPhase.Began)
            {
                //タッチを始めた座標を取得
                TouchPositionFrist = touch.position;
            }
            // 指をスライドさせている時
            else if (touch.phase == TouchPhase.Moved)
            {
                // プレイヤーを移動させる関数へ座標を渡す
                PlayerMove(TouchPositionFrist, touch.position);
            }
            // 指を離した時
            if (touch.phase == TouchPhase.Ended)
            {
                // プレイヤーの速度を0にする
                PlayerRigidbody.velocity = new Vector3(0, 0, 0);
            }
        }
    }

プレイヤーを動かす関数

    void Start () 
    {
        // プレイヤーのRigidbodyコンポーネントを取得
        PlayerRigidbody = GetComponent<Rigidbody>();
    }
    void PlayerMove (Vector3 v1, Vector3 v2)
    {
        // 二つのベクトルから指をスライドさせた方向を求める
        Vector3 direction = (v2 - v1).normalized;
        // 指をスライドさせた方向とは逆向きにプレイヤーを移動
        PlayerRigidbody.velocity = -direction * PlayerSpeed;
    }

プレイヤーに進行方向を向かせる

PlayerMove関数に追加

    void PlayerMove (Vector3 v1, Vector3 v2)
    {
        Vector3 direction = (v2 - v1).normalized;
        PlayerRigidbody.velocity = direction * PlayerSpeed;
        // 進行方向に向かせる(2Dであることに気をつける)
        float angle = GetAngle(direction);
        transform.eulerAngles = new Vector3(0, 0, angle);
    }

アークタンジェントを使ってZ軸の向きを求める

    float GetAngle(Vector3 v)
    {
        float rad = Mathf.Atan2(v.y, v.x);
        return rad * Mathf.Rad2Deg;
    }

移動制限を設ける

Start関数でスクリーンの大きさを取得します

プレイヤーをスクリーン内で動かすようにするためです

Camera.main.ScreenToWorlePointでカメラがNullだよみたいなエラーが出た場合、 CameraのTagが設定されていない可能性があります。CameraのTagを"MainCamera"にすると直ります。

    void Start () 
    {
        Debug.Log("!!START!!");
        playerRigidbody = GetComponent<Rigidbody>();
        // スクリーンの大きさを取得
        min = Camera.main.ScreenToWorldPoint(new Vector3(0, 0, 10f));
        max = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, 10f));
    }

そしてPlayerMove関数を以下のように変更します。

Mathf.Clamp関数は定めた範囲から出た場合、内側に戻してくれます。

marginは余裕を持たせるために設定しました。

    void PlayerMove (Vector3 v1, Vector3 v2)
    {
        // 指をスライドさせた方向に移動
        Vector3 direction = (v2 - v1).normalized;
        playerRigidbody.velocity = direction * playerSpeed;
        // 進行方向に向かせる(2Dであることに気をつける)
        float angle = GetAngle(direction);
        transform.eulerAngles = new Vector3(0, 0, angle - 90f);
        // 移動制限を設ける
        Vector3 playerPosition = transform.position;
        float margin_x = max.x / 20f;
        float margin_y = max.y / 20f;
        playerPosition.x = Mathf.Clamp(playerPosition.x, min.x + margin_x, max.x - margin_x);
        playerPosition.y = Mathf.Clamp(playerPosition.y, min.y + margin_y, max.y - margin_y);
        transform.position = playerPosition;
    }

Camera.main.ScreenToWorlePointのエラーについて

blog.be-style.jpn.com

今回書いたコード

github.com

おわりに

今回はプレイヤーを動かすシステムを作成しました

次は弾を発射するシステムを作っていきます