2015-01-05 5 views
0

저는 C++의 noob 종류이며 단순한 게임을 만들려고합니다. 내가 클래스 스프라이트라고 만든하위 클래스의 요소가있는 클래스 목록을 전달하는 C++

: 이것은 내 문제입니다 "충돌"라는 메소드를 가지고

class Sprite 
{ 
private: 
    Point2D sp_pos; 
    Point2D sp_vel; 
    SDL_Surface* sp_img; 
    Point2D sp_center; 
    Point2D sp_size; 
    double sp_radius; 
    bool sp_animated; 
    int sp_frames; 
    int sp_cur_frame; 

public: 
    Sprite() {} 
    Sprite(Point2D pos, Point2D vel, SDL_Surface *img, ImageInfo info, bool animated = false, int frames = 0); 
    virtual void draw(SDL_Surface* screen); 
    virtual void update(); 
    void setInfo (ImageInfo info); 
    void setPos(Point2D pos) { sp_pos = pos; } 
    void setVel(Point2D vel) { sp_vel = vel; } 
    void setImg (SDL_Surface* img) { sp_img = img; } 
    void setNextFrame() { sp_cur_frame++; } 
    void setFrame(int frame) { sp_cur_frame = frame; } 
    void setAnimated(bool animated) { sp_animated = animated; } 
    void changeVelX (int c) { sp_vel.setX(c);} 
    void changeVelY (int c) { sp_vel.setY(c);} 
    void changePosX (int c) { sp_pos.setX(c);} 
    void changePosY (int c) { sp_pos.setY(c);} 
    SDL_Surface* getImg() { return sp_img; } 
    Point2D getPos() { return sp_pos; } 
    Point2D getVel() { return sp_vel; } 
    Point2D getCenter() { return sp_center; } 
    Point2D getSize() { return sp_size; } 
    double getRadius() { return sp_radius; } 
    int getCurFrame() { return sp_cur_frame; } 
    int getFrames() { return sp_frames; } 
    bool collide(Sprite &another_sprite); 
}; 

,이 방법은 두 스프라이트 간의 충돌을 감지하고 다음과 같이 작동합니다

bool Sprite::collide(Sprite &another_sprite) 
{ 
    double d = getPos().dist(another_sprite.getPos()); 

    if (d < (getRadius() + another_sprite.getRadius())) 
     return true; 
    else 
     return false; 
} 

메서드가 제대로 작동합니다. 내 문제는 다음과 같이 발생합니다. "Sprite"의 하위 클래스 인 다른 클래스를 구현했으며 내 게임에서 적을 나타낼 것입니다. 예를 들어 클래스 enemy1 : public Sprite, 클래스 enemy2 : public Sprite 등이 있습니다. 서로 다른 행동을하기 때문에 서로 다릅니다.

bool group_collide(std::list<Sprite> &group, Sprite other_object) 
{ 
    bool collision = false; 

    for (std::list<Sprite>::iterator sprite = group.begin(), end = group.end(); sprite != end; ++sprite) 
    { 
     if (sprite->collide(other_object)) 
     { 
      Sprite exp = Sprite(sprite->getPos(), Point2D(0, 0), exp_image, exp_info, true, 7); 
      exp_group.push_back(exp); 
      if(Mix_PlayChannel(-1, explosion, 0) == -1) 
      { 
       //abort(); 
      } 
      sprite = group.erase(sprite); 
      collision = true; 
     } 
    } 
    return collision; 
} 

int group_group_collide(std::list<Sprite> &group, std::list<Sprite> &other_group) 
{ 
    int scored = 0; 

    for (std::list<Sprite>::iterator it1 = group.begin(), end1 = group.end(); it1 != end1; ++it1) 
    { 
     if (group_collide(other_group, *it1)) 
     { 
      it1 = group.erase(it1); 
      scored += 10; 
     } 

    } 
    return scored; 
} 

