Ajuda com SFML em C++

13 respostas
J
Tenho um codigo que faz a colisão entre 2 circulos, após a colisão eles retornam para lado oposto com o mesmo angulo e a mesma velocidade, mas tem um problema, os circulos sempre colidem no mesmo ponto, gostaria de saber se tem alguma forma deles colidirem em pontos aleatorios da tela? O codigo é o seguinte:
#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;
}

13 Respostas

ViniGodoy

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/

J

A colisao aqui deu certo, eles colidem e voltam, mas sempre colidem no mesmo ponto
:frowning:
Ja to usando a SFML, acho que usar a box2D ficaria meo ruim

ViniGodoy

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.

J

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.

ViniGodoy

O que você quer dizer com “colidem no mesmo lugar”? E “colidirem em lugares diferentes”?

J

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

ViniGodoy

Não seria só usar random nos vetores iniciais?

J

sim, eu tava tentando fazer isso, com a função rand e srand, mas nao consegui
:frowning:

ViniGodoy

Inclua:

Em seguida, no início do main, faça:

Depois, para sortear, faça algo como:

ViniGodoy

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&lt;int&gt; distribution(0, 350); std::mt19937 engine; // Mersenne twister MT19937 auto gerador = std::bind(distribution, engine); int x = gerador(); int y = gerador();

J

Mas ali no int x, eu faço com o y tbm né?

ViniGodoy

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 &lt;= 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.

J

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;
}
Criado 2 de novembro de 2012
Ultima resposta 8 de nov. de 2012
Respostas 13
Participantes 2