20
12

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 5 years have passed since last update.

Photon使ってUnityでカーゲームが作りたい

Last updated at Posted at 2019-06-22

Unityでオンラインゲーム作れるようになりたい!!!
UnityではPhoton Realtime SDKを使えば無料でできると聞いたので、制作過程を記します。使用したUnityのバージョンは2018.3.6です。

#1. photonアカウントとアプリの準備
まずはphotonでアカウントを作成します。
新しいアプリを作成するを選んでください。
スクリーンショット 2019-06-15 18.50.20.png

こんな感じで今回作るゲームの情報を入れておきます。今回使うのはPhoton Realtimeです。
スクリーンショット 2019-06-15 18.55.33.png

作成するを押して、以下の画面になります。詳細を確認しましょう
スクリーンショット 2019-06-15 18.55.48.png

このアプリケーションIDはあとで使うので、コピーしておきましょう!
スクリーンショット 2019-06-15 18.58.57.png

#2. Unity側の準備
Unityでオンライン化したいプロジェクトに対し、AssetStoreからPhoton Unity Networking Classic-FreeをImportします。Photonは似たようなAseetが沢山あるので注意してください。
スクリーンショット 2019-06-22 18.19.39.png

Unityのプロジェクトをphotonと繋げるところからやっていきましょう。

Importするとすぐ、AppIDを打ち込む画面が現れます。先ほどコピーしたアプリケーションIDをペーストしてください。
スクリーンショット 2019-06-15 18.59.17.png

入れ損ねた場合や間違えた場合はWindow > Photon Unity NetWorking > HighLight Server Setting から、PhotonServerSettingのInspectorから編集できます。
スクリーンショット 2019-06-20 12.24.03.png
さっきPhotonのマイページで作ったアプリケーションIDをAppidに入力してください。下の画像の青いところです。日本なのでRegionをJpにしておきます。Auto-join Lobbyにチェックをつけて、ゲーム開始時に自動でロビーに入るようにします。
スクリーンショット 2019-06-15 19.00.22.png

Photonに接続するスクリプトを書きます。
Hierarchy Viewに空のオブジェクト(PhotonManager)を作って、下のスクリプト(PhotonManager.cs)をアタッチしてください。

PhotonManager.cs
using UnityEngine;
using System.Collections;
 
public class PhotonManager : MonoBehaviour {
 
    void Start() {
        // Photonに接続する(引数でゲームのバージョンを指定できる)
        PhotonNetwork.ConnectUsingSettings(null);
    }
 
    // ロビーに入ると自動的に呼ばれる
    void OnJoinedLobby() {
        Debug.Log("ロビーに入りました");
 
        // ルームに入室する
        PhotonNetwork.JoinRandomRoom();
    }
 
    // ルームに入室すると自動的に呼ばれる
    void OnJoinedRoom() {
        Debug.Log("ルームへ入室しました");
    }
 
    // ルームの入室に失敗すると自動的に呼ばれる
    void OnPhotonRandomJoinFailed() {
        Debug.Log("ルームの入室に失敗しました");
 
        // ルームがないと入室に失敗するため、その時は自分で作る
        // 引数でルーム名を指定できる
        PhotonNetwork.CreateRoom("myRoomName");
    }
}

実行してConsoleを確認してみましょう。こんな感じになっていたら成功です!
スクリーンショット 2019-06-22 17.58.35.png

ちなみにphotonに繋げないWi-fiもあるみたいです。ポート番号が解放されていないとそうなるみたいです。Wi-fiを変えたらうまくいくということがありました。

3. プレイヤーを生成する

今のままでは1人プレイしかできないので、各プレイヤーが操作できる車を生成できるようにします。とりあえず2人プレイできるようにしましょう。オブジェクトの位置や角度を同期させるには、PhotonNetworkを用います。

接続中の人数

int PhotonNetwork.countOfPlayers

現在このアプリケーションをプレイしているユーザー数(マスターサーバーで5秒間隔で取得可能)を取得できます。(by Photon Network Class Reference)

ネットワーク越しのPrefabの生成

static GameObject PhotonNetwork.Instantiate(string prefabName, Vector3 position, Quaternion rotation, int group)

ネットワーク越しにプレハブからインスタンス作成します。このプレハブは**"Resources"フォルダー直下**に配置されている必要があります。Resourcesフォルダーのプレハブを使う代わりに、手動でInstantiateしてPhotonViewを割り当てることもできます。(by Photon Network Class Reference)

