• 게임
  • 산업 분야
  • 리소스
  • 커뮤니티
  • 학습
  • 문의하기
개발
Unity 엔진
모든 플랫폼 위한 2D 및 3D 게임 제작
다운로드플랜 및 가격
수익화
인앱 결제/인앱 구매(IAP)
스토어 간 IAP 검색 및 관리
Mediation
수익 / 매출 극대화 및 수익화 / 수익 창출 최적화(하다)
Ad Quality
앱 유저. '광고 지면'의 타겟 고객 경험 보호
탭조이
장기적인 유저. '광고 지면'의 타겟 고객 충성도 구축
모든 수익화 / 수익 창출 제품
사용자 확보
사용자 확보
모바일 사용자를 검색하고 Acquire
Unity 벡터 AI
적합한 게임으로 플레이어 연결
Aura 디바이스 단위 광고
최대 참여/인게이지먼트 시 기기 내 사용자 도달률
모든 성장 제품
활용 부문
3D 협업
실시간 3D 프로젝트 빌드 및 검토
몰입형 교육
몰입도 높은 환경 제작
고객 경험
인터랙티브 3D 경험 제작
모든 업계 솔루션
산업 분야
제조업
운영 우수성 확보
리테일
상점 경험을 온라인 경험으로 전환
자동차
혁신 및 차량 내 경험 향상
전체 산업 분야
테크니컬 라이브러리
기술 자료
공식 유저. '광고 지면'의 타겟 고객 매뉴얼 및 API 레퍼런스
개발자 툴
릴리스 버전 및 이슈 트래커
로드맵
예정된 기능 검토
용어집
기술 용어 라이브러리
분석 자료
활용 사례
실제 성공 사례
베스트 프랙티스 가이드
전문가 팁
모든 리소스
새로운 기능
블로그
업데이트, 정보, 기술 팁
뉴스
뉴스, 스토리, 보도 센터
커뮤니티 허브
토론
토론, 문제 해결, 소통
이벤트
글로벌 이벤트 및 현지 이벤트
커뮤니티 사례
Made with Unity
Unity 크리에이터 소개
Livestreams
개발자, 크리에이터, Insider와의 소통
Unity Awards
전 세계 Unity 크리에이터 축하
모든 레벨 지원
Unity Learn
무료로 Unity 기술 마스터
전문 교육
Unity 강사와 함께 팀의 역량을 강화하세요
Unity 처음 사용하시나요
시작하기
학습 시작하기
Unity 필수 학습 길잡이
Unity 사용이 처음이신가요? 여정 시작하기
사용법 가이드
실용적인 팁 및 베스트 프랙티스
교육
학생용
커리어 시작하기
교육 담당자 대상 교육
교육 효율 극대화
교육 라이선스
교육 기관에 Unity 강력한 기능 도입
자격증
Unity 숙련도를 입증하세요
지원 옵션
도움 받기
성공을 위한 Unity
Success 플랜
전문가 지원을 통해 더 빠르게 목표 도달률 달성
FAQ
일반적인 질문에 대한 답변
문의하기
유니티 팀과 소통하기
플랜 및 가격
언어
  • English
  • Deutsch
  • 日本語
  • Français
  • Português
  • 中文
  • Español
  • Русский
  • 한국어
소셜
통화
구매
  • 제품
  • 유니티 애즈
  • 구독
  • Unity 에셋 스토어
  • 리셀러
교육
  • 학생
  • 교육 담당자
  • 기관
  • 인증 시험
  • 레벨업 아카데미
  • Skills Development Program
다운로드
  • Unity Hub
  • 다운로드 아카이브
  • 베타 프로그램
Unity Labs
  • Labs
  • Publications
리소스
  • Unity 학습 플랫폼
  • 커뮤니티
  • 기술 자료
  • Unity QA
  • FAQ
  • Services Status
  • 활용 사례
  • Made with Unity
Unity
  • 회사
  • 뉴스레터
  • 블로그
  • 이벤트
  • 채용 정보
  • 도움말
  • Press
  • 파트너
  • 투자자
  • 어필리에이트
  • 보안
  • 소셜 임팩트
  • Inclusion & Diversity
  • 문의하기
Copyright © 2025 Unity Technologies
  • 법적 고지 사항
  • 개인정보처리방침
  • 쿠키
  • 개인정보 판매 또는 공유 금지

