A presentation at 넥슨 개발자 컨퍼런스 2012 in April 2012 in Seoul, South Korea by Jubok Kim
NDC2012 | 김주복 해당 이미지는 DSP 엔터테인먼트의 자산입니다 Ⓒ 2012 NEXON Corporation & devCAT Studio. All Rights Reserved M2 team, Game Development Team for Project M2 in longCAT (The 3rd New Development Division in NEXON Corp.). M2 team Director is Kim, Dong-Gun | Project M2 is produced by Kim, Dong-Gun GT-R team, Engine Development Team for Project M2 and more. GT-R Team Technical Director is Jeon, Hyeong-Kyu
이 강연을 저의 멘붕 방지에 지대한 도움을 주신 카라 멤버 여러분과 DSP 미디어에 헌정합니다 죽어라 들은 건 점핑인데 사진은 루팡 맥락없이 카라 짤이 나오니 양해를…
Previously on NDC2010… NDC2010 – M2 아키텍처 리뷰, 완벽한 MMO 클라이언트 설계에의 도전
컴퍼넌트 시스템 논의의 연장 프로시저 레이어의 문제 해결 방안 등 뻔하고 당연한 이야기 게다가 페이지 수도 글자도 많… 해당 이미지는 네이버 만화와 김성모 프로덕션의 자산입니다
w o r k i n p r o g r e s s 이 강연은 현재 개발 중인 게임의 구현 방식에 대한 것으로, 최종적으로 발매된 게임은 전혀 다른 형태로 구현되어 있을 수도 있음을 알려드립니다
해당 이미지는 DSP 엔터테인먼트의 자산입니다 개념 미제 소고 지속효과 지속효과 클래스 탈출처리 메시지 트랜잭션 피처 의존성 금지와 사건 통지 프리젠테이션 액터 이터레이션 속도 설계 원칙과 인지적 한계 기획자 무용론? 재활용에 대한 관점 설계 목표 재변경
김주복 넥슨12년차|NDC강연6년차 @eiaserinnys | beforu.egloos.com 2001 2001 2003 2005 2006 2008 2009 2010 2011 무선사업팀 도트디자이너 마비노기팀 리드 프로그래머 마비노기 프로그래밍팀 팀장 그 룹 웨 어 개 발 팀 팀 장 W 팀 테 크 니 컬 디 렉 터 개 발 3 본 부 3 실 실 장 마비노기 2 개발 디렉터 신규개발3본부 1실 실장 GDC 엔지니어링 세션 강연
지속효과 지속효과클래스 탈출처리 메시지트랜잭션 피처 해당 이미지는 DSP 엔터테인먼트의 자산입니다
컴퍼넌트의 상호의존성을 전면금지하는 설계를 시험 설계 원칙을 엄밀하게 지키는 것이 유지보수에 더 나은 코드가 될 것이다! NDC2010 – M2 아키텍처 리뷰, 완벽한 MMO 클라이언트 설계에의 도전
익숙하지 않은 설계가 이상한 구현으로 발현 절차와 객체가 서로 책임을 떠넘기는 이상한 세계 NDC2010 – M2 아키텍처 리뷰, 완벽한 MMO 클라이언트 설계에의 도전
나름대로 기준을 세워 프로시저 함수군을 정리 게임의 규칙에 해당하는 함수와 컴퍼넌트를 구성하는 함수로 분류 NDC2010 – M2 아키텍처 리뷰, 완벽한 MMO 클라이언트 설계에의 도전
개별 작업자가 각자 이해한 상태를 기준으로 작업 이 시스템이 뭔지 잘 모르겠긴 한데 일은 해야 하는데 어쩔 거야 수많은 버그로 귀결 일어나다가 다시 쓰러진다거나 위치가 이곳저곳으로 튄다거나 T 포즈로 굳은 채로 이동한다거나 뒷목이 뻣뻣한 채로 디버깅한다거나 어째 아침에 회사 가기가 싫다거나 이게 사는 건가
엔지니어링 리부트란 이름으로 4개월간 진행 개발 진도가 상당히 나간 프로젝트에서는 이례적인 결정 엔지니어링 리부트 OT NDC2011 – 이무림, 고양이가 개발한다
“복합액션(현행 액션) 도입계획” 엔지니어링 리부트 – 복합액션 도입계획
여러 게임 시스템에서 공통적으로 등장 대표적인 사례가 날리기 전작 전투 시스템의 상징과도 같은 시스템 동적 분기가 필요한 몇 가지 변화가 추가 굉장히 간단해 보이는 변화인데…
DefenderReationImplementation:: ProcessHitReaction CCombatant:: ResolveAsAttacker StartBlowAction:: Execute BlowHandlers:: StartBlow StartBlowProcedure Handle TrivialCase CCombatMgr:: ScheduleHitEvent Handle NormalCase ProcessWallCollision (BlowEnd::Fall) AdjustBlowEndByKynapse (BlownEnd::Wall) ReserveBlowEndOperation CombatMgr:: OnAnimationEvent Caction:: CombatBlowAway FallEnd:: Execute WallSmashed::Execute ‘WallSmashed*Blowed’ LifeAndDeath:: FallEnd WallSlide::Execute ‘WallSlide’ ‘WallToSlideToDownPose’ Bounce:: Execute
Write-Only-Code 데이터와 비동기 처리가 연달아 이어짐 사실 작업자는 있는 도구로 성실하게 구현한 것 프로시저 레이어의 혼돈과 맞물려 상승작용 비동기 처리의 중간 단계 코드가 여기저기 파편화되어 존재
액션에는 어떤 효과가 수반되는 것이 보통 공격은 보통 일정 시간 동안 이동과 추가 공격이 불가 피격은 보통 처음부터 끝까지 이동이나 여타 동작이 불가 이동할 수 없고 다른 짓할 수 없고 등등… 마법 시전을 시작하면서 별도 조작계로 변경
효과는 반드시 종료되어야 이전엔 액션 로직 단위로 처리했으나… 시작하는 시점에 설정한 효과를 처리가 종료되는 시점에 일괄 해제 분기가 들어가며 문제 효과가 액션 로직이 바뀌어도 유지되어야 함 분기가 발생할 때 해제하고 다시 설정하면 오동작의 가능성
지옥 입구에 오신 것을 환영합니다 RideHandlers:: RideOnVehicleReplied FinishLiftingExecution:: Execute RideHandlers:: RideOnTurretReplied InterationExecution:: Execute RideHandlers:: RideOnVehicleReplied ItemAction:: DropOrHold ItemAction:: ReleaseItem PickUpItemExecution:: Execute DefenderReactionImpl:: CancelPropLift StartReviveExecution:: Execute ThrowLiftedExecution:: Execute TryLiftingSuccessExecution:: Execute 어쩌지…
정의 게임이 인지하는 객체 동작의 최소 단위 사실 게임 디자이너는 블로우~벽에 부딪히는 동작을 별개라고 인지하지 않는다 ex. 공격 동작, 날리기 과정 전체 등 특성 코드에서 구현 액션 로직의 분기를 처리 끝날 때 종속된 효과를 모두 해제 ☆☆☆ 서로 중첩되지 않음 ☆☆☆ 새로운 액션이 실행되면 이전 액션이 종료됨
괄호 닫기 처리의 완결성 확보 어떤 경로를 타고 실행되더라도 액션이 끝나면 정리됨 서로 중첩되지 않는다는 특성으로부터 가능
당연히 문제들은 산더미처럼 남아있고…
“스테이터스 리뉴얼 계획” 엔지니어링 리부트 – 스테이터스 리뉴얼 계획
ex. 탈것에 탑승 탑승한 상태에는 연결 관계가 성립 애니메이션 포즈를 계산할 때, 탑승물의 특정 본과 탑승자의 특정 본을 연결 내리는 시점에 연결 관계를 해제 문제는…
탑승 – 중립 – 공격 – 중립 – 하차 괄호 닫기 처리를 제대로 하려면 액션보다 큰 단위가 필요
복잡한 종료 조건 중 하나라도 누락하면…
정의 별도의 중립 포즈를 강제하는 지속적인 캐릭터의 상태 ex. 스탠딩→탑승 포즈 특성 ☆☆☆ 액션과 중첩될 수 있음 ☆☆☆ 연관된 액션 셋트를 갖는 일이 많음 끝날 때 종속된 효과를 모두 해제 서로 중첩되지 않음
경험적으로 이런 문제는 뭔가 예쁘게 해결되지 않는다 뭔가 생각지도 못한 상황은 항상 생기고 때우다 보면 코드는 망가지고 퇴근은 늦어지고 가정이 무너지고 국가가 무너지고
스테이터스는 임의의 시점/사유로 종료된다 액션과 스테이터스가 가장 크게 다른 점
연관 없는 시스템의 간섭이 중단의 원인 ex. 필드에 탑승물을 남긴 채로 로그아웃하면 탑승물은 자기 상태를 정리해야 함 조합 폭발의 가능성 새 시스템이 기존 구현을 찾아서 검토해야 함 탑승 → 피격 탑승 → 로그아웃 탑승 → 지역이동 탑승 → 거래 탑승 → 물건 집기 탑승 → …
로그아웃 죽을 때 지역 이동 시 보기만 해도 딱 ‘이 골치아픈 것들…’이란 생각이 드는데,
또 다른 종류의 괄호 닫기, 상태 이상 액션/스테이터스와는 다르다 ex. 독, 스턴, 슬로우와 같은 상태 이상 걸려있는 동안 특정한 효과가 지속 보통 공격(액션)하거나 탑승(스테이터스)하더라도 끊기지 않음
당연하다, 게임의 모든 효과는 둘 중 하나 순간적이고 영구적이거나, 레벨업이 되어 체력의 최대치가 증가하는 연산은 순간적이고 영구적으로 반영된다 지속적이고 단기적이다 독에 걸려 체력이 감소하는 효과는 지속적이고 끝나면 사라지는 단기적인 것이다 vs. 해당 이미지는 Activision Blizzard의 자산입니다
처리하고 지나가면서 잊어버리면 된다 체력을 회복하거나, 위치를 이동하거나… DB에 반영하는 문제로 가면 또 다른 문제가 되긴 하지만
처리가 시간적으로 분산 적용 시점, 지속되는 도중, 종료 시점 등 업데이트 시작 끝
예상할 수 없는 사유의 종료에 대응해야 하기 때문 고로 게임에서 괄호 닫기가 중요한 문제인 것은 너무나 당연 ( )
정의 수명을 가짐 시작/종료 시점과 지속 중 정해진 효과를 실행 ☆☆☆ 종료할 때 괄호 닫기를 수행 ☆☆☆ 모든 효과를 클린업 많은 개념에 연계 여러 동작이 지속효과를 수반 액션, 스테이터스, 상태이상 등 사실 마음에 드는 이름은 아닌데 명확하면서 길지 않은 표현이 잘 없어서… 차라리 괄호 효과라고 할까
( ( ) )
( ( )( )( 중립
지속효과의 속성은 조금씩 다르다 액션 상태이상 스테이터스 예외적 중단 가능? 배타적? × × ○ ○ × ○ 기왕 분류해보는 거 제대로 해보면…
클래스 4 ○ ○ 스테이터스, 다자관계
클래스1 체력감소 ( 예외적중단× 배타적× 독 상태이상 이동금지 ( ( ) 공격 액션 부착관계 탑승관계 스테이터스
클래스1 ( 예외적중단× 배타적× 클래스2 예외적중단○ 배타적○ 독 상태이상 ( ) 이동금지 ( 예외적중단× 배타적○ 클래스4 체력감소 공격 액션 부착관계 탑승관계 스테이터스
클래스1 체력감소 ( 예외적중단× 배타적× 독 상태이상 클래스2 ( 예외적중단× 배타적○ 클래스4 예외적중단○ 배타적○ ( 이동금지 공격 액션 부착관계 탑승관계 스테이터스 )( )( ) 이동금지 피격 중립
예) 탑승, 거래, 컷신… …하다가 맞으면? …하다가 독으로 죽으면? …하다가 네트웍이 끊겨서 로그오프하면? …하다가 (운영자가 불러서) 워프되면?
지역이동 피격 잡기 해제 처리 같은 동작이지만 구현이 다름 탑승 종료 처리 공통이어야 하지만 리전 이동 시에만 처리 중
사건은 지속 효과을 모름 리전이 이동을 알려주기 위해서 탑승, 거래 등에 대해서 다 알아야 하나? 지속 효과는 사건을 모름 탑승, 거래 등이 리전 이동, 로그오프, 피격 등 모든 사건을 다 알아야 하나? 어느 쪽의 책임도 아니다! 중재자를 도입하자!
정의 클래스 4 지속 효과가 예상하지 못한 방식으로 종료되는 경우 클린업하는 처리 “예상된 정상적인 전이가 아닌 경우, 먼저 기존 상태에서 탈출한다”
물론 이걸 아무 대책 없이 대응하는 게임은 당연히 없는데…
ㅁㅂㄴㄱ의 지역 이동 탈출 처리의 의존성 CServerWorld:: CharacterLeaveRegion CCharacter:: OnLeaveRegionBefore CCharacter:: LeaveRegion CCharacter:: OnLeaveRegionBegin CCharacter:: OnLeaveRegionEnd CQuestComponent:: DestroyAllInstantQuests CTransportComponent:: OnLeaveRegionBegin CSummonMaster:: OnLeaveRegion CShowdownComponent:: OnLeaveRegion CDemiGodComponent:: OnLeaveRegion CPetPVPComponent:: OnLeaveRegion CTameMgr:: OnLeaveRegion CFashionComponent:: OnLeaveRegion CAviationComponent:: OnLeaveRegion CTransportComponent:: OnLeaveRegion CEventComponent:: OnLeaveRegion CVehicleComponent:: OnLeaveRegion CConditionComponent:: OnLeaveRegion CJoustComponent:: OnLeaveRegion
현재 지역 이동 탈출 처리의 의존성 ㅁㅂㄴㄱ보다 구현된 시스템 요소 수가 적어서 단순한 요인은 제외하고 GrappleProcedure. EndGrappleAndSync EscapeSequence. EndGrapplingRelation ByGrappler EscapeSequence. EscapeAndSync WorldProcedure. LeaveRegion EscapeSequence. EndGrapplingRelation ByGrappledOne LeanbackProcedure. EndAndSync EscapeSequence. EndLeanBack PropProcedure. SetPropInstaller EscapeSequence. EndRidingRelation PropProcedure. DestroyInstalledProp EscapeSequence. EndCurrentAction ByLeavingRegion RidingProcedure. RideOffVehicleAndSync ActionProcedure. End LocationComponent. OnLeaveRegion
장점 사건/지속효과 양쪽의 코드가 단순해짐 유사한 처리의 파편화를 방지 구현부가 일원화되어 있으므로, 새로운 전이와 모든 조합에 대해서 검토해 보게 됨 단점 탈출 처리기는 모든 사건/지속효과를 알아야 함 손 댈 수 없이 거대한 코드 블록으로 자라날 가능성이 있음 테이블화시켜서 비교적 단순한 형태로 줄이는 것이 가능하리라고 예상 어떻든 문제 해결?
ex. 탑승 중 피격 function 피격 { 탈출처리요청(사유:피격) { 탑승자를 탑승이 아닌 상태로 전환 탑승물을 태운 사람이 없는 상태로 전환 } 피격에 수반되는 실제 처리 } 피격 처리는 이 과정에 대해서 전혀 인지하지 못함
처리가 발생할 때마다 발송하는 경우 클라이언트에서 메시지를 동시에 받지 못함 이후 메시지가 늦게 도착할 경우 이상한 모습이 보이거나 심지어 그 사이에 조작도 가능해짐
전체를 메시지로 보내는 경우 취지에도 어긋나고 논리적으로 불가능 외부에서는 탈출처리에서 어떤 지속효과에 영향을 미칠 지 모르고, 따라서 전체 메시지가 무슨 동작을 해야 할 지 모름 가능하다고 해도 낭비 (각기 다른 탈출처리 이유)×(각기 다른 지속효과)의 조합만큼 메시지를 만들어야 함 On…Handler() 같은 형태로 코드가 만들어지는 이유 사실 이런 형태로 구현하는 것은 메시징 방식의 제약 안에서 문제를 풀어야 하기 때문이기도 함 ………… 완전히 다른 접근이 필요하다는 결론
한 요청에 대한 응답을 한 번에 발송 처리가 발생할 때마다 메시지를 쌓아둠
순차적으로 실행하면서 공지가 필요한 변경을 그때그때 바로 누적
장점 코드가 단순해짐 탈출처리가 적용 가능해지기 때문에 메시지 구성을 위해서 다양한 맥락을 고려하지 않아도 됨 몇 종류의 응답 프로토콜을 범용적으로 활용 예를 들어 특정 락을 걸고 풀거나, 스테이터스를 설정하거나, 액션을 실행하는 등의 간단한 동작은 조합해서 메시지를 발송 이터레이션 가속화의 가능성 해당 이미지는 한승연 본인의 자산입니다 미제를 설명하면서 다시 설명할 예정 단점 메시지의 크기를 통제하기 어려움 작은 메시지를 합산하면서 헤더의 오버헤드가 늘어나고, 얼마나 커질지 파악하기가 어려움 자주 쓰이는 형태의 조합을 컴파일하는 방법으로 최적화가 가능할 것으로 예상 뭐 어쨌든 간에…
지속효과 괄호 닫기를 개념화하여 안전한 클린업을 보장 탈출처리 다른 지속효과간의 전이 과정을 단순화 메시지 트랜잭션 전이 과정을 자연스러운 형태로 코딩 가능
복기: 프로시저 레이어 컴퍼넌트는 다른 컴퍼넌트에 의존 불가 컴퍼넌트 간 협업이 필요한 작업을 프로시저로 분리
복잡하고 불편하다! 한 컴퍼넌트를 두 개로 나눠서 만들어야 함 분류 기준이 없다! 컴퍼넌트 소속이 아닌 프로시저군은 분류가 어렵다
딱히 문제도 아니고 문제가 아닌 것도 아니고… 맞는 방향이란 생각은 드는데 이론적 기반이 없는 것이 문제 객체 지향 패러다임에서 크게 벗어난 접근 지속 가능한 개발 방법론으로 정립할 수 있을지 의문 해당 이미지는 아마도 한승연…본인의 자산입니다
<도메인 주도 설계> ‘소프트웨어의 복잡성을 다루는 지혜’라는 부제 뭔가 막 해결될 것 같은 기분이 든다 레드썬 좀 날림으로 소개를 하자면…
소프트웨어는 도메인 지식의 반영 소프트웨어를 사용하는 사용자의 활동이나 관심사 해결해야 하는 핵심 문제 영역을 의미 은행용 소프트웨어라면 계좌 개설이나 대출 업무 절차에 관한 지식과 개념들 게임이라고 하면 게임 디자인 UI 애플리케이션 도메인 인프라스트럭처
온라인 게임에서는 익숙한 모델 클라이언트 언어가 C++이라 서버까지 객체 지향 패러다임이 강력히 주도한 덕분? OOP 따라서 객체 모델링하고 함수가 쿼리 DB에 직접 날리지 말고 중간에 대리자 넣고… 같은 당연한 이야기 당장의 내용과는 무관하지만 강력히 읽어보실 것을 추천
=객체로 모델링하는 것이 부자연스러운 연산 1. 객체를 구성하는 게 아니라 도메인의 개념과 관련 2. 인터페이스가 모델의 외적 측면에서 정의 3. 연산이 상태를 갖지 않는다 오늘날 흔히 하는 실수는 행위를 적절한 객체로 다듬는 것 을 너무나도 쉽게 포기해서 점점 절차적 프로그래밍에 빠지는 것이다. 하지만 객체의 정의에 어울리지 않는 연산을 강제로 객 체에 포함시킨다면 해당 객체는 자신의 개념적 명확성을 잃어버 리고 이해하거나 리팩터링하기 힘들어질 것이다. 복잡한 연산은 단순한 객체를 손쉽게 궁지로 몰아넣어 해당 객체의 역할을 불 분명하게 만들 수 있다. pp107, 도메인 주도 설계 프로시저 레이어의 특성과 일치! 해당 이미지는 DSP…, 아니 셀카니 아마도 한승연…본인의 자산입니다
게임 로직을 서술하는 서비스 컴퍼넌트를 조작하는 과정을 기술 상태의 정합성은 컴퍼넌트가, 절차는 피처가 책임 독립된 게임 시스템의 기능 집합 게임 디자이너가 보는 게임 시스템의 단위 ‘새로운 기획을 만들었다’고 할 때, 기획 하나와 피처 하나가 대강 대응 ex. 전투, 거래, 마법, 원거리교전, 탑승, …
파트 1에서 지적했던 문제 컴퍼넌트가 메시지를 핸들링하는 것은 설계 원칙에 어긋난다 피처에 두면 된다! 메시지 = 게임 시스템의 기능 명세이므로
Feature ServiceContract RequestA ReplyA RequestB ReplyB : IFeature MessageHandler FunctionA : IFeatureFunction Use() Do() FunctionB IFeatureContract RequestA() 메시지 분배기 로직 처리 ReplyA() = 0 Use() RequestB() Do() ReplyB() = 0 자동생성 클라이언트 서버
메시지 컨트랙트 정의 피처 펑션으로 토스하는 어댑터 피처 구성 메시징 코드 (자동 생성) 피처 펑션
장점 설계 원칙 면에서 깔끔하다! 탈출 처리, 메시지 트랜잭션과 함께 개별 기능 구현이 다른 기능에 의존하지 않는 높은 독립성을 획득 가능 피처와 컴퍼넌트 간의 임피던스 불일치 해결 거래 같은 다자 관계는 하나의 컴퍼넌트에서 해결할 수 없기 때문에 필연적으로 발생 개별 기능 단위로 엄밀하게 가용 조건을 통제 가능 단점 일반적인 설계에 비해 간접층이 늘어남 각각의 구현체가 단순해진 대신, 전체 흐름을 파악하기 위해서 알아야 하는 구조가 늘어남 트레이드 오프?
너무 간단해서 인생이 허무한 지경 Feature : IFeature 컴퍼넌트 레이어 지속 효과들 FunctionA : IFeatureContract IFeatureFunction RequestA() Use() ReplyA() = 0 Do() RequestB() ReplyB() = 0 ActionComponent Flag StatusComponent Flag FunctionB AbnormalCondition Component Use() Do() ActionLockComponent Flag
여러가지 심각한 문제를 해결하긴 했는데… 뭔가 아직도 해결이 미진한 부분이 많고… …결정적으로 새로운 문제들도 수면 위로 부상
의존성 금지와 사건 통지 프리젠테이션 액터 이터레이션 속도 해당 이미지는 DSP 엔터테인먼트의 자산입니다
해당 이미지는 구하라 본인의 자산입니다 1 | 의존성 금지와 사건 통지
불편한 탄생 과정 컴퍼넌트 간 의존성은 강력하게 금지되나 자신의 정합성은 유지해야 함 의존성이 객체만으로 프로그래밍을 한다는 건 불가능한 일 어쩔 수 없이 컴퍼넌트 프로시저 개념이 도출 그 외의 프로시저 코드는 피처의 기능으로 정리되었음 NDC2010 – M2 아키텍처 리뷰, 완벽한 MMO 클라이언트 설계에의 도전
이건 이것대로 해결해야 할 문제 중요한 처리 중 대부분을 컴퍼넌트 프로시저가 수행
상호 의존성을 갖지 못하기 때문에 필연적
프리젠테이션 의존성 금지를 트리거로 해결 많은 경우 프리젠테이션은 제네릭한 트리거를 받아서 해석, 처리
구현체를 보기만 해도 마음이 불편해짐
본질적으로 같은 문제 컴퍼넌트→다른 컴퍼넌트로 사건 전달 로직→프리젠테이션으로 사건 전달 해당 이미지는 구하라 본인의 자산…이었던가 좋은 방법이 없어 숙고 중 다른 시각에서 해결할 수 있지 않을까도 고민 중 eoi
해당 이미지는 박규리 본인의 자산입니다 2 | 프리젠테이션 액터
타입에 따라서 패스가 다른 경우가 보통 로직 프로그래머 입장에서는 수정하기가 어려운 경우가 많다
서버에서는 로직 액터의 생성까지만 관여 프리젠테이션 액터는 로직 액터의 정보를 바탕으로 자신을 구축 로직이 UI에 정보를 통지하지 않고, UI가 로직을 모니터링하는 것과 유사 CharacterTag 로직 프리젠테이션 Animator Inventory RenderActor EquipmentHolder Status AbnormalCondition 로직 생성 이후에 별도 과정으로 구축 SoundActor Particle ControllerBackLink
프리젠테이션 액터를 균일화 게임 디자이너나 아티스트가 ‘얘는 왜 이걸 할 수 없어요?’라고 놀랄 필요가 없음 게임 로직에서 특정한 프리젠테이션 처리가 가능한지 알 필요가 없음 프리젠테이션 쪽에서 게임 로직에 대해서 알 필요가 없음 게임 플레이의 프로토타이핑이나 연출을 시험할 때 좀 더 용이 CharacterTag 로직 Inventory 프리젠테이션 Animator RenderActor EquipmentHolder SoundActor Status AbnormalCondition Particle ControllerBackLink eoi
해당 이미지는 니콜 본인의 자산…아니 구하라던가;; 3 | 느린 이터레이션
프로토타이핑, 빠른 이터레이션의 중요성 프리젠테이션에 투자하면 팔 수 있던 시대가 지나버렸음 주류 (콘솔) 게임이 NDS와 소셜 게임이 가져온 “파괴적 혁신”에 패배 GDC2011 동향보고
라이브 시스템의 복잡도 기존 피처와 상호 작용하므로 독립적 프로토타이핑이 어려움 돌아가는 시스템 위에서 테스트하지 않으면 의미가 없는 경우가 많음
서버-클라이언트 메시징 변경에 재컴파일이 필요 필연적으로 이터레이션 속도의 감소가 동반 ServiceContract RequestA ReplyA Feature : IFeature FunctionA : IFeatureFunction MessageHandler IFeatureContract RequestA() 메시지 분배기 Use() 로직 처리 ReplyA() = 0 Do() 클라이언트 서버
스크립트로 작성된 피처에 전달하면 다운 없는 개발이 가능 Feature ServiceContract RequestA ReplyA : IFeature FunctionA : IFeatureFunction Use() Do() MessageHandler IFeatureContract 메시지 분배기 RequestA() 로직 처리 ReplyA() = 0 스크립트 라우터 스크립트 스크립트 스크립트 스크립트 라우터 클라이언트 서버 eoi
설계 원칙과 인지적 한계 기획자 무용론? 재활용에 대한 관점 설계 목표 재변경 해당 이미지는 DSP 엔터테인먼트의 자산입니다
사실, 프로시저와 피처의 논리적 구조는 동일 설계 원칙 측면에서는 큰 차이가 없으나 인지적 차이는 하늘과 땅 코드가 마음 속의 어떤 모델에 대응하는가 여부가 매우 중요함 분류 방식, 실제 구현 등에서 거의 차이가 없음
올바른 설계에는 인지적인 측면이 중요 설계 원칙으로 해결되지 않는 문제의 판단 기준은 인간의 인지 능력 OAOO를 지켜야 하는 이유가 곰곰히 생각해보면 인간의 인지 능력의 한계 때문 마인드 모델을 공유하기 위해서 노력이 필요 도메인 주도 설계에서 강조하는 것도 일맥상통 엔지니어링 리부트 OT
결론이 난 개념과 구조는 허탈할 정도로 간단 그럼에도 개념을 정제하고 게임 디자이너와 동기화하는데 어려움을 겪음 아니 게임 디자이너가 문제가 아니라 프로그래머들끼리도 힘들었음;;; Feature : IFeature 컴퍼넌트 레이어 지속 효과들 FunctionA : IFeatureContract IFeatureFunction RequestA() Use() ReplyA() = 0 Do() RequestB() ReplyB() = 0 ActionComponent Flag StatusComponent Flag FunctionB AbnormalCondition Component Use() Do() ActionLockComponent Flag
우리 스스로 무엇을 만들고 있는지 정확히 모르고 있기 때문? 합의된 모델을 구현하는 게 아니라 프로그래머가 원하는 대로 구현하는 게 보통 디자인과 불일치하는 구현체에 대해서 게임 디자이너가 통제를 할 방법이 없는 게 당연 게임 로직의 모델을 정식화하고 공유하는 노력이 필요 게임 디자인에 있어서도 팀 전체의 인지적인 한계가 똑같이 문제가 됨 게임 디자이너는 올바른 모델을 제시하기 위해 프로그래밍을 알아야 한다. 반대로, 프로그래머도 게임 디자이너의 모델을 성실하게 구현해야 한다.
목표는 게임 로직 코드를 재활용하는 것이었으나… 로직이 프리젠테이션에 암묵적 의존 관계를 형성하지 않을 수가 없다 그리고 프리젠테이션 의존성은 게임 로직 재활용에 가장 큰 걸림돌 하지만 프리젠테이션을 개선하지 않는다면 게임을 다시 만드는 의미가 없다! 꼭 그런 건 아니지만 많은 경우 그렇다
게임 디자인 도메인에서 개념의 재활용을 목표로 재활용 가능한 개념을 증류하려는 노력이 유효하다고 판단
원칙을 준수하는 설계의 추후 수익률은 높지 않을 전망 → 큰 문제는 해결, 완벽한 설계보다는 인지친화적인 설계가 더욱 중요 게임 디자인을 정확하게 반영하는 설계의 중요성 → 정확한 설계 많은 이터레이션과 게임의 성공 가능성 문제가 부각 → 기민한 설계
‘인지 친화적이고 / 정확하며 / 기민한 설계에의 도전’ ……중언부언이라 결국 파트 3에서도 ‘완벽한’이라고 줄여서 쓸 거 같긴 함 해당 이미지는 DSP 엔터테인먼트의 자산입니다
R e f e r e n c e s 에릭 에반스, 2003“도메인 주도 설계” 김주복, NDC2010“M2 아키텍처 리뷰: 완벽한 MMO 클라이언트 설계에의 도전” 이무림, NDC2011“고양이가 개발한다” 김주복, 2011“GDC2011 동향보고” 김주복, 2011“엔지니어링 리부트 OT” 김주복, 2011“엔지니어링 리부트: 복합액션 도입 계획” 김주복, 2011“엔지니어링 리부트: 스테이터스란 무엇인가” 김주복, 2011“엔지니어링 리부트: 메시지 라우팅 방식 변경” 김주복, 2011“엔지니어링 리부트: 탈출 처리 도입과 이후 진행” Special thanks to“카라 and DSP 미디어”
해당 이미지는 DSP 엔터테인먼트의 자산입니다 @eiaserinnys | beforu.egloos.com 감사합니다 챕터가 모자라서 그만… 미안합니다 지영양
View 프로젝트 M2 아키텍처 리뷰: 완벽한 MMO 클라이언트 설계에의 도전, 파트 2 on Notist.
Dismiss
2010년 파트 1 발표 이후로 <마비노기 2: 아레나>의 클라이언트 아키텍처 설계를 재편한 과정을 소개하며 지속 효과(Ongoing Effect), 탈출 처리, 상태가 없는 피처 컨트랙트 등의 개념을 소개합니다.