アマゾンバナーリンク

UnityとPhoton Pun2で作るオンラインアクションゲーム制作その6 オンラインゲーム化

2020年4月1日

今回は今まで作ったものをオンラインゲーム化します!イメージは以下のようになります。

前回まではオフラインで動くゲームでしたが、今回からオンラインで動くように設定していきます。オンラインで動くように設定するためには以下の2点を設定する必要があります。

  • ゲームを管理するオブジェクトの作成
  • Playerオブジェクトの設定とプレハブ化

ゲームを管理するオブジェクト

今回のゲームではプレイヤーがログインすると同時にプレイヤーキャラクターのオブジェクトを生成し動けるようにしなければなりません。

なので、プレイヤー接続時に操作するキャラクターを生成するオブジェクトを作成します。

仮にこのオブジェクトの名前をゲームを管理するのでCGameManagerと名づけます。

CGameManager.csのソースコード

GameManagerに以下のCGameManagerScriptをアタッチします

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using Photon.Pun;
using Photon.Realtime;

public class CGameManagerScript : MonoBehaviourPunCallbacks
{
	//誰かがログインする度に生成するプレイヤーPrefab
	public GameObject playerPrefab; 
	void Start()
	{
		if (!PhotonNetwork.IsConnected)   //Phootnに接続されていなければ
		{
			SceneManager.LoadScene("Launcher"); //ログイン画面に戻る
			return; 
		}
		//Photonに接続していれば自プレイヤーを生成
		GameObject Player = PhotonNetwork.Instantiate(this.playerPrefab.name, new Vector3(0f, 0f, 0f), Quaternion.identity, 0);
	}
  void OnGUI()
  {
      //ログインの状態を画面上に出力
      GUILayout.Label(PhotonNetwork.NetworkClientState.ToString());
  }
}

GameManagerScriptはScene battleが読み込まれた直後に処理が開始されます。
つまり、Scene battleが読み込まれた直後に自プレイヤーを作成します

Playerオブジェクトの設定とプレハブ化

Playerオブジェクトのオンライン化設定は以下の手順を行います。

  1. PhotonViewコンポーネントを追加します。
  2. PhotonTransformViewを追加します。
  3. PhotonAnimatorViewを追加します。
  4. CharacterControlScriptのUpdate関数までのコードを以下のように変更します。
  5. unitychanのinspectorビューを以下の画像のように設定します。

変更後のCCharacterControlScript.csのソースコード

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;

public class CCharacterControlScript : MonoBehaviour 
{ 
    //オンライン化に必要なコンポーネントを設定
    public PhotonView myPV;
    public PhotonTransformView myPTV;
 
    private Camera mainCam;
 
    //移動処理に必要なコンポーネントを設定
    public Animator animator;                 //モーションをコントロールするためAnimatorを取得
    public CharacterController controller;    //キャラクター移動を管理するためCharacterControllerを取得
 
    //移動速度等のパラメータ用変数(inspectorビューで設定)
    public float speed;         //キャラクターの移動速度
    public float jumpSpeed;     //キャラクターのジャンプ力
    public float rotateSpeed;   //キャラクターの方向転換速度
    public float gravity;       //キャラにかかる重力の大きさ
 
    Vector3 targetDirection;        //移動する方向のベクトル
    Vector3 moveDirection = Vector3.zero;
 
    // Start関数は変数を初期化するための関数
    void Start () 
  {
        if (myPV.IsMine)    //自キャラであれば実行
        {
            //MainCameraのtargetにこのゲームオブジェクトを設定
            mainCam = Camera.main;  
            mainCam.GetComponent<CCameraScript>().target = this.gameObject.transform;
        }
    }
 
    // Update関数は1フレームに1回実行される
    void Update () 
    { 
        if (!myPV.IsMine)
        {
            return;
        }
 
        moveControl();  //移動用関数
        RotationControl(); //旋回用関数
 
        //最終的な移動処理
        //(これが無いとCharacterControllerに情報が送られないため、動けない)
        controller.Move(moveDirection * Time.deltaTime); 
    }

	void moveControl()
	{
		//★進行方向計算
		//キーボード入力を取得
		float v = Input.GetAxisRaw("Vertical");         //InputManagerの↑↓の入力       
		float h = Input.GetAxisRaw("Horizontal");       //InputManagerの←→の入力 
														//カメラの正面方向ベクトルからY成分を除き、正規化してキャラが走る方向を取得
		Vector3 forward = Vector3.Scale(Camera.main.transform.forward, new Vector3(1, 0, 1)).normalized;
		Vector3 right = Camera.main.transform.right; //カメラの右方向を取得
													 //カメラの方向を考慮したキャラの進行方向を計算
		targetDirection = h * right + v * forward;
		//★地上にいる場合の処理
		if (controller.isGrounded)
		{
			//移動のベクトルを計算
			moveDirection = targetDirection * speed;
			//Jumpボタンでジャンプ処理
			if (Input.GetButton("Jump"))
			{
				moveDirection.y = jumpSpeed;
			}
		}
		else        //空中操作の処理(重力加速度等)
		{
			float tempy = moveDirection.y;
			//(↓の2文の処理があると空中でも入力方向に動けるようになる)
			//moveDirection = Vector3.Scale(targetDirection, new Vector3(1, 0, 1)).normalized;
			//moveDirection *= speed;
			moveDirection.y = tempy - gravity * Time.deltaTime;
		}
		//★走行アニメーション管理
		if (v > .1 || v < -.1 || h > .1 || h < -.1) //(移動入力があると)
		{
			animator.SetFloat("Speed", 1f); //キャラ走行のアニメーションON
		}
		else    //(移動入力が無いと)
		{
			animator.SetFloat("Speed", 0f); //キャラ走行のアニメーションOFF
		}
	}

	void RotationControl()  //キャラクターが移動方向を変えるときの処理
	{
		Vector3 rotateDirection = moveDirection;
		rotateDirection.y = 0;
		//それなりに移動方向が変化する場合のみ移動方向を変える
		if (rotateDirection.sqrMagnitude > 0.01)
		{
			//緩やかに移動方向を変える
			float step = rotateSpeed * Time.deltaTime;
			Vector3 newDir = Vector3.Slerp(transform.forward, rotateDirection, step);
			transform.rotation = Quaternion.LookRotation(newDir);
		}
	}
}

とりあえずここまでで設定は完了です。次にプレハブ化をします。

プレハブ化(Prefab)

プレハブ化とはあるオブジェクトを再利用したいとき、そのデータをProjectビューに保存しておくことを言います。

今回のunitychanオブジェクトはプレイヤーがゲームに接続したときにGameManagerを通して生成したいのでプレハブ化をしておく必要があります。

プレハブ化の手順は以下の通りです。

  • HierarchyビューのunitychanオブジェクトをProjectビューのAsset/Resourcesフォルダ内にドラッグ&ドロップ(PlayerのプレハブはResourcesフォルダ内直下に置く必要があります)
  • Hierarchyビューのunitychanオブジェクトを削除(Delete)

これでunitychanのプレハブが完成しました。最後にこのプレハブをGameManagerのPlayerPrefabにドラッグ&ドロップでセットします。

実行結果

2つのウインドウを開き、それぞれでログインした結果です。2キャラが上手く同期できていることがわかります。