'Unity', Unity 로고 및 기타 Unity 상표는 미국 및 기타 국가에서 유니티 테크놀로지스 또는 계열사의 상표 또는 등록상표입니다(여기에서 자세한 정보 확인). 기타 명칭 또는 브랜드는 해당 소유자의 상표입니다.

Hero background image
Last updated January 2020, 10 min. read

스크립터블 오브젝트로 게임을 설계하는 세 가지 방법

이 웹페이지는 이해를 돕기 위해 기계 번역으로 제공됩니다. 기계 번역으로 제공되는 콘텐츠에 대한 정확도나 신뢰도는 보장되지 않습니다. 번역된 콘텐츠의 정확도에 관해 의문이 있는 경우 웹페이지의 공식 영어 원문을 참고해 주시기 바랍니다.
여기를 클릭하세요.

이 페이지에서 얻을 수 있는 것: 게임 코드를 쉽게 변경하고 디버그할 수 있도록 Scriptable Objects로 아키텍처를 설계하는 방법에 대한 팁입니다.

이 팁은 Ryan Hipple, Schell Games의 수석 엔지니어로, 게임 아키텍처에 Scriptable Objects를 사용하는 고급 경험을 가진 사람에게서 나왔습니다. Ryan의 Scriptable Objects에 대한 Unite 강연을 여기<4>에서 시청할 수 있습니다; Unity 엔지니어 Richard Fine의 Scriptable Objects에 대한 훌륭한 소개<5> 세션도 추천합니다.

  • 스크립터블 오브젝트란?
  • 게임 엔지니어링의 3대 요소
  • 변수 설계
  • 예: 플레이어의 건강 포인트
  • 이벤트 설계
  • 코드 예제: GameEvent ScriptableObject
  • 코드 예제: GameEventListener
  • 플레이어의 죽음을 처리하는 이벤트 시스템
  • 기타 시스템 설계

스크립터블 오브젝트란?

ScriptableObject는 스크립트 인스턴스와 독립적으로 대량의 공유 데이터를 저장할 수 있게 해주는 직렬화 가능한 Unity 클래스입니다. 스크립터블 오브젝트를 사용하면 변경 사항 및 디버깅을 더 쉽게 관리할 수 있습니다. 게임의 다양한 시스템<1> 간에 유연한 통신 수준을 구축할 수 있어, 제작 과정에서 이를 더 쉽게 변경하고 조정할 수 있으며, 구성 요소를 재사용할 수 있습니다.

게임 엔지니어링의 3대 요소

모듈형 디자인 사용:

  • 서로 직접적으로 의존하는 시스템을 만들지 마십시오. 예를 들어, 인벤토리 시스템은 게임의 다른 시스템과 통신할 수 있어야 하지만, 이들 간에 하드 참조를 만들고 싶지 않습니다. 이는 시스템을 서로 다른 구성과 관계로 재조립하기 어렵게 만듭니다.
  • 장면을 깨끗한 슬레이트로 만드십시오: 장면 간에 일시적인 데이터가 존재하지 않도록 하십시오. 씬을 히트할 때마다 씬이 완전히 브레이크된 후 새로 로드되어야 합니다. 이렇게 하면 다른 장면에 존재하지 않았던 고유한 동작을 가진 장면을 가질 수 있으며, 해킹을 할 필요가 없습니다.
  • 프리팹을 설정하여 독립적으로 작동하도록 하십시오. 가능하면 씬으로 드래그하는 모든 프리팹이 각각의 기능을 포함하도록 해야 합니다. 그러면 팀의 규모가 상대적으로 커서 씬이 여러 프리팹으로 구성되며 각 프리팹이 개별적인 기능을 포함하는 경우에 소스를 컨트롤하기가 매우 수월해집니다. 그렇게 하면 대부분의 체크인은 프리팹 수준에서 이루어져 장면에서의 충돌이 줄어듭니다.
  • 각 구성 요소가 단일 문제를 해결하는 데 집중하도록 하십시오. 이렇게 하면 여러 구성 요소를 조합하여 새로운 것을 만드는 것이 더 쉬워집니다.

