Unity3Dで3D脱出ゲームの作り方、パート3です。
がんばれ、ゴールはあと少し・・・。
カメラの移動
Unity: Stealth – Camera Movement
プレイヤーがちょうどよく収まる感じにシーンビューを調整します。
camera_mainを選択してGameObject → Align With Viewを選択します。
これでcamera_mainのPositionやRotationが調整されます。
camera_mainを選択してCameraMovementという名前でC#スクリプトを作成して編集します。
using UnityEngine; using System.Collections; public class CameraMovement : MonoBehaviour { public float smooth = 1.5f; private Transform player; private Vector3 relCameraPos; private float relCameraPosMag; private Vector3 newPos; void Awake(){ player = GameObject.FindGameObjectWithTag (Tags.player).transform; relCameraPos = transform.position - player.position; relCameraPosMag = relCameraPos.magnitude - 0.5f; } void FixedUpdate(){ Vector3 standardPos = player.position + relCameraPos; Vector3 abovePos = player.position + Vector3.up * relCameraPosMag; Vector3[] checkPoints = new Vector3[5]; checkPoints [0] = standardPos; checkPoints [1] = Vector3.Lerp (standardPos, abovePos, 0.25f); checkPoints [2] = Vector3.Lerp (standardPos, abovePos, 0.5f); checkPoints [3] = Vector3.Lerp (standardPos, abovePos, 0.75f); checkPoints [4] = abovePos; for(int i = 0; i < checkPoints.Length; i++){ if(ViewingPosCheck(checkPoints[i])){ break; } } transform.position = Vector3.Lerp (transform.position, newPos, smooth * Time.deltaTime); } bool ViewingPosCheck(Vector3 checkPos){ RaycastHit hit; if(Physics.Raycast (checkPos, player.position - checkPos, out hit, relCameraPosMag)){ if(hit.transform != player){ return false; } } newPos = checkPos; return true; } void SmoothLookAt(){ Vector3 relPlayerPosition = player.position - transform.position; Quaternion lookAtRotation = Quaternion.LookRotation (relPlayerPosition, Vector3.up); transform.rotation = Quaternion.Lerp (transform.rotation, lookAtRotation, smooth * Time.deltaTime); } }
カードキーの取得
char_ethanオブジェクトを選択してPlayerInventoryという名前でC#スクリプトを作成して編集します。
using UnityEngine; using System.Collections; public class PlayerInventory : MonoBehaviour { public bool hasKey; }
Modelsのprop_keycardをシーンビューにドロップしてPosition X:-22 Y:0.4 Z:32に変更します。
AssetsのAnimatorsを選択してAnimator Controllerを作成してKeycardAnimatorという名前に変更します。
KeycardAnimatorを選択したまま、Modelsのprop_keycardを展開してそこにあるSpinをAnimatorビューにドロップします。
AnimatorビューのSpinを選択してFoot IKにチェックを入れます。
prop_keycardオブジェクトを選択してKeycardAnimatorをprop_keycardオブジェクトのAnimator Controllerにアタッチします。
続けてSphere Colliderを追加してRadius 0.92、Is Triggerにチェックを入れます。
続けてLightを追加してRange 4.5、Intensity 2.5、Colorを水色に変更します。
prop_keycardオブジェクトを選択してKeyPickupという名前でC#スクリプトを作成して編集します。
using UnityEngine; using System.Collections; public class KeyPickup : MonoBehaviour { public AudioClip keyGrab; private GameObject player; private PlayerInventory playerInventory; void Awake(){ player = GameObject.FindGameObjectWithTag (Tags.player); playerInventory = player.GetComponent<PlayerInventory>(); } void OnTriggerEnter(Collider other){ if(other.gameObject == player){ AudioSource.PlayClipAtPoint(keyGrab, transform.position); playerInventory.hasKey = true; Destroy (gameObject); } } }
prop_keycardオブジェクトのKey Pickup(Script)のKey GrabにAudioのkeycard_pickupをアタッチします。
prop_keycardオブジェクトのAnimatorのApply Root Motionのチェックをはずします。
prop_keycardオブジェクトを展開してprop_keycard_cardを選択してMesh RendererのUse Light Probesにチェックを入れます。
最後にprop_keycardオブジェクトをPrefabsにドロップします。
自動扉(ドア1枚)
AssetsのModelsのdoor_generic_slideをシーンビューにドロップして、Position X:-6 Y:0 Z:7、Rotation Y:90に変更します。
door_generic_slideオブジェクトを展開してdoor_generic_slide_panelオブジェクトを選択してUse Light Probesにチェックを入れます。
door_generic_slideオブジェクトを選択してSphere Colliderを追加してCenter Y:1、Radius 3にします。
door_generic_slide_panelオブジェクトを選択してBox Colliderを追加します。
AssetsのAnimatorsを選択してAnimator Controllerを作成してSingleDoorAnimatorという名前に変更します。
SingleDoorAnimatorを選択してAnimatorビューを選択して、ParametersにBoolのOpenを追加します。
AssetsのModelsのdoor_generic_slideを展開してClosedとOpenをAnimatorビューにドロップします。
ClosedからOpenへTransitionを作成してConditionsをOpen trueにします。
OpenからClosedへTransitionを作成してConditionsをOpen falseにします。
Transitionを150%に引き伸ばします。(説明するの面倒なので動画を見よう!)
door_generic_slideオブジェクトを選択してSingleDoorAnimatorをdoor_generic_slideオブジェクトのAnimator ControllerにアタッチしてApply Root Motionのチェックをはずします。
door_generic_slide_panelオブジェクトを選択してRigidbodyを追加してUse Gravityのチェックをはずして、Is Kinematicにチェックをいれます。
door_generic_slideオブジェクトを選択してAudio Sourceを追加してDoorAnimationという名前でC#スクリプトを追加して編集します。
using UnityEngine; using System.Collections; public class DoorAnimation : MonoBehaviour { public bool requireKey; public AudioClip doorSwishClip; public AudioClip accessDeniedClip; private Animator anim; private HashIDs hash; private GameObject player; private PlayerInventory playerInventory; private int count; void Awake(){ anim = GetComponent<Animator>(); hash = GameObject.FindGameObjectWithTag(Tags.gameController).GetComponent<HashIDs>(); player = GameObject.FindGameObjectWithTag (Tags.player); playerInventory = player.GetComponent<PlayerInventory>(); } void OnTriggerEnter(Collider other){ if (other.gameObject == player) { if (requireKey) { if (playerInventory.hasKey) { count++; } else { audio.clip = accessDeniedClip; audio.Play (); } } else { count++; } } else if(other.gameObject.tag == Tags.enemy){ if(other is CapsuleCollider){ count++; } } } void OnTriggerExit(Collider other){ if(other.gameObject == player || (other.gameObject.tag == Tags.enemy && other is CapsuleCollider)){ count = Mathf.Max (0, count-1); } } void Update(){ anim.SetBool (hash.openBool, count > 0); if(anim.IsInTransition(0) && !audio.isPlaying){ audio.clip = doorSwishClip; audio.Play (); } } }
door_generic_slideオブジェクトのDoor Animation(Script)のDoor Swish ClipにAudioのdoor_open、Access Denied ClipにAudioのdoor_accessDeniedをアタッチします。door_generic_slideオブジェクトのSphere ColliderのIs Triggerのチェックを入れます。
door_generic_slideオブジェクトをPrefabsにドロップします。
door_generic_slideオブジェクトを2つ複製して、
1つをPosition X:-15.9 Y:0 Z:7、もう1つをPosition X:-7.9 Y:0 Z:37にします。
自動ドア(2枚)
AssetsのModelsのdoor_exit_outerをシーンビューにドロップしてPosition X:-22 Y:0 Z:46、Rotation Y:270にします。
door_exit_outerオブジェクトを展開して子要素のUse Light Probesにチェックを入れます。
door_exit_outerオブジェクトを選択してSphere Colliderを追加してIs Triggerにチェックをいれ、Center X:-1 Y:1 Z:0、Radius 2にします。
door_exit_outerオブジェクトの子要素を選択してBox Colliderを追加します。
AssetsのAnimatorsのSingleDoorAnimatorを複製して、複製してできたのをDoubleDoorAnimatorという名前に変更します。
DoubleDoorAnimatorを選択してAnimatorビューを選択します。
Openを選択してModelsのdoor_exit_outerを展開してdoor_exitOuter_openedをOpenのInspectorのMotionにドロップします。
Closedを選択してModelsのdoor_exit_outerを展開してdoor_exitOuter_closedをClosedのInspectorのMotionにドロップします。
door_exit_outerオブジェクトを選択してDoubleDoorAnimatorをdoor_exit_outerオブジェクトのAnimator ControllerにアタッチしてApply Root Motionのチェックをはずします。
door_exit_outerオブジェクトの2つの子要素を選択してRigidbodyを追加してUse Gravityのチェックをはずし、Is Kinematicのチェックをいれます。
DoorAnimationスクリプトをdoor_exit_outerオブジェクトへドロップします。
door_exit_outerオブジェクトのDoor Animation(Script)のDoor Swish ClipにAudioのdoor_openを設定し、Access Denied ClipにAudioのdoor_accessDeniedを設定します。Require Keyにチェックを入れます。
door_exit_outerオブジェクトをPrefabsにドロップします。
LiftDoorsTrackingと言う名前でC#スクリプトを作成して編集します。
using UnityEngine; using System.Collections; public class LiftDoorsTracking : MonoBehaviour { public float doorSpeed = 7f; private Transform leftOuterDoor; private Transform rightOuterDoor; private Transform leftInnerDoor; private Transform rightInnerDoor; private float leftClosedPosX; private float rightClosedPosX; void Awake(){ leftOuterDoor = GameObject.Find ("door_exitOuter_left_001").transform; rightOuterDoor = GameObject.Find ("door_exitOuter_right_001").transform; leftInnerDoor = GameObject.Find ("door_exitInner_left_001").transform; rightInnerDoor = GameObject.Find ("door_exitInner_right_001").transform; leftClosedPosX = leftInnerDoor.position.x; rightClosedPosX = rightInnerDoor.position.x; } void MoveDoors(float newLeftXTarget, float newRightXTarget){ float newX = Mathf.Lerp (leftInnerDoor.position.x, newLeftXTarget, doorSpeed * Time.deltaTime); leftInnerDoor.position = new Vector3 (newX, leftInnerDoor.position.y, leftInnerDoor.position.z); newX = Mathf.Lerp (rightInnerDoor.position.x, newRightXTarget, doorSpeed * Time.deltaTime); rightInnerDoor.position = new Vector3 (newX, rightInnerDoor.position.y, rightInnerDoor.position.z); } public void DoorFollowing(){ MoveDoors (leftOuterDoor.position.x, rightOuterDoor.position.x); } public void CLoseDoors(){ MoveDoors (leftClosedPosX, rightClosedPosX); } }
リフトの設置
AssetsのModelsのprop_lift_exitをシーンビューにドロップしてPosition X:-21.85 Y:1.5 Z:48、Rotation Y:270にする。
prop_lift_exitオブジェクトを展開してdoor_exit_innerの2つの子要素を選択してprop_lift_exitオブジェクトの残りの3つの子要素を選択してUse Light Probesにチェックを入れる。
prop_lift_exitオブジェクトに空のGameObjectを作成してprop_lift_colliderという名前に変更します。
prop_lift_colliderオブジェクトを選択してMesh Colliderを追加してMeshにprop_lift_exit_collision_001を選択します。
prop_lift_exitオブジェクトを選択してBox Colliderを追加してIs Triggerにチェックをいれ、Center X:0 Y:-1.1 Z:0、Size X:3.3 Y:0.5 Z:3.5にします。
続いてRigidbodyを追加してUse Gravityのチェックをはずして、Is Kinematicにチェックをいれます。
続いてAudio Sourceを追加してPlay On AwakeのチェックをはずしてLoopにチェックを入れてAudio ClipにAudioのlift_raiseを設定します。
prop_lift_exitオブジェクトにLiftTriggerという名前でC#スクリプトを追加して編集します。
using UnityEngine; using System.Collections; public class LiftTrigger : MonoBehaviour { public float timeToDoorsClose = 2f; public float timeToLiftStart = 3f; public float timeToEndLevel = 6f; public float liftSpeed = 3f; private GameObject player; private Animator playerAnim; private HashIDs hash; private CameraMovement camMovement; private LiftDoorsTracking liftDoorsTracking; private bool playerInLift; private float timer; void Awake(){ player = GameObject.FindGameObjectWithTag (Tags.player); playerAnim = player.GetComponent<Animator>(); hash = GameObject.FindGameObjectWithTag(Tags.gameController).GetComponent<HashIDs>(); camMovement = Camera.main.gameObject.GetComponent<CameraMovement>(); liftDoorsTracking = GetComponent<LiftDoorsTracking>(); } void OnTriggerEnter(Collider other){ if(other.gameObject == player){ playerInLift = true; } } void OnTriggerExit(Collider other){ if(other.gameObject == player){ playerInLift = false; timer = 0f; } } void Update(){ if (playerInLift) LiftActivation (); if (timer < timeToDoorsClose) { liftDoorsTracking.DoorFollowing (); } else { liftDoorsTracking.CloseDoors(); } } void LiftActivation(){ timer += Time.deltaTime; if(timer >= timeToLiftStart){ playerAnim.SetFloat(hash.speedFloat, 0f); camMovement.enabled = false; player.transform.parent = transform; transform.Translate(Vector3.up * liftSpeed * Time.deltaTime); if(!audio.isPlaying){ audio.Play (); } } } }
prop_lift_exitオブジェクトをPrefabsにドロップします。
Playボタンを押して実行する。
・・・
リフトの内側のドアが開かない。
開かないけど素通りできる。
NullReferenceException: Object referece not set to an instance of an object
わかった。
LiftDoorsTrackingスクリプトをprop_lift_exitオブジェクトにアタッチするとエラーがでなくなる。
あとLiftDoorsTrackingスクリプトでdoor_exit_…の名前が違うのでそれも直す。
leftOuterDoor = GameObject.Find ("door_exit_outer_left_001").transform; rightOuterDoor = GameObject.Find ("door_exit_outer_right_001").transform; leftInnerDoor = GameObject.Find ("door_exit_inner_left_001").transform; rightInnerDoor = GameObject.Find ("door_exit_inner_right_001").transform;
次がラストパートです!
コメントを残す