Unity3Dで3D脱出ゲームの作り方、パート1(ゲームの設定とアラームの仕方)

脱出ゲームといっても日本の脱出ゲームではなく、敵に見つからないように建物内から逃げ出すゲームです。

今回のゲームが最後のチュートリアルのゲーム作りになります。このチュートリアルを終えたあとに、オリジナルゲームの作成を開始するのです!

Unityのチュートリアル、Stealthを元に作っていきます。説明は最小限です。どんどん作ってしまいます。

ゲームの全体像

Unity: Stealth – Project Overview



へーと聞くだけです。

ゲームの設定とライトの調整

Unity: Stealth – Game Setup and Lighting



Unityを起動して新しいプロジェクトを作成します。
必要なAssetsをダウンロードしてインポートします。
Assetsをダウンロード

Stealthという名前でシーンを保存する。
モデルのenv_stealth_staticをHierarchyにドロップする。
モデルのprop_battleBusをHierarchyにドロップしてPosition X:-11 Y:0 Z:17.5、Roation Y:270にする。
env_stealth_staticオブジェクトにMesh Colliderを追加する。
モデルのenv_stealth_collisionを展開してenv_stealth_collision_001をドラックしてenv_stealth_staticオブジェクトのMesh ColliderのMeshにドロップする。

env_stealth_staticオブジェクトとprop_battleBusオブジェクトを選択してStaticをチェックする。子要素も変更する。

env_stealth_staticオブジェクトのextents以外とprop_battleBusオブジェクトを選択してLayerをPlayAreaに変更する。子要素も変更する。

env_stealth_staticオブジェクトのextentsを選択してLayerをExtentsに変更する。子要素も変更する。

Main Cameraをcamera_mainという名前に変更する。
camera_mainのRendering PathをDeferred Lightingに変更してBackgroundの色を黒にしてClipping PlanesのFarを100にする。

Prefabsのlights_bakedをHierarchyにドロップする。

Point Lightを作成して名前をlight_playArea_pointに変更してPosition X:-2.5 Y:2 Z:7にしてColorを黄色にしてRangeを8にする。
light_playArea_pointを2つDuplicateしてPositionのYをそれぞれ5と9にする。
作成した3つのlight_playArea_pointをlights_bakedオブジェクトの子要素にする。

EditのRenderer Settingsを変更する。
Fogをチェック、Fog Colorを青紫、Fog Densityを0.04、Linear Fog Startを3、Linear Fog Endを24、Ambient Lightを黒にする。

EditのProject SettingsのQualityを変更する。
LevelsのGoodを選択してPixel Light Countを6にする。

WindowのLightmappingを変更する。
BakeタブにしてModeをDirectional Lightmaps、QualityをLow、Resolutionを30、Paddingを2にして・・・、Directional LightmapはProライセンスが必要だからできないそうだ。。Dual Lightmapsのままにして、設定はDirectional LightmapsでBakeする。

Directional Lightを作成してlight_main_directionalと言う名前にする。
light_main_directionalのTagをMainLight、Colorを青、Shadow TypeをSoft Shadows、Biasを0.01、Culling MaskからExtentsをはずす。
light_main_directionalをDuplicateしてligh_alarm_directionalという名前にする。
ligh_alarm_directionalのTagをAlarmLight、Colorを濃茶色、Intensityを0、Culling MaskのExtentsにチェックを入れる。
light_main_directionalとligh_alarm_directionalを選択して、LightmappingをRealtimeOnlyにする。

アラームライト

Unity: Stealth – Alarm Lights



ligh_alarm_directionalを選択してAlarmLightという名前でC#スクリプトを追加して編集します。
using UnityEngine;
using System.Collections;

public class AlarmLight : MonoBehaviour
{
	public float fadeSpeed = 2f;
	public float highIntensity = 2f;
	public float lowIntensity = 0.5f;
	public float changeMargin = 0.2f;
	public bool alarmOn;

	private float targetIntensity;

	void Awake()
	{
		light.intensity = 0f;
		targetIntensity = highIntensity;
	}

	void Update()
	{
		if(alarmOn)
		{
			light.intensity = Mathf.Lerp (light.intensity, targetIntensity, fadeSpeed * Time.deltaTime);
			CheckTargetIntensity();
		}
		else
		{
			light.intensity = Mathf.Lerp (light.intensity, 0f, fadeSpeed * Time.deltaTime);
		}
	}

	void CheckTargetIntensity()
	{
		if(Mathf.Abs (targetIntensity - light.intensity) < changeMargin)
		{
			if(targetIntensity == highIntensity)
			{
				targetIntensity = lowIntensity;
			}
			else
			{
				targetIntensity = highIntensity;
			}
		}
	}
}

