Unity(C#)初心者・入門者向けチュートリアル ひよこのたまご

AndroidやiOS向けアプリを簡単に作れるゲーム開発環境Unity(ユニティ)の使い方を、チュートリアル方式で一緒に学びましょう!

【Unity9】UNETでマルチプレイヤーなオンラインゲーム開発【UNET1】

Unity5.1.1f1 Personal(2015年7月)

マルチプレイヤーネットワーキングシステムであるUNETが、Unity5.1から標準搭載されました!
そして、少し前からUNETのチュートリアルがあがっていたので、今回から記事にまとめていきたいと思います〜


今後ブログ記事をアップしていく中でよく分からないけど動いたというパターンや、誤った説明等拙い点が多々あるかと思います〜

間違いなどお気付きの点がありましたら、コメント等で教えて下さると助かります〜



UNET Part 1 - Setup and Movement Syncing - YouTube


【目標】ホストプレイヤーとクライアントプレイヤーに別々の動きをさせる

①下準備

まずは「Main」と「Menu」という名前で、Sceneを2つ作ります〜
今から編集するのはMainシーンですので、Mainシーンを開いておいて下さい〜


次にPlaneを作成し、SizeをX:100,Z:100に変更し、灰色のMaterialを作成し取り付けて下さい〜


続いてCubeを作成し、PositionをY:0.5に変更して下さい〜
また作成したCubeをコピーしてもうひとつCubeを作り、適当な場所へ配置して下さい〜
コピーしたCubeのScaleはX,Y,Z全て2に変更しておきましょう〜


f:id:hiyotama:20150611115927p:plain
Mainシーンに床1つとCube2つを配置


最後にEnvironmentという名前で空のゲームオブジェクトを作成し、PlaneとCube2つを子オブジェクトして下さい〜


f:id:hiyotama:20150611120209p:plain
フィールドはEnvironmentオブジェクトの子オブジェクトとする


②Player作成
続いてPlayerを作成します〜AssetsからImport Package>Charactersを選択し、Standard Assetを用意します〜


f:id:hiyotama:20150611120717p:plain
Character選択


続いてStandard Asset>Characters>FirstPersonCharacter>PrefabにFPSControllerというプレハブがあるので、Hierarchy上へドラッグ&ドロップして下さい〜
名前は「Player」に変更します〜


f:id:hiyotama:20150611121052p:plain
ドラッグ&ドロップ!


次にPrefabsフォルダを作成し、Playerオブジェクトをドラッグ&ドロップしてプレハブ化しましょう〜


f:id:hiyotama:20150611121414p:plain
ドラッグ&ドロップ!


Playerの子オブジェクトとしてCapsuleオブジェクトを作成します〜
Capsuleオブジェクトに最初から付いているCapsule ColliderはRemove Componentで消して下さい〜


f:id:hiyotama:20150611121825p:plain
Capsuleオブジェクトを子オブジェクトにする



今のままだと地面に埋まってしまうので、PlayerのPositionをX:0, Y: 1, Z: 0に変更します〜


f:id:hiyotama:20150611121636p:plain



とりあえず一人称視点でフィールドを動くPlayerが完成しました〜ゲームを実行すると、矢印キーで移動、スペースキーでジャンプ、マウスを動かすことで視点が変わります〜


ここまではネットワークと全く関係ない部分ですので、混乱せずにこられたかと思います〜


③NetworkManagerを作成する
いよいよここからネットワークと関係してきます!


まずは「NetworkManager」という名前で空のゲームオブジェクトを作成して下さい〜
次にInspectorビューからAddComponent>Network>NetworkManagerを取り付けて下さい〜


f:id:hiyotama:20150611123535p:plain
NetworkManagerコンポーネント


動画ではOffLineの時にMenuシーンを、Onlineの時にMainシーンを指定したかったようですがうまくいっていないようなので、Offline SceneとOnline Sceneの設定は今回はまだしません〜


今回はインターネット越しではなく自分のパソコン内(ローカル環境)でUNETを使うので、Network InfoのNetworkAddressはlocalhost(127.0.0.1と入力しても同じ意味)のままにしておいて下さい〜


ポートは外部からデータを受け取る時の入り口で、今回はローカル環境で完結させるので、Network Portについても今回は設定する必要はありません〜


Spawn Infoでは、ネットワークに接続した時に作成する、自分が操作するプレイヤーを設定することができます〜早速Player Prefabに、先ほど作成したPlayerプレファブを設定しましょう〜


f:id:hiyotama:20150611124446p:plain
ドラッグ&ドロップすると・・・


f:id:hiyotama:20150611124505p:plain
NetworkIdentityが無いですよというエラーが発生する


というわけで、PlayerプレハブにNetworkIdentityコンポーネントを付けて回避しましょう〜
Hierarchy上にあるPlayerプレハブにAdd Component>Network>NetworkIdentityで取り付け、Local Player Authorityにチェックを入れて下さい〜
Local Player Authorityにチェックを入れることで、他のプレイヤーと自分が操作するプレイヤーが区別されるようになります〜


ここまでできたらApplyボタンを押して下さい〜Projectビュー上のPlayerプレハブに変更が反映されます〜


f:id:hiyotama:20150611131437p:plain
Network Identityを取り付けApplyボタンを押すことで変更を反映


f:id:hiyotama:20150611125138p:plain
NetworkManagerのSpawn Info>Player Prefabに、Playerプレハブを設定できるようになった


続いてNetworkManagerHUD(ヘッドアップディスプレイ)コンポーネントを取り付けます〜GUIでネットワークに接続したりを指示できるようになります〜
NetworkManagerのInspectorビューからAdd Component>Network>NetworkManagerHUDを選択して下さい〜取り付けるだけで、特に設定することなく使えます〜


f:id:hiyotama:20150611125828p:plain
ゲームを実行するとGUIが出てくる


④Playerの動きをインスタンスごとに分ける
今の状態で既に自キャラと相手キャラの2オブジェクトを作成して動かすことはできますが、片方のオブジェクトを動かした時、もう片方のオブジェクトも全く同じ動きをしてしまう状態にあります〜


対策として、まずはHierarchyにあるPlayerオブジェクトにNetwork Transformコンポーネントを付けます〜これを付けることで、位置情報を同期させることができるそうです〜


さて、まずはNetworkTransformのTramsform Sync ModeをSync Rigidbody 3DからSync Transformに変更しましょう〜Character ControllerとFirst PersonController(Script)を使って移動している場合は、Sync Transformに変更するそうです〜


続いてPlayerが方向を変更した時に変更したことが分かりやすいように、鉄砲のようなものを取り付けます〜Playerの子オブジェクトにCubeを取り付け、Transformを以下のような設定にして下さい〜また、Box Colliderは取り除いておいて下さい〜


f:id:hiyotama:20150611141353p:plain


次にPlayerオブジェクトをApplyして変更を反映し、Hierarchy上にあるPlayerオブジェクトは削除します〜


ここまで準備ができたら、Buildして実際に動かしてみましょう〜File>Build Settingsを選択し、Add CurrentでMainシーンをビルドの対象にし、Build And Runを実行します〜


f:id:hiyotama:20150611135707p:plain
Buildして実行


これで2人のプレイヤーが1つのゲーム空間で同時に存在できるようになりました〜
左側がビルドして作ったゲーム画面、右側が開発環境のゲーム画面です〜


f:id:hiyotama:20150611140452p:plain


それでは開発環境のほうをホスト、ビルド環境のほうをクライアントで遊んでみましょう〜まずは開発環境で「LAN Host(H)」と書かれたボタンをクリックして適当に動かして下さい〜

次にビルド環境のほうで「LAN Client(C)」と書かれたボタンをクリックして下さい〜


すると、相手プレイヤーを確認することができます〜


f:id:hiyotama:20150611140734p:plain
相手プレイヤーがいる


しかし今の状態だと先ほど説明したように、2オブジェクトが全く同じ動きをしてしまいます〜


この状態を回避するために、Playerプレハブに付いているコンポーネントを非アクティブ状態にしておき、Playerプレハブを生成した時に各コンポーネントをアクティブ化する必要があります〜


まずはPlayerに付いているCharacter ControllerとFirst Person Controllerを非アクティブ化します〜


f:id:hiyotama:20150611142940p:plain
チェックを外して非アクティブ化


次にPlayerの子オブジェクトであるFirstPersonCharacterのCameraとAudio Listenerも非アクティブ化します〜


f:id:hiyotama:20150611143045p:plain
チェックを外して非アクティブ化


最後にMain Cameraの名前を「Scene Camera」に変更して下さい〜


それでは、コンポーネントを比アクティブからアクティブへ変更する「Player_NetworkSetup」スクリプトを作成していきます〜以下ソースです〜

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;	//ネットワーク関連で必要なライブラリー

//継承はMonoBegaviourではなくNetworkBehaviour
public class Player_NetworkSetup : NetworkBehaviour {
	//SerializeField: publicでなくてもInspector上で変数内容を指定できる
	[SerializeField]Camera FPSCharacterCam;	//FirstPersonCharacterのCamera
	[SerializeField]AudioListener audioListener;	//FirstPersonCharacterのAudio Listener

	void Start ()
	{
		//自分が操作するオブジェクトに限定する
		if (isLocalPlayer) {
			//FPSCharacterCamを使うため、Scene Cameraを非アクティブ化
			GameObject.Find("Scene Camera").SetActive(false);
			GetComponent<CharacterController>().enabled = true;	//Character Controllerをアクティブ化
			//FirstPersonControllerをアクティブ化
			GetComponent<UnityStandardAssets.Characters.FirstPerson.FirstPersonController>().enabled = true;
			//FirstPersonCharacterの各コンポーネントをアクティブ化
			FPSCharacterCam.enabled = true;
			audioListener.enabled = true;
		}
	}
}

Player_NetworkSetup.cs


まずはSerialize Fieldに、CameraとAudio Listenerを設定してあげましょう〜Playerの子オブジェクトであるFIrstPersonCharacterをそれぞれドラッグ&ドロップしてあげれば指定できます〜


f:id:hiyotama:20150611144700p:plain
ドラッグ&ドロップ!


それではスクリプトに入ります〜

isLocalPlayerがtrueの時のみStartメソッドを実行するようになっています〜


isLocalPlayerは自分が操作するPlayerに対してのみtrueになりますので、画面上にPlayerが2人いても自分が操作するPlayerのコンポーネントのみをアクティブ化することができます〜

isLocalPlayer変数を使うためにはNetworkBehaviourを継承する必要があります〜そして、NetworkBehaviourを継承するためには「using UnityEngine.Networking」とスクリプトの頭に書いておく必要があります!


再度Buildを行い動作を確認してみると、今度は自プレイヤーと相手プレイヤーが別々の動きをします!


動画がpart1の途中ですが長くなってしまったので、今回はここまでです〜

ありがとうございました〜


【Unity9】UNETでマルチプレイヤーなオンラインゲーム開発【UNET1】
【Unity9】UNETでプレイヤーの動きを補間し、なめらかな動きを実現する【UNET1-2】
【Unity9】UNETでネットワーク越しに傾き(Rotation)を同期させる【UNET2】
【Unity9】UNETでオンライン開始時のプレイヤー生成位置を変更する【UNET2-2】
【Unity9】UNETのネットワークトラフィックを軽減し、効率化する【UNET3】
【Unity9】UNETのlatency(遅延時間)を改善する【UNET4】
【Unity9】UNETのlatency(遅延時間)を表示して、ちょっとだけ改善する【UNET4-2】
【Unity9】UNETのSyncVarのhookの使用例と、前時代の同期方法【UNET5】
【Unity9】UNETを使ってRotationを同期させる【UNET6】
【Unity9】UNETで各プレイヤーにPlayerIDを設定する【UNET7】
【Unity9】UNETで敵プレイヤーにダメージを与える!【UNET8】
【Unity9】UNETでHPを画面に表示し、Playerへダメージを与える【UNET9】
【Unity9】UNETでHPが0以下になった時、Playerを破壊する!【UNET10】
【Unity9】UNETで死んだPlayerを生き返らせる!【UNET11】
【Unity9】UNETでゾンビAIを出現させる!【UNET12】
【Unity9】UNETでゾンビ生成時にユニークなIDを付ける!【UNET13】
【Unity9】UNETでゾンビを撃つ!【UNET14】
【Unity9】UNETでゾンビに攻撃させる!【UNET15】
【Unity9】UNETでゾンビの動きをスムーズにシンクロさせる!【UNET16】
【Unity9】UNETでゾンビ発生地点を増やす【UNET17】
【Unity9】UNETで発生したバグを取り除く【UNET18】
【Unity9】Unity MultiPlayerを使ってネットワーク越しにマッチメイキング!【UNET19】
【Unity9】GUIを改善して、Network Managerを見やすくする!【UNET20】
【Unity9】表示したGUI(Network Manager)を機能させる!【UNET20-2】
【Unity9】UNETでAnimationを同期させる!【UNET21】