그래서, 사실, 그룹 스프라이트와 스프라이트의 목록 사이 collisons를 감지 충돌, 그리고 group_group_collide는 그룹 사이의 충돌을 감지합니다 다음과 같이 나는 group_collide 및 group_group_collide라는 다른 두 도우미 기능, 그 일을 실행 스프라이트 (두 개의 다른 목록). 발생하는 문제는 적어도 네 가지 유형의 적이 존재하며 모두 Sprite 클래스의 하위 클래스이지만 스프라이트 목록을 만들고 스프라이트의 하위 클래스 인 요소를 추가하면 컴파일 오류가 발생합니다. 내 솔루션은 모든 종류의 적을 위해 group_collide 및 group_group 충돌 방법을 쓰고 있었지만, 이것은 매우 비 효과적입니다. 이 문제에 접근하는 더 좋은 방법이 있습니까?

편집 :

의견을 보내 주셔서 감사합니다. 당신이 제안으로 나는 포인터 목록으로 목록을 정의 :

std::list<Sprite*> enemy_group; 

그리고 예를 들어, 내가 이런 식으로 클래스 스프라이트의 서브 클래스입니다 "카미카제"의 요소를 추가하고 (방법 업데이트는 다르다 목록 반복 그러나

enemy_group.push_back(new Kamikaze(enemy_pos, enemy_vel, 0, enemy_image, enemy_info)); 

:이 클래스는)

는 방법 업데이트가 Sprite 클래스가 아닌 가미 클래스에서 호출
for (list<Sprite*>::iterator it = enemy_group.begin(), end = enemy_group.end(); it != end; ++it) { 
       (*it)->draw(screen); 
       (*it)->update(); 
       if ((*it)->getPos().getY() > SCREEN_HEIGHT + 30) 
       { 
        delete *it; 
        it = enemy_group.erase(it); 
       } 
      } 

, 그러므로 나는 또한 객체 슬라이스 확률값을 이 접근 방식으로, 아마도 내가 한 짓에 뭔가 잘못된 것이 있습니까?

+0

