이 페이지에서는 스크립터블 객체를 로직 컨테이너로 사용하는 방법에 대해 설명합니다. 이렇게 하면 필요할 때 호출할 수 있는 델리게이트 객체 또는 작은 작업 묶음으로 취급할 수 있습니다.
이 가이드는 전자책과 함께 제공되는 데모를 통해 Unity 개발자를 지원하기 위해 제작된 6개의 미니 가이드 시리즈 중 네 번째입니다, 스크립터블 오브젝트로 Unity에서 모듈식 게임 아키텍처 만들기.
이 데모는 고전적인 공과 패들 아케이드 게임 메커니즘에서 영감을 얻은 것으로, 스크립터블 오브젝트가 테스트 가능하고 확장 가능하며 디자이너 친화적인 컴포넌트를 만드는 데 어떻게 도움이 되는지 보여줍니다.
전자책, 데모 프로젝트, 이 미니 가이드는 Unity 프로젝트에서 스크립터블 오브젝트 클래스와 함께 프로그래밍 디자인 패턴을 사용하기 위한 모범 사례를 제공합니다. 이러한 팁은 코드를 간소화하고 메모리 사용량을 줄이며 코드 재사용성을 높이는 데 도움이 될 수 있습니다.
이 시리즈에는 다음 문서가 포함되어 있습니다:
스크립터블 오브젝트 데모 프로젝트와 이 미니 가이드 시리즈를 살펴보기 전에 디자인 패턴의 핵심은 아이디어에 불과하다는 점을 기억하세요. 모든 상황에 적용되지는 않습니다. 이러한 기술을 통해 Unity 및 스크립터블 오브젝트로 작업하는 새로운 방법을 배울 수 있습니다.
각 패턴에는 장단점이 있습니다. 특정 프로젝트에 의미 있게 도움이 되는 것만 선택하세요. 디자이너가 Unity 에디터에 크게 의존하고 있나요? 스크립터블오브젝트 기반 패턴은 개발자와의 협업을 돕는 좋은 선택이 될 수 있습니다.
궁극적으로 가장 좋은 코드 아키텍처는 프로젝트와 팀에 맞는 아키텍처입니다.
전략 패턴을 사용하면 인터페이스 또는 기본 스크립터블 오브젝트 클래스를 정의한 다음 런타임에 해당 델리게이트 오브젝트를 상호 교환할 수 있도록 만들 수 있습니다.
한 가지 애플리케이션은 특정 작업을 수행하기 위한 알고리즘을 스크립터블 객체로 캡슐화한 다음 다른 작업의 컨텍스트에서 해당 스크립터블 객체를 사용하는 것입니다.
예를 들어, 적 유닛 클래스를 위한 AI 또는 경로 찾기 시스템을 작성하는 경우 경로 검색 기술(예: A*, Dijkstra 등)을 사용하여 스크립터블 오브젝트를 생성할 수 있습니다.
적 유닛 자체에는 실제로 경로 찾기 로직이 포함되지 않습니다. 대신 별도의 "전략" 스크립터블 객체에 대한 참조를 유지합니다. 이 설계의 핵심은 객체를 교환하는 것만으로 다른 알고리즘으로 바꿀 수 있다는 것입니다. 런타임에 다양한 동작을 선택할 수 있는 한 가지 방법입니다.
모노비헤이비어가 작업을 수행해야 할 때 자체 메서드가 아닌 스크립터블 오브젝트의 외부 메서드를 호출합니다. 예를 들어 스크립터블 오브젝트에는 적 유닛을 구동하고 목적지를 지정하기 위한 MoveUnit 또는 SetTarget에 대한 공용 메서드가 포함될 수 있습니다.
추상 베이스 클래스나 인터페이스를 사용하여 이 패턴을 개선할 수 있습니다. 이렇게 하면 전략을 구현하는 스크립터블 객체를 다른 스크립터블 객체로 교체할 수 있습니다. 이 핫스왑 가능한 스크립터블 오브젝트는 런타임에 즉시 참조하는 모노비헤이비어에 '플러그'됩니다.
게임 조건으로 인해 적 유닛이 동작을 변경해야 하는 경우, 외부 컨텍스트(모노비헤이비어)에서 해당 조건을 확인할 수 있습니다. 그런 다음 다른 스크립터블 오브젝트를 응답으로 연결할 수 있습니다.
구현 세부 사항을 스크립터블 오브젝트로 분리하면 팀 간의 책임 분담도 더 원활하게 할 수 있습니다. 한 개발자는 스크립터블 오브젝트 내부의 알고리즘에 집중하고, 다른 개발자는 모노비헤이비어 컨텍스트에서 작업할 수 있습니다.
이 플러그 가능한 동작을 만들려면 다음과 같이 하세요:
- 전략의 기본 클래스 또는 인터페이스를 정의합니다: 이 클래스 또는 인터페이스에는 전략을 실행하는 데 필요한 메서드와 프로퍼티가 포함되어야 합니다.
- 스크립터블 오브젝트 클래스를 생성합니다: 각 전략은 서로 다른 구현 방식을 제공할 수 있습니다. 예를 들어 간단한 AI 알고리즘을 구현하는 클래스와 더 복잡한 알고리즘을 구현하는 클래스를 만들 수 있습니다.
- 전략을 구현하는 스크립터블 오브젝트를 만듭니다: 누락된 로직을 채우고 필요한 값으로 인스펙터를 채웁니다.
- 상황에 맞게 전략을 활용하세요: 모노비헤이비어에서 스크립터블 오브젝트에 구현된 메서드와 프로퍼티를 호출합니다. 이러한 메서드를 더 쉽게 호출하려면 종속성을 매개변수로 전달하세요.
이렇게 코드를 정리하면 동일한 전략의 다른 구현 간에 쉽게 전환할 수 있습니다. 이렇게 플러그 가능한 동작을 사용하면 디버깅 및 유지 관리가 더 쉬워집니다.
알고리즘이나 전략이 복잡할 필요는 없습니다. 예를 들어, 패들볼소 프로젝트는 심플오디오델리게이트에서 상당히 기본적인 오디오 재생 시스템을 보여줍니다.
추상 클래스인 AudioDelegateSO는 AudioSource 매개변수를 받아들이는 단일 Play 메서드를 정의합니다. 그런 다음 구체적인 구현에서 이를 재정의합니다.
SimpleAudioDelegateSO 서브클래스는 오디오 클립의 배열을 정의합니다. 임의의 클립을 선택하고 재정의된 재생 메서드 구현을 사용하여 재생합니다. 이렇게 하면 사용자 지정 범위 내에서 피치 및 볼륨에 변화가 추가됩니다.
몇 줄에 불과하지만 아래 코드 스니펫으로 다양한 오디오 효과를 만들 수 있습니다.
이 특정 예제는 오디오를 많이 사용하는 데는 적합하지 않지만, 여기서는 전략 패턴에서 스크립터블 오브젝트의 기본 사용 데모로 제시합니다.
디자이너는 코드를 건드리지 않고도 다양한 스크립터블 오브젝트를 생성하여 음향 효과를 표현할 수 있습니다. 다시 말하지만, 기본 스크립터블 오브젝트가 완성되면 개발자의 최소한의 지원만 필요합니다.
이제 패들볼소에서는 누구나 공이 레벨 벽 중 하나에 부딪힐 때 재생할 새로운 사운드 배열을 설정할 수 있습니다. 디자이너는 에디터에서 전적으로 작업하기 때문에 창의적인 독립성과 유연성을 확보할 수 있습니다. 이 접근 방식을 사용하면 개발자가 더 이상 모든 디자인 결정을 지원할 필요가 없으므로 프로그래밍 리소스를 확보할 수 있습니다.
패턴 데모에서 오디오 예시를 볼 수도 있습니다. 각 사운드는 인스턴스마다 약간의 차이가 있는 약간 다른 SimpleAudioDelegateSO 에셋에서 파생됩니다.
이 예제에서는 각 코너에 오디오 소스가 포함되어 있습니다. 커스텀 오디오 모디파이어 모노비헤이비어는 스크립터블 오브젝트 기반 델리게이트를 사용하여 사운드를 재생합니다.
음높이의 차이는 각 스크립터블 오브젝트 에셋의 설정(BeepHighPitched_SO, BeepLowPitched_SO 등)에서만 발생합니다.
스크립터블 오브젝트를 사용하여 액션 로직을 제어하면 디자인 팀이 아이디어를 더 쉽게 실험할 수 있습니다. 이를 통해 디자이너는 개발자로부터 보다 독립적으로 작업할 수 있습니다.
패들볼소 프로젝트도 목표 시스템에서 전략 패턴을 사용합니다. 런타임에 변경할 필요는 없지만 각 객체를 스크립터블 오브젝트로 캡슐화하면 승패 조건을 유연하게 테스트할 수 있습니다.
추상 베이스 클래스인 ObjectiveSO는 목표의 이름과 완료 여부와 같은 값을 보유합니다.
그런 다음 ScoreObjectiveSO와 같은 구체적인 서브클래스는 각 목표를 완료하는 방법에 대한 실제 로직을 구현합니다. ObjectiveSO의 CompleteObjective 메서드를 재정의하고 승리 조건 로직을 추가하여 이를 수행합니다.
플레이어가 특정 점수를 달성하거나 특정 수의 적을 처치해야 하나요? 특정 위치에 도착하거나 특정 품목을 픽업해야 하나요? 이는 스크립터블 오브젝트 기반 목표가 될 수 있는 일반적인 승리 조건입니다.
ObjectiveManager는 스크립터블 오브젝트에 대한 더 큰 컨텍스트 역할을 합니다. ObjectiveSO 목록을 유지 관리하고 각 스크립터블 오브젝트에 의존하여 완료 여부를 판단합니다. 모든 ObjectiveSO에 완료 상태가 표시되면 게임이 종료된 것입니다.
예를 들어 점수 목표를 구현하는 한 가지 방법을 보여주는 ScoreObjectiveSO가 있습니다:
- 커스텀 플레이어 점수 구조체는 플레이어 ID, 인터페이스의 UI 요소, 실제 점수 값과 일치합니다.
- ScoreManager 컴포넌트가 업데이트될 때마다 목표는 승리 조건을 확인합니다.
- 플레이어의 점수가 m_TargetScore를 충족하거나 초과하면 우승한 PlayerScore 오브젝트를 이벤트로 전송합니다.
ObjectiveManager는 주어진 모든 목표가 완료되었는지 여부만 확인합니다. 각 목표 자체의 세부 사항을 인식하지 못합니다.
다시 말하지만, 여기서 목표는 모듈화입니다. 이렇게 하면 기존 ObjectiveSO에 영향을 주지 않고 각 ObjectiveSO를 사용자 지정할 수 있습니다.
패들볼소 게임의 목표는 단 하나뿐입니다. 플레이어 중 한 명이 승리 점수 목표에 도달하면 게임 플레이가 종료됩니다.
그러나 이를 확장하거나 목표를 결합하여 더 복잡한 목표 시스템을 만들 수도 있습니다. 실험을 통해 새로운 게임 모드(예: 시간이 다 되기 전에 최소 점수 획득)를 만들 수 있는지 알아보세요.
로직이 스크립터블오브젝트 안에 캡슐화되어 있으므로 ObjectiveSO를 다른 것으로 바꿀 수 있습니다. 새로운 승리 조건을 만들려면 ObjectiveManager에서 목록을 재구성하기만 하면 됩니다. 어떤 의미에서 목표는 주변 컨텍스트에 '플러그인'하는 것입니다.
ObjectiveSO의 편리한 기능 중 하나는 게임 오브젝트 간에 메시지를 전송하는 데 사용되는 이벤트입니다. 다음으로 스크립터블 오브젝트를 사용하여 이 이벤트 중심 아키텍처를 구현하는 방법을 살펴보겠습니다.
스크립터블 오브젝트를 사용한 디자인 패턴에 대한 자세한 내용은 전자책에서 확인하세요. 스크립터블 오브젝트로 Unity에서 모듈식 게임 아키텍처 만들기. 다음에서 일반적인 Unity 개발 디자인 패턴에 대한 자세한 내용을 확인할 수도 있습니다. 게임 프로그래밍 패턴으로 코드 수준 높이기.