SFML Как сделать правильное столкновение пули с астероидом многоугольника ConvexShape? Obs: (в коде перед работой с CircleShape) - PullRequest
0 голосов
/ 28 октября 2019

[! [Введите описание изображения здесь] [1]] [1] Я просто пытаюсь работать над SFML-кодом астероидной игры, в которой пуля столкновений проверяется с помощью астероида CircleShape по радиусу. Я просто изменил форму на ConvexShape, но не могу найти решениеисправлено столкновение между вектором пули с вектором астероида ConvexShape.Radius не работает правильно. Я иду положить оригинальный код из asteroid.cpp bullet.cpp и level.cpp это последний, где ocurr условно для уничтожения пули и сломал или убить астероид на расстоянии радиуса. Есть изображения, где проверяют все коды столкновения. Пожалуйста, попробуйте в bullet.cppкод, пуля рисуется как линия вершины, а не как форма.

код Asteroid.cpp

#include "Asteroid.hpp"

const float Asteroid::speed[3] = {0.03f, 0.05f, 0.07f};
const float Asteroid::radius[3] = {40.0f, 20.0f, 10.0f};

Asteroid::Asteroid(int level):
    is_alive(true),
    level(level) {
    int angle = rand() % 360;
    direction = sf::Vector2f(cos(angle * DEG2RAD), sin(angle * DEG2RAD));

    int x = rand() % APP_WIDTH;
    int y = rand() % APP_HEIGHT;
    sf::Vector2f position(x, y);
    setPosition(position);
    shape.setPointCount(8);
    shape.setRadius(radius[level]);
    shape.setFillColor(sf::Color::Black);
    shape.setOutlineColor(sf::Color::White);
    shape.setOutlineThickness(1);
    shape.setOrigin(radius[level], radius[level]);
}

Asteroid::Asteroid(sf::Vector2f position, float angle, int level):
    is_alive(true),
    level(level) {
    direction = sf::Vector2f(cos(angle * DEG2RAD), sin(angle * DEG2RAD));

    setPosition(position);
    shape.setPointCount(8);
    shape.setRadius(radius[level]);
    shape.setFillColor(sf::Color::Black);
    shape.setOutlineColor(sf::Color::White);
    shape.setOutlineThickness(1);
    shape.setOrigin(radius[level], radius[level]);
}

Asteroid::~Asteroid() {
}

bool Asteroid::isAlive() {
    return is_alive;
}

void Asteroid::update(float frametime) {
    if (!is_alive) return;

    sf::Vector2f distance = direction * speed[level] * frametime;
    move(distance);

    sf::Vector2f position = getPosition();

    if (position.x < -radius[level])
        position.x = APP_WIDTH;
    else if (position.x > APP_WIDTH)
        position.x = 0.0f;

    if (position.y < -radius[level])
        position.y = APP_HEIGHT;
    else if (position.y > APP_HEIGHT)
        position.y = 0.0f;
    setPosition(position);
}

void Asteroid::draw(sf::RenderTarget& target, sf::RenderStates states) const {
    states.transform *= getTransform();
    target.draw(shape, states);
}

int Asteroid::getLevel() {
    return level;
}

void Asteroid::breakDown() {
    level++;

    if (level > 2) {
        is_alive = false;
        return;
    }

    shape.setRadius(radius[level]);
    shape.setOrigin(radius[level], radius[level]);
    float angle = rand() % 360;
    direction = sf::Vector2f(cos(angle * DEG2RAD), sin(angle * DEG2RAD));
}

bool Asteroid::checkPoint(sf::Vector2f point) {
    float ax = getPosition().x;
    float ay = getPosition().y;

    float px = point.x;
    float py = point.y;

    float sqrDistance = ((ax - px) * (ax - px)) + ((ay - py) * (ay - py));
    float sqrRadius = radius[level] * radius[level];

    return (sqrDistance <= sqrRadius);
}

//----------------------------------------------------------------------
a bullet.cpp code

#include "Bullet.hpp"

const float Bullet::lifetime = 1000.0f;
const float Bullet::speed = 0.9f;

Bullet::Bullet(sf::Vector2f position, float angle):
    is_alive(true),
    remaining_life(lifetime),
    direction(cos(angle * DEG2RAD), sin(angle * DEG2RAD)) {
    setPosition(position);
}

Bullet::~Bullet() {
}

bool Bullet::isAlive() {
    return is_alive;
}

void Bullet::update(float frametime) {
    if (!is_alive) return;

    remaining_life -= frametime;
    if (remaining_life <= 0) is_alive = false;

    sf::Vector2f distance = direction * speed * frametime;
    move(distance);
}