[이중 발송] (http://en.wikipedia.org/wiki/Double_dispatch#Double_dispatch_in_C.2B.2B) 유형의 문제와 비슷합니다. 매우 비슷한 예가 링크 된 위키피디아 페이지에 표시됩니다. – en4bz

+1

'Sprite'에서 파생 된 클래스를'std :: list '에 저장할 수 없습니다. 시도해 볼 수도 있지만 다음과 같이 처리 할 수 ​​있습니다 : http://stackoverflow.com/questions/274626/what-is-object-slicing – PaulMcKenzie

+0

또한'충돌'은 아마도 순수한'가상'함수 여야합니다. – en4bz

답변

0
  1. , 당신은 std::list<Sprite*>std::list<Sprite>를 교체해야합니다. 현재 전달 된 모든 하위 클래스는 Sprite로 축소됩니다. 포인터 목록을 사용하면이를 피할 수 있습니다.

  2. 원하는 결과를 얻으려면 가상 함수 을 사용해야합니다.기본 클래스

:에서는

//This way you'll have a default collision method for a Sprite... 
//...but you'll be able to re-define it in subclasses. 
//I don't do THIS ONE often so I'm not sure if you'll have to perform additional steps 

virtual bool Sprite::collide(Sprite &another_sprite) 
{ 
    ... 
} 

//And this way you are making collied a pure virtual function and Sprite an abstract class... 
//...meaning you can't instantiate it, but you can use it with a pointer or reference. 
//Every subclass of Sprite must have a body of function collide defined 

//you do this only in header of class Sprite 
virtual bool virtual bool Sprite::collide(Sprite &another_sprite) = 0; 

소집단 그래서

//if you have made collide pure virtual function, you can do this 
//not sure about the first case though 
bool SubSprite::collide(Sprite &another_sprite) 
{ 
    ... 
} 

, collide 메소드 또는 참조, 호출하는 스프라이트 포인터로부터 호출 을 subcl의 지정된 기능에 리디렉션하십시오. 나귀.

같은 것은 group_collide입니다.

추가 설명 : 순수 가상 함수 collide이 포인터 또는 참조에서 호출 그래서 때마다

//lets assumme you have 2 sprite types, Kamikaze and NotKamikaze 
Sprite *sprite1 = new Kamikaze(); 
Sprite *sprite2 = new NotKamikaze(); 

//and lets assume collide uses pointer instead, just for this example, so it's shorter 
virtual bool Sprite::collide(Sprite *another_sprite) = 0; 

bool Kamikaze::collide(Sprite *another_sprite); 
bool NotKamikaze::collide(Sprite *another_sprite); 

//when you call collide from Sprite*, it **automatically** picks the sub-class collude method 

//sprite1 is of type Sprite*, but allocated memory is of Kamikaze 
//so the only function called is Kamikaze::collide 
sprite1->collide(sprite2); 

//sprite2 is of type Sprite*, but allocated memory is of NotKamikaze 
//so the only function called is NotKamikaze::collide 
sprite2->collide(sprite2); 

, 프로그램이 자동으로 오른쪽 하나를 선택합니다. 모든 스프라이트 유형에 대해 다른 유형을 원한다면, 이것이 필요한 것입니다.

"개체 조각화"가 문제가되는 곳입니다. 스프라이트는 포인터 또는 참조로 존재할 수 있지만 추상이 아닌 서브 클래스에만 존재할 수 있습니다. 따라서 Sprite *Sprite sprite1 = new Sprite();은 작동하지 않지만 Sprite *Sprite sprite1 = new SpriteSubClass();이 작동합니다.

당신이 Sprite::collide 순수 가상하지를 한 경우는, 스프라이트는 더 이상 추상 클래스 없을 것입니다, 당신은 Sprite 클래스 자체에서 메서드 실행을 할 수 있으며, 당신이 Sprite *Sprite sprite1 = new Sprite();을 할 수 있습니다. 그러나 하위 클래스 만 보면서 필요로 할 것입니다.

메소드 이름은 공유되지만 서브 클래스별로 동작이 다를 때마다 가상이어야합니다.

+0

충돌이 다른 스프라이트에 대해 다르게 작동하면 한 가지 유형으로 만 호출하면 작동하지 않습니다. 그들은 서로를 호출해야 할 것이고, 공통적 인 동작이기 때문에 기본 클래스에 들어가므로 일부 다른 함수는 가상 일 것입니다 (예 : get_bounding_points 등). –

+0

순수 가상 기능을 사용하면 원하는 방법이 자동으로 선택됩니다. 메소드의 동작이 기본 클래스에서 정의되지 않았기 때문에 메서드가 순수 가상 인 경우에는 기본 클래스로 이동하지 않습니다. Sprite * 또는 Sprite &에서 호출하고 오른쪽 하위 클래스에서 충돌을 호출합니다. 내 대답을 업데이트 했으므로 예제를 살펴보십시오. 내가 당신의 질문을 정확하게 이해한다면, 이것은 당신이 필요로하는 것과 정확히 같습니다. – cruelcore1

+0

당신의 대답은 완벽했습니다, 그것은 나를 도왔습니다. kamikaze 클래스에 대한 업데이트 메서드를 정의 할 때 몇 가지 문제가있었습니다. 메서드를 수퍼 클래스에서 "오버로드"하지 않았지만 설명에 따라 올바르게 처리했습니다. 감사합니다;) – dpalma

3

I get compilation errors when I create a list of sprites and add elements that are subclasses of sprites.

모든 파생 클래스는 표준 : : 목록과 같은 객체 컨테이너에 맞추기 위해 '슬라이스'됩니다. std::list<Sprite*> //(Preferably a smart pointer)은 실제 개체를 다른 곳에 저장해야하지만이 문제를 방지합니다. Laserbreath에 의해 대답에 주어진

+0

답변 해 주셔서 감사합니다. 나는 당신이 제안한 것을 시도 할 것입니다. – dpalma

관련 문제