1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Unity 2020.3で作るWebVRゲーム【フードキャッチ】

Last updated at Posted at 2021-07-30

概要

  • Unity 2020.3でカンタンなVRのゲームを作成します
  • 食べ物をカゴでキャッチするゲームを作成します
  • 最終的にWebGLでデプロイしてブラウザで楽しめるVRのコンテンツを作成します
  • 一日で完成できたモノなので手順を参考にして作ってもらえれば幸いです

素材(Asset)

WebVR用のパッケージ

完成物

  • Bowlを操作して落ちてくる食べ物をキャッチするゲームです

Videotogif (3).gif

作成手順

ゲームの作成

3Dのプロジェクトを新規作成する

image.png

素材(Asset)を全てインポートする

  • 上記の素材(Asset)を全てインポートします

サンプルのシーンをコピーする

  • RPGPP_LTのサンプルシーンを使用します
  • シーン自体をコピーして複製し任意の名前をつけます
  • 複製したシーンを加工していきます

image.png

サンプルのシーンのオブジェクトを整理する

  • Environmentという空のオブジェクトを作成します
  • 作成したオブジェクトを親にして全てのオブジェクトを子にします
  • Environmentの位置を調整します
    • Position X:0 Y:-35 Z:-85
    • Rotation X:0 Y:110 Z:0

image.png

カメラの視点をマウスで動かせるようにする

  • DragMove.csというスクリプトを作成して以下の内容を記述します
  • 作成したスクリプトをMainCameraにアタッチします
  • MoveObjにカメラのオブジェクトであるMainCameraをアタッチします
  • アタッチ後に実行するとマウスのドラッグでカメラの視点を動かすことができます
  • MainCameraの位置を調整します
    • Position X:0 Y:0 Z:0

image.png

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

public class DragMove : MonoBehaviour
{
    public GameObject moveObj;
    private Vector3 newAngle = new Vector3(0, 0, 0);
    private Vector3 lastMousePosition;

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // マウスクリック開始(マウスダウン)時にカメラの角度を保持(Z軸には回転させないため).
            newAngle = moveObj.transform.localEulerAngles;
            lastMousePosition = Input.mousePosition;
        }
        else if (Input.GetMouseButton(0))
        {
            // マウスの移動量分カメラを回転させる.
            newAngle.y -= (Input.mousePosition.x - lastMousePosition.x) * 0.1f;
            newAngle.x -= (Input.mousePosition.y - lastMousePosition.y) * 0.1f;
            moveObj.transform.localEulerAngles = newAngle;
            lastMousePosition = Input.mousePosition;
        }
    }
}

ゲーム全体を管理するスクリプトを作成する

  • TextMechProTextScoreTextTimeTextというオブジェクトを作成します
  • 作成するとCanvasが自動的に生成されるのでアンカーなどで位置を調整します
  • 空のオブジェクトでGameControlを作成します
  • GameControlに以下のスクリプトを作成してアタッチします
  • スクリプトにScoreTextTimeTextをアタッチします

image.png

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

public class GameManager : MonoBehaviour
{
    public TextMeshProUGUI scoreText;
    public TextMeshProUGUI timeText;

    public static float time = 60;
    public static int score = 0;

    // Update is called once per frame
    void Update()
    {
        GameEndCheck();
        scoreText.text = $"SCORE: {score}";
    }

    void GameEndCheck()
    {
        if (time > 0)
        {
            time -= Time.deltaTime;
            timeText.text = $"TIME: {Math.Floor(time)}";
        }
        else
        {
            timeText.text = "TIME: 0";
        }
    }
}

各食べ物のオブジェクトの設定

  • 各食べ物のオブジェクトに対して回転させたり点数を設定できるようにします
  • 食べ物のオブジェクトをCtrl + Aで全て選択している状態で以下のScaleを設定します
    • Scale X:15 Y:15 Z:15
  • RigidbodySphereColliderを設定します
  • Fruitsというタグを設定します
  • FruitのスクリプトをAdd Componentで追加します
  • スクリプトのscoreでそれぞれに個別の点数を設定することができます

image.png

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

public class Fruit : MonoBehaviour
{
    public int score = 1;
    float rotateSpeed = 1.0f;

    void Update()
    {
        transform.Rotate(new Vector3(0, rotateSpeed, 0), Space.Self);
    }
}

食べ物を繰り返し生成する

  • 先ほど作成したGameControlに以下のスクリプトを作成してアタッチします
  • スクリプトのFruitsは配列なので任意の数を設定してください
  • それぞれのElementFREE Food PackPrefabをアタッチします
  • カメラの周囲(水平の円状)に食べ物のオブジェクトが生成されます
  • Unityで動作させているときのみキーボードのスペースキーで食べ物を生成できます

image.png

using System.Collections;
using UnityEngine;