env_stealth_staticオブジェクトを展開してpropsを展開して6個のprop_megaphone_00数を選択します。
TagをSirenにして、Audio Sourceを追加してalarm_triggeredをAudio Clipに設定して、Play On AwakeのチェックをはずしてLoopにチェックを入れて3D Sound SettingsのMin Distanceを5にします。

タグの管理

Unity: Stealth – Tag Management



ScriptsフォルダにTagsというC#スクリプトを作成します。
using UnityEngine;
using System.Collections;

public class Tags : MonoBehaviour
{
	public const string player = "Player";
	public const string alarm = "AlarmLight";
	public const string siren = "Siren";
	public const string gameController = "GameController";
	public const string mainLight = "MainLight";
	public const string fader = "Fader";
	public const string enemy = "Enemy";
}

AssetsにAlarmLightというスクリプトがあるので、それをScriptsフォルダに投げ込みます。

スクリーンのフェイド

Unity: Stealth – Screen Fader



Unity4.6でGUI Textureがなくなってる・・。
調べて思い出した。別のチュートリアルでGUI TextureではなくてCanvasを使って文字を表示させていた。

Unity3Dで3Dシューティングの作り方、パート2(3Dの敵、追跡、スライダーでHPの表示、攻撃)
プレイヤーのHPの表示画面の作成の箇所でCanvas使ってHPの表示をしています。

Unity3Dで3Dシューティングの作り方、パート3(スコアの表示、多数の敵、ゲームオーバー画面)
ゲームオーバーのときにScreenFaderで画面を切り替えています。

GUI Textureはスクリプトで画面の表示を操作しているけど、CanvasだとAnimationを使って画面の表示を操作している。うーん、自力で作るのめんどくさいので、また今度にしよう。何もせずに動画の説明だけ眺めるだけにします。

ゲームコントローラー

Unity: Stealth – Game Controller



空のGameObjectを作成してgameControllerという名前にしてTagをGameControllerにします。Audio Sourceを追加して、music_normalというAudio Clipをアタッチします。Loopにチェックを入れて、Volumeを0.8にします。

空のGameObjectを作成してsecondaryMusicという名前にしてgameControllerの子要素にします。Audio Souceを追加して、music_panicというAudio Clipを追加して、Loopにチェックを入れて、Volumeを0にします。

gameControllerを選択して、C#スクリプトをLastPlayerSightingという名前で追加します。LastPlayerSightingを編集します。
using UnityEngine;
using System.Collections;

public class LastPlayerSighting : MonoBehaviour
{
	public Vector3 position = new Vector3(1000f, 1000f, 1000f);
	public Vector3 resetPosition = new Vector3(1000f, 1000f, 1000f);
	public float lightHighIntensity = 0.25f;
	public float lightLowIntensity = 0f;
	public float fadeSpeed = 7f;
	public float musicFadeSpeed = 1f;

	private AlarmLight alarm;
	private Light mainLight;
	private AudioSource panicAudio;
	private AudioSource[] sirens;

	void Awake()
	{
		alarm = GameObject.FindGameObjectWithTag(Tags.alarm).GetComponent<AlarmLight>();
		mainLight = GameObject.FindGameObjectWithTag (Tags.mainLight).light;
		panicAudio = transform.Find ("secondaryMusic").audio;
		GameObject[] sirenGameObjects = GameObject.FindGameObjectsWithTag (Tags.siren);
		sirens = new AudioSource[sirenGameObjects.Length];

		for(int i = 0; i < sirens.Length; i++)
		{
			sirens[i] = sirenGameObjects[i].audio;
		}
	}

	void Update()
	{
		SwitchAlarms ();
		MusicFading ();
	}

	void SwitchAlarms()
	{
		alarm.alarmOn = (position != resetPosition);

		float newIntensity;

		if (position != resetPosition)
		{
			newIntensity = lightLowIntensity;
		}
		else
		{
			newIntensity = lightHighIntensity;
		}

		mainLight.intensity = Mathf.Lerp (mainLight.intensity, newIntensity, fadeSpeed * Time.deltaTime);

		for(int i = 0; i < sirens.Length; i++)
		{
			if(position != resetPosition && !sirens[i].isPlaying)
			{
				sirens[i].Play ();
			}
			else if (position == resetPosition)
			{
				sirens[i].Stop();
			}
		}
	}

	void MusicFading()
	{
		if (position != resetPosition) {
			audio.volume = Mathf.Lerp (audio.volume, 0f, musicFadeSpeed * Time.deltaTime);
			panicAudio.volume = Mathf.Lerp (panicAudio.volume, 0.8f, musicFadeSpeed * Time.deltaTime);
		}
		else
		{
			audio.volume = Mathf.Lerp (audio.volume, 0.8f, musicFadeSpeed * Time.deltaTime);
			panicAudio.volume = Mathf.Lerp (panicAudio.volume, 0f, musicFadeSpeed * Time.deltaTime);
		}
	}
}

