Programming 

씬 불러오기

 

작성 기준 버전 :: 2019.2

 

[이 포스트의 내용은 유튜브 영상으로도 시청하실 수 있습니다]

 

유니티 엔진의 씬은 게임의 맵이나 레벨 개념에 해당한다. 그리고 대부분의 게임은 하나보다 많은 맵이나 레벨, 즉 씬으로 구성된다. 그래서 게임에서 다른 씬으로 넘어가기 위해서는 씬과 씬 사이를 이동하기 위해서 다른 씬을 불러오는 방법을 알아야 한다.

 

씬 세팅하기

 

 

먼저 프로젝트를 제일 처음 생성했을 때 있는 씬에 큐브 오브젝트를 생성하고 카메라 앞 왼쪽 화면에 보이게 적당히 배치한 다음 씬을 저장한다. [Ctrl + S] 단축키를 누르면 간단하게 씬의 변경 내용을 저장할 수 있다.

 

그리고 프로젝트 뷰의 Scenes 폴더 아래에 지금 로드되어 있는 씬인 Sample Scene의 이름을 Scene1로 변경한다.

 

그 다음에는 이 Scene1에서 이동하게 될 새로운 씬을 생성하자.

 

 

프로젝트 뷰에 우클릭하고 [Create > Scene] 항목을 선택하면 새로운 씬을 생성할 수 있다. 새로 생성한 씬의 이름은 Scene2로 한다.

 

 

이렇게 생성한 씬 애셋을 더블 클릭하면 하이어라키에 열려있던 씬이 Scene1에서 Scene2로 바뀐다.

 

 

그리고 Scene2에는 Shpere 게임 오브젝트를 생성해서 카메라 앞 오른쪽 화면에 보이게 배치한다. 이렇게 하면 Scene1에 있다가 Scene2를 불러오면 화면 앞에 있는 게임 오브젝트의 모양이 바뀌면서 씬이 바뀌었다는 것을 명확하게 알 수 있을 것이다.

 

Scene2를 저장하고 다시 Scene1로 돌아간다.

 

SceneMover 스크립트 작성하기

 

그 다음에는 SceneMover라는 이름으로 C# 스크립트를 생성하자.

 

using UnityEngine.SceneManagement;

 

제일 먼저 스크립트의 상단에 using UnityEngine.SceneManagement; 라는 코드를 작성한다. 이 코드는 개발자가 스크립트 에디터에게 "SceneMover.cs 파일에서 UnityEngine.SceneManagement 네임스페이스에 들어있는 씬과 관련된 기능을 사용하겠다"라고 알려주는 역할을 한다.

 

참고로 네임스페이스라는 것은 C#에서 특정한 기능을 묶어두는 데 주로 사용된다.

 

여기 UnityEngine.SceneManagement 네임스페이스에서는 유니티 엔진의 씬과 관련된 기능들이 담겨있다.

 

public class SceneMover : MonoBehaviour

{

    void Update()

    {

        if(Input.GetKeyDown(KeyCode.Space))

        {

            SceneManager.LoadScene("Scene2");

        }

    }

}

 

네임스페이스 선언이 끝나면 Update 함수에서 스페이스 키를 입력을 받았을 때, SceneManager.LoadScene 함수를 호출하게 만든다. 이 함수로 다른 씬을 불러올 수 있다. 

 

매개변수에 불러오고자하는 씬의 이름이나 번호를 넣으면 된다. 우리는 Scene1에서 Scene2로 이동할 생각이기 때문에 Scene2라는 이름을 넣어주면 된다.

 

코드를 저장하고 에디터로 돌아가서 게임 오브젝트를 하나 만들고 거기에 SceneMover 컴포넌트를 추가한다.

 

 

그리고 플레이 버튼을 누르고 스페이스 키를 눌러보면 Scene2라는 씬이 빌드 세팅에 추가되지 않았거나 애셋 번들로부터 불러올 수 없어서 로드할 수 없다는 로그가 나온다.

 