부품을 쉽게 변경하고 편집할 수 있도록 하십시오:

  • 게임의 가능한 한 많은 부분을 데이터 기반으로 만드십시오. 게임 시스템을 데이터 처리 기계처럼 설계하면, 게임이 실행 중일 때도 효율적으로 변경할 수 있습니다.
  • 시스템이 가능한 한 모듈화되고 구성 요소 기반으로 설정되어 있다면, 아티스트와 디자이너를 포함하여 이를 편집하기가 더 쉬워집니다. 디자이너가 명시적인 기능을 요청하지 않고 게임에서 사물을 조합할 수 있다면 – 각기 하나의 작업만 수행하는 작은 구성 요소를 구현한 덕분에 – 그들은 새로운 게임 플레이/메커니즘을 찾기 위해 이러한 구성 요소를 다양한 방식으로 결합할 수 있습니다. Ryan은 그의 팀이 게임에서 작업한 가장 멋진 기능 중 일부가 이 과정에서 나왔다고 말하며, 이를 "출현 디자인"이라고 부릅니다.
  • 팀이 런타임에 게임을 변경할 수 있는 것이 중요합니다. 런타임에 게임을 더 많이 변경할 수록, 균형과 값을 찾을 수 있으며, Scriptable Objects처럼 런타임 상태를 저장할 수 있다면, 좋은 위치에 있는 것입니다.

디버그를 쉽게 하세요:

이것은 실제로 첫 두 가지의 하위 기둥입니다. 게임의 모듈화 수준이 높을수록 일부만 따로 테스트하기가 쉬워집니다. 게임을 수정할 수 있는 자유도가 높을수록, 즉 자체 인스펙터 뷰가 있는 기능이 많을수록 디버그하기가 더 쉽습니다. 인스펙터에서 디버그 상태를 볼 수 있도록 하고, 디버그할 계획이 없을 때는 기능이 완성되었다고 생각하지 마세요.

변수 설계

ScriptableObjects로 만들 수 있는 가장 간단한 것 중 하나는 자가 포함된 자산 기반 변수입니다. 아래는 FloatVariable의 예이지만, 이는 다른 직렬화 가능한 유형으로도 확장됩니다.

팀의 모든 사람은 기술적이지 않더라도 새로운 FloatVariable 자산을 생성하여 새로운 게임 변수를 정의할 수 있습니다. 모든 MonoBehaviour 또는 ScriptableObject는 이 새로운 공유 값을 참조하기 위해 공용 float 대신 공용 FloatVariable을 사용할 수 있습니다.

더 나아가, 하나의 MonoBehaviour가 FloatVariable의 값을 변경하면, 다른 MonoBehaviour도 그 변경을 볼 수 있습니다. 이것은 서로 참조할 필요가 없는 시스템 간의 메시징 레이어를 생성합니다.

예: 플레이어의 건강 포인트

예: 플레이어의 건강 포인트

이것의 예시 사용 사례는 플레이어의 체력 포인트(HP)입니다. 로컬 싱글 플레이어 게임에서 플레이어의 HP는 이름이 PlayerHP인 FloatVariable일 수 있습니다. 플레이어가 피해를 입으면 PlayerHP에서 차감되고, 플레이어가 치유되면 PlayerHP에 추가됩니다.

이제 장면에 체력 바 프리팹을 상상해 보세요. 체력 바는 PlayerHP 변수를 모니터링하여 디스플레이를 업데이트합니다. 코드를 변경하지 않아도 PlayerMP 변수와 같은 다른 변수를 쉽게 참조할 수 있습니다. 체력 바는 장면의 플레이어에 대해 아무것도 알지 못하며, 플레이어가 쓰는 동일한 변수에서 읽기만 합니다.

이렇게 설정되면 PlayerHP를 감시할 더 많은 것을 추가하기가 쉽습니다. 플레이어 HP가 낮아지면 음악 시스템이 변경될 수 있으며, 적들은 플레이어가 약하다는 것을 알면 공격 패턴을 변경할 수 있고, 화면 공간 효과는 다음 공격의 위험성을 강조할 수 있습니다. 여기서 중요한 것은 플레이어 스크립트에서 이러한 시스템에 메시지를 보내지 않으며, 시스템이 플레이어 게임 오브젝트에 대해 알 필요도 없다는 점입니다. 게임이 실행 중일 때 인스펙터에서 PlayerHP의 값을 변경하여 테스트할 수도 있습니다.

FloatVariable의 값을 편집할 때, ScriptableObject에 저장된 값을 변경하지 않기 위해 데이터를 런타임 값으로 복사하는 것이 좋습니다. 이렇게 하면 MonoBehaviour는 디스크에 저장된 InitialValue를 편집하지 않도록 RuntimeValue에 접근해야 합니다.

이벤트 설계