Playボタンでゲームをスタートして音楽を流してみます。
gameControllerのLast Player Sighting(Script)のPositionを変えるとサイレンが鳴るようになります。

最後にgameControllerをPrefabsに入れてプレハブ化します。

監視カメラと首フリ

Unity: Stealth – CCTV Cameras




Modelsからprop_cctvCamをHierarchyにドロップしてPosition X:-8 Y:3 Z:16.1、Rotation Y:180にします。Use Light Probesにチェックをいれprop_cctvCamオブジェクトを展開してprop_cctvCam_jointオブジェクトのUse Light Probesもチェックをいれ、prop_cctvCam_jointオブジェクトを展開してprop_cctvCam_bodyオブジェクトのUse Light Probesもチェックを入れます。

ModelsのCollision Meshesの中にあるprop_cctvCam_collisionをドラッグしてprop_cctvCam_bodyオブジェクトにドロップします。ドロップしたprop_cctvCam_collisionオブジェクトのPositionをX:0 Y:0.15 Z:0.35へ変更します。

prop_cctvCam_collisionオブジェクトにMesh Colliderを追加してIs Triggerにチェックを入れ、Mesh RendererとMesh Filterを削除します。

prop_cctvCam_bodyオブジェクトを選択してRotation X:60にします。

prop_cctvCam_collisionオブジェクトにLightを追加してLightのTypeをSpot、Rangeを9.5、Spot Angleを90、Colorを赤、LightmappingをRealtimeOnlyにします。Texuturesのfx_cameraView_alpをLightのCookieにドロップします。

prop_cctvCam_collisionオブジェクトにCCTVPlayerDetectionという名前でC#スクリプトを追加します。
using UnityEngine;
using System.Collections;

public class CCTVPlayerDetection : MonoBehaviour {
	private GameObject player;
	private LastPlayerSighting lastPlayerSighting;

	void Awake(){
		player = GameObject.FindGameObjectWithTag (Tags.player);
		lastPlayerSighting = GameObject.FindGameObjectWithTag(Tags.gameController).GetComponent<LastPlayerSighting>();
	}

	void OnTriggerStay(Collider other){
		if(other.gameObject == player){
			Vector3 relPlayerPos = player.transform.position - transform.position;
			RaycastHit hit;

			if(Physics.Raycast(transform.position, relPlayerPos, out hit)){
				if(hit.collider.gameObject == player){
					lastPlayerSighting.position = player.transform.position;
				}
			}
		}
	}
}

prop_cctvCamオブジェクトを選択してPrefabsにドロップします。

prop_cctvCamオブジェクトを2つDupulicateして合計3つにします。そのうち1つを選択してPosition X:-21 Y:2.2 Z:2に変更します。もう1つ選択してPosition X:-23 Y:1.8 Z:24に変更してprop_cctvCamオブジェクトを展開してprop_cctvCam_bodyのRotation X:30、Scale Z:1.8へ変更します。prop_cctvCam_collisionオブジェクトを選択してIntensityを4にしてPrefabのApplyをクリックします。

AssetsのAnimationsフォルダへ行きcctvSweepと言う名前でAnimationを作成します。

ぐはっ、ビデオ通りにはできません。。

prop_cctvCam_jointオブジェクトを選択してAnimationを追加します。
AnimationビューからAdd CurveをクリックしてcctvSweepを作成します。
必要なのはRotationなのでそれだけ追加します。
cctvSweepをprop_cctvCam_jointオブジェクトのAnimationにドロップします。

Animationビューに戻って、keyframeを追加して2:00の位置に移動させます。2:00のkeyframeのRotation Yを60に変更します。AssetsのAnimationsにあるcctvSweepのWrap ModeをPing Pongに変更します。

これで監視カメラが首をフリフリするようになります。

Unity: Stealth – Laser Grids



Modelsのfx_laserFence_lasersをシーンビューの適当な場所にドロップします。
作成されたfx_laserFence_lasersをfx_laserFence_lasers_001という名前に変更します。
fx_laserFence_lasers_001オブジェクトのPosition X:-8 Y:1.21 Z:5.62、Rotation Y:90、Scale Z:3.62に変更して、Box Colliderを追加してIs Triggerをチェックします。

fx_laserFence_lasers_001オブジェクトにAudio Sourceを追加してAudio Clipにはlaser_hum、Loopをチェック、3D Soud SettingsのMin Distaceを1.8に変更し、さらにLightを追加してRangeを5、Colorを赤、Intensityを0.6、LightmappingをRealtimeOnlyに変更します。

fx_laserFence_lasers_001オブジェクトにLaserBlinkingという名前でC#スクリプトを追加して編集します。
using UnityEngine;
using System.Collections;