유니티에서 씬을 불러오기 위해서는 씬이 저장된 애셋 번들이 있든지 아니면 씬이 빌드 세팅에 추가되어 있어야 한다.

 

빌드 세팅에 씬 추가하기

 

씬을 빌드 세팅에 추가 시켜보자.

 

 

우선 상단 메뉴바에서 [File > Build Settings...] 항목을 선택하면 빌드 세팅 창이 열린다.

 

 

창 위쪽에 비어있는 Scenes In Build 칸을 볼 수 있는데 여기에 추가된 씬들은 게임에 포함되어 빌드된다.

 

만들어둔 Scene1과 Scene2를 Scenes In Build 칸에 끌어다 놓으면 Scenes In Build 칸에 추가한 씬이 표시될 것이다.

 

빌드 세팅 창을 끄고 다시 플레이를 시킨 뒤, 스페이스 버튼을 눌러보면 Scene1에서 Scene2로 이동하면서 Cube 오브젝트가 사라지고 Sphere 오브젝트가 나타난다.

 

이게 바로 제일 기본적인 씬 이동 방법이다.

 

Additive로 씬 불러오기

 

첫 번째 방법은 씬을 완전히 이동하는 방법이었다면 이번에는 기존의 씬을 남겨둔 상태로 새로운 씬을 겹쳐서 불러오는 방법을 알아보자.

 

public class SceneMover : MonoBehaviour

{

    void Update()

    {

        if(Input.GetKeyDown(KeyCode.Space))

        {

            SceneManager.LoadScene("Scene2", LoadSceneMode.Additive);

        }

    }

}

 

매개변수 "Scene2"뒤에 콤마(,)를 찍으면 두 번째 매개변수로 넣을 수 있는 옵션이 나타나는데, 형식이 LoadSceneMode 열거형인 것을 알 수 있다.

 

LoadSceneMode 모드에는 Single과 Addtive, 두 가지가 있는데 우선 Single은 기본 옵션으로 앞에서 구현한 것처럼 씬을 불러오면 이전 씬은 완전히 사라지고 새로운 씬으로 바뀌는 옵션이다. 그리고 Additive는 앞의 씬을 남겨두고 거기에 얹어서 새로운 씬을 불러오는 것이다.

 

두 번째 매개변수에 LoadSceneMode.Additive를 넣어준 뒤 코드를 저장하고 에디터로 돌아가서 게임을 플레이 시킨 다음에 스페이스 키를 누르면 Scene1이 남아있는 상태로 Scene2가 불러와지는 것을 볼 수 있다.

 

다만 콘솔 창을 보면 로그가 굉장히 많이 발생하고 씬을 불러오기 전보다 매우 밝은 것을 알 수 있는데, 이것은 씬 안에 소리를 감지하는 Audio Listener라는 컴포넌트와 Directional Light가 두 개가 있어서 발생하는 문제이다. 그리고 메인 카메라도 중복으로 두 개가 있는 상태이다.

 

이런 문제들 때문에 Addtive로 불러올 씬에는 불필요한 카메라나 Directional Light를 만들지 않는 것이 좋다.

 

비동기 방식 씬 불러오기

 

지금까지 사용한 LoadScene 함수는 동기 방식 함수이다. 이게 무슨 의미인가하면 LoadScene 함수로 씬을 호출하면 씬을 불러오는 과정이 끝날 때까지 다른 일을 아무 것도 하지 못한다는 뜻이다.

 

이 예시처럼 씬에 고작 오브젝트가 몇 개만 있는 게임이라면 LoadScene 함수만으로 씬을 불러와도 되겠지만 최신 게임들처럼 씬 하나에 엄청나게 많은 오브젝트들이 들어있는 무거운 게임이라면 씬을 불러오는 긴 시간동안 아무 것도 하지 못하게 될 것이다.

 