Ryan이 ScriptableObjects 위에 구축하는 것을 좋아하는 기능 중 하나는 이벤트 시스템입니다. 이벤트 아키텍처는 서로에 대한 직접적인 정보를 갖고 있지 않은 시스템 간에 메시지를 보내 코드를 모듈화하는 데 도움이 됩니다. 이들은 업데이트 루프에서 지속적으로 모니터링하지 않고도 상태 변화에 반응할 수 있게 해줍니다.

다음 코드 예제는 GameEvent ScriptableObject와 GameEventListener MonoBehaviour의 두 부분으로 구성된 이벤트 시스템에서 가져온 것입니다. 디자이너는 중요 메시지를 나타내는 GameEvent를 프로젝트에 생성하여 보낼 수 있습니다. GameEventListener는 특정 GameEvent가 발생하기를 기다리고 UnityEvent를 호출하여 응답합니다(이는 진정한 이벤트가 아니라 직렬화된 함수 호출에 가깝습니다).

코드 예제: GameEvent ScriptableObject

GameEvent ScriptableObject:

코드 예제: GameEventListener

GameEventListener:

플레이어의 죽음을 처리하는 이벤트 시스템

플레이어의 죽음을 처리하는 이벤트 시스템

이것의 예는 게임에서 플레이어의 죽음을 처리하는 것입니다. 아주 다양한 실행 관련 항목이 변경될 수 있는 지점이지만, 이 모든 로직을 어디에 코딩해야 하는지 결정하기 어려울 수 있습니다. 플레이어 스크립트가 게임 종료 UI나 음악 변경을 트리거해야 할까요? 적이 프레임마다 플레이어가 아직 살아있는지 확인해야 할까요? 이벤트 시스템은 이러한 문제의존성을 피할 수 있게 해줍니다.

플레이어가 죽으면 Player 스크립트가 OnPlayerDied 이벤트에서 Raise를 호출합니다. 플레이어 스크립트는 단순히 브로드캐스트일 뿐이기 때문에 어떤 시스템이 이벤트와 연관되어 있는지 알 필요가 없습니다. 게임 오버(Game Over) UI는 OnPlayerDied 이벤트에 반응하여 애니메이션화를 시작하며, 카메라 스크립트는 화면을 검은색으로 채우기 시작할 수 있으며, 음악 시스템은 음악을 변경할 수 있습니다. 각 적이 OnPlayerDied를 듣고, 조롱 애니메이션을 트리거하거나 대기 행동으로 돌아가는 상태 변화를 일으킬 수 있습니다.

이 패턴은 플레이어의 죽음에 대한 새로운 반응을 추가하는 것을 매우 쉽게 만듭니다. 또한, 테스트 코드나 인스펙터의 버튼에서 이벤트에서 Raise를 호출하여 플레이어의 죽음에 대한 반응을 쉽게 테스트할 수 있습니다.

Schell Games에서 구축한 이벤트 시스템은 훨씬 더 복잡한 것으로 발전하였으며, 데이터 전달 및 자동 생성 유형을 허용하는 기능이 있습니다. 이 예제는 그들이 오늘 사용하는 것의 본질적인 출발점이었습니다.

기타 시스템 설계

Scriptable Objects는 단순한 데이터일 필요는 없습니다. MonoBehaviour를 통해 구현한 시스템을 스크립터블 오브젝트로도 구현할 수 있는지 확인해 보세요. DontDestroyOnLoad MonoBehaviour에 InventoryManager를 두는 대신, ScriptableObject에 넣어보세요.

장면에 묶여 있지 않기 때문에 Transform이 없고 Update 함수도 받지 않지만, 특별한 초기화 없이 장면 로드 간 상태를 유지합니다. 인벤토리에 액세스하기 위한 스크립트가 필요한 경우 싱글톤 대신 인벤토리 시스템 오브젝트에 대한 공용 레퍼런스를 사용하세요. 테스트 인벤토리 또는 튜토리얼 인벤토리를 교체하는 것이 싱글톤을 사용하는 것보다 쉽습니다.

여기에서 플레이어 스크립트가 인벤토리 시스템에 대한 참조를 가져오는 것을 상상할 수 있습니다. 플레이어가 생성될 때 시스템이 플레이어가 소유하고 있던 모든 오브젝트를 인벤토리에 요청하고 장비를 생성할 수 있습니다. 장비 UI는 인벤토리를 참조하고 아이템을 반복하여 무엇을 그릴지 결정할 수 있습니다.