главная страница статьи файлы о сайте ссылки |
Георгий Мошкин Как сделать крутые летающие пульки? Очень просто! Вообще-то тема создания летающих - одна из важнейших для программирования игр. Файлы к статье: pulki.zip (10kb) Итак, у нас есть пульки и есть игрок с пушкой. Нужно сделать так, чтобы игрок стрелял пульками, и они продолжали лететь в своих направлениях, даже если игрок уже пошёл в другую сторону. Вначале опишем игрока: игрок находиться в точке X,Y и смотрит в какую-то сторону (угол PHI). В Delphi это выглядит так: type Tigrok=record Пулька тоже имеет координаты X,Y и направление PHI: type Tpulka=record Но здесь есть дополнительные данные. Это связано с тем, что пуля может лететь только определённое время, потому что из-за трения воздуха она упадёт. Поэтому задан параметр letit. Чтобы вовремя "убрать" пулю, нам нужно знать как давно был сделан выстрел. Для этого я ввёл параметр life. Когда игрок ходит, то меняются его координаты X и Y. Направление, в котором ходит игрок, определяется углом PHI. Например, игрок находится в точке X=0, Y=0: X=0 Если скорость передвижения игрока составляет
10 пикселей за одну перерисовку экрана, то в следующий момент координата
игрока будет следующей: Тут всё просто. Если игрок смотрит под углом 0 градусов, т.е. PHI=0, то он попадёт в точку с координатой: X=0+10*COS(0)=0+10*1=10 То есть он окажеться в точке (10,0). То же относится и к пулькам: пульки могут перемещаться в определённом направлении с определённой скоростью. Выше мы задавали два типа: игрока и пульку. Вот эти типы: type Tigrok=record type Tpulka=record Теперь зададим переменные этих типов. Сначала зададим игрока: var igrok1:Tigrok; А как задать пульки? Ведь одновременно могут лететь сотни и даже тысячи пуль! Одной переменной здесь не обойтись, поэтому нужен массив. Зададим массив из 101 пульки: pulki:array[0..100] of Tpulka; Почему 101 пулька? Вообще это значение вы выбираете сами. Всё зависит от ного, как много пуль будет одновременно летать в вашей игре. Просто делайте их такое количество, чтобы всегда хватало свободных пуль. Что значит "свободных пуль"? Свободные пули - это такие пули, которые не летят: letit=false Если пуля не летит, значит она свободна, и мы можем запустить её в полёт! Рисовать на экране следует только те пули, которые летят: letit=true Например, если вы залпом выпустите все 101 пулю залпом, то какое-то время ни один игрок в уровне не сможет стрелять. Дело в том, что пока пули летят, у них запись letit:=true, и мы не можем задавать им другое направление полёта. Итак, у нас есть пульки pulki:array[0..100] of Tpulka, есть игрок igrok1:Tigrok. Нужно наладить между ними взаимодействие. Сначала надо как-нибудь подвигать игроком и выбрать направление стрельбы. Будем считать, что игрок может стрелять в ту сторону, куда сейчас смотрит. Сам процесс выстрела описывается следующим образом: координата свободной пули = координата игрока + небольшое смещение Данное смещение необходимо с той целью, чтобы игрок не попал сам в себя. Ведь если пуля будет выходить из самого игрока, то используемые в вашей игре алгоритмы проверки столкновений приведут к уменьшению энергии игрока. Нарисуем игрока. Пусть это будет кружочек: glBegin(GL_LINE_STRIP); Курожочек нарисован с помощью GL_LINE_STRIP из линий. В точках окружности мы помещаем 10 точек, между которыми проводим линии. Далее нужно нарисовать пушку игрока. Для этого нарисуем линию, которая как бы убежала от игрока в направлении его движения: glBegin(GL_LINES); То есть мы берём угол PHI, наклоняем линию под этим углом и рисуем. Пульку нарисовать тоже просто. Причём пулька рисуется абсолютно так же, как и пушка. Но только линию мы сделаем покороче: glBegin(GL_LINES); Длина определяется разницей чисел, на которые умножается SIN и COS, то есть: glVertex3f(x+cos(phi*3.14/180), y+sin(phi*3.14/180),0) будет короче, чем glVertex3f(x+6*cos(phi*3.14/180),
y+6*sin(phi*3.14/180),0); Но дело тут не в том, что 3<6. Ведь: glVertex3f(x+13*cos(phi*3.14/180),
y+13*sin(phi*3.14/180),0); будет самой короткой из этих линий. Вообщем мы рисуем обычный вектор. В примере, который вы можете скачать с этой страницы, идёт отрисовка игрока: with igrok1 do Потом для 101 пульки мы делаем цикл: for i:=0 to 100 do В этом цикле мы проверяем как давно у нас летит пулька: if (pulki[i].letit=true) and (pulki[i].life>200) then Если пулька летит слишком долго, то then pulki[i].letit:=false; Потом смотрим: если время полёта пули (life) пока что в заданных нами пределах (<=200), то рисуем эту пульку: if (pulki[i].letit=true) then Если мы будем много стрелять, то в скоро не останеться свободных пуль, так как life всегда равняется нулю. Чтобы время, которое прошло после начала полёта данной пули увеличивалось, мы делаем простое увеличение в каждом кадре отрисовки: pulki[i].life:=pulki[i].life+1; // увеличиваем время полёта Само перемещение пульки делается очень просто: у нас есть угол, есть текущие координаты. Нужно изменить текущие координаты, прибавив к ним вектор направления. Вектор направления описывается очень просто: VECTOR=(cos(phi),sin(phi)) Поэтому перемещение пули будет выглядеть так: with pulki[i] do x:=x+3*cos(phi*3.14/180); То есть каждый кадр мы будем перемещать пульку по направлению PHI на три пикселя. Потом реализовано движение игрока. Более подробно этот вопрос описан в других моих статьях. Теперь одна важная вещь: temp:=false; - если
нашли пулю, то будет true Это самая важная часть в программе. Важно понять, что если одновременно летит много пуль, то выстрелить будет невозможно, так как у всех пуль будет LETIT=TRUE. То есть, например, если летит 101 пуля, то стрелять уже не получится. И в программе вы это увидите. Через определённое время пули исчезают, так как наращивается переменная LIFE каждой пули. При превышении определённого значения мы "вырубаем" пулю: if (pulki[i].letit=true) and (pulki[i].life>200) thenthen pulki[i].letit:=false; Другая важная часть в этой программе - это перемещение игрока. Как вы смогли заметить, перемещение игрока и пули выполняются одинаковым способом с применением тригонометрических функций: SIN и COS. Понять, как это происходит, очень просто: когда угол PHI = 0, то COS(PHI)=1 SIN(PHI)=0 и мы движемся вправо: x:=x+1 Когда PHI=45, то движемся наискосок. Это связано с тем что COS(45)=0,7 SIN(45)=0,7: x:=x+0,7 корень из ( 0,7*0,7 + 0,7*0,7) = 0,99 То есть вообще-то, каким бы ни был угол PHI, перемещаемся на одинаковое расстояние. Это относится и к игроку и к пулям. Пример с пульками очень важен в плане понимания "многозадачности" в играх. Пульки куда-то летят. Куда лететь они сами знают (у них есть текущая координата и угол). Похожие приёмы используются в разных местах при создании игр. |