2013-07-28 34 views
7

Próbuję dziedziczyć z Transformable i Drawable w SFML, aby moje obiekty ... dobrze, transformowalne i drawable. Robię prostą grę typu breakout, ale być może robię to w niewłaściwy sposób. Oto mój kod:Dziedziczenie z przekształcalne i Drawable w SFML

#include <SFML/Graphics.hpp> 
#include <SFML/System.hpp> 

class Player : public sf::Transformable, public sf::Drawable { 
    public: 
     Player(int x, int y); 
     ~Player() {}; 

     sf::RectangleShape p_rect; 

     void doMovement(const sf::RenderWindow& window); 
     sf::FloatRect getGlobalBounds() const; 
    private: 
     virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const { 
      states.transform *= getTransform(); 
      target.draw(p_rect, states); 
     } 

}; 

class Ball : public sf::Transformable, public sf::Drawable { 
    public: 
     Ball(int r, int x, int y); 
     ~Ball() {}; 

     sf::CircleShape b_circle; 

     void doXMovement(); 
     void doYMovement(); 
     bool doXCollisions(const Player& player); 
     bool doYCollisions(const Player& player); 
     sf::FloatRect getGlobalBounds() const; 
    private: 
     virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const { 
      states.transform *= getTransform(); 
      target.draw(b_circle, states); 
     } 

     bool right; 
     bool up; 
}; 

Player::Player(int x, int y) { 
    p_rect = sf::RectangleShape(sf::Vector2f(x, y)); 
} 

void Player::doMovement(const sf::RenderWindow& window) { 
    setPosition(sf::Mouse::getPosition(window).x, 500); 
    if (getPosition().x < 0) 
     setPosition(0, 500); 
    else if (getPosition().x > 720) 
     setPosition(720, 500); 
} 

sf::FloatRect Player::getGlobalBounds() const { 
    return getTransform().transformRect(p_rect.getGlobalBounds()); 
} 

Ball::Ball(int r, int x, int y) { 
    b_circle = sf::CircleShape(r); 
    b_circle.setPosition(x, y); 
    right = true; 
    up = false; 
} 

void Ball::doXMovement() { 
    if (right) 
     move(1, 0); 
    else 
     move(-1, 0); 
} 

void Ball::doYMovement() { 
    if (up) 
     move(0, -1); 
    else 
     move(0, 1); 
} 

bool Ball::doXCollisions(const Player& player) { 
    bool coll; 
    if (getGlobalBounds().intersects(player.getGlobalBounds())) { 
     right = !right; 
     coll = true; 
    } else 
     coll = false; 

    if (getPosition().x >= 800 - b_circle.getRadius()) 
     right = false; 
    else if (getPosition().x <= 0) 
     right = true; 
    return coll; 
} 

bool Ball::doYCollisions(const Player& player) { 
    bool coll; 
    if (getGlobalBounds().intersects(player.getGlobalBounds())) { 
     up = !up; 
     coll = true; 
    } else 
     coll = false; 
    if (getPosition().x <= 0) 
     up = false; 
    return coll; 
} 

sf::FloatRect Ball::getGlobalBounds() const { 
    return getTransform().transformRect(b_circle.getGlobalBounds()); 
} 

int main() { 
    sf::RenderWindow window(sf::VideoMode(800, 600), "Breakout"); 
    window.setMouseCursorVisible(false); 
    Player player(80, 10); 
    Ball ball(3, 100, 100); 
    sf::Clock clock; 
    while (window.isOpen()) { 
     sf::Event event; 
     while (window.pollEvent(event)) { 
      if (event.type == sf::Event::Closed) 
       window.close(); 
     } 
     player.doMovement(window); 
     if (clock.getElapsedTime().asMilliseconds() >= 3) { 
      clock.restart(); 
      if (!ball.doYCollisions(player)) 
       ball.doXCollisions(player); 
      ball.doYMovement(); 
      ball.doXMovement(); 
     } 
     window.clear(sf::Color::Black); 
     window.draw(player); 
     window.draw(ball); 
     window.display(); 
    } 
    return 0; 
} 

Teraz przenoszenie i rysowanie działa (prawie) zgodnie z oczekiwaniami, jednak kolizje są nieco nieporęczne. Najpierw problemy z kolizjami:

  1. Czy muszę zaimplementować funkcję getGlobalBounds tak jak ja? A może jest lepszy sposób na to, co zawiera Transformable and Drawable?
  2. Czy należy wykonywać transformacje bezpośrednio na kształtach, czy też powinienem przekazać transformacje do funkcji rysowania, jak obecnie?

