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

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

【Unity9】UNETで死んだPlayerを生き返らせる!【UNET11】

Unity5.1.1p3 Personal(2015年7月)

前回の続きです〜

前回はPlayerのHPが0になった時、Playerをゲーム画面上から消すところまでいきました〜

今回は画面上に出現したボタンを押し、Playerを生き返らせるところまで進めます〜



UNET Part 11 - Player Resurrection - YouTube

【目標】死んだPlayerを生き返らせる!

①Player_Healthスクリプト加筆修正

Player_Healthスクリプトに少し加筆していきます〜

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
using UnityEngine.UI;

public class Player_Health : NetworkBehaviour {
	
	[SyncVar (hook = "OnHealthChanged")] private int health = 100;
	private Text healthText;
	
	private bool shouldDie = false;
	public bool isDead = false;
	
	public delegate void DieDelegate();
	public event DieDelegate EventDie;
	
//********** 開始 **********//
	//Player再生成のためのevent
	public delegate void RespawnDelegate();
	public event RespawnDelegate EventRespawn;
//********** 終了 **********//

	void Start () {
		healthText = GameObject.Find("Health Text").GetComponent<Text>();
		SetHealthText();
	}
	
	void Update () {
		CheckCondition();
	}
	
	void CheckCondition ()
	{
		if (health <= 0 && !shouldDie && !isDead) {
			shouldDie = true;
		}
		
		if (health <= 0 && shouldDie) {
			if (EventDie != null) {
				EventDie ();
			}
			shouldDie = false;
		}
		
//********** 開始 **********//
		//HPが1以上あるのにisDead=trueの時
		if (health > 0 && isDead){
			//EventRespawnに何か登録されている時
			if (EventRespawn != null){
				//EventRespawn実行
				EventRespawn();
			}
			isDead = false;
		}
//********** 終了 **********//
	}
	
	void SetHealthText ()
	{
		if (isLocalPlayer) {
			healthText.text = "Health " + health.ToString();
		}
	}
	
	public void DeductHealth(int dmg)
	{
		health -= dmg;
	}
	
	void OnHealthChanged (int hlth)
	{
		health = hlth;
		SetHealthText();
	}
	
//********** 開始 **********//
	public void ResetHealth ()
	{
		//Player_RespawnスクリプトのCmdRespawnOnServerメソッドが[Command]のため、
		//SyncVarが機能する
		health = 100;
	}
//********** 終了 **********//
}

Player_Health.cs


EventRespawnというeventを作成し、healthが1以上あるのにisDeadがtrueの時に実行するようにしました〜


また、healthを100に回復するResetHealthというメソッドを作成しました〜

②生き返らせるためのボタンを作成

続いてPlayer復活用のボタンを作成していきます〜MainシーンでHierarchy > Create > UI > Buttonを選択し、名前を「Respawn Button」にして下さい〜
また、ButtonのTextは「Respawn!」に変更して下さい〜


f:id:hiyotama:20150715202029p:plain


Buttonは非アクティブ化しておきます〜


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


非アクティブ化したUIパーツをアクティブ化するには、Findメソッドが使えなかったりでなかなか大変です〜なので、対策をしておきます〜

まずは空GameObjectを作成します〜名前は「GameManager」にします〜


f:id:hiyotama:20150715202400p:plain
GameManager


GameManagerに下のスクリプト(GameManager_References)を付けます〜

using UnityEngine;
using System.Collections;

public class GameManager_References : MonoBehaviour {

	public GameObject respawnButton;
}

GameManager_References.cs


作成したら、public変数のrespawnButtonに、Respawn Buttonオブジェクトを指定します〜


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


これでButtonオブジェクトが非アクティブ化しても呼び出しやすいようになりました〜(後述)

③Player_Respawnスクリプト作成

それでは続いて、Player_Respawnスクリプトを新規作成して、Playerプレハブに取り付けて下さい〜


Player_DeathスクリプトでPlayerの姿を消しましたが、その逆をやっている感じです〜


以下ソースです〜

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
using UnityEngine.UI;

public class Player_Respawn : NetworkBehaviour {

	//Player_Healthスクリプト
	private Player_Health healthScript;
	//照準画像
	private Image crossHairImage;
	//Respawnボタン
	private GameObject respawnButton;
	
