SFML How can made correct collision bullet to ConvexShape polygon asteroid?obs:(in code before work with CircleShape)

三世轮回 提交于 2020-01-25 07:00:30

问题


[![enter image description here][1]][1]I just trying working on SFML code of asteroid game where collision bullet is checked with asteroid CircleShape by radius.I just changed shape to ConvexShape but cant find solution for made correct collision between bullet vector with Asteroid vector ConvexShape.Radius not work correctly. I go put a original code from asteroid.cpp bullet.cpp and level.cpp this last where ocurr conditional for kill bullet and broke or kill asteroid by distance of radius.Have images where the collision code check all.Please Attemption in bullet.cpp code the bullet is drawned like vertex line not like shape.

the Asteroid.cpp code

#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:


I'd try to use rectangles instead of circles, working with rectangles is always easier. This is the way i'd do it:

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


来源:https://stackoverflow.com/questions/58592628/sfml-how-can-made-correct-collision-bullet-to-convexshape-polygon-asteroidobs

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!