많은 작은 다형성 클래스에 대한 유연한 대안 (속성 또는 메시지 또는 이벤트로 사용) C ++


9

내 게임에는 정말 유용하지만 천천히 고통스러워지는 두 가지 클래스가 있습니다. 메시지 및 속성 (속성은 본질적으로 구성 요소입니다).

둘 다 기본 클래스에서 파생되며 정적 ID를 포함하므로 시스템은 원하는 클래스에만주의를 기울일 수 있습니다. 잘 작동하고 있습니다 ... 제외하고 ...

게임을 확장하면서 새로운 메시지 유형과 속성 유형을 지속적으로 만들고 있습니다. 매번 클래스 ID와 하나 또는 두 개의 표준 데이터 유형 또는 포인터를 얻기 위해 2 개의 파일 (hpp 및 cpp)과 1 톤의 상용구를 작성해야합니다.

새로운 아이디어를 실제로 다루기 시작했습니다. 새 메시지 또는 속성 유형을 만들고 싶을 때 다음과 같은 내용을 입력하고 싶습니다.

ShootableProperty:  int gunType, float shotspeed;

ItemCollectedMessage:  int itemType;

헤더와 cpp 파일을 만드는 대신 부모 클래스 등을 포함한 생성자를 작성하는 대신

논리적으로 내 마음에 1 또는 2 줄이있는 것을 수행하는 것은 약 20-40 줄 (가드 포함하고 모든 것을 포함)입니다.

이 문제를 해결할 프로그래밍 패턴이 있습니까?

스크립팅은 어떻습니까? (아무것도 알지 못합니다) ... 거의 동일한 클래스를 정의하는 방법이 있습니까?


한 클래스의 모습은 다음과 같습니다.

// Velocity.h

#ifndef VELOCITY_H_
#define VELOCITY_H_

#include "Properties.h"

#include <SFML/System/Vector2.hpp>

namespace LaB
{
namespace P
{

class Velocity: public LaB::Property
{
public:
    static const PropertyID id;

    Velocity(float vx = 0.0, float vy = 0.0)
    : velocity(vx,vy) {}
    Velocity(sf::Vector2f v) : velocity(v) {};

    sf::Vector2f velocity;
};

} /* namespace P */
} /* namespace LaB */
#endif /* LaB::P_VELOCITY_H_ */



// Velocity.cpp

#include "Properties/Velocity.h"

namespace LaB
{
namespace P
{

const PropertyID Velocity::id = Property::registerID();

} /* namespace P */
} /* namespace LaB */

2D 벡터와 2D 벡터를 기대하는 ID에 대한 모든 것. (일부 속성에는 더 복잡한 요소가 있지만 동일한 아이디어입니다.)


3
이것 좀 봐, 그것은 당신을 도울 수 있습니다. gameprogrammingpatterns.com/type-object.html

1
정적 초기화가 아닌 템플릿이 도움이 될 것 같습니다. 이 경우 확실히 훨씬 쉬워 질 수 있지만 해당 ID로 수행하려는 작업과 상속을 사용하는 이유에 대한 자세한 정보 없이는 말하기가 어렵습니다. 공용 상속을 사용하지만 가상 함수는 사용하지 않는 것이 코드 냄새입니다. 이것은 다형성이 아닙니다!
ltjax

이를 구현하는 타사 라이브러리를 찾았습니까?
Boris

답변:


1

C ++은 강력하지만 장황하다 . 원하는 것이 모두 다른 작은 다형성 클래스가 많으면 선언하고 정의하는 데 많은 소스 코드가 필요합니다. 실제로 할 일은 없습니다.

ltjax가 말했듯이, 당신이 여기서하는 일은 적어도 당신이 제공 한 코드에 대한 다형성 이 아닙니다 . 하위 클래스의 특정 구현을 숨길 공통 인터페이스를 볼 수 없습니다. 클래스 ID를 제외하고는 실제 클래스 ID와 중복됩니다. 이름입니다. 이것은 일부 데이터를 포함하는 클래스의 무리 인 것처럼 보이지만 실제로는 복잡하지 않습니다.

