На прошлом уроке наши прямоугольники врага и игрока пересеклись. Допустим у нас игра танчики – там вобще происходит пересечение с четырех сторон, вид сверху. Итак подробно разберем что и как происходит и как не запутаться в этом:
Видеоверсия http://www.youtube.com/watch?v=j5z0UcHWWNk
Начнем сначала.
Наш спрайт – это текстура+прямоугольник.
Координаты у нас всегда берут свое начало с левого верхнего угла. Внутри прямоугольника такая же ситуация – левая верхняя его часть это координата 0,0. Если у прямоугольника размер 20 на 10, то координата 20,10 это есть его правый нижний угол. А 20/2 и 10/2 это его середина, то есть 10,5.
В sfml у нас было setOrigin(w/2,h/2), это и есть перенос начала координат (того самого 0,0 из левого верхнего угла) в середину. Зачем? Не всегда это нужно. Если вы хотите вращать вокруг центра персонажа, то нужно. Иначе он будет вращаться вокруг левого верхнего угла своего спрайта.
Мы заговорили об этом по той причине, что при взаимодействии объектов это играет важную роль.

Весь пример приведу на координате Х, аналогично всё для Y. Вверху мировые координаты Х. Белый круг это начало отсчета, то есть нулевая точка. Черный прямоугольник это враг, справа от него серый квадрат – игрок. 600 – ширина врага. и тд. Вот смотрите – оранжевая стрелочка указывает на столкновение двух прямоугольников. Именно в этот момент условие if (враг.getRect().intersects(игрок.getRect())) будет равно истине (true). И уже внутри этого условия мы должны выталкивать эти прямоугольники в противоположные друг от друга стороны.
Если враг шёл вправо и встретился игроком, значит координата х врага будет равна координата игрока Х минус ширина врага и будет происходить это до тех пор , пока спрайты соприкасаются.
Важный момент – если прописать пересечение игрока с врагом только для врага, то игрок при перемещении будет выталкивать врага. Таким образом нужно прописать пересечение и для игрока тоже.
Перейдем к практике, чтобы было понятнее на деле. Я переделал слегка карту в ещё один полигон для испытаний:

Если виснете в выталкивании объектов – открывайте первую картинку из урока и подставляйте туда мысленно свои. Или рисуйте от руки на листике и у вас в итоге получится. Так же советую вам выводить переменные координат в консоль , чтобы понимать на верном вы пути, или нет.
Давайте сделаем так, что когда враг коснется игрока – он остановится и не станет его сбивать. стоп-стоп-стоп-стоп.
(убийство врага я пока убрал, чтобы не убить случайно во время эксперимента, там три строчки максимум)
Итак, вот код остановки врага при столкновении с игроком:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
for (it = entities.begin(); it != entities.end(); it++)//проходимся по эл-там списка { if ((*it)->getRect().intersects(p.getRect()))//если прямоугольник спрайта объекта пересекается с игроком { if ((*it)->name == "EasyEnemy"){//и при этом имя объекта EasyEnemy,то.. if ((*it)->dx>0)//если враг идет вправо { std::cout << "(*it)->x" << (*it)->x << "\n";//коорд игрока std::cout << "p.x" << p.x << "\n\n";//коорд врага (*it)->x = p.x - (*it)->w; //отталкиваем его от игрока влево (впритык) (*it)->dx = 0;//останавливаем std::cout << "new (*it)->x" << (*it)->x << "\n";//новая коорд врага std::cout << "new p.x" << p.x << "\n\n";//новая коорд игрока (останется прежней) } if ((*it)->dx < 0)//если враг идет влево { (*it)->x = p.x + p.w; //аналогично - отталкиваем вправо (*it)->dx = 0;//останавливаем } } } } |
Выводим в консоль переменные и смотрим на их значение во время столкновения и после выталкивания. старая координата врага не превысит новую т.к происходит выталкивание.
Если убрать остановку врага dx=0, то можно наблюдать как игрок сталкивает врага, идя на него.
вместо dx=0 для врага можно написать dx*=-1; тогда при столкновении с игроком враг поменяет свое направление на противоположное. получается в стиле “ударил и убежал” )
Итак, теперь давайте сделаем так, чтобы игрок тоже не мог идти навстречу врагу при столкновении спрайтов, тем самым не смог с ним соприкоснуться (пишем чуть ниже):
1 2 3 |
///////выталкивание игрока if (p.dx < 0) { p.x = (*it)->x + (*it)->w; }//если столкнулись с врагом и игрок идет влево то выталкиваем игрока if (p.dx > 0) { p.x = (*it)->x - p.w; }//если столкнулись с врагом и игрок идет вправо то выталкиваем игрока |
Еще одним способ – запретить идти влево (нажимать клавишу влево) если на пути слева мешает спрайт врага.
Теперь вы можете не давать игроку и врагу столкнуться и слиться воедино.
Домашнее задание к уроку 25 sfml:
http://www.youtube.com/watch?v=4aW8WSDV9Yo
задание 1:
добавить рандомный таймер (сделать его с интервалом не менее 1 сек), который даст врагу противоположное направление.
задание 2:
при виде поблизости игрока (ну скажем в пределах 400 координат) враг должен резко ускориться в его сторону и постараться задавить игрока, при этом над головой врага должно появиться диалоговое облачко (как в комиксах) с надписью : “ААААААH!!!”
задание 3:
при столкновении игрока с врагом толкнуть в сторону игрока, нанести ему урон. особое внимание уделить выталкиванию игрока рядом со стеной, т.к его может телепортировать немного не туда. враг при этом не должен останавливаться.
Здравствуйте Павел. Вопрос такой. Мое консольное приложение в VS2013 pro нормально запускается и работает, а из Windows 8.1 exe файл запускается с ошибкой. (failed to create texture, invalid size <0x0>). Заранее благодарю.
Привет. Пишите на форум, создав тему с этим вопросом.
Спасибо за урок, очень доходчиво!
Кстати, а как сделать релиз игры, чтоб запускать на другом компьютере?
пожалуйста) такой вопрос уже не раз был на форуме – ищите