렌더 로직을 GameObject 클래스 밖으로 옮기기위한 전술


10

게임을 만들 때 종종 모든 개체가 상속하는 다음 게임 개체를 만듭니다.

public class GameObject{
    abstract void Update(...);
    abstract void Draw(...);
}

따라서 루프를 업데이트하면 모든 게임 오브젝트를 반복하고 상태를 변경할 수있는 기회를 제공 한 다음 다음 드로우 루프에서 모든 게임 오브젝트를 다시 반복하고 스스로 그릴 수있는 기회를 제공합니다.

간단한 포워드 렌더러를 사용하는 간단한 게임에서는 꽤 잘 작동하지만 종종 모델, 여러 텍스처 및 게임 오브젝트 사이에 긴밀한 결합을 만드는 팻 드로우 방법을 저장해야하는 거대한 게임 오브젝트로 이어집니다. 현재의 렌더링 전략 및 렌더링 관련 클래스

렌더링 전략을 앞으로에서 지연으로 변경하려면 많은 게임 오브젝트를 업데이트해야합니다. 그리고 내가 만든 게임 객체는 재사용 할 수 없습니다. 물론 상속 및 / 또는 구성은 코드 복제와 싸우고 구현 변경을 조금 더 쉽게 만들 수 있지만 여전히 부족하다고 느낍니다.

더 좋은 방법은 GameObject 클래스에서 Draw 메서드를 모두 제거하고 Renderer 클래스를 만드는 것입니다. 게임 오브젝트는 여전히 어떤 모델로 표현할 것인지, 어떤 텍스처를 모델에 페인트해야하는지와 같은 비주얼에 관한 데이터를 포함해야하지만, 렌더링 방법은 렌더러에게 맡겨야합니다. 그러나 렌더링에는 종종 테두리가 많이 있기 때문에 GameObject에서 렌더러로의 긴밀한 커플 링이 제거되지만 렌더러는 여전히 모든 게임 오브젝트에 대해 알고 있어야합니다. 단단히 결합. 이것은 몇 가지 좋은 관행을 위반합니다. 아마도 데이터 지향 디자인이 트릭을 수행 할 수 있습니다. 게임 오브젝트는 확실히 데이터 일 것이지만, 렌더러는 어떻게 이것에 의해 구동됩니까? 잘 모르겠습니다.

그래서 나는 길을 잃었고 좋은 해결책을 생각할 수 없습니다. 나는 MVC의 원칙을 사용하려고 시도했지만 과거에는 게임에서 그것을 사용하는 방법에 대한 아이디어가 있었지만 최근에는 생각했던 것처럼 적용되지 않습니다. 여러분 모두이 문제를 해결하는 방법을 알고 싶습니다.

어쨌든 다음과 같은 디자인 목표를 달성하는 방법에 관심이 있습니다.

  • 게임 오브젝트에 렌더링 로직이 없습니다
  • 게임 오브젝트와 렌더 엔진 간의 느슨한 결합
  • 아는 렌더러
  • 렌더 엔진 간의 런타임 전환

이상적인 프로젝트 설정은 별도의 '게임 로직'과 서로 참조 할 필요가없는 렌더 로직 프로젝트입니다.

존 카맥 (John Carmack)은 트위터에 그가 유연하게 시스템을 가지고 있다고 말하면서 런타임에 렌더링 엔진을 교체 할 수 있고 시스템에 렌더러 (소프트웨어 렌더러 및 하드웨어 가속 렌더러)를 사용하도록 지시 할 수 있다는 생각에 기차가 시작되었다. 동시에 차이점을 검사 할 수 있습니다. 지금까지 프로그래밍 한 시스템은 그처럼 유연하지 않습니다.

답변:


7

커플 링을 해제하는 빠른 첫 단계 :

게임 오브젝트는 비주얼이 무엇인지에 대한 식별자를 참조하지만 데이터는 아닙니다. 문자열과 같은 간단한 것을 말합시다. 예 : "human_male"

렌더러는 "human_male"참조를로드 및 유지 관리하고 사용할 핸들을 객체로 다시 전달합니다.

끔찍한 의사 코드의 예 :

GameObject( initialization parameters )
  me.render_handle = Renderer_Create( parameters.render_string )

- elsewhere
Renderer_Create( string )

  new data handle = Resources_Load( string );
  return new data handle

- some time later
GameObject( something happens to me parameters )
  me.state = something.what_happens
  Renderer_ApplyState( me.render_handle, me.state.effect_type )