	void Start () {
		//Player_Healthスクリプトをキャッシュ
		healthScript = GetComponent<Player_Health>();
		//eventを登録
		healthScript.EventRespawn += EnablePlayer;
		//照準画像をキャッシュ
		crossHairImage = GameObject.Find("Crosshair Image").GetComponent<Image>();
		SetRespawnButton();
	}
	
	void SetRespawnButton ()
	{
		if (isLocalPlayer) {
			//GameManagerを経由してRespawnButtonを取得
			respawnButton = GameObject.Find("GameManager").GetComponent<GameManager_References>().respawnButton;
			//onClick.AddListener: ボタンがクリックされた時にメソッドを実行する
			respawnButton.GetComponent<Button>().onClick.AddListener(CommenceRespawn);
			//ボタンを消す
			respawnButton.SetActive(false);
		}
	}
	
	void Update () {
	
	}
	
	//メモリーリーク等の不具合が起きた時の対策
	void OnDisable()
	{
		healthScript.EventRespawn -= EnablePlayer;
	}
	
	//Player_DeathスクリプトのDisablePlayerメソッドのfalseをtrueに変えた感じ
	//(health > 0 && isDead)の時に実行される
	void EnablePlayer()
	{
		GetComponent<CharacterController> ().enabled = true;
		GetComponent<Player_Shooting> ().enabled = true;
		GetComponent<BoxCollider> ().enabled = true;
		
		Renderer[] renderers = GetComponentsInChildren<Renderer> ();
		foreach (Renderer ren in renderers) {
			ren.enabled = true;
		}
		
		if(isLocalPlayer){
			GetComponent<UnityStandardAssets.Characters.FirstPerson.FirstPersonController> ().enabled = true;
			crossHairImage.enabled = true;
			//Respawnボタンを消す(動画の人が後で修正した箇所)
			respawnButton.SetActive(false);
		}
	}
	
	//Respawnボタンを押した時に実行
	void CommenceRespawn()
	{
		CmdRespawnOnServer();
	}
	
	[Command]
	void CmdRespawnOnServer()
	{
		//healthを100に戻し、SyncVarを機能させる
		healthScript.ResetHealth();
	}
	
}

Player_Respawn.cs


StartメソッドにてEnablePlayerメソッドをeventとして登録しています〜Player_Healthスクリプト内で、(health > 0 && isDead)の条件が満たされた時に実行されるeventでした〜
また、Startメソッド最後でSetRespawnButtonメソッドが呼ばれています〜


SetRespawnButtonメソッドでは、先ほど作成したGameManagerを経由してRespawnボタンを取得しています〜

続いてonClick.AddListenerで、ボタンが押された時にCommenceRespawnメソッドが実行されるよう登録しています〜

デフォルトが非アクティブ状態なので大丈夫だと思いますが、一応ボタンを消しています〜


OnDisableメソッドはPlayer_Deathメソッドと同じで、念のためといった感じで記述しています〜


EnablePlayerメソッドですが、Player_DeathスクリプトのDisablePlayerメソッドとほとんど真逆の内容です〜

isDeadはPlayer_Healthスクリプトで変更しているので、こちらにはありません〜


最後にPlayer_Deathスクリプトに一行追加して終わりです〜以下ソースです〜

	void DisablePlayer ()
	{
		GetComponent<CharacterController> ().enabled = false;
		GetComponent<Player_Shooting> ().enabled = false;
		GetComponent<BoxCollider> ().enabled = false;
		
		Renderer[] renderers = GetComponentsInChildren<Renderer> ();
		
		foreach (Renderer ren in renderers) {
			ren.enabled = false;
		}
		
		healthScript.isDead = true;
		
		if(isLocalPlayer){
			GetComponent<UnityStandardAssets.Characters.FirstPerson.FirstPersonController> ().enabled = false;
			crossHairImage.enabled = false;
//********** 開始 **********//
			//Respawnボタンをアクティブ化
			GameObject.Find("GameManager").GetComponent<GameManager_References>().respawnButton.SetActive(true);
//********** 終了 **********//
		}
	}

Player_Death.cs


一番最後の行にRespawnボタンをアクティブ化する記述を追加しただけです〜

④結果


それではゲームを実行してみましょう〜


f:id:hiyotama:20150715210604p:plain
殺された時にRespawnボタンが出現


f:id:hiyotama:20150715210629p:plain
ボタンを押すとhealthが回復し、復活


うまくいきました〜

動画の最後でゾンビボットという言葉が聞こえたので、次回は敵キャラが出てくる感じです〜


それでは、今回はここまでです〜

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


【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】