7

オブジェクトを作成するために、SFML の Transformable および Drawable から継承しようとしています...まあ、変換可能で描画可能です。私は簡単なブレイクアウト ゲームを作っていますが、おそらくこれは間違った方法で行っているのでしょう。これが私のコードです:

#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;
}

移動と描画は (ほぼ) 期待どおりに動作するようになりましたが、衝突は少し不安定です。最初に私の衝突の問題:

  1. 私が行った方法で getGlobalBounds 関数を実装する必要がありますか? または、Transformable と Drawable に含まれるものでそれを行うより良い方法はありますか?
  2. シェイプに対して直接変換を実行する必要がありますか、それとも現在のように描画関数に変換を渡す必要がありますか?

おそらく素早い修正である描画で何か奇妙なことも起こっています. 現在、getPosition メソッドは、ボール オブジェクトに対して正しくない値を返します。それが返す領域は、少し下と右にシフトしているようです。考えられる理由は何ですか?

あなたが与えることができるどんな助けにも感謝します!

編集: また、一般的な C++ のヒントも歓迎します。私はまだ初心者です。

4

1 に答える 1

2

私があなたなら、次のTransformableAndDrawableように呼ばれる新しいクラスを定義します。

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

このクラスでは、変換可能および描画可能クラスで一般的に必要とされるすべてのメンバーを定義する必要があります。また、このクラスでは、変換可能および描画可能クラスで一般的に実装できるすべてのメソッドを定義する必要があります。次に、次のようにクラスを から継承する必要がありますTransformableAndDrawable

class Player : TransformableAndDrawable {
    // Your code here
}

さて、最初の質問に対する答えは次のとおりです。指定されたTransformableAndDrawableメソッドが一般的なメソッドである場合、そのメソッドをクラスに実装するので、継承元のすべてのクラスTransformableAndDrawableがこのメソッドを持つことになります。

p_rectと のように異なる名前を付ける代わりに、p_circleこれらのメンバーに のように同じ名前を付けるp_shapeと、命名の問題が発生しなくなります。また、p_shape を祖先クラスまたはインターフェイス (使用しているライブラリでどのクラスが定義されているかわかりません) であると宣言し、必要な場合にのみ形状の性質を指定できると思います (それが円または長方形またはその他のもの)。

2 番目の質問について: あなたの実装方法は気に入っていますが、2 つの間違いがあります。

  • それはスケーラブルではありません: 私たちは一般的な解決策、つまり、現在および将来的に作業している任意の形状に使用できるクラスが必要ですよね?
  • それは十分に一般的ではありません: 形状のグローバルな境界を知りたい場合、形状の性質には興味がありません。知らないうちに形状の性質を処理するコードを好むでしょう

要するに、次のことを行う必要があります。

  1. から継承されるラッパー クラスを作成しTransformableDrawable

  2. ラッパー クラスでは、形状の性質にとらわれず、できるだけ一般的にしてRectangleShapeくださいCircleShape

  3. 描画可能クラスと変換可能クラスをすべてラッパー クラスから継承するため、クラス間で機能を共有できます。

  4. ラッパー クラスの何かが継承されたクラスに適していない場合は、そのクラスのメソッドを上書きします。

編集:

使用しているライブラリを詳しく調べたところ、 と の両方の祖先である Shape というクラスがあることがわかりましCircleShapeRectangleShape。したがって、これらのクラスを使用する代わりにShape、コードはより一般的で再利用可能になります。

于 2013-07-28T17:17:23.397 に答える