다른 씬을 불러오는 도중에 팁을 보여준다든지 플레이어에게 미니 게임을 할 수 있게 한다든지 해서 씬이 불러와지는 시간에 플레이어가 지루함을 느끼지 않도록 하려면 다른 작업을 처리할 수 있어야 한다. 거기에 필요한게 비동기 방식 씬 불러오기이다.

 

public class SceneMover : MonoBehaviour

{

    void Update()

    {

        if(Input.GetKeyDown(KeyCode.Space))

        {

            StartCoroutine(LoadSceneCoroutine());

        }

    }

 

    IEnumerator LoadSceneCoroutine()

    {

        yield return SceneManager.LoadSceneAsync("Scene2");

    }

}

 

LoadSceneAsync 함수를 사용하면 함수가 씬을 불러오는 도중에 다른 작업을 처리할 수 있게 된다.

 

단, 이 함수를 제대로 사용하려면 코루틴과 함께 사용해야 한다.

 

코드를 저장하고 에디터로 돌아가서 게임을 플레이 시킨 다음 스페이스 키를 누르면 사실 눈에 띄는 변화는 없다.

 

비동기 씬 로딩이 효과가 있으려면 그만큼 불러올 씬이 무겁고 불러올게 많아야 의미가 있다.

 

비동기 씬 불러오기 방식을 응용하는 방법은 아래의 포스트에서 확인할 수 있다.

 

[로딩 화면 구현하기(UI 방식)]

 

[로딩 화면 구현하기(로딩 씬 방식)]

반응형

Amazon Web Services .NET 용 비동기 API


.NET Framework 4.5, Windows Store 및 Windows Phone 8 용 비동기 API


.NET 용 AWS SDK는 .NET Framework 버전 4.5, Windows Store 및 Windows Phone 8에 대한 새로운 작업 기반 비동기 패턴을 사용한다. async 및 await 키워드를 사용하면 차단하지 않고 모든 AWS 제품에 대한 비동기 작업을 수행하고 관리 할 수 있다. 작업 기반 비동기 패턴에 대한 자세한 내용은 MSDN의 작업 기반 비동기 패턴 (TAP)을 참조하면 된다.



.NET Framework 3.5 용 비동기 API


.NET 용 AWS SDK는 .NET 클라이언트 클래스에 의해 노출 된 대부분의 메소드 호출의 비동기(async)버전을 지원한다. 비동기 메소드를 사용하면 서비스의 응답에 코드 블록이 없어도 AWS 서비스를 호출 할 수 있다. 예를 들어 Amazon S3 또는 DynamoDB에 데이터를 쓰도록 요청한 다음 AWS가 요청을 처리하는 동안 코드가 다른 작업을 계속하도록 할 수 있다.


비동기 요청 메서드의 구문


AWS 서비스에 비동기 요청을 하는 데에는 두 가지 단계가 있다. 첫 번째는 요청에 대한 Begin 메서드를 호출하는 것이다. 이 메서드는 비동기 작업을 시작한다. 해당 End 메서드는 서비스에서 응답을 검색하고 작업 중에 발생할 수 있는 예외를 처리 할 수 있는 기회를 제공한다.

참고

End 메서드를 호출 할 필요는 없다. 오류가 없다고 가정하면 End를 호출했는지 여부에 관계없이 비동기 작업이 완료된다.


Begin 메서드 구문


PutItemRequest와 같은 리퀘스트 오브젝트 매개변수를 가져 오는 것 외에도 비동기 Begin 메서드는 두 가지 추가 매개변수인 콜백 함수와 상태 오브젝트를 사용한다. Begin 메서드는 서비스 리퀘스트 오브젝트를 반환하는 대신 IAsyncResult 형식의 결과를 반환합니다. 이 유형의 정의에 대해서는 MSDN 설명서를 참조하면 확인할 수 있다.


동기식 메서드

PutItemResponse PutItem( PutItemRequest putItemRequest )


비동기식 메서드