- some time later
Renderer_Render()
  for each renderable thing
    for each rendering back end
        setup graphics for thing.effect
        render it

- finally
GameObject_Destroy()
  Renderer_Destroy( me.render_handle )

어쨌든 현실 세계 객체와 같은 것을보고 책임에 따라 OOP로 바꾸는 순수한 OOP에서 단순한 변화로 조건이 충족됩니다.

  • 게임 오브젝트에 렌더링 로직이 없음 (완료, 모든 오브젝트가 알고있는 것은 핸들이므로 자신에게 효과를 적용 할 수 있음)
  • 게임 오브젝트와 렌더 엔진 사이의 느슨한 결합
  • 아는 렌더러가 아님 (완료, 자신에 대해서만 알고 있음)
  • 렌더 엔진 간의 런타임 전환이 바람직합니다 (렌더러 _Render () 단계에서 수행되며 두 백엔드를 작성해야 함).

클래스의 간단한 리팩토링을 넘어서 검색 할 수있는 키워드는 "엔티티 / 컴포넌트 시스템"및 "종속성 주입"및 잠재적으로 "MVC"GUI 패턴으로 기존의 뇌 기어를 회전시킬 수 있습니다.


이것은 내가 전에 한 것과는 매우 다릅니다. 잠재적 인 잠재력이있는 것처럼 들립니다. 운 좋게도 나는 기존 엔진에 제약을받지 않아서 땜질 할 수 있습니다. 의존성 주입은 항상 내 뇌를 아프게하지만, 언급 한 용어를 찾아 볼 것입니다.
Roy T.

2

내 엔진을 위해 한 일은 모든 것을 모듈로 그룹화하는 것입니다. 그래서 나는 GameObject수업을 가지고 있으며 다음과 같은 핸들을 가지고 있습니다.

  • ModuleSprite-스프라이트 그리기
  • 모듈 무기-총기
  • ModuleScriptingBase-스크립팅
  • 모듈 입자-입자 효과
  • ModuleCollision-충돌 감지 및 응답

나는 그래서 Player클래스와 Bullet클래스를. 둘 다에서 파생 GameObject되고에 추가됩니다 Scene. 그러나 Player다음과 같은 모듈이 있습니다.

  • 모듈 스프라이트
  • 모듈 무기
  • 모듈 입자
  • 모듈 충돌

그리고 Bullet이러한 모듈이 있습니다

  • 모듈 스프라이트
  • 모듈 충돌

일을 조직하는이 방법은 당신이 가지고있는 "죽음의 다이아몬드"방지 Vehicle하는 VehicleLand과를 VehicleWater지금 당신이 원하는을 VehicleAmphibious. 대신 당신은 a를 가질 Vehicle수 있고 a ModuleWater와 a를 가질 수 있습니다 ModuleLand.

추가 된 보너스 : 일련의 속성을 사용하여 객체를 만들 수 있습니다. 기본 유형 (Player, Enemy, Bullet 등) 만 알고 있으면 해당 유형에 필요한 모듈에 대한 핸들을 만듭니다.

내 장면에서 다음을 수행합니다.

  • Update모든 GameObject핸들을 호출하십시오 .
  • ModuleCollision핸들 이있는 충돌 검사 및 충돌 응답을 수행하십시오 .
  • 물리 처리 후 최종 위치에 대해 알리려면 UpdatePost모든 GameObject핸들을 호출하십시오 .
  • 플래그가 설정된 오브젝트를 삭제하십시오.
  • m_ObjectsCreated목록 에서 목록으로 새 개체를 추가 m_Objects하십시오.

그리고 객체 단위가 아닌 모듈별로 구성 할 수 있습니다. 그런 다음의 목록을 렌더링하고 ModuleSprite무리를 업데이트 하고 목록 ModuleScriptingBase과 충돌합니다 ModuleCollision.


컴포지션과 같은 소리! 아주 좋아요 그래도 렌더링 팁을 많이 보지 못합니다. 다른 모듈을 추가하여 어떻게 처리합니까?
Roy T.

아, 네. 이는이 시스템의 단점 GameObject입니다. 예를 들어 Sprite의 "뱀"을 렌더링하는 방법에 대한 특정 요구 사항이있는 경우 ModuleSprite해당 특정 기능에 대한 자식을 생성 ModuleSpriteSnake하거나 ( ) 새 모듈을 모두 추가해야합니다 ( ModuleSnake). 다행히 그들은 단지 포인터이야,하지만 난 코드를 본 적이 GameObject문자 그대로 한 모든 객체가 할 수 있습니다.
knight666
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.