2010-02-09 8 views
21

저는 Java 2D 및 Newtonian 물리학을 사용하는 간단한 게임을 디자인하고 있습니다. 현재 내 주요 "게임 루프는"같은 :OO 방식의 게임 디자인

기업이 현재의 힘이 적용 기반으로 속도와 위치를 조정합니다 자동으로 업데이트하도록 지시
do { 
    for (GameEntity entity : entities) { 
    entity.update(gameContext); 
    } 

    for (Drawable drawable : drawables) { 
    drawable.draw(graphics2d); 
    } 
} while (gameRunning); 

. 그러나 나는 다른 행동을 나타 내기 위해 엔티티가 필요하다. 예 : "나쁜 녀석"이 선수에 의해 발사되는 경우 엔티티는 파괴되어 게임 세계에서 제거되어야합니다.

내 질문 : 객체 지향 방식으로 이것을 수행하는 가장 좋은 방법은 무엇입니까? 지금까지 본 모든 예에서는 게임 루프를 Game 등의 God 클래스에 통합하여 다음 단계를 수행합니다. 충돌 감지, 나쁜 사람 살해, check-if-player-killed, 다시 칠 등 모든 게임 상태 (남은 생명 등)를 캡슐화합니다. 즉, 절차입니다. 모든 로직은 Game 클래스에 있습니다. 누구든지 더 나은 접근법을 추천 할 수 있습니까?

여기에 지금까지 생각했던 옵션입니다

  • 는 기업이 게임 상태를 필요한 경우 자체를 제거하거나 업데이트 할 수있는 각 개체에 GameContext 전달 (예 :이 경우 "실행되지"하는 플레이어가 죽임).
  • GameEntity을 중앙 Game 클래스의 청취자로 등록하고 이벤트 지향 접근 방식을 사용합니다. 예 : 충돌이 발생하면 두 참가자에게 충돌이 발생하여 CollisionEvent이 발생합니다.
+2

가 나는 버그를 발견 한 것 같아요 - (gameRunning)는'당신이 원하는하면서'이다 –

답변

14

나는 두 개의 상용 게임 엔진과 긴밀하게 협력하고 그들은 유사한 패턴을 따르

  • 객체가 아니라 전체 개체 (물리적, 렌더링 가능한, 어떤처럼) 게임 엔티티의 구성 요소 나 측면을 나타냅니다를 . 각 유형의 구성 요소에는 구성 요소가있는 각 엔티티 인스턴스에 대해 하나씩 구성 요소의 거대한 목록이 있습니다.

  • '게임 엔티티'유형 자체는 고유 한 ID입니다. 각각의 거대한 구성 요소 목록에는 엔티티 ID에 해당하는 구성 요소 (있을 경우)를 찾기위한 맵이 있습니다.

  • 구성 요소가 업데이트해야하는 경우 서비스 또는 시스템 개체에서 호출됩니다. 각 서비스는 게임 루프에서 직접 업데이트됩니다. 또는 종속성 그래프에서 업데이트 순서를 결정하는 스케줄러 개체에서 서비스를 호출 할 수 있습니다.

    • 당신은 자유롭게 모든 조합에 대한 새로운 클래스를 작성하거나 복잡한 상속을 나무를 사용하지 않고 기능 을 결합 할 수 있습니다 : 여기

    이 방법의 장점이다. 당신이 빛 은 자동차 경주 또는 스카이 박스와 공통점이 무엇을 (게임 엔티티의 기본 클래스에 넣어 수에 대한 모든 게임 실체를 가정 할 수 거의 기능이 있습니다

  • ?)

  • 룩 - 업 비싼 보일 수 있지만 서비스가 모든 구성 요소 특정 유형의 을 반복 하여 집중적 인 작업의 대부분을 을하고 있습니다 ID - 투 - 컴포넌트. 이 경우 하나의 깔끔한 목록에 필요한 모든 데이터를 저장하는 것이 좋습니다.

+0

@ 에반 : 답변 해 주셔서 감사합니다. 나는 당신에게 물어보기로 한 것입니다 :이 경우 엔 엔티티의 제거를 어떻게 처리합니까? 예를 들어, Collidable 애스펙트가 있고 CollisionManager가 충돌을 감지하면 엔티티가 제거되어야합니다. 아마도 CollisionManager는 엔티티의 Collidable 측면만을 참조하기 때문에 다양한 목록에서 엔티티 (Drawable, Collidable 등)의 모든 ** 측면을 제거하기 위해 어떤 접근 방식을 취합니까? – Adamski

+1

내가 언급하지 않은 누락 된 부분은 메시지 또는 이벤트입니다. 각 시스템은 모든 메시지 유형에 가입하거나 메시지를 게시 할 수 있습니다. 물리 시스템은 게임 플레이 시스템이 가입 할 수있는 "충돌"메시지를 게시 할 수 있으며 응답으로 "엔티티 삭제"메시지를 게시 할 수 있습니다. 엔티티를 생성하고 삭제하는 다른 시스템은 엔티티 삭제 메시지 유형에 가입 할 수 있습니다. 이것은 직접 함수 호출보다 많은 작업이지만, 모든 것이 디커플링이라는 이름입니다. –

