
ㅁ 스크립트를 저장합니다. ============================================================================== 마지막으로 컷씬 카메라를 끄고 오디오 리스너 구성요소를 Near Camera로 다시 돌려보내기 전에 플레이어가 결과를 볼 수 있도록 몇 초간을 정지 시킵니다: spaceShip 객체는 방벽 안에 앉아있는 우주선 모델입니다. ㅁ Awake()함수를 아래의 스크립트와 매치되도록 변경합니다. 이 함수는 LevelStatus의 첫 함수 바로 위에 위치하고 있을 것입니다. 본 튜토리얼 번역서는 (주)지피엠스튜디오가 운영하는 "유니티코리아" 회원님들을 위한 메뉴얼 번역 자료 입니다.
컷씬
컷씬들은 플레이어들에게 이벤트 또는 알아야할 스토리상의 요소를 들려주는 유용한 방법을 제공합니다. 이론적으로 이들은 플레이어로 부터 씬을 잘라내는 것은 최소한으로 유지해야합니다. 그렇기 때문에 우리는 2개의 컷씬만을 사용합니다.
첫 번째는 플레이어가 레벨 상에 필요한 모든 연료통을 모으는 데에 성공하여 우주선이 풀렸을 때 발생합니다. 이 컷신은 '화면 속의 화면' 기술을 이용하여 나타나기 때문에 플레이어가 시퀀스가 재생되는 도중에도 계속 플레이할 수 있습니다.
이 컷씬을 위해 전체화면을 사용하지 않는 한 가지 매우 실용적인 이유는 씬이 완료될 때까지 플레이어가 실질적으로 앞이 안보이기 때문에, 로봇, 플레이어, 조종, 등의 모든 게임 요소를 멈추어야 하기 때문입니다.
☆ 참고
근처의 상자들에 올라서서 우주선에 접근하는 것은 여전히 가능하지만, 우주선은 이 시점에서는 아직 잠겨있으며 이륙하지 않을 것입니다. (방벽이 풀릴 때까지 메쉬 컬라이더가 트리거 유형으로 바뀌지 않기 때문입니다.)
두 번째 컷씬은 플레이어가 방벽이 비활성화 된 후 우주선을 건드릴 때 발생합니다. 전체 화면으로 재생되는 이 씬에서는 게임오버 시퀀스로 전환 되기 전, 우주선이 이륙하고 자유롭게 새로운 모험을 위해 날아가는 것을 보게 됩니다.
이제 첫 번째 씬을 자세히 알아봅시다...
방벽 해제시키기
우리는 방벽에 애니메이션을 추가할 때 레벨의 방벽파트를 처음 맞닥뜨린 적이 있습니다. 본 챕터의 초반부분에서 우리는 이 방벽에 음향효과도 추가하였습니다. 이제 우리는 이 방벽을 가동할것입니다. 하지만 우선, 우리는 방벽의 가동이 모든 연료통을 모았을 때만 가능하도록 해야 합니다 (완전한 스크립트 코드는 부록에서 찾아볼 수 있습니다):
ㅁ ThirdPersonStatus 스크립트를 열고 FoundItem() 함수를 찾으십시오.
ㅁ 한 블록의 주석 후에 아래의 코드를 추가하십시오. (아래의 코드를 함수의 닫는 기호인 중괄호(}) 전에 입력하도록 하십시오. 그렇지 않으면 코드가 작동하지 않을 것입니다!)
==============================================================================
if (remainingItems == 0)
{
levelStateMachine.UnlockLevelExit(); // ...그리고 우리의 플레이어를 레벨 밖으로
// 나올 수 있게 합니다.
}
==============================================================================
ㅁ LevelStatus 스크립트를 엽니다. 이 스크립트에서 두개의 컷신이 모두 처리됩니다. (완전한 스크립트 코드는 부록에서 찾아볼 수 있습니다.)
ㅁ 스크립트 가장 위에 아래의 코드를 추가하십시오:
==============================================================================
var exitGateway: GameObject;
var levelGoal: GameObject;
var unlockedSound: AudioClip;
var levelCompleteSound: AudioClip;
var mainCamera: GameObject;
var unlockedCamera: GameObject;
var levelCompletedCamera: GameObject;
==============================================================================
☆ 참고
위의 코드는 두 번째 컷신에도 필요한 변수들을 포함하고 있습니다.
ㅁ 다음, Awake()함수에 아래의 스크립트 코드를 추가하십시오:
==============================================================================
levelGoal.GetComponent(MeshCollider).isTrigger = false;
==============================================================================
이 부분은 매우 결정적입니다. 이 코드는 두 번째 컷신을 너무 이르게 트리거 되는 것을 방지합니다. isTrigger 스위치가 꺼져있음으로 인해 우주선은 방벽이 여전히 활성화 돼 있는 한 그냥 배경의 일부가 됩니다.
이제 해제 시퀀스 자체를 알아봅시다.
ㅁ LevelStatus 스크립트에 아래의 함수를 추가합니다. (자세한 사항은 진행하면서 설명할것입니다.)
==============================================================================
function UnlockLevelExit()
{
mainCamera.GetComponent(AudioListener).enabled = false;
==============================================================================
유니티는 한 무대에 오직 하나의 오디오 리스너 구성요소만을 지원합니다. 이는 주로 씬의 메인 카메라에 부착되어있지만, 우리는 씬에서 여러 개의 카메라를 사용하고 있기 때문에 하나의 오디오 리스너가 한 번 에 하나만 활동하도록 해야 합니다. 우리는 우리의 "방벽 해제" 음향 효과를 듣고 싶기 때문에, 오디오 리스너를 우리의 컷씬 카메라에 잠시 활성시킬 것입니다. 다음, 우리는 컷씬 카메라를 활성화하고 카메라의 오디오 리스너 구성요소를 활성화해야합니다:
unlockedCamera.active = true;
unlockedCamera.GetComponent(AudioListener).enabled = true;
==============================================================================
방벽에는 반복 재생하는 음향효과가 첨부되어있습니다. 이제 우리는 이 음향효과를 정지해야합니다:
==============================================================================
exitGateway.GetComponent(AudioSource).Stop();
==============================================================================
이제 우리는 "방벽 해제" 음향효과를 재생할 차례입니다:
==============================================================================
if (unlockedSound)
{
AudioSource.PlayClipAtPoint(unlockedSound, unlockedCamera.GetComponent(Transform).position, 2.0);
}
==============================================================================
음향 효과가 시작함에 따라, 우리는 애니메이션 시퀀스를 시작할 수 있습니다. 우리는 순서대로 스크립트 코드를 이용하여 애니메이션을 실행할것입니다. 아래의 소수의 코드는 이 시퀀스를 실행할것입니다. 코드의 첫 번째 줄은 시퀀스가 시작하기 전에 지연시간을 추가하여 플레이어의 의식에 각인시킬 컷씬 애니메이션을 위한 시간을 벌어줍니다. (애니메이션 시퀀스를 따라갈 수 있도록 각 지점에 주석들을 남겨놓았습니다.)
==============================================================================
yield WaitForSeconds(1);
exitGateway.active = false; // ...방벽이 바로 해제되었다가...
yield WaitForSeconds(0.2); //...1/4초 동안 잠시 멈추었다가...
exitGateway.active = true; //...이제 방벽이 다시 반짝이고....
yield WaitForSeconds(0.2); //...또 한번 짧은 멈춤이 있다가...
exitGateway.active = false; ////...방벽은 영원히 중단됩니다!
==============================================================================
이제 우리는 배에 접근할 수 있습니다! 이제 우리가 해야 할 일은 우주선의 메쉬 컬라이더를 보통 컬라이더 대신에 트리거로 바꾸는 일 뿐입니다:
==============================================================================
levelGoal.GetComponent(MeshCollider).isTrigger = true;
==============================================================================
==============================================================================
yield WaitForSeconds(4); // 플레이어에게 결과를 보여줄 시간을 줍니다.
// 카메라를 교대합니다.
unlockedCamera.active = false; // 이렇게 함으로서 NearCamera가 화면을 독점하도록 할 수있습니다.
unlockedCamera.GetComponent(AudioListener).enabled = false;
mainCamera.GetComponent(AudioListener).enabled = true;
}
==============================================================================
컷씬 카메라 자체를 만드는 것이 우리가 해야 할 다음 단계입니다. 컷씬 카메라는 그냥 또 하나의 카메라 게임 객체로서, 게임 자체에 사용하던 카메라와 동일합니다. 지금 만들어봅시다:
ㅁ 씬에 새 카메라를 추가합니다.
ㅁ CutSceneCamera1이라고 이름 짓습니다.
ㅁ 카메라에 SmoothLookAt 스크립트를 추가합니다.
ㅁ SmoothLookAt 스크립트에 spaceShip 모델을 드래그 해놓아 카메라가 어디를 향해야하는 알도록 합니다.
ㅁ 나머지 속성을 아래와 같이 설정합니다:
Cut Scene Camera 1의 속성.
이 카메라는 우주선이 있는 압수품 보관소를 보도록 하여 방벽이 명확하게 보이도록 해야 합니다. 위의 설정을 사용하면 비슷한 화면을 볼 수 있을 것이나 이 값들을 수정해도 좋습니다:
Cut Scene Camera 1 위치시키기.
다음, CutSceneCamera1 카메라 설정을 아래와 같이 수정하십시오:
Cut Scene Camera 1의 카메라 구성요소 설정.
카메라는 기본적으로는 비활성화 되어있어야 합니다. 그리고 카메라는 스크립트에 의해 활성화 될 것이기 때문에 스크립트가 지시하기 전까지는 아무것도 렌더링 하지 않길 바랍니다. 카메라를 비활성화 하는 것은 매우 간단합니다: 그냥 Inspector 창 우측 상단에 위치한 Cut Scene Camera 1 옆에 있는 체크박스의 체크를 푸시면 됩니다.
또한 Normalized View Port Rect 속성을 설정하는데 에 주의를 기울이십시오. 이 값들은 화면 우측상단 구석에 표시되는 카메라의 스크린 내의 출력 위치를 정의합니다. 카메라의 Depth값 또한 NearCamera의 Depth값 보다 높은 10으로 설정되어 메인 게임 화면위에 나타나도록 할것입니다.
우리는 이 시퀀스를 테스트 해보아야 하기 때문에 LevelStatus 스크립트의 속성을 아래와 같이 설정하십시오:
Level Status 스크립트의 속성 설정하기
(역자: LevelStatus스크립트의 속성을 수정하려면 Hierarchy Pane의 Level 객체를 클릭하면 됩니다.)
★ 팁
위의 스크린샷에서는 임의적으로 Item Needed의 값을 2로 설정하였습니다. 이렇게 함으로서 먼저 대부분의 레벨을 돌아다니면서 연료통을 모으며 시간을 버리는 대신, 두개의 연료통만을 모으는 것만으로 컷신 을 테스트 할 수 있게 해줍니다. 모든 것이 완료되었을 땐 좀 더 높은 값으로-- 20 정도로-- 되돌려 놓는 것을 잊지 마십시오.
이제 게임을 플레이 하면, 아래의 그림처럼 컷씬이 나타나는 것을 볼 수 있을 것입니다.
우리의 첫 컷신이 실행되고 있습니다.
☆ 참고
메인 뷰와 삽입된 컷씬에 보이는 초당 프레임수 카운터는 최적화에 관한 챕터에서 다루고 있습니다.
마지막 컷씬은 약간 더 복잡합니다. 우리는 우주선이 이륙하여 날아가 버리도록 해야 합니다. 우리는 이를 스크립팅을 통해서 해낼 수도 있지만, 대신 애니메이션클립을 이용하는 것이 훨씬 쉽습니다:
ㅁ 방벽안의 spaceShip 모델을 클릭하여 선택합니다. (또는 Hierarchy Pane의 spaceShip 모델을 클릭합니다)
ㅁ Animations 폴더로부터 ShipAnimation 애니메이션클립을 Project 뷰에 드래그 해놓고 Inspector 창에 나타난 애니메이션 구성요소의 Spaceship Animation 속성에 추가시킵니다.
이렇게 하면 이제 spaceship의 Inspector창에서 애니메이션 구성요소를 볼 수 있을 것입니다. 이제 플레이버튼을 누르면 이륙하는 우주선을 볼 수 있을 것입니다. 그러나 우리는 레벨이 완료되었을때 에만 우주선이 이륙하도록 해야 합니다. 우리는 이를 스크립트를 이용하여 곧 구현할것입니다. 그러나 유니티 는 기본적으로 사용자가 애니메이션들을 자동으로 재생하길 원한다고 전제하고 있습니다. 우리는 이를 원하지 않기 때문에 게임을 정지시킨상태에서:
ㅁ spaceShip 애니메이션 구성요소 안의 "Play Automatically(자동으로 재생)" 체크박스의 체크를 풉니다.
spaceShip 객체의 애니메이션 설정.
다음 단계는 두 번째 컷신 카메라를 만드는 일입니다:
ㅁ 새 카메라 객체를 만듭니다.
ㅁ CutSceneCamera2라고 이름 짓습니다.
ㅁ 아래의 그림처럼 카메라를 압수품 보관소 건물 위에 위치시킵니다:
CutSceneCamera2를 위치시키기.
카메라가 바라보는 방향에 대해서는 걱정하지 마십시오: 우리는 카메라의 위치에만 관심이 있습니다.
카메라에 부착된 스크립트가 나머지를 해결할것입니다.
ㅁ SmoothLookAt 스크립트를 카메라에 추가하십시오.
ㅁ SmoothLookAt 스크립트에 spaceShip 모델을 드래그 하여 스크립트가 어떤 카메라가 어떤것을 바라보고 있어야하는지 알도록 합니다.
CutSceneCamera1과 마찬가지로, 우리는 이 카메라 또한 기본적으로 비활성화 시켜 놓아야 하지만, 나머지 설정은 다음 페이지에 보일 스크린샷과 같이 약간 다릅니다. 주요 차이점으로, 이 카메라는 화면 구석에 나타나기 보다는 전체화면에 나타나야하므로, Normalized View Port Rect 속성이 이를 염두에 두고 설정되었습니다.
CutSceneCamera2의 설정.
이제 컷씬 자체를 다루어봅시다. 두 번째 컷씬은 씬을 트리거 하는데 쓰이는 메시지들이 체인에 따라 전달되어야 하기 때문에 우리의 첫 컷씬보다는 약간 어렵습니다:
초기의 트리거는 플레이어가 spaceShip 모델을 건드렸을 때 발생합니다. (첫 번째 컷씬이 재생되고 나면, spaceShip 모델은 단단한 물체가 아닌 트리거로서 작용합니다.)
spaceShip모델은 그러므로 이 트리거 이벤트를 다룰 스크립트가 필요합니다:
ㅁ 새 Javascript 스크립트 에셋을 생성합니다.
ㅁ HandleSpaceshipCollision이라고 이름 짓습니다.
ㅁ 아래의 코드를 스크립트 안에 추가합니다 (완전한 스크립트 코드는 부록에 실려 있습니다):
==============================================================================
private var playerLink : ThirdPersonStatus;
function OnTriggerEnter (col : Collider)
{
playerLink=col.GetComponent(ThirdPersonStatus);
if (!playerLink) // 플레이어가 아닌 경우
{
return;
}
else
{
playerLink.LevelCompleted();
}
}
==============================================================================
위의 코드가 하는 일은 플레이어가 우주선을 건드렸는지, 건드렸다면 플레이어의 ThirdPersonStatus 스크립트 속 LevelCompleted() 함수를 호출합니다.
ㅁ spaceShip 객체에 새 스크립트를 추가합니다.
ThirdPersonStatus 스크립트의 LevelCompleted() 함수는 훨씬 짧으며 비슷한 기능을 합니다.
ㅁ 아래의 함수를 ThirdPersonStatus 스크립트에 추가합니다:
==============================================================================
function LevelCompleted()
{
levelStateMachine.LevelCompleted();
}
==============================================================================
levelStateMachine은 LevelStatus 스크립트를 연결하는 속성입니다. 레벨 완료 애니메이션이 레벨과 관련된 스크립트들이 알아야할 유일한 애니메이션이기에 LevelStatus가 바로 이 애니메이션이 발생하는 곳입니다.
ㅁ 이제 LevelCompleted() 함수를 LevelStatus에 추가하십시오. (자세한 사항은 진행하면서 설명할것입니다):
==============================================================================
function LevelCompleted()
{
==============================================================================
먼저, 우리의 첫 컷씬에 했었던 동일한 오디오 리스너 전환을 할것입니다:
==============================================================================
mainCamera.GetComponent(AudioListener).enabled = false;
levelCompletedCamera.active = true;
levelCompletedCamera.GetComponent(AudioListener).enabled = true;
==============================================================================
다음, 우리는 플레이어가 우주선 안에 있다는 환상을 주기 위하여 플레이어를 숨길 것입니다. 이를 하기 위해서는 "HidePlayer" 메시지를 플레이어의 ThirdPeronController 스크립트에 보낼 것입니다. 그리하면 함수는 플레이어의 렌더링을 멈추고 플레이어는 보이지 않게 됩니다:
==============================================================================
playerLink.GetComponent(ThirdPersonController).SendMessage("HidePlayer");
==============================================================================
신중을 기하기 위해, 우리는 또한 물리적으로 플레이어를 우리가 알고 있는 안전한 곳으로 옮길 것입니다. (로봇들은 플레이어가 보이거나 안 보이는 지를 확인하지 않으며 여전히 운행 중입니다.) 이 경우, 우리는 플레이어를 500 유닛정도 상승시켜 위급한 상황으로부터 벗어날 수 있도록 할것입니다.
==============================================================================
playerLink.transform.position+=Vector3.up*500.0; // 플레이어를 500 유닛만큼 움직입니다.
==============================================================================
이제 우리는 레벨 완료 음향 효과를 시작할 것입니다. 이 경우엔 우주선이 이륙하는 소리입니다:
==============================================================================
if (levelCompleteSound)
{
AudioSource.PlayClipAtPoint(levelCompleteSound, levelGoal.transform.position, 2.0);
}
==============================================================================
이제 우리는 이전에 기록해 두었던 타임라인 기반의 애니메이션을 시작하고 재생이 끝나기를 기다립니다:
==============================================================================
levelGoal.animation.Play();
yield WaitForSeconds (levelGoal.animation.clip.length);
==============================================================================
마지막으로, "Game Over"신을 불러옵니다.
==============================================================================
Application.LoadLevel("GameOver"); //...게임 오버 시퀀스를 보여줍니다.
}
==============================================================================
다음 우리는 우주선 모델이 레벨이 시작되었을 때 트리거로 설정 돼 있지 않도록 해야 하며 또한 playerLink가 Player 게임객체를 가리키도록 해야 합니다. 우리는 스크립트가 불러질 때 유니티에 의해 자동으로 호출 되는 Awake()함수 안에서 playerLink 변수를 정의할것입니다.
==============================================================================
private var playerLink: GameObject;
function Awake()
{
levelGoal.GetComponent(MeshCollider).isTrigger = false;
playerLink = GameObject.Find("Player");
if (!playerLink)
Debug.Log("Could not get link to Lerpz");
levelGoal.GetComponent(MeshCollider).isTrigger = false; // 이 부분을 확실히!
}
==============================================================================
마지막으로 우리는 업데이트된 스크립트의 속성을 아래와 같이 설정해야합니다:
Level Status 스크립트 속성의 마지막 설정.
결과적으로, 사용자가 모든 연료통을 모으고 우주선으로 뛰어들면, 아래와 같이 보일 것입니다:
임무 완수! 우리의 영웅이 새 모험을 위한 이륙을 하고 있습니다.
다음 챕터에서는 최적화 기술에 대해 알아볼 것입니다.
본 자료를 다른 곳에 개제 하실 때에는 아래의 번역과 출처를 명확히 밝혀 주시기 바랍니다.
본 자료는 제3자가 상업적인 용도로 사용 할 수 없음을 밝힙니다.
번역 : 유니티코리아 [U3K]게임인생
출처 : 유니티코리아(www.unity3dkorea.com
'Game Engine > Unity' 카테고리의 다른 글
No.12 Unity 3D Platform Tutorial "Script Appendix" [보너스 - 스크립트 부록] (0) | 2010.08.09 |
---|---|
No.11 Unity 3D Platform Tutorial "Optimizing" [완결] (0) | 2010.08.09 |
No.9 Unity 3D Platform Tutorial "Audio & Finishing Touches #1" (0) | 2010.08.09 |
No.8 Unity 3D Platform Tutorial "Adversaries" (0) | 2010.08.09 |
No.7 Unity 3D Platform Tutorial "The GUI #2" (0) | 2010.08.09 |