• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Kolizja w SFML

0 głosów
957 wizyt
pytanie zadane 5 sierpnia 2017 w C i C++ przez Programeł Gaduła (3,500 p.)

Witam

Mam problem z kolizją. Chce aby po dotknięciu graczem o obiekt lub w niego wejście pojawił się napis w konsoli "Kolizja!".

 klasa Object:

class Object
{
public:
    float width;
    float height;
    bool kolizja;    

    sf::Vector2f position;
    sf::RectangleShape shape;


    Object(float w, float h, float x, float y) : width(w), height(h), position(x,y), shape(sf::Vector2f(w,h)) {}
    
    bool isColision(Object object);
    void Colision();
};

int main:

int main()
{
    sf::RenderWindow window(sf::VideoMode(800,600),"SFML Kolizja");
    
    Object gracz = Object(60,130,100,460);
    gracz.shape.setFillColor(sf::Color::Green);
    gracz.shape.setPosition(gracz.position);

    Object obiekt = Object(90,300,500,300);
    obiekt.shape.setFillColor(sf::Color::White);
    obiekt.shape.setPosition(obiekt.position);

    while(window.isOpen())
    {
        sf::Event event;
        while(window.pollEvent(event))
        {
            if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) window.close();     
  
            if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::D) gracz.shape.move(10.f,0);

            if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::A) gracz.shape.move(-10.f,0);              
            
            if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::W) gracz.shape.move(0.f,-10.f);

            if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::S) gracz.shape.move(0.f,10.f);
        }
                  
        window.clear();

        window.draw(obiekt.shape);
        window.draw(gracz.shape);

        gracz.isColision(obiekt);
        gracz.Colision();

        window.display();
     }

    return 0;
}

metody klasy Object :

bool Object::isColision(Object object)
{
    if(position.x > object.position.x + object.width || position.x + width < object.position.x ||
        position.y > object.position.y + object.height || position.y + height < object.position.y)
            return kolizja=false ;
    else return kolizja=true;
}

void Object::Colision()
{
    if(kolizja == true) std::cout<<"Kolizja!"<<std::endl;
    else {}
}

za każdą pomoc wielkie dzięki :]

1
komentarz 5 sierpnia 2017 przez niezalogowany
edycja 5 sierpnia 2017

Mam kilka takich uwag na później (skoro odpowiedź chyba padła):
1. Nie katuj się zbędną ilością kodu. Zamieniaj takie rzeczy:

sf::Event event;
while (window.pollEvent(event))
{
	if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) window.close();
	if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::D) gracz.shape.move(10.f, 0);
	if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::A) gracz.shape.move(-10.f, 0);
	if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::W) gracz.shape.move(0.f, -10.f);
	if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::S) gracz.shape.move(0.f, 10.f);
}

Na takie:

sf::Event event;
while (window.pollEvent(event))
{
	if (event.type == sf::Event::KeyPressed)
	{
		if(event.key.code == sf::Keyboard::Escape) window.close();
		if (event.key.code == sf::Keyboard::D) gracz.shape.move(10.f, 0);
		if (event.key.code == sf::Keyboard::A) gracz.shape.move(-10.f, 0);
		if (event.key.code == sf::Keyboard::W) gracz.shape.move(0.f, -10.f);
		if (event.key.code == sf::Keyboard::S) gracz.shape.move(0.f, 10.f);
	}
}

Ładnie i pięknie, a jak dodasz jeszcze 20 klawiszy to nadal będzie przejrzyście.

2. Obsługę ruchu rób za pomocą funkcji isKeyPressed:

sf::Event event;
while (window.pollEvent(event))
{
	if (event.type == sf::Event::KeyPressed)
	{
		if(event.key.code == sf::Keyboard::Escape) window.close();
	}
}
// Caly kod bys wiedzial zeby nie umieszczac w petli z eventami
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) gracz.shape.move(0.f, -10.f);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) gracz.shape.move(0.f, 10.f);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) gracz.shape.move(-10.f, 0);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) gracz.shape.move(10.f, 0);

Dzięki temu prostokąt zaczyna się poruszać od razu i ruch jest ciągły.

3. Obsługa czasu jest ważna by gra którą zrobisz chodziła wszędzie z tą samą szybkością. Proponuję zrobić taki mały prosty zabieg na sam początek przygody z SFML: Przed petlą główną gry:

sf::Clock clock;
float dt = 0;

Wewnątrz niej:

float speed = 200; // druga zaleta - maksymalna predkosc bedzie w miare logiczna - px/s - zawsze i wszedzie (powiedzmy)
sf::Vector2f velocity;

if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) velocity.y -= speed;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) velocity.y += speed;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) velocity.x -= speed;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) velocity.x += speed;
dt = clock.restart().asSeconds(); // mierzenie czasu pomiedzy framesami
gracz.shape.move(velocity*dt); // zmiana polozenia predkosc razy czas sama fizyka
window.clear();
...
komentarz 5 sierpnia 2017 przez PoetaKodu Stary wyjadacz (10,990 p.)
Nie powinno się restartować zegara w każdej klatce bo traci się bardzo dużo precyzji. Zamiast tego powinno się zapisywać poprzedni czas i odejmować go od aktualnego czasu.
komentarz 5 sierpnia 2017 przez niezalogowany
Masz rację. Po prostu chciałem lekko zwrócić uwagę na tę kwestię i dałem najprostszy przykład.

1 odpowiedź

+1 głos
odpowiedź 5 sierpnia 2017 przez PoetaKodu Stary wyjadacz (10,990 p.)
    return kolizja=false ;
else return kolizja=true;

Tak to nie działa. Po co zwracasz jakąkolwiek wartość skoro

  1. nie używasz jej dalej;
  2. masz do tego zmienną, która powinna to przechować;
  3. nie rozumiesz jak to działa?

Usuń returny z "isColision". Poza tym "kolizja" po angielsku piszemy przez dwa L - "collision".

Bonus: przy każdym wywołaniu isColision kopiujesz obiekt, który sprawdzasz:

bool Object::isColision(Object object)

Przekazujesz go poprzez wartość, przez co musi on zostać dosłownie skopiowany do argumentu 'object' w tej funkcji. Jeśli object będzie przechowywało więcej danych lub gdy samych obiektów będzie więcej odczujesz znaczny spadek wydajności. Zamiast tego powinieneś takie obiekty przekazywać przez const refa - zapobiegniesz wtedy możliwości zmiany tego obiektu (bo po co - potrzebny jest on do sprawdzenia a nie modyfikacji) przy czym nie będziesz go kopiował, tylko przekażesz samą referencję:

bool Object::isColision(const Object &object)

 

komentarz 5 sierpnia 2017 przez Programeł Gaduła (3,500 p.)
Ok dzięki za Bonus ale dalej nie wiem co mam zrobić aby ta kolizja działała :/
komentarz 5 sierpnia 2017 przez PoetaKodu Stary wyjadacz (10,990 p.)
Przeczytaj zdanie, które napisałem przed słowem "Bonus".

Podobne pytania

0 głosów
0 odpowiedzi 182 wizyt
pytanie zadane 14 marca 2018 w C i C++ przez zpawlo00 Początkujący (310 p.)
0 głosów
2 odpowiedzi 558 wizyt
pytanie zadane 5 stycznia 2017 w C i C++ przez Szedou Nowicjusz (200 p.)
+6 głosów
7 odpowiedzi 1,575 wizyt

93,425 zapytań

142,421 odpowiedzi

322,646 komentarzy

62,785 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

VMware Cloud PRO - przenieś swoją infrastrukturę IT do chmury
...