脱出ゲームといっても日本の脱出ゲームではなく、敵に見つからないように建物内から逃げ出すゲームです。
今回のゲームが最後のチュートリアルのゲーム作りになります。このチュートリアルを終えたあとに、オリジナルゲームの作成を開始するのです!
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にする。
アラームライト
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フォルダに投げ込みます。
スクリーンのフェイド
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に入れてプレハブ化します。
監視カメラと首フリ
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に変更します。
これで監視カメラが首をフリフリするようになります。
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が完了するのにとても時間がかかります。
コメントを残す