Coś dziwnego dzieje się również z rysunkiem, który jest prawdopodobnie szybką naprawą. W tej chwili metoda getPosition zwraca nieprawidłowe wartości dla mojego obiektu kulowego. Obszar, który powraca, wydaje się być przesunięty w dół i nieco w prawo. Może być jakikolwiek powód?

Dzięki za pomoc, jaką możesz dać!

EDYCJA: Także ogólne wskazówki C++ są mile widziane, nadal jestem początkujący.

Odpowiedz

1

Gdybym był tobą chciałbym zdefiniować nową klasę o nazwie TransformableAndDrawable takiego:

class TransformableAndDrawable : public sf::Transformable, public sf::Drawable { 
    // Your code here 
} 

W tej klasie należy zdefiniować wszystkie elementy, które są zwykle potrzebne w klasach Transformable i rozciągliwych. Ponadto w tej klasie należy zdefiniować wszystkie metody, które można ogólnie zastosować w klasach przekształcalnych i losowalnych. Następnie, swoje zajęcia powinny być dziedziczone od TransformableAndDrawable, tak:

class Player : TransformableAndDrawable { 
    // Your code here 
} 

Teraz odpowiedź na pierwsze pytanie brzmi: chciałbym wdrożyć w TransformableAndDrawable klasy danej metody, jeżeli jest to ogólna metoda, więc wszystkie klasy odziedziczone po TransformableAndDrawable będą miały tę metodę.

Zamiast podawać różne nazwy, na przykład p_rect i p_circle, należy podać tych członków o tej samej nazwie, na przykład p_shape, aby uniknąć problemów z nazewnictwem. Ponadto, uważam, że możesz zadeklarować, że twoja p_shape jest klasą lub interfejsem przodka (nie wiem, jakie klasy są zdefiniowane w bibliotece, z którą pracujesz) i tylko wtedy, gdy jest to konieczne, określ naturę kształtu (czy jest to okrąg lub prostokąt lub coś innego).

Co do drugiego pytania: Lubię sposób zostały wdrożone rzeczy, ale zostały wykonane dwa błędy:

  • nie jest skalowalny: chcemy ogólne rozwiązanie klasy, które mogą być wykorzystywane do kształt, nad którym pracujesz teraz i w przyszłości, nieprawdaż?
  • Nie jest to wystarczająco ogólne: gdy chcę poznać globalne granice kształtu, to nie interesuje mnie natura kształtu, wolałbym twój kod, aby obsłużyć naturę kształtu bez mojej wiedzy

krótko mówiąc, należy wykonać następujące czynności:

  1. Utwórz klasę otoki, które będą dziedziczone z Transformable i Drawable

  2. W swojej klasy otoki, b Agnostyczny dla natury kształtu, być jak najbardziej ogólny, mam nadzieję, że istnieje jakaś klasa lub interfejs, który jest przodkiem zarówno dla RectangleShape i CircleShape.

  3. Dziedziczenie wszystkie rozciągliwej i umożliwiającego przejście klasy z klasy otoki, więc trzeba będzie wspólną funkcjonalność wśród swoich klasach

  4. Jeśli coś w swojej klasie owijarki nie jest dobre dla klasy, który został odziedziczony po nim, zastąpić metodę w tej klasie.

EDIT:

Szukałem do biblioteki używasz dokładniej i okazało się, że istnieje klasa o nazwie Shape, który jest przodkiem zarówno CircleShape i RectangleShape. Tak więc zamiast tych klas używaj numeru Shape, a Twój kod będzie bardziej ogólny i możliwy do ponownego użycia.

+0

Świetnie, myślałem o stworzeniu superklasy dla tych klas, ponieważ naprawdę nienawidzę pisać tego samego kodu dwa razy. Mam nadzieję, że robiąc to, jestem w stanie naprawić mój dziwny problem z rysunkiem. – mrobinson7627

+0

Czy dobrze jest rzutować wskaźnik kształtu podczas korzystania z funkcji getRadius? To by działało, ale mam wrażenie, że to może być zła praktyka. Osobiście tak nie uważam, ponieważ jest to klasa, która musi mieć kształt koła. EDYCJA: tak: 'if (getPosition(). X> = 800 - dynamic_cast (kształt) -> getRadius())' – mrobinson7627

+0

Możesz przekonwertować, ale uważam, że powinieneś wdrożyć funkcjonalność do tego w superklasie i tam możesz wspierać dowolną klasę za pomocą szablonów. –