void Bullet::draw(sf::RenderTarget& target, sf::RenderStates states) const {
    sf::Vertex line[] = {
        sf::Vertex(getPosition()),
        sf::Vertex(getPosition() + (direction * 5.0f))
    };
    target.draw(line, 2, sf::Lines, states);
}

void Bullet::kill() {
    is_alive = false;
}

//-----------------------------------------------
a level.cpp code

#include "Level.hpp"

Level::Level() {
    for (int i=0; i < 3; i++) {
        Asteroid a(0);
        asteroids.push_back(a);
    }
}

Level::~Level() {
}

void Level::onEvent(const sf::Event& event) {
    ship.onEvent(event);

    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space)) {
        Bullet bullet(ship.getPosition(), ship.getRotation());
        bullets.push_back(bullet);
    }
}

void Level::update(float frametime) {
    ship.update(frametime);
    std::vector<Bullet>::iterator start_bullets = bullets.begin();
    while (start_bullets != bullets.end()) {
        if (start_bullets->isAlive()) {
            start_bullets->update(frametime);
            ++start_bullets;
        } else
            start_bullets = bullets.erase(start_bullets);
    }

    std::vector<Asteroid>::iterator start_asteroids = asteroids.begin();
    while (start_asteroids != asteroids.end()) {
        if (start_asteroids->isAlive()) {
            start_asteroids->update(frametime);
            ++start_asteroids;
        } else
            start_asteroids = asteroids.erase(start_asteroids);
    }

    std::vector<Asteroid> new_asteroids;
    start_asteroids = asteroids.begin();

    while (start_asteroids != asteroids.end()) {
        start_bullets = bullets.begin();
        while (start_bullets != bullets.end()) {
            if (!start_bullets->isAlive()) {
                ++start_bullets;
                continue;
            }

            if (start_asteroids->checkPoint(start_bullets->getPosition())){
                start_bullets->kill();
                start_asteroids->breakDown();

                if (start_asteroids->isAlive()) {
                    sf::Vector2f position = start_asteroids->getPosition();
                    float angle = rand() % 360;
                    Asteroid a(position, angle, start_asteroids->getLevel());
                    new_asteroids.push_back(a);
                }
                break;
            }
            ++start_bullets;
        }
        ++start_asteroids;
    }
    asteroids.insert(asteroids.end(), new_asteroids.begin(), new_asteroids.end());
}

void Level::show(sf::RenderTarget& target) {
    target.draw(ship);

    for(std::vector<Bullet>::iterator it = bullets.begin(); it != bullets.end(); ++it)
        target.draw(*it);

    for(std::vector<Asteroid>::iterator it = asteroids.begin(); it != asteroids.end(); ++it)
        target.draw(*it);
}

void Level::start() {
}


  [1]: https://i.stack.imgur.com/bBPsG.png

1 Ответ

0 голосов
/ 28 октября 2019

Я бы попробовал использовать прямоугольники вместо кругов, работать с прямоугольниками всегда проще. Вот как я бы это сделал:

class Rectangle : public sf::RectangleShape {
    public:
        Rectangle(float x, float y, float width, float height) : 
            sf::RectangleShape(sf::Vector2f(width, height)) {
            setPosition(sf::Vector2f(x, y));
        }

        void move(float dx, float dy) {
            setPosition(sf::Vector2f(getPosition().x + dx, getPosition().y + dy));
        }

        bool intersects(Rectangle rectangle) {
            for(int i = getPosition().x; i < getPosition().x + getSize().x; i ++) {
                for(int j = getPosition().y; j < getPosition().y + getSize().y; j ++) 
                {
                    if( (i >= rectangle.getPosition().x && i <= 
                    rectangle.getPosition().x + rectangle.getSize().x) 
                    && (j >= rectangle.getPosition().y && j <= 
                    rectangle.getPosition().y + rectangle.getSize().y ))
                    return true;
                }
            }
            return false;
        }
};

class Asteroid : public Rectangle {

};

class Bullet : public Rectangle {

};

int main() {

    std::vector<Asteroid*> asteroids;
    std::vector<Bullet*> bullets;

    if(asteriods.size() > 0 && bullets.size > 0) {
        for(Asteroid* asteroid : asteriods) {
            for(Bullet* bullet : bullets) {
                if(bullet->intersects(*asteroid)) {
                    std::cout << "Intersects!" std::endl;
                }
            }
        }
    }

    return 0;
}
...