PhotonManagerのOnJoinedRoomの中を書き加えていきます。

PhotonManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PhotonManager : MonoBehaviour
{
    void Start()
    {
        // Photonに接続する(引数でゲームのバージョンを指定できる)
        PhotonNetwork.ConnectUsingSettings(null);
    }

    // ロビーに入ると呼ばれる
    void OnJoinedLobby()
    {
        Debug.Log("ロビーに入りました。");

        // ルームに入室する
        PhotonNetwork.JoinRandomRoom();
    }

    // ルームに入室すると呼ばれる
    void OnJoinedRoom()
    {
        Debug.Log("ルームへ"+ PhotonNetwork.countOfPlayers +"人入室しました。");
        //CarPrefabを生成する
        transform.rotation = Quaternion.Euler(0, 180, 0); //Carの向きが逆になってになってしまう問題を解決
        
        if (PhotonNetwork.countOfPlayers < 2)
        { 
            transform.position = new Vector3(66, 0, 0);
            GameObject car1 = PhotonNetwork.Instantiate("CarPrefab", transform.position, transform.rotation, 0);
            car1.name = "car1";
        }
        if (PhotonNetwork.countOfPlayers == 2)
        {
            transform.position = new Vector3(60, 0, 0);
            Debug.Log("2台目生成できたよ");
            GameObject car2 = PhotonNetwork.Instantiate("CarPrefab", transform.position, transform.rotation, 0);
        }

    }

    // ルームの入室に失敗すると呼ばれる
    void OnPhotonRandomJoinFailed()
    {
        Debug.Log("ルームの入室に失敗しました。");

        // ルームがないと入室に失敗するため、その時は自分で作る
        // 引数でルーム名を指定できる
        PhotonNetwork.CreateRoom("myRoomName");
    }

}

Resourcesフォルダ

PhotonはResourcesというフォルダからPrefabを生成するというシステムらしいです。

Carの名前をCarPrefab、
Prefabsフォルダの名前をResourcesに変えるか、新たにResourcesというフォルダを作るかしましょう。

Photon Viewコンポーネント

同期するオブジェクトにつけるコンポーネントです。
CarPrefabのInspectorを開き、Photon ViewPhoton Transform Viewをつけます。PositionとRotationにチェックを入れましょう。Photon Transform ViewをPhoton ViewのObserved Componentsにドラッグ&ドロップします。

このようにクライアント間で通信を行いたい際にオブジェクトにPhotonViewコンポーネントを追加し、Obaserved(監視対象)を指定すると、そのオブジェクトが同期されるようになります。
CarPrefabのInspevtorはこんなかんじになります。
スクリーンショット 2019-06-22 21.33.50.png

逆に、同期したくないオブジェクトはPhotonNetwork越しに生成すると厄介なことになります。
カメラとか、、、、、、、、、むやみに同期させない方が良いということを学びました。ネットワーク負荷の軽減のためにも、同期するオブジェクトは必要最低限にすることを心がけましょう。

CarPrefabの子オブジェクトのMainCameraを消してください。カメラはあとでプレイヤー別になるようにしますが、今ついていると2人以上になったとき同期しておかしなことになります。適当な位置にに固定カメラを設置しておきましょう。
CarPrefabの準備が済んだら、CarPrefabをResourcesにいれてPrefab化してください。Hierarchyに残ったCarPrefabは消しちゃって大丈夫です。

スクリーンショット 2019-06-22 21.33.34.png

実行して、Scene Viewにcar1が生成されたのを確認できたら成功です!
ちゃんと2台生成したCarが同期しているか、ビルドして確認しましょう。

☆. 同期の確認方法

Photonは沢山Buildします。Buildしないと1つのパソコンで2人分の動作確認ができないからです。
手始めに今どんな挙動を見せるのか確認してみます。PC向けAppをBuildしてください。
動作確認をする際は、まずAppを起動し、次にUnityの再生ボタンを押すようにしてください。
スクリーンショット 2019-06-22 21.52.01.png
Windowedにチェックを入れておくと楽です。チェックを入れないと全画面で起動します。
スクリーンショット 2019-06-22 21.54.43.png

2台出たら成功です。
しかしこのままでは片方が移動するともう片方も移動してしまっています。次の章で直していきましょう。

4. プレイヤーをユーザーが各自で操作できるようにする