IAsyncResult BeginPutItem( GetSessionTokenRequest getSessionTokenRequest, {AsyncCallback callback}, {Object state} )


AsyncCallback 콜백

비동기 작업이 완료되면 콜백 함수가 호출된다. 함수가 호출되면 IAsyncResult 유형의 단일 매개 변수를 받는다. 콜백 함수는 다음의 시그니처를 가진다.

void Callback( IAsyncResult asyncResult )


오브젝트 상태(Object state)

세 번째 매개변수인 state는 asyncResult 매개변수의 AsyncState 속성, 즉 asyncResult.AsyncState로 콜백 함수에서 사용할 수있는 사용자 정의 오브젝트이다.


패턴 호출(Calling Patterns)

  • 콜백 함수와 상태 객체 전달.
  • 콜백 함수를 전달하지만 상태 객체에 null을 전달한다.
  • 콜백 함수와 상태 객체 모두에 대해 null을 전달한다.

이 주제는 이러한 각 패턴의 예를 제공한다.


IAsyncResult.AsyncWaitHandle 사용


경우에 따라 Begin 메서드를 호출하는 코드가 비동기 작업이 완료될 때까지 대기하도록 호출하는 다른 메서드를 사용해야 할 수도 있다. 이러한 상황에서는 WaitHandle이 IAsyncResult 반환 값의 IAsyncResult.AsyncWaitHandle 속성에서 반환한 메서드를 전달할 수 있다. 그런 다음 이 메서드는 이 WaitHandle에서 WaitOne을 호출하여 비동기 작업이 완료될 때까지 대기할 수 있다.


예제


뒤의 모든 예제는 모두 다음 초기화 코드를 통해서 초기화 되었다고 가정한다.

public static void TestPutObjectAsync()
{
  // Create a client AmazonS3Client

  // AmazonS3Client 클라이언트를 생성한다.
  client = new AmazonS3Client();

  PutObjectResponse response;
  IAsyncResult asyncResult;

  //
  // Create a PutObject request

  // PutObject 요청을 생성한다.
  //
  // You will need to use your own bucket name below in order
  // to run this sample code.

  // 이 샘플 코드를 실행하려면 아래에 자신의 버킷 이름을 사용해야 한다.
  //
  PutObjectRequest request = new PutObjectRequest
  {
    BucketName = "{PUT YOUR OWN EXISTING BUCKET NAME HERE : 당신이 가진 실제 버킷 이름을 여기에 넣어라}",
    Key = "Item",
    ContentBody = "This is sample content..."
  };

  //
  // additional example code

  // 추가 예제 코드
  //
}


지정된 콜백이 없는 경우(No Callback Specified)


다음 예제 코드에서는 BeginPutObject를 호출하고 작업을 수행한 다음 EndPutObject를 호출하여 서비스 응답을 검색한다. EndPutObject에 대한 호출은 try 블록에 포함되어 작업 중에 발생할 수 있는 예외를 잡는다.


asyncResult = client.BeginPutObject(request, null, null);


while ( ! asyncResult.IsCompleted )

{
  //
  // Do some work here

  // 작업을 여기서 처리한다.
  //
}


try

{
  response = client.EndPutObject(asyncResult);
}
catch (AmazonS3Exception s3Exception)

{
  //
  // Code to process exception

  // 예외 처리 코드
  //
}



간단한 콜백(Simple Callback)


이 예제에서는 다음 콜백 함수가 정의되어 있다고 가정한다.