public class FruitsGenerater : MonoBehaviour
{
    public GameObject[] fruits;

    void Start()
    {
        StartCoroutine("CoroutineFruitsGenarate");
    }

# if UNITY_EDITOR
    void Update()
    {
        if (Input.GetKey(KeyCode.Space))
        {
            GenerateFruit();
        }
    }
# endif

    private Vector3 RandHorizonCircleVec3(
        float aMin = 0,
        float aMax = 180,
        float rMin = 5,
        float rMax = 5,
        float yHeight = 1
    )
    {
        var angle = Random.Range(aMin, aMax);
        var radius = Random.Range(rMin, rMax);
        var rad = angle * Mathf.Deg2Rad;
        var px = Mathf.Cos(rad) * radius;
        var pz = Mathf.Sin(rad) * radius;
        return new Vector3(px, yHeight, pz);
    }

    private void GenerateFruit()
    {
        int enemyRnd = Random.Range(0, fruits.Length);
        GameObject fruit = Instantiate(
            fruits[enemyRnd],
            // RandHorizonCircleVec3(60, 100, 10, 10, 5),
            RandHorizonCircleVec3(50, 110, 10, 10, 5),
            Quaternion.identity
        );
        Destroy(fruit, 4f);
    }

    IEnumerator CoroutineFruitsGenarate()
    {
        while (true && GameManager.time > 0)
        {
            GenerateFruit();
            yield return new WaitForSeconds(1);
        }
    }
}

カメラを親にしてボウルを操作できるようにする

  • 以下のBowl.000のオブジェクトを使用します

image.png

  • MainCameraの子にしてBowlにリネームします
  • Bowlの位置とスケールを調整します
    • Position X:0 Y:-5 Z:-10
    • Scale X:50 Y:60 Z:50

image.png

ボウルの中で食べ物をキャッチして点数を加算する

  • ボウルのSphereという球形のオブジェクトを作成します
  • Sphereの位置を調整します
    • Position X:0 Y:0.01 Z:0
    • Scale X:0.005 Y:0.005 Z:0.005
  • Sphereに落ちてくる食べ物が接触することで点数が加算されます
  • Sphereを作ることでボウルの中に入らないと点数が入らないようになります

image.png

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

public class Player : MonoBehaviour
{
    public GameObject catchVFX;

    void OnCollisionEnter(Collision col)
    {
        if (col.gameObject.tag == "Fruits") {
            GameManager.score += col.gameObject.GetComponent<Fruit>().score;
            GameObject tempVfx = Instantiate(
                    catchVFX, 
                    new Vector3(
                        col.gameObject.transform.position.x,
                        col.gameObject.transform.position.y,
                        col.gameObject.transform.position.z
                    ),
                    catchVFX.transform.rotation
                );
            Destroy(tempVfx, 0.3f);
            Destroy(col.gameObject);
        }
    }
}

キャッチしたときのパーティクルの設定をする

  • EffectTexturesAndPrefabsのパーティクルの大きさを調整します
    • Scale X:5 Y:5 Z:5
    • 親ではなく子のパーティクル2つのスケールを変更します

image.png

  • SphereにパーティクルのPrefabをアタッチします

image.png

WebVR化する

作成したシーンの複製(シーンのバックアップ)

  • 別のシーンファイルでWebVR化していきます
  • シーンファイルを選択してCtrl + Dで複製できます
  • 複製したシーンファイルはWebVR用とわかるよう名前を変更しておきます

WebVRのパッケージをインストールしサンプルのシーンの追加

  • 以下の記事に手順が記載されています
    • パッケージの追加から各種設定
    • サンプルシーンの追加

サンプルシーンからWebXRCameraSetのコピー

  • WebXRCameraSetCtrl + Cでコピーします

image.png

WebVR化するシーンにWebXRCameraSetの貼り付けて設定する

  • 先ほど複製したWebVR化のシーンを開きます
  • 開いてHierarchyCtrl + VでコピーしたWebXRCameraSetを貼り付けます
  • 貼り付けた後は元からあるMainCameraは無効にしておきます
  • MainCameraからBowlをコピーして同じ構造でWebXRCameraSetCameraFollowerの子にします
    • WebXRCameraSet/Cameras/CameraFollower/Bowl/Sphere

image.png

WebVRとしてビルドする

  • Build Settingsで複製したシーンを追加してビルドします
    • 元からあるシーンは削除します
  • ビルドでできたファイルをウェブサーバーにアップロードするとWebVRとして遊べます

ふりかえり

  • シューティング以外にも一視点型のゲームができました
  • WebVRとなるとコントローラーの採用が難しいのでカメラで操作させるゲーム性がよさそうです
  • 制限がありそうですが制限があるうえでいろいろなゲーム性を考えられると思います
  • 実際に作ったモノでCameraFollowerの子にしないと動作しないのでアセらず設定しましょう
1
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?