SFML и C++ Уроки \ Разработка игр › Форумы › SFML Graphics › Collision Detection.
В этой теме 16 ответов, 2 участника, последнее обновление Dallon Avery 8 года/лет, 4 мес. назад.
-
АвторСообщения
-
Собственно, продолжая знакомиться с sfml2.1 я делаю игру Breakout, которая должна выглядеть минимум так как показано на картинке. Моя же главная задача, это правильно воспроизвести столкновение шарика-мяча (окружность) с кирпичикми (прямоугольниками), без учёта гравитации. А вот как это сделать я не имею понятия, знаю только то, что простым sf::CircleShape shape(50); тут не отделаешься.
Я немало порылся в интернете и нашёл то, что может мне помочь – Circle-AABB intersection test, где AABB – это это параллелепипед со сторонами, параллельными осям координат, ограничивающий некоторый геометрический объект в пространстве, по определению на Википедии. Так что от этого и надо плясать.
Можете ли вы объяснить на примере принцип работы такого подхода или предложить свой вариант?
Вложения:
You must be logged in to view attached files.а как трехмерный паралеллепипед вписывается в 2д игру? тогда эти две стороны , которые тебе нужны, превращаются в квадрат..
а вобще – шарик можно сделать и спрайтом с прозрачностью по бокам (и он будет квадратным, хоть этого и не видно), и при столкновении мяча с прямоугольником можно прописать условия , которые толкнут мяч в нужную сторону от этой их общей точки. например если шар летит влево-вверх, при этом касается кирпичика – то направление по Y шара меняется на противоположное. ну как то так, своего рода псевдофизика получается. но работать будет
это самое простое решение, которое пришло в голову сразу же, другое пока не думал. может тебя это устроит:)
Твой вариант мне очень нравится, из-за своей хитрожопости, но я хочу использовать как можно более точную реализацию физики столкновений. Без спрайтов =)
Вот примерно так будет выглядеть моя версия. Осталось всё это заставить двигаться.
Вложения:
You must be logged in to view attached files.А вот и код, который я имею, взгляните, может подскажите чего:
C++123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170#include <SFML\Graphics.hpp>using namespace sf; using namespace std;bool intersects (const RectangleShape & rect1,const RectangleShape & rect2){FloatRect r1=rect1.getGlobalBounds();FloatRect r2=rect2.getGlobalBounds();return r1.intersects (r2);}int clamp (const int x, const int a, const int b){return min(max(a,x),b);}int main(){const int width = 640;const int height= 480;Texture back;if(!back.loadFromFile("background.jpg"))return -1;Sprite background;background.setTexture(back);background.setPosition(0,0);VideoMode videoMode(width, height);ContextSettings antialiasing;antialiasing.antialiasingLevel = 8;RenderWindow window(videoMode,"Rectangle Collision", Style::Default, antialiasing);//wallsRectangleShape top;RectangleShape left;RectangleShape right;//RectangleShape bottom;//bricksRectangleShape brick1;brick1.setSize(Vector2f(60,12));brick1.setPosition(40,40);brick1.setFillColor(Color(255,255,255,128));brick1.setOutlineColor(Color::Black);brick1.setOutlineThickness(3);RectangleShape brick2;brick2.setSize(Vector2f(60,12));brick2.setPosition(150,40);brick2.setFillColor(Color(255,255,255,128));brick2.setOutlineColor(Color::Black);brick2.setOutlineThickness(3);RectangleShape brick3;brick3.setSize(Vector2f(60,12));brick3.setPosition(260,40);brick3.setFillColor(Color(255,255,255,128));brick3.setOutlineColor(Color::Black);brick3.setOutlineThickness(3);RectangleShape brick4;brick4.setSize(Vector2f(60,12));brick4.setPosition(370,40);brick4.setFillColor(Color(255,255,255,128));brick4.setOutlineColor(Color::Black);brick4.setOutlineThickness(3);RectangleShape brick5;brick5.setSize(Vector2f(60,12));brick5.setPosition(480,40);brick5.setFillColor(Color(255,255,255,128));brick5.setOutlineColor(Color::Black);brick5.setOutlineThickness(3);RectangleShape paddle;top.setPosition(0, 0);top.setSize(Vector2f(640, 5));top.setFillColor(Color(0,151,255));top.setOutlineColor(Color(0,151,255));/*bottom.setPosition(0, 475);bottom.setSize(Vector2f(640, 5));bottom.setFillColor(Color(0,151,255));bottom.setOutlineColor(Color(0,151,255));*/left.setPosition(0, 0);left.setSize(Vector2f(5, height));left.setFillColor(Color(0,151,255));left.setOutlineColor(Color(0,151,255));right.setPosition(635,0);right.setSize(Vector2f(5, height));right.setFillColor(Color(0,151,255));right.setOutlineColor(Color(0,151,255));//paddlepaddle.setPosition(width/2-45, height-50-12);paddle.setSize(Vector2f(90, 12));paddle.setFillColor(Color::Red);paddle.setOutlineColor(Color::Green);paddle.setOutlineThickness(3);//ballCircleShape ball(10);ball.setPosition(width/2, height/2);ball.setFillColor(Color(255,255,255,128));ball.setOutlineColor(Color::Yellow);ball.setOutlineThickness(3);Vector2<float> ballSpeed(0.1,0.1);Time deltaTime;Clock clock;while (window.isOpen()){deltaTime = clock.restart();float dtAsSeconds = deltaTime.asSeconds();window.clear(Color::White);window.draw(background);window.draw(top);/*window.draw(bottom);*/window.draw(left);window.draw(right);window.draw(brick1);window.draw(brick2);window.draw(brick3);window.draw(brick4);window.draw(brick5);window.draw(paddle);window.draw(ball);window.display();Event event;while (window.pollEvent(event)){if ( (event.type == Event::Closed) ||((event.type == Event::KeyPressed) && (event.key.code==Keyboard::Escape)) )window.close();}//move paddleif(Keyboard::isKeyPressed(Keyboard::Left)){paddle.move(-5/50.0, 0);}else if (Keyboard::isKeyPressed(Keyboard::Right)){paddle.move(5/50.0, 0);}//keep paddle inside the windowif (intersects(paddle, left) || intersects(paddle, right)){FloatRect l = left.getGlobalBounds();FloatRect r = right.getGlobalBounds();Vector2f p = paddle.getPosition();p.x = clamp(p.x, l.left + l.width+5, r.left-paddle.getGlobalBounds().width-5);paddle.setPosition(p.x, p.y);}}return EXIT_SUCCESS;}вот тут разбиралась эта игра, только на паскале. но принцип тот же и объяснение тоже.
Принцип-то у него совсем другой. Ну да ладно, я уже заставил мячик летать по экрану и отталкиваться от краёв окна.
Осталось теперь сделать отталкивание от прямоугольников.
Вот здесь наглядно показаны примеры пересечения фигур: Collision Detection in Games
Вопрос: можно ли двигать фигуру(клавиатурой в функции update), нарисованную с помощью VertexArray?
И если эта фигура прямоугольник, можно ли напиать функцию для пересечения окружности и одной из граней прямоугольника?
Что я имею ввиду под этим? Вот что:
Таков мой прямоугольник, нарисованный с помощью VertexArray:
C++123456789VertexArray rectangle (Quads, 4);rectangle[0].position = Vector2f(240, 440);rectangle[0].color = Color::Yellow;rectangle[1].position = Vector2f(380,440);rectangle[1].color = Color::Green;rectangle[2].position = Vector2f(380,460);rectangle[2].color = Color::Blue;rectangle[3].position = Vector2f(240,460);rectangle[3].color = Color::Red;Вопрос, можно ли доказать пересечение CircleShape ball(10); где радиус 10, с линией соединяющую rectangle[0] и rectangle[1]???
Попробуй пошамань с getRect
Вот зацените:
C++123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311#include <SFML\Graphics.hpp>#include <iostream>using namespace sf; using namespace std;/*AABB-Circle DistanceStep one:Vector dist = B.centre - A.centreStep two:clamp dist to A.extendsif(dist.x >= 0)clamp.x = min(dist.x,extents.x)if(dist.x < 0) clamp.x = max(dist.x,-extents.x)if(dist.y >= 0)clamp.y = min(dist.y,extents.x)if(dist.y < 0) clamp.y = max(dist.y,-extents.x)Step three:Take the differencediff = dist - clampFinal step:Find the distance between A and BDistance = diff.magnitude - B.radius*/void updateBallPhysics();bool intersects (const RectangleShape & rect1,const RectangleShape & rect2){FloatRect r1=rect1.getGlobalBounds();FloatRect r2=rect2.getGlobalBounds();return r1.intersects (r2);}int clamp (const int x, const int a, const int b){return min(max(a,x),b);}bool win();int main(){const int width = 640;const int height= 480;Font font;if(!font.loadFromFile("assets/comic.ttf"))cout << "ERROR" << endl;Texture back;if(!back.loadFromFile("assets/background.jpg"))return -1;Texture redball;if(!redball.loadFromFile("assets/ball.png"))return -1;Sprite background;background.setTexture(back);background.setPosition(0,0);VideoMode videoMode(width, height);ContextSettings antialiasing;antialiasing.antialiasingLevel = 8;RenderWindow window(videoMode,"Rectangle Collision", Style::Default, antialiasing);//wallsRectangleShape top;RectangleShape left;RectangleShape right;RectangleShape bottom;//RectangleShape bottom;//bricksRectangleShape brick1;brick1.setSize(Vector2f(60,12));brick1.setPosition(40,40);brick1.setFillColor(Color(255,255,255,128));brick1.setOutlineColor(Color::Black);brick1.setOutlineThickness(3);RectangleShape brick2;brick2.setSize(Vector2f(60,12));brick2.setPosition(150,40);brick2.setFillColor(Color(255,255,255,128));brick2.setOutlineColor(Color::Black);brick2.setOutlineThickness(3);RectangleShape brick3;brick3.setSize(Vector2f(60,12));brick3.setPosition(260,40);brick3.setFillColor(Color(255,255,255,128));brick3.setOutlineColor(Color::Black);brick3.setOutlineThickness(3);RectangleShape brick4;brick4.setSize(Vector2f(60,12));brick4.setPosition(370,40);brick4.setFillColor(Color(255,255,255,128));brick4.setOutlineColor(Color::Black);brick4.setOutlineThickness(3);RectangleShape brick5;brick5.setSize(Vector2f(60,12));brick5.setPosition(480,40);brick5.setFillColor(Color(255,255,255,128));brick5.setOutlineColor(Color::Black);brick5.setOutlineThickness(3);//paddleRectangleShape paddle;paddle.setPosition(width/2-45, height-50-12);paddle.setSize(Vector2f(90, 12));paddle.setFillColor(Color::Red);paddle.setOutlineColor(Color::Green);paddle.setOutlineThickness(3);//ballRectangleShape ball;ball.setPosition(width/2, height/2);ball.setSize(Vector2f(20,20));//ball.setOutlineColor(Color(255,255,255,128));//ball.setFillColor(Color(255,255,255,128));//ball.setOutlineThickness(1);ball.setTexture(&redball);Vector2<float> ballSpeed(0.15, 0.15);top.setPosition(0, 0);top.setSize(Vector2f(640, 5));top.setFillColor(Color(0,151,255));top.setOutlineColor(Color(0,151,255));top.setFillColor(Color::Yellow);bottom.setPosition(0, 475);bottom.setSize(Vector2f(640, 5));bottom.setFillColor(Color(0,151,255));bottom.setOutlineColor(Color(0,151,255));bottom.setFillColor(Color::Yellow);left.setPosition(0, 0);left.setSize(Vector2f(5, height));left.setFillColor(Color(0,151,255));left.setOutlineColor(Color(0,151,255));left.setFillColor(Color::Yellow);right.setPosition(635,0);right.setSize(Vector2f(5, height));right.setFillColor(Color(0,151,255));right.setOutlineColor(Color(0,151,255));right.setFillColor(Color::Yellow);Text gamename, start, won, lost;gamename.setFont(font);gamename.setString("Arkanoid");gamename.setCharacterSize(48);gamename.setColor(Color::Red);gamename.setPosition(210, 100);//startstart.setFont(font);start.setString("Press SPACE to start");start.setCharacterSize(32);start.setColor(Color::Green);start.setPosition(165, 200);//wonwon.setFont(font);won.setString("You won!");won.setCharacterSize(32);won.setStyle(Text::Bold);won.setColor(Color::Green);won.setPosition(250, 200);//lostlost.setFont(font);lost.setString("Game Over!");lost.setCharacterSize(24);lost.setStyle(Text::Bold);lost.setColor(Color::Red);lost.setPosition(250, 200);//GameStatesenum GameStates {STARTSCREEN, GAME, WIN, GAMEOVER};int gameState = STARTSCREEN;while (window.isOpen()){window.clear(Color::White);switch(gameState){case STARTSCREEN:window.draw(background);window.draw(gamename);window.draw(start);break;case GAME:window.draw(background);window.draw(top);//window.draw(bottom);window.draw(left);window.draw(right);window.draw(brick1);window.draw(brick2);window.draw(brick3);window.draw(brick4);window.draw(brick5);window.draw(paddle);window.draw(ball);break;case WIN:window.draw(background);window.draw(won);break;case GAMEOVER:window.draw(background);window.draw(lost);break;}window.display();Event event;while (window.pollEvent(event)){if ( (event.type == Event::Closed) ||((event.type == Event::KeyPressed) && (event.key.code==Keyboard::Escape)) )window.close();else if((event.type == Event::KeyPressed) && (event.key.code==Keyboard::Space) && (gameState == STARTSCREEN))gameState = GAME;}if(gameState!=GAME)continue;ball.move(ballSpeed.x, ballSpeed.y);//move paddleif(Keyboard::isKeyPressed(Keyboard::Left)){paddle.move(-0.3, 0);}else if (Keyboard::isKeyPressed(Keyboard::Right)){paddle.move(0.3, 0);}//keep paddle inside the windowif (intersects(paddle, left) || intersects(paddle, right)){FloatRect leftWall = left.getGlobalBounds();FloatRect rightWall = right.getGlobalBounds();Vector2f p = paddle.getPosition();p.x = clamp(p.x, leftWall.left + leftWall.width+5, rightWall.left-paddle.getGlobalBounds().width-5);paddle.setPosition(p.x, p.y);}//ball collides with wallsif(intersects(ball, top)){ballSpeed.y = -ballSpeed.y;}if(intersects(ball, left) || intersects(ball, right)){ballSpeed.x = -ballSpeed.x;}//ball collides with paddleif(intersects(ball, paddle)){ballSpeed.y= -ballSpeed.y;}//ball collides with bricksif(intersects(ball, brick1)){FloatRect b1 = brick1.getGlobalBounds();FloatRect bBall = ball.getGlobalBounds();brick1.move(width+1, height+1);ballSpeed.y= -ballSpeed.y;}if(intersects(ball, brick2)){FloatRect b2 = brick2.getGlobalBounds();FloatRect bBall = ball.getGlobalBounds();brick2.move(width+1, height+1);ballSpeed.y= -ballSpeed.y;}if(intersects(ball, brick3)){FloatRect b3 = brick3.getGlobalBounds();FloatRect bBall = ball.getGlobalBounds();brick3.move(width+1, height+1);ballSpeed.y= -ballSpeed.y;}if(intersects(ball, brick4)){FloatRect b4 = brick4.getGlobalBounds();FloatRect bBall = ball.getGlobalBounds();brick4.move(width+1, height+1);ballSpeed.y= -ballSpeed.y;}if(intersects(ball, brick5)){FloatRect b5 = brick5.getGlobalBounds();FloatRect bBall = ball.getGlobalBounds();brick5.move(width+1, height+1);ballSpeed.y= -ballSpeed.y;}//Game wonif(brick1.getPosition().x > width && brick2.getPosition().x > width && brick3.getPosition().x > width && brick4.getPosition().x > width && brick5.getPosition().x > width){gameState = WIN;}//game overif(ball.getPosition().y > 480){gameState = GAMEOVER;}}return EXIT_SUCCESS;}всё работает теперь? теперь можно подумать над сокращением кода или вынесением его из тела главной ф-ции:)
Да, всё работает. Хочу теперь раскидать всё по хедерам, что посоветуешь?
-
АвторСообщения
Для ответа в этой теме необходимо авторизоваться.