问题
[![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