Unityでスマホゲームを作ってみました その1

manbyのeラーニングでUnity(ユニティ)が追加されましたので、早速スマートフォン用ゲームを作成してみました。

まずは開発環境を整えます。Unityの公式ホームページ(https://unity.com/)から「Unity Hub」をダウンロードします。インストール後、ログインする必要がありますのでUnityのアカウントを作成するか、Googleアカウント等でログインします。

次に、Unity HubからUnityをダウンロードします。いくつかバージョンがありますが、LTS(Long Time Support)と書いてあるものがお勧めです。私は2020.3.9f1と2019.4.27f1をダウンロードしました。

また、C#のスクリプトを編集するためMicrosoftのVisual Studioも必要になります。こちらも一緒にダウンロードしてしまいましょう。インストールが済めば準備は完了です。

それではUnity Hubを立ち上げましょう。今回は2Dのゲームを作成するのでテンプレートは2Dを選択します。Unityのバージョンは2019.4.27f1にしました。

Unityが起動したら、まずはFile → Build SettingからAndroidを選択 → Switch Platformを押してAndroidの制作環境にします。

また、Game ViewがFree Aspectになっている場合は、16:9Landscapeに変更し、実機とあまり差が無いようにします。

次に、Window → Asset Storeを開き、素材をダウンロードし、インポートします。今回は「Sprite Pack #1 – Tap and Fly」を選びました。こちらからメインキャラクターとして黄色い鳥、背景用として雲を2種類、障害物としてサボテンを使用します。

では制作の方に移っていきます。インポートしたSprite Packの中からTap and Fly → Sprites → Player → player_fly_f02をHierarchyウィンドウにドラッグ&ドロップし、名前をPlayerにします。サイズが小さかったのでScaleをX:Y:Z=4:4:4にしました。

そして、Inspectorの最下段、Add Component → Physics 2d → Rigidbody 2DとPolygon Collider 2Dを追加します。Rigidbody 2Dはキャラクターが自由落下する際の演算に必要で、Polygon Collider 2Dは当たり判定の範囲設定に必要です。

Unityを実行して、キャラクターが落ちていけば成功です。

また、デフォルトでは当たり判定が広めに設定されていましたので、Edit Colliderで画像ギリギリになるように調整しました。

では次に、アニメーションをつけていきます。こちらの記事を参考にしました。

まずは新たにSceneを作成し、名前をAnimation(任意)とします。そしてSceneウィンドウかHierarchyにキャラクターのスプライトをドラッグ&ドロップします。次にAdd Component → Miscellaneus → Animatorを追加します。

続いて、Hierarchyウィンドウでキャラクターを選択した状態でWindow → Animation → Animationを選択し、アニメーション編集ウィンドウを開きます。ここへ、キャラクターのスプライトを動かしたい順番にドラッグ&ドロップします。ファイル名としては、player_fly_f01、player_fly_f02、player_fly_f03で、最後にもう一度player_fly_f01を追加します。動かしてみるとこのようになります。

それではキャラクターを動かすためにスクリプトを記述していきます。ファイル名はPlayerScripts(任意)とし、manabyの動画を参考に以下のように記述しました。青線の部分が追記した箇所です。

PlayerScripts

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerScript : MonoBehaviour
{
    // Start is called before the first frame update
    public float upForce;
    private Rigidbody2D rigidbody2D;

    void Start()
    {
        rigidbody2D = GetComponent<Rigidbody2D>();
    }

    // Update is called once per frame
    void Update()
    {
            if (Input.GetMouseButtonDown(0))
            {
                rigidbody2D.velocity = Vector2.zero;
                rigidbody2D.AddForce(new Vector2(0, upForce));
            }
        
    }
}

ファイルを保存したら、GameSceneにもどり、Hierarchyのキャラクターにドラッグ&ドロップします。同様に、AnimationのPlayerもドラッグ&ドロップします。Hierarchyでキャラクターを選択し、InspectorのPlayerScriptsのUpForceの欄が0になっていますので、ひとまず300と入力します。これがマウスをクリックした際の上昇値になります。

Unityを実行してキャラクターがパタパタと羽ばたきながら落ちていき、マウスをクリックすると上昇すれば成功です。

では次に障害物を作成します。インポートしたSprite Packの中からSprites → Background → scene_02_midground(サボテン)をHierarchyにドラッグ&ドロップして、Add Component → Physics 2d → Rigidbody 2DとPolygon Collider 2Dを追加しました。こちらも当たり判定が広めに設定されていましたので、Edit Colliderで画像ギリギリになるように調整しました。

また、障害物は落下しませんのでRigidbody2DのGravityScaleは0にし、ぶつかったという判定が必要なのでCircleCollider2DのIsTriggerにチェックを入れました。続いて、スクリプトを作成します。名前はObstacleScript(任意)とし、下記のようにコードを記述しました。自動生成されたオブジェクトが完全に画面外に出たら消えるように、-20fのmarginを設けています。

ObstacleScript

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ObstracleScript : MonoBehaviour
{
    private Rigidbody2D rigidbody2D;
    private float speed = -100f;
    private float margin = -20f;

    // Start is called before the first frame update
    void Start()
    {
        speed = Random.Range(-100, -400);
        rigidbody2D = GetComponent<Rigidbody2D>();
        rigidbody2D.AddForce(new Vector2(speed, 0));
    }

    // Update is called once per frame
    void Update()
    {
        Vector2 position = transform.position;
        if (position.x < Camera.main.ViewportToWorldPoint(Vector2.one).x + margin)
        {
            Destroy(gameObject);
        }
    }
}

次に、Hierarchyに空のオブジェクトを作成し、名前をGameControl(任意)とします。そして障害物をランダム生成するスクリプトを下記のように作成し、GameControlにアタッチします。

ObstraclePrefab(GameControlにアタッチ)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ObstraclePrefab : MonoBehaviour
{
    public GameObject obstacle;
    public float spawnRate = 1f;
    public float obstacleMin = -5f;
    public float obstacleMax = 5f;

    private float timeSinceLastSpawned;
    private Vector2 obstaclePosition = new Vector2(0, 0);

    // Start is called before the first frame update
    void Start()
    {
        timeSinceLastSpawned = 0f;
    }

    // Update is called once per frame
    void Update()
    {
        timeSinceLastSpawned += Time.deltaTime;

        if (timeSinceLastSpawned >= spawnRate)
        {
            timeSinceLastSpawned = 0f;
            float spawnYPosition = Random.Range(obstacleMin, obstacleMax);
            GameObject obstacles;
            obstaclePosition = obstacle.transform.position = new Vector2(10, spawnYPosition);
            obstacles = Instantiate(obstacle, obstaclePosition, Quaternion.identity);
        }
    }
}

また、スクリプトをアタッチしたscene_02_midground(サボテン)はProjectフォルダへ移してプレハブ化し、Hierarchyからは削除します。そしてGameControlを選択した状態でInspedtorのObstracleの欄にscene_02_midgroundのプレハブをドラッグ&ドロップします。

Unityを実行し、ランダムにサボテンが流れてくれば成功です。

同じ要領で、背景用に雲を2種類追加し、さらに背景の色を空色に変更します。追加するスプライトは、scene_01_cloudとscene_02_cloudです。サボテンと同様にスクリプトを記述し、アタッチします。サボテンほど沢山生成する必要はありませんので、数値を変更しました。

Cloud1Script(scene_01_cloudにアタッチし、scene_01_cloudをProjectフォルダへ)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Cloud1Script : MonoBehaviour
{
    private Rigidbody2D rigidbody2D;
    private float speed = -50f;
    private float margin = -20f;

    // Start is called before the first frame update
    void Start()
    {
        rigidbody2D = GetComponent<Rigidbody2D>();
        rigidbody2D.AddForce(new Vector2(speed, 0));
    }

    // Update is called once per frame
    void Update()
    {
        Vector2 position = transform.position;
        if (position.x < Camera.main.ViewportToWorldPoint(Vector2.one).x + margin)
        {
            Destroy(gameObject);
        }
    }
}

Cloud2Script(scene_02_cloudにアタッチし、scene_02_cloudをProjectフォルダへ)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Cloud2Script : MonoBehaviour
{
    private Rigidbody2D rigidbody2D;
    private float speed = -40f;
    private float margin = -20f;

    // Start is called before the first frame update
    void Start()
    {
        rigidbody2D = GetComponent<Rigidbody2D>();
        rigidbody2D.AddForce(new Vector2(speed, 0));
    }

    // Update is called once per frame
    void Update()
    {
        Vector2 position = transform.position;
        if (position.x < Camera.main.ViewportToWorldPoint(Vector2.one).x + margin)
        {
            Destroy(gameObject);
        }
    }
}

Cloud1Prefab(GameControlにアタッチ)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Cloud1Prefab : MonoBehaviour
{
    public GameObject obstacle;
    public float spawnRate = 1f;
    public float obstacleMin = -5f;
    public float obstacleMax = 5f;

    private float timeSinceLastSpawned;
    private Vector2 obstaclePosition = new Vector2(0, 0);

    // Start is called before the first frame update
    void Start()
    {
        timeSinceLastSpawned = 0f;
    }

    // Update is called once per frame
    void Update()
    {
        timeSinceLastSpawned += Time.deltaTime;

        if (timeSinceLastSpawned >= spawnRate)
        {
            timeSinceLastSpawned = -15f;
            float spawnYPosition = Random.Range(obstacleMin, obstacleMax);
            GameObject obstacles;
            obstaclePosition = obstacle.transform.position = new Vector2(10, spawnYPosition);
            obstacles = Instantiate(obstacle, obstaclePosition, Quaternion.identity);
        }
    }
}

Cloud2Prefab(GameControlにアタッチ)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Cloud2Prefab : MonoBehaviour
{
    public GameObject obstacle;
    public float spawnRate = 1f;
    public float obstacleMin = -5f;
    public float obstacleMax = 5f;

    private float timeSinceLastSpawned;
    private Vector2 obstaclePosition = new Vector2(0, 0);

    // Start is called before the first frame update
    void Start()
    {
        timeSinceLastSpawned = 0f;
    }

    // Update is called once per frame
    void Update()
    {
        timeSinceLastSpawned += Time.deltaTime;

        if (timeSinceLastSpawned >= spawnRate)
        {
            timeSinceLastSpawned = -10f;
            float spawnYPosition = Random.Range(obstacleMin, obstacleMax);
            GameObject obstacles;
            obstaclePosition = obstacle.transform.position = new Vector2(10, spawnYPosition);
            obstacles = Instantiate(obstacle, obstaclePosition, Quaternion.identity);
        }
    }
}

作成したCloud1PrefabとCloud2PrefabはGameControlにアタッチし、InspedtorのObstracleの欄にそれぞれscene_01_cloud、scene_02_cloudのプレハブをドラッグ&ドロップします。

背景の色はMainCameraを選択し、Backgroundの色をクリックすると色変更出来るようになりますので、お好みの色に変更してください。

以上を踏まえてUnityを実行するとこのようになります。

その2に続きます

その3はこちら

  • 0
  • 0
  • 0

おすすめのタグ

Laffey(ラフェィ)

色々な物・もの・モノを作って記事にしています

作者のページを見る

関連記事

寄付について

「novalue」は、‟一人ひとりが自分らしく働ける社会”の実現を目指す、
就労継続支援B型事業所manabyCREATORSが運営するWebメディアです。

当メディアの運営は、活動に賛同してくださる寄付者様の協賛によって成り立っており、
広告記事の掲載先をお探しの企業様や寄付者様を随時、募集しております。

寄付についてのご案内