public static void SimpleCallback(IAsyncResult asyncResult)
{
  Console.WriteLine("Finished PutObject operation with simple callback :
간단한 콜백으로 PutObject 작업 완료");
}


다음 코드는 BeginPutObject를 호출하고 위의 콜백 함수를 지정한다. PutObject 작업이 완료되면 콜백 함수가 호출된다. 단순 콜백 함수는 asyncResult 매개 변수의 AsyncState 속성에 액세스하지 않기 때문에 BeginPutObject를 호출하면 state 매개 변수에 null이 지정된다. 호출 코드나 콜백 함수는 EndPutObject를 호출하지 않는다. 따라서 서비스 응답이 효과적으로 삭제되고 작업 중에 발생하는 예외는 무시된다.


asyncResult = client.BeginPutObject(request, SimpleCallback, null);



클라이언트와의 콜백(Callback with Client)


이 예제에서는 다음 콜백 함수가 정의되어 있다고 가정한다.


public static void CallbackWithClient(IAsyncResult asyncResult)
{
  try

  {
    AmazonS3Client s3Client = (AmazonS3Client) asyncResult.AsyncState;
    PutObjectResponse response = s3Client.EndPutObject(asyncResult);
    Console.WriteLine("Finished PutObject operation with client callback :
클라이언트 콜백으로 PutObject 작업 완료");
  }
  catch (AmazonS3Exception s3Exception)

  {
    //
    // Code to process exception

    // 예외 처리 코드
    //
  }
}


다음 코드는 BeginPutObject를 호출하고 앞의 콜백 함수를 지정한다. PutObject 작업이 완료되면 콜백 함수가 호출된다. 이 예제에서 BeginPutObject를 호출하면 state 매개 변수에 대한 AmazonS3 클라이언트 객체가 지정된다. 콜백 함수는 클라이언트를 사용하여 EndPutObject 메소드를 호출하고 서버 응답을 검색한다. 콜백이 EndPutObject를 호출할 때 연산 중에 발생한 모든 예외가 수신되므로이 호출은 try 블록 내에 배치된다.


asyncResult = client.BeginPutObject(request, CallbackWithClient, client);



상태 오브젝트를 사용한 콜백(Callback with State Object)


이 예제에서는 다음 클래스와 콜백 함수가 정의되어 있다고 가정한다.


class ClientState
{
  AmazonS3Client client;
  DateTime startTime;

  public AmazonS3Client Client
  {
    get { return client; }
    set { client = value; }
  }

  public DateTime Start
  {
    get { return startTime; }
    set { startTime = value; }
  }
}


public static void CallbackWithState(IAsyncResult asyncResult)
{
  try

  {
    ClientState state = asyncResult.AsyncState as ClientState;
    AmazonS3Client s3Client = (AmazonS3Client)state.Client;
    PutObjectResponse response = state.Client.EndPutObject(asyncResult);
    Console.WriteLine("Finished PutObject. Elapsed time(
완료된 PutObject. 경과 시간) : {0}", (DateTime.Now - state.Start).ToString());
  }
  catch (AmazonS3Exception s3Exception)

  {
    //
    // Code to process exception

    // 예외 처리 코드
    //
  }
}


다음 코드는 BeginPutObject를 호출하고 위의 콜백 함수를 지정한다. PutObject 작업이 완료되면 콜백 함수가 호출된다. 이 예제에서 BeginPutObject에 대한 호출은 state 매개변수에 대해 이전에 정의된 ClientState 클래스의 인스턴스를 지정한다. 이 클래스는 AmazonS3 클라이언트와 BeginPutObject가 호출된 시간을 포함한다. 콜백 함수는 AmazonS3 클라이언트 객체를 사용하고 EndPutObject 메소드를 호출하여 서버 응답을 검색한다. 콜백은 작업의 시작 시간을 추출하여 비동기 작업이 완료되는 데 걸리는 시간을 출력하는 데 사용한다.


이전 예제와 마찬가지로 EndPutObject가 호출될 때 작업 중에 발생하는 예외가 수신되므로 이 호출은 try 블록 내에 배치된다.


asyncResult = client.BeginPutObject( request, CallbackWithState, new ClientState { Client = client, Start = DateTime.Now } );



완성된 샘플


다음 코드 샘플은 비동기 요청 메서드를 호출 할 때 사용할 수있는 패턴을 보여준다.


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;

using Amazon;
using Amazon.Runtime;
using Amazon.S3;
using Amazon.S3.Model;

namespace async_aws_net
{
   class ClientState
   {
      AmazonS3Client client;
      DateTime startTime;

      public AmazonS3Client Client
      {
         get { return client; }
         set { client = value; }
      }

      public DateTime Start
      {
         get { return startTime; }
         set { startTime = value; }
      }
   }

   class Program
   {
      public static void Main(string[] args)
      {
         TestPutObjectAsync();
      }

      public static void SimpleCallback(IAsyncResult asyncResult)
      {
         Console.WriteLine("Finished PutObject operation with simple callback");
         Console.Write("\n\n");
      }

      public static void CallbackWithClient(IAsyncResult asyncResult)
      {
         try

         {
            AmazonS3Client s3Client = (AmazonS3Client) asyncResult.AsyncState;
            PutObjectResponse response = s3Client.EndPutObject(asyncResult);
            Console.WriteLine("Finished PutObject operation with client callback");
            Console.WriteLine("Service Response:");
            Console.WriteLine("-----------------");
            Console.WriteLine(response);
            Console.Write("\n\n");
         }
         catch (AmazonS3Exception s3Exception)

         {
            //
            // Code to process exception
            //
         }
      }

      public static void CallbackWithState(IAsyncResult asyncResult)
      {
         try

         {
            ClientState state = asyncResult.AsyncState as ClientState;
            AmazonS3Client s3Client = (AmazonS3Client)state.Client;
            PutObjectResponse response = state.Client.EndPutObject(asyncResult);
            Console.WriteLine("Finished PutObject operation with state callback that started at {0}",

                (DateTime.Now - state.Start).ToString() + state.Start);
            Console.WriteLine("Service Response:");
            Console.WriteLine("-----------------");
            Console.WriteLine(response);
            Console.Write("\n\n");
         }
         catch (AmazonS3Exception s3Exception)

         {
            //
            // Code to process exception
            //
         }
      }

      public static void TestPutObjectAsync()
      {
         // Create a client
         AmazonS3Client client = new AmazonS3Client();

         PutObjectResponse response;
         IAsyncResult asyncResult;

         //
         // Create a PutObject request
         //
         // You will need to change the BucketName below in order to run this
         // sample code.
         //
         PutObjectRequest request = new PutObjectRequest
         {
           BucketName = "PUT-YOUR-OWN-EXISTING-BUCKET-NAME-HERE",
           Key = "Item",
           ContentBody = "This is sample content..."
         };

         response = client.PutObject(request);
         Console.WriteLine("Finished PutObject operation for {0}.", request.Key);
         Console.WriteLine("Service Response:");
         Console.WriteLine("-----------------");
         Console.WriteLine("{0}", response);
         Console.Write("\n\n");

         request.Key = "Item1";
         asyncResult = client.BeginPutObject(request, null, null);
         while ( ! asyncResult.IsCompleted )

         {
           //
           // Do some work here
           //
         }
         try

         {
           response = client.EndPutObject(asyncResult);
         }
         catch (AmazonS3Exception s3Exception)

         {
           //
           // Code to process exception
           //
         }

         Console.WriteLine("Finished Async PutObject operation for {0}.", request.Key );
         Console.WriteLine("Service Response:");
         Console.WriteLine("-----------------");
         Console.WriteLine(response);
         Console.Write("\n\n");

         request.Key = "Item2";
         asyncResult = client.BeginPutObject(request, SimpleCallback, null);

         request.Key = "Item3";
         asyncResult = client.BeginPutObject(request, CallbackWithClient, client);

         request.Key = "Item4";
         asyncResult = client.BeginPutObject(request, CallbackWithState,
            new ClientState { Client = client, Start = DateTime.Now } );

         Thread.Sleep( TimeSpan.FromSeconds(5) );
      }
   }
}



참고사항


반응형

+ Recent posts