public class LaserBlinking : MonoBehaviour{
	public float onTime;
	public float offTime;

	private float timer;

	void Update(){
		timer += Time.deltaTime;

		if(renderer.enabled && timer >= onTime){
			SwitchBeam();
		}

		if(!renderer.enabled && timer >= offTime){
			SwitchBeam();
		}
	}

	void SwitchBeam(){
		timer = 0f;

		renderer.enabled = !renderer.enabled;
		light.enabled = !light.enabled;
	}
}

同じようにfx_laserFence_lasers_001オブジェクトにLaserPlayerDetectionという名前でC#スクリプトを追加して編集します。
using UnityEngine;
using System.Collections;

public class LaserPlayerDetection : MonoBehaviour {
	private GameObject player;
	private LastPlayerSighting lastPlayerSighting;

	void Awake(){
		player = GameObject.FindGameObjectWithTag (Tags.player);
		lastPlayerSighting = GameObject.FindGameObjectWithTag(Tags.gameController).GetComponent<LastPlayerSighting>();
	}

	void OnTriggerStay(Collider other){
		if(renderer.enabled){
			if(other.gameObject == player){
				lastPlayerSighting.position = other.transform.position;
			}
		}
	}
}

Prefabsにfx_laserFence_lasers_001をドロップします。

fx_laserFence_lasers_001を5つ複製して002,003,004,005,006のように名前をそれぞれ変更します。

fx_laserFence_lasers_002オブジェクト
Position X:-8 Y:1.21 Z:9.23

fx_laserFence_lasers_003オブジェクト
Position X:-17.93 Y:1.21 Z:24.08

fx_laserFence_lasers_004オブジェクト
Position X:-23.92 Y:1.21 Z:26.1
Rotation Y:0

fx_laserFence_lasers_005オブジェクト
Position X:-8.95 Y:1.21 Z:25.99
Scale Z:5.6、On Time:1.5、Off Time:1.5

fx_laserFence_lasers_006オブジェクト
Position X:-8.95 Y:1.21 Z:29.96
Scale Z:5.6、On Time:1.5、Off Time:1.55


Modelsのprop_switchUnitをシーンビューの適当なところにドロップします。
prop_switchUnitオブジェクトのPosition X:-11.5 Y:0 Z:11.3、Rotation Y:180、Staticにチェックを入れて子要素も反映させます。

prop_switchUnitオブジェクトにBox Colliderを追加してCenter X:0.3 Y:0.8 Z:-0.15、Size X:1.3 Y:1.6 Z:0.81にします。続いてSphere Colliderを追加してIs Triggerにチェックをいれ、Center X:0 Y:1 Z:1、Radius 1.5にします。

prop_switchUnitオブジェクトにAudio Sourceを追加してPlay On Awakeのチェックをはずし、Audio Clipにはswitch_deactivationをアタッチします。

prop_switchUnitオブジェクトにLaserSwitchDeactivationと言う名前でC#スクリプトを作成して編集します。
using UnityEngine;
using System.Collections;

public class LaserSwitchDeactivation : MonoBehaviour {
	public GameObject laser;
	public Material unlockedMat;

	private GameObject player;

	void Awake(){
		player = GameObject.FindGameObjectWithTag (Tags.player);
	}

	void OnTriggerStay(Collider other){
		if(other.gameObject == player){
			if(Input.GetButton("Switch")){
				LaserDeactivation();
			}
		}
	}

	void LaserDeactivation(){
		laser.SetActive (false);

		Renderer screen = transform.Find ("prop_switchUnit_screen_001").renderer;
		screen.material = unlockedMat;
		audio.Play ();
	}
}

prop_switchUnitオブジェクトのUnlocked MatにはMaterialsのprop_switchUnit_screen_unlocked_matをアタッチします。

Prefabsにprop_switchUnitオブジェクトをドロップします。
prop_switchUnitオブジェクトを3つ複製して合計4つにして名前の後ろにそれぞれ_001, _002, _003, _004をつけます。

prop_switchUnit_001オブジェクト
fx_laserFence_lasers_001オブジェクトをLaserにアタッチします。

prop_switchUnit_002オブジェクト
Position X:-1.6 Y:0 Z:11.3
fx_laserFence_lasers_002オブジェクトをLaserにアタッチします。

prop_switchUnit_003オブジェクト
Position X:-17.7 Y:0 Z:33.3
fx_laserFence_lasers_003オブジェクトをLaserにアタッチします。

prop_switchUnit_004オブジェクト
Position X:-30 Y:0 Z:33.3
fx_laserFence_lasers_004オブジェクトをLaserにアタッチします。


最後にWindow → Lightmpaaing
QualityをHighにしてPaddingを3にしてBakeします。
Bakeが完了するのにとても時間がかかります。

コメントを残す

メールアドレスが公開されることはありません。