그러나 이것은 문제를 해결하지 못합니다. 최소한의 코드로 많은 메시지와 속성을 만들고 싶습니다. 코드가 적다는 것은 버그가 적기 때문에 현명한 결정입니다. 불행히도 당신에게는 단일 솔루션이 없습니다. 이러한 메시지와 속성으로 무엇을할지 정확히 알지 못하면 자신의 요구에 가장 적합한 것을 말하기가 어렵습니다 . 옵션을 공개하겠습니다.

  1. C ++ 템플릿을 사용하십시오 . 템플릿은 컴파일러가 "코드를 작성할"수있는 좋은 방법입니다. 언어가 언어를 더 잘 지원하도록 발전함에 따라 C ++ 세계에서 점점 더 눈에 띄게되고 있습니다 (예 : 이제 다양한 수의 템플릿 매개 변수를 사용할 수 있음 ). 템플릿 메타 프로그래밍 (template metaprogramming) 템플릿을 통한 자동화 된 코드 생성에 전념하는 전문 분야가 있습니다. 문제는 어렵다. 이러한 기술을 사용하려는 경우 비 프로그래머가 새로운 속성을 직접 추가 할 수 있다고 기대하지 마십시오.

  2. 평범한 C 매크로를 사용하십시오 . 구식이며 학대하기 쉽고 오류가 발생하기 쉽습니다. 그들은 또한 만들기가 매우 간단합니다. 매크로는 단지 전처리기에 의해 수행되는 영광스러운 복사-붙여 넣기이므로 실제로는 거의 변하지 않는 수많은 것들을 만드는 데 매우 적합합니다. 그러나 매크로는 종종 전체 프로그램 디자인에서 결함을 숨기기 위해 사용되므로 다른 프로그래머가 사용하기를 좋아하지 않습니다. 그러나 때로는 도움이됩니다.

  3. 다른 옵션은 외부 도구를 사용하여 코드를 생성하는 것입니다. 이전 답변에서 이미 언급 되었으므로 확장하지는 않겠습니다.

  4. 덜 장황한 다른 언어가 있으며 클래스를 더 쉽게 만들 수 있습니다. 그래서 경우에 당신은 이미 (또는 당신이 그들을 가진 계획) 스크립트 바인딩을 가지고, 스크립트에서 그 클래스를 정의하는 것은 옵션이 될 수 있습니다. C ++에서 액세스하는 것은 상당히 복잡하며 클래스 생성 단순화의 이점을 대부분 잃게됩니다. 따라서 이것은 아마도 다른 언어로 대부분의 게임 로직을 수행 할 계획 일 경우에만 가능합니다.

  5. 마지막으로, 데이터 중심 디자인 사용을 고려해야 합니다. 직접 제안한 것과 비슷한 레이아웃을 사용하여 간단한 텍스트 파일로 이러한 "클래스"를 정의 할 수 있습니다. 사용자 정의 형식과 구문 분석기를 작성하거나 이미 사용 가능한 여러 옵션 (.ini, XML, JSON 및 기타) 중 하나를 사용해야합니다. 그런 다음 C ++ 측면에서 다양한 종류의 객체 모음을 지원하는 시스템을 만들어야합니다. 이는 스크립팅 접근 방식과 거의 동일하며 (필요에 따라 더 많은 작업이 필요할 수도 있음), 더 정확하게 요구 사항에 맞출 수 있습니다. 그리고 간단하게 만들면 프로그래머가 아닌 사람도 스스로 새로운 것을 만들 수 있습니다.


0

코드 생성 도구는 어떻습니까?

예를 들어, 작은 텍스트 파일로 메시지 유형과 멤버를 정의하고 코드 생성 도구가 구문 분석하고 모든 상용구 C ++ 파일을 빌드 전 단계로 작성할 수 있습니다.

ANTLR 또는 LEX / YACC와 같은 기존 솔루션이 있으며 속성 및 메시지의 복잡성에 따라 자체적으로 롤링하는 것은 어렵지 않습니다.


LEX / YACC aproach의 대안으로, 약간의 수정만으로 매우 유사한 파일을 생성해야 할 때 간단하고 작은 파이썬 스크립트와 태그가 포함 된 C ++ 코드 템플릿 파일을 사용합니다. python 스크립트는 템플리트에서 이러한 태그를 검색하여 작성중인 요소의 대표 토큰으로 대체합니다.
victor

0

Google의 프로토콜 버퍼 ( http://code.google.com/p/protobuf/ )에 대해 조사하는 것이 좋습니다 . 일반 메시지를 처리하는 매우 영리한 방법입니다. struct-llike 패턴으로 속성을 지정하면 코드 생성기가 클래스를 생성하는 모든 작업 (Java, C ++ 또는 C #)을 수행합니다. 생성 된 모든 클래스에는 텍스트 및 이진 파서가 있으므로 텍스트 기반 메시지 초기화 및 직렬화에 모두 적합합니다.


내 메시징 중심은 내 프로그램의 핵심입니다. 프로토콜 버퍼에 큰 오버 헤드가 발생하는지 알고 있습니까?
Bryan

API는 각 메시지의 빌더 클래스이고 메시지 자체의 클래스이기 때문에 큰 오버 헤드가 발생하지 않는다고 생각합니다. Google은이를 인프라의 핵심으로 사용합니다. 예를 들어 Google App Engine 엔티티는 지속되기 전에 모두 프로토콜 버퍼로 변환됩니다. 의심스러운 경우 현재 구현과 프로토콜 버퍼 사이의 비교 테스트를 구현하는 것이 좋습니다. 오버 헤드가 수용 가능하다고 생각되면 사용하십시오.
dsilva.vinicius
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.