bool PhotonView.isMine

PhotonViewの所有者が「自分」で、このクライアントからコントロール可能の場合trueです。
PUNは所有権という概念があります。それぞれのPhotonViewをコントロールしたり破棄できる主体のことです。 所有者がローカルPhotonPlayerの場合trueです。 シーンのPhotonViewで、Master client上で動作しているならtrueです。(by Photon Network Class Reference)

プレイヤーを操作するスクリプトの部分に、isMineの条件を足します。プレイヤーを操作しているCarUserControl.csを書き換えていきましょう。

CarUserControl.cs
using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
using UnityStandardAssets.Vehicles.Car;

public class CarUserControl : MonoBehaviour
{
    private PhotonView myPhotonView;
    private CarController m_Car;
    float h; //horizontal
    float v; //Vertical

    private void Start()
    {
        this.myPhotonView = GetComponent<PhotonView>();
        m_Car = GetComponent<CarController>();
    }
    private void FixedUpdate()
    {
        
        if (myPhotonView.isMine) //自分のPhotonViewだったら
        {
            if (RaceManager.instance.isRacing == true)
            {
                h = CrossPlatformInputManager.GetAxis("Horizontal");
                v = CrossPlatformInputManager.GetAxis("Vertical");
            }
            
            m_Car.Move(h, v, v, 0);
        }
    }
}

Builidして、それぞれのCarを動かすことができていれば成功です!

5. 各プレイヤーを追従するカメラを作る

失敗例

その①
PhotonViewのついたCameraを子オブジェクトに持つCarPrefabをPhotonNetworkから生成した場合
→ カメラが同期してちゃんと自分の車につかない

その②
PhotonViewのないCameraを子オブジェクトに持つCarPrefabをPhotonNetworkから生成した場合
→ 操作とカメラが逆転する謎現象が起きた

その③
PhotonViewのついたCameraをPhotonNetworkから生成し、CarPrefabを追従するようにした場合
→ これもカメラが同期して自分の車につかない

全部Buildしないと気づかない失敗です。同期したくないオブジェクトはPhotonNetwork越しに生成すると厄介なことになります。ネットワーク負荷の軽減のためにも、同期するオブジェクトは必要最低限にすることを心がけましょう。

成功例

PhotonViewのついてないCameraをPhotonNetworkを介さずに生成した場合

まずはCameraをCameraPrefabに改名し、CameraScriptをつけてください。CarUserControl.csとCameraScript.csに書き加えていきます。
CarUserControlのAwakeでCameraをCarの子オブジェクトとしてPhotonNetworkを介さずに生成します。CameraPrefabをResourcesに入れてください。

CarUserControl.cs
using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
using UnityStandardAssets.Vehicles.Car;

public class CarUserControl : Photon.PunBehaviour
{
    private PhotonView myPhotonView;
    private CarController m_Car;
    float h; //horizontal
    float v; //Vertical

    private void Awake()
    {
        this.myPhotonView = GetComponent<PhotonView>();
        m_Car = GetComponent<CarController>();

        if (myPhotonView.isMine) //Carが自分の車である場合
        {
            GameObject camPrefab = (GameObject)Resources.Load("CameraPrefab"); //ResourcesフォルダからCameraPrefabをとってくる
            Vector3 CameraPosition = new Vector3(0, 3, 5); //カメラの相対座標
            GameObject cam = Instantiate(camPrefab, transform.position + CameraPosition, transform.rotation); //CameraPrefabを生成する
            cam.transform.parent = gameObject.transform; //Cameraの親オブジェクトはCarとする
        }
    }
    private void FixedUpdate()
    {
        
        if (myPhotonView.isMine)
        {
            if (RaceManager.instance.isRacing == true)
            {
                h = CrossPlatformInputManager.GetAxis("Horizontal");
                v = CrossPlatformInputManager.GetAxis("Vertical");
            }
            
            m_Car.Move(h, v, v, 0f);
        }
    }
}

再生してカメラがついてくることを確認したら、Buildして動作確認しましょう。
完成品の動画

順位つけたりもしたいですね。

お疲れ様でした!

#参考資料
基本説明 - Photon Unity Networking
UnityでPUNを使ったオンラインマルチプレイの実装-準備編-
Unity猫本のサンプルゲームをPhotonでオンライン対戦ゲーム化してみた
Unityカーレース

20
12
0

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
20
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?