6

우리가 작업 한 특정 엔진에서 우리는 그래픽 표현과 논리를 분리 한 다음 원하는 것을 위해 메시지를 보낼 개체를 가지고있었습니다. 우리는 로컬 시스템이나 네트워크에 게임을 존재시킬 수 있고 코드 관점에서 서로 구별 할 수 없도록이 작업을 수행했습니다. (명령 패턴)

우리는 실제 물리 모델링을 즉시 변경할 수있는 별도의 객체로 수행해야했습니다. 이것은 중력 등으로 쉽게 엉망이되게합니다.

우리는 이벤트 구동 코드 (리스너 패턴)와 많은 타이머를 많이 사용했습니다.

예를 들어 충돌 이벤트를 수신 할 수있는 교차 가능한 개체에 대한 기본 클래스가 있습니다. 건강 상자에 서브 클래 싱했습니다. 충돌시 플레이어 엔터티에 충돌하면 명령을 충돌자에게 보내 건강을 얻고 메시지를 보내어 들리는 모든 사람에게 소리를 보내고 충돌을 비활성화하고 애니메이션을 활성화하여 그래픽을 제거합니다 장면 그래프를 만들고, 나중에 다시 인스턴스를 생성 할 타이머를 설정합니다. 그것은 복잡하게 들리지만 정말로 그렇지 않았습니다.

12 년이 지난 후 우리는 장면의 추상적 개념을 가지고 있었기 때문에 게임은 일련의 장면이었습니다. 장면이 끝나면 일반적으로 명령을 보내 현재 장면을 내리고 다른 장면을 시작하는 이벤트가 발생했습니다.

+0

감사합니다 - 여기에 좋은 조언. – Adamski

+0

이벤트 호출/레지스트리/처리 및 데이터를 용이하게하기 위해 여기서 중개자 패턴을 사용하는 것이 좋습니다. 그렇지 않으면 모든 하위 시스템과 게임 엔티티를 서로 연결해야합니다. – dvide

3

메인 게임 클래스가 있기 때문에 모든 로직이 해당 클래스에서 발생해야한다고 동의하지 않습니다.

동안 단순화 여기 그냥 내 지점을 확인하기 위해 예를 흉내 :

이제
mainloop: 
    moveEntities() 
    resolveCollisions() [objects may "disappear"/explode here] 
    drawEntities()  [drawing before or after cleanEntitites() ain't an issue, a dead entity won't draw itself] 
    cleanDeadEntities() 

당신은 버블 클래스가 있습니다

Bubble implements Drawable { 

handle(Needle needle) { 
    if (needle collide with us) { 
     exploded = true; 
    } 
} 

draw (...) { 
    if (!exploded) { 
     draw(); 
    } 
    } 
} 

그래서, 물론, 돌봐 메인 루프있다 엔티티간에 메시지를 전달하지만 Bubble과 Needle 사이의 충돌과 관련된 논리는 Game 클래스의 주 게임에는 분명 없습니다.

나는 귀하의 경우에도 운동과 관련된 모든 논리가 주 수업에서 일어나지 않는다고 확신합니다.

나는 "모든 논리가 주류에서 일어난다"는 당신의 성명서에 당신이 굵은 글씨로 적었던 것에 동의하지 않습니다.

이것은 단순히 올바르지 않습니다.

좋은 디자인 : 게임의 다른 "보기"(예 : 미니 맵)를 쉽게 제공 할 수 있고 "프레임 단위의 완벽한 재생기"를 쉽게 코딩 할 수 있으면 디자인은 그다지 좋지 않습니다. 즉, 입력과 시간 만 기록하면 재생 된 게임을 정확하게 재현 할 수 있어야합니다. Age of Empires, Warcraft 3 등이 재생 : 그것은 사용자 입력 및 기록 된 시간 (재생 파일이 일반적으로 너무 작음)입니다.).

+0

감사합니다. 나는 게임 루프를 완전히 제거하는 것을 옹호하지 않았습니다. 가능한 한 간단하게 유지하는 것이 좋습니다. – Adamski

1

game은 모델과 뷰를 분리하여 유지하는 실험이었습니다. 관찰자 패턴을 사용하여 게임의 상태 변화를 뷰에 알리지 만, 이벤트는 더 풍부한 컨텍스트를 제공합니다. 원래이 모델은 키보드 입력으로 구동되었지만 분리로 인해 타이머 구동 애니메이션을 쉽게 추가 할 수있었습니다.

부록 : 게임의 모델을 별도로 유지해야하지만 필요한만큼 많은 클래스에 해당 모델을 다시 추가 할 수 있습니다.

2

필자의 엔진 (raw & dirty)을 작성했지만 괜찮은 OO 모델이있는 미리 빌드 된 엔진은 Ogre입니다. 나는 그것을 (개체 모델/API) 살펴 보길 권합니다. 노드 할당은 다소 펑키하지만, 더 많이 보면서 이해할 수 있습니다. 또한 실용적인 게임 예제를 통해 매우 잘 설명됩니다.

나는 몇 가지 트릭을 직접 배웠다.

+0

좋은 물건 - 그것을 체크 아웃합니다. – Adamski