게임 속의 배우가 스스로를 그릴 책임이 있습니까?


41

저는 게임 개발에 익숙하지 않지만 프로그래밍에는 익숙하지 않습니다.

JavaScript canvas요소를 사용하여 Pong 유형 게임을하고 있습니다.

Paddle다음 속성을 가진 객체를 만들었습니다 ...

  • width
  • height
  • x
  • y
  • colour

또한 다음 Pong과 같은 속성 을 가진 객체가 있습니다 ...

  • width
  • height
  • backgroundColour
  • draw().

draw()방법은 현재 재설정 중이며 canvas질문이 발생한 곳입니다.

해야 Paddle객체가이 draw()그 도면에 대한 방법은 책임, 또는해야 draw()Pong객체가 배우 그리기에 대한 책임 (내가 잘못된거야 만약 내가 그 올바른 용어입니다 가정, 저를 수정하시기 바랍니다).

나는이 것이 advantagous 될 것이라고 생각 Paddle나는 두 개체의 인스턴스로, 그 자체를 그려을 Player하고 Enemy. 가에없는 경우 Pongdraw(), 두번 유사한 코드를 작성해야 할 것입니다.

가장 좋은 방법은 무엇입니까?

감사.


답변:


49

액터가 스스로 그리는 것은 좋은 디자인이 아닙니다. 두 가지 주요 이유가 있습니다 :

1) 렌더 코드를 삽입하기 전에 다른 작업을 수행했을 것으로 예상되는 단일 책임 원칙을 위반 합니다.

2) 확장이 어렵다. 모든 액터 유형이 자체 드로잉을 구현하고 일반적으로 그리는 방식을 변경해야하는 경우 많은 코드를 수정해야 할 수도 있습니다. 상속을 과도하게 사용하지 않으면 이것을 어느 정도 완화 할 수 있지만 완전히는 아닙니다.

렌더러가 그림을 처리하는 것이 좋습니다. 결국, 이것이 렌더러라는 의미입니다. 렌더러의 draw 메소드는 "렌더링 설명"객체를 가져야하며 여기에는 사물을 렌더링하는 데 필요한 모든 것이 포함되어 있습니다. 색상과 같은 (예상 적으로 공유 된) 지오메트리 데이터, 인스턴스 특정 변환 또는 재료 속성에 대한 참조. 그런 다음, 그 표현을 묘사하는 것이 무엇인지에 대해서는 신경 쓰지 않습니다.

그러면 액터는 자신이 생성 한 렌더 설명을 유지할 수 있습니다. 액터는 일반적으로 논리 처리 유형이므로 필요에 따라 상태 변경을 렌더 설명으로 푸시 할 수 있습니다. 예를 들어 액터가 손상을 입으면 렌더 설명의 색상을 빨간색으로 설정하여이를 나타낼 수 있습니다.

그런 다음 모든 보이는 액터를 간단하게 반복하고 렌더 설명을 렌더러에 넣은 다음 해당 작업을 수행하도록 할 수 있습니다 (기본적으로 더 일반화 할 수 있음).


14
"렌더러 드로잉 코드"의 경우 +1이지만 단일 책임 원칙의 경우 -1로 프로그래머가 good보다 더 많은 해를 끼쳤습니다 . 그것은 올바른 생각을 가지고 있지만 ( 문제의 분리) , 그것이 언급 된 방식 ( "모든 수업은 오직 하나의 책임을 가져야하고 그리고 / 또는 변경해야 할 이유는 하나만 있어야합니다")잘못 입니다.
BlueRaja-대니 Pflughoeft

2
BlueRaja가 지적했듯이 1의 경우 -1-이 원칙은 이상적이지만 실용적이지는 않습니다. 확장을 크게 어렵게 만들지 않기 때문에 2의 경우 -1입니다. 전체 렌더링 엔진을 변경해야하는 경우 액터 코드에 포함 된 것보다 더 많은 코드를 변경해야합니다. actor.draw(renderer,x,y)보다 훨씬 선호 합니다 renderer.draw(actor.getAttribs(),x,y).
corsiKa

1
좋은 대답입니다! 글쎄 "당신은 단일 책임 원칙을 위반하지 않을 것"은 내 십계명에 속하지는 않지만 여전히 고려해야 할 좋은 원칙입니다.
FxIII

@glowcoder 요점은 아닙니다. actor.draw ()는 {renderer.draw (mesh, attribs, transform); }. OpenGL에서는 struct RenderDetail { glVAO* vao; int shader; int texture; Matrix4f* transform; }렌더러를 다소 유지 합니다. 그런 식으로 렌더러는 데이터가 나타내는 것을 신경 쓰지 않고 처리합니다. 이 정보를 바탕으로 그리기 호출 순서를 정렬하여 전반적인 GPU 호출을 줄 일지 여부도 결정할 수 있습니다.
감속

16

방문자 패턴은 여기에 유용 할 수 있습니다.

할 수있는 일은 호출 할 (특정) 렌더러 메소드를 결정하는 각 액터에 각 오브젝트를 그리는 방법과 자신을 그리는 방법을 알고있는 Renderer 인터페이스입니다.

interface Renderer {
    void drawPaddle(Player owner, Rectangle position);
    // Note: the Renderer chooses the Color based on which player the paddle belongs to

    // Also drawBackground, drawBall etc.
}

interface Actor {
    void draw(Renderer renderer);
}

class Paddle implements Actor {
    void draw(Renderer renderer) {
        renderer.drawPaddle(this.owner, this.getBounds());
    }
}

이런 식으로 다른 그래픽 라이브러리 나 프레임 워크로 포팅하는 것은 여전히 ​​쉽습니다 (한 번 게임을 Swing / Java2D에서 LWJGL로 포팅했으며이 패턴을 사용하는 대신 매우 기뻤 Graphics2D습니다).

또 다른 장점이 있습니다 : 렌더러는 액터 코드와 별도로 테스트 할 수 있습니다


2

귀하의 예에서 Pong 객체가 draw ()를 구현하고 자신을 렌더링하도록하고 싶습니다.

이 규모의 프로젝트에서 큰 이익을 얻지는 못하지만 일반적으로 게임 논리와 시각적 표현 (렌더링)을 분리하는 것은 가치있는 활동입니다.

이것에 의해 update ()가 될 수있는 게임 오브젝트가 있지만 렌더링 방법을 모릅니다. 시뮬레이션에만 관심이 있습니다.

그런 다음 Pong 객체에 대한 참조가있는 PongRenderer () 클래스가 있고 Pong () 클래스 렌더링을 담당합니다. 이에는 Paddles 렌더링 또는 PaddleRenderer 클래스가 처리해야 할 수 있습니다.

이 경우 우려의 분리는 클래스가 부풀어 질 수 있음을 의미하는 상당히 자연스러운 것이므로, 사물이 렌더링되는 방식을 수정하기가 더 쉬워지고 더 이상 시뮬레이션의 계층 구조를 따를 필요가 없습니다.


-1

당신이 그것을 할 것 인 경우에 Pong코드를 복제 할 필요가의 무승부 (), 당신은 wouldnt가 '- 단순히 전화 Paddle하여 패의 각각의 무승부 () 함수를. 그래서 당신 Pong의 draw ()에서

humanPaddle.draw();
compPaddle.draw();

-1

모든 객체는 게임 업데이트 코드 또는 드로우 코드에 의해 호출되어야하는 자체 드로우 기능을 포함해야합니다. 처럼

class X
{
  public void Draw( )
  {
     // Do something 
  } 
}

class Y
{
  public void Draw( )
   { // Do Something 
   } 
}

class Game
{
  X objX;
  Y objY;

  @Override
  public void OnDraw( )
  {
      objX.Draw( );
      objY.Draw( ); 
  } 
}

이것은 코드가 아니라 그리기 개체를 수행하는 방법을 보여주기위한 것입니다.


2
이것은 "도면 작성 방법"이 아니라 단일 방법입니다. 이전 답변에서 언급 했듯이이 방법에는 몇 가지 단점이 있으며 이점은 거의 없지만 다른 패턴에는 상당한 이점과 유연성이 있습니다.
Troyseph

고맙지 만 장면에 액터를 그리는 다양한 방법에 대한 간단한 예를 들었으므로이 방법을 언급했습니다.
user43609
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.