#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>
#include <sstream>
bool collision(sf::RenderWindow &Window, sf::Shape Circle1, sf::Shape &Circle2){//função de colisão entre os circulos
if((abs(Circle1.GetPosition().x - Circle2.GetPosition().x)) +
abs((Circle1.GetPosition().y - Circle2.GetPosition().y)) <= 100){
return true;
}else{
return false;
}
}
int main()
{
int x = 350;
int y = 100;
int xVetor = 3;
int yVetor = 3;
int x2 = 300;
int y2 = 300;
int x2Vetor = -3;
int y2Vetor = -3;
bool collided = false;
sf::Shape Circle1 = sf::Shape::Circle(0, 0, 50, sf::Color(0, 0, 0), 1, sf::Color(0, 0, 0));
sf::Shape Circle2 = sf::Shape::Circle(0, 0, 50, sf::Color(0, 0, 0), 1, sf::Color(0, 0, 0));
sf::RenderWindow Window(sf::VideoMode(800, 600, 32), "Colisão entre Circulos");
//GAME LOOP
while(Window.IsOpened()){
sf::Event Event;
while(Window.GetEvent(Event)){
if(Event.Type == sf::Event::Closed || Event.Key.Code == sf::Key::Escape)
Window.Close();
}
Circle1.SetPosition(x, y);
Circle2.SetPosition(x2, y2);
x += xVetor;
if((x < 50) || (x > 750)){
xVetor *= (-1);
}
y += yVetor;
if ((y < 50) || (y > 550)){
yVetor *= (-1);
}
x2 += x2Vetor;
if((x2 < 50) || (x2 > 750)){
x2Vetor *= (-1);
}
y2 += y2Vetor;
if ((y2 < 50) || (y2 > 550)){
y2Vetor *= (-1);
}
//CHAMADA DE FUNÇÔES
if (collision(Window, Circle1, Circle2) && !collided){
yVetor *= (-1);
xVetor *= (-1);
y2Vetor *= (-1);
x2Vetor *= (-1);
collided = true;
}
if (!collision(Window, Circle1, Circle2) && collided){
//x2Vetor *= (-1);
collided = false;
}
Window.Clear(sf::Color(255, 255, 255));
Window.Draw(Circle1);
Window.Draw(Circle2);
Window.Display();
sf::Sleep(0.01f);
}
return EXIT_SUCCESS;
}
Ajuda com SFML em C++
13 Respostas
Sua fórmula de colisão de círculos está incorreta.
Dois círculos colidem quando a distância entre seus dois centros for menor do que a distância entre os raios.
De qualquer forma, se você quer uma física mais realista no seu game, recomendo que use uma engine, como a Box2D:
http://box2d.org/
A colisao aqui deu certo, eles colidem e voltam, mas sempre colidem no mesmo ponto

Ja to usando a SFML, acho que usar a box2D ficaria meo ruim
Por que? A SFML é uma biblioteca gráfica, a Box2D é uma biblioteca de física. Elas se complementam. Além disso, a Box2D é uma lib estática, não depende de nenhuma dll.
Por que é um exercicio da faculdade e nao sei se o professor aceitaria usar box2D, o trabalho ja ta feito, a questao de colidirem em lugares diferentes é parte minha, uma questao de aprender alem do que o professor pede e dar uma enfeitada tambem.
O que você quer dizer com “colidem no mesmo lugar”? E “colidirem em lugares diferentes”?
Isso no mesmo lugar eu digo em ralação ao eixo x e o eixo y, sempre colidem no mesmo ponto x,y na tela
Não seria só usar random nos vetores iniciais?
sim, eu tava tentando fazer isso, com a função rand e srand, mas nao consegui

Inclua:
Em seguida, no início do main, faça:
Depois, para sortear, faça algo como:
Só um comentário, no C++11, já seria possível usar as classes de números aleatórios:
Vamos supor que você quisesse gerar números de 0 até 350, você poderia fazer:
std::uniform_int_distribution<int> distribution(0, 350);
std::mt19937 engine; // Mersenne twister MT19937
auto gerador = std::bind(distribution, engine);
int x = gerador();
int y = gerador();
Mas ali no int x, eu faço com o y tbm né?
Sim, é só um exemplo. Um comando como:
Vai gerar um número entre 0 até 349. Se você quiser especificar um intervalo, use o método:
int random(int min, int max) {
return min + (rand % (max+1 - min));
}
Essa função inclui ambos os números na possibilidade de geração. Ou seja:
random(10,50) vai gerar um número entre 10 e 50.
Outra coisa. Corrija sua função de colisão.
Ela está errada. Como falei, a colisão entre círculo ocorre só se a distância entre os centros for menor do que a soma dos raios.
O calculo correto seria:
bool collision(const sf::Shape& Circle1, const sf::Shape& Circle2) {
Vector2f diff = Circle1.GetPosition() - Circle2.GetPosition();
float dist = sqrt(diff.GetPosition().x * diff.GetPosition().x + diff.GetPosition().y * diff.GetPosition().y);
return dist <= 100;
}
Não achei na documentação formas de calcular diretamente o tamanho do vetor, ou mesmo o produto escalar.
Simplificaria um bocado os cálculos.
Eu fiz isso que você falou, mas o circulo não vai pra uma aprte aleatoria da tela na hora da colisão, ele vai no inicio da tela, se ficar iniciando e fechando a tela, os dois circulos iniciais começam em posições diferentes e direções diferentes, queria saber se tem como eles irem pra uma posição aleatória da tela na hora da colisão, por via das duvidas o codigo atual esta assim:
#include <SFML/Graphics.hpp>
const int CIRCLE1WIDTH = 10;
const int CIRCLE1HEIGHT = 10;
const int CIRCLE2WIDTH = 10;
const int CIRCLE2HEIGHT = 10;
bool collision(sf::RenderWindow &Window, sf::Shape Circle1, sf::Shape &Circle2){//função de colisão entre os circulos
if((abs(Circle1.GetPosition().x - Circle2.GetPosition().x)) +
abs((Circle1.GetPosition().y - Circle2.GetPosition().y)) <= 100){
return true;
}else{
return false;
}
}
int main()
{
srand(time(0));
int x = rand() % 800;
int y = rand() % 600;
int xVetor = 3;
int yVetor = 3;
int x2 = 300;
int y2 = 300;
int x2Vetor = -3;
int y2Vetor = -3;
bool collided = false;
sf::Shape Circle1 = sf::Shape::Circle(0, 0, 50, sf::Color(0, 0, 0), 1, sf::Color(0, 0, 0));
sf::Shape Circle2 = sf::Shape::Circle(0, 0, 50, sf::Color(0, 0, 0), 1, sf::Color(0, 0, 0));
sf::RenderWindow Window(sf::VideoMode(800, 600, 32), "Colisão entre Circulos");
//GAME LOOP
while(Window.IsOpened()){
sf::Event Event;
while(Window.GetEvent(Event)){
if(Event.Type == sf::Event::Closed || Event.Key.Code == sf::Key::Escape)
Window.Close();
}
Circle1.SetPosition(x, y);
Circle2.SetPosition(x2, y2);
x += xVetor;
if((x < 50) || (x > 750)){
xVetor *= (-1);
}
y += yVetor;
if ((y < 50) || (y > 550)){
yVetor *= (-1);
}
x2 += x2Vetor;
if((x2 < 50) || (x2 > 750)){
x2Vetor *= (-1);
}
y2 += y2Vetor;
if ((y2 < 50) || (y2 > 550)){
y2Vetor *= (-1);
}
//CHAMADA DE FUNÇÔES
if (collision(Window, Circle1, Circle2) && !collided){
yVetor *= (-1);
xVetor *= (-1);
y2Vetor *= (-1);
x2Vetor *= (-1);
collided = true;
}
if (!collision(Window, Circle1, Circle2) && collided){
//x2Vetor *= (-1);
collided = false;
}
Window.Clear(sf::Color(255, 255, 255));
Window.Draw(Circle1);
Window.Draw(Circle2);
Window.Display();
sf::Sleep(0.01f);
}
return EXIT_SUCCESS;
}