DiNGS – программирование игр в домашних условиях. Часть 15
АрхивПрограммазм (архив)Клавиши в игре, метеоры и другие эффекты...
Многие играли в космические стрелялки, где маленький отважный истребитель выносит с экрана полчища врагов ураганным огнем лазерных пушек, но мало кто задумывался как это реализовано. Ах, какая ерунда! Как бы не так. Все это достаточно сложно и есть много методов решения этой проблемы.
Но как это соотносится с программированием Понга? Во многих играх, даже не стрелялках используются выстрелы. Вспомните тот же «Арканоид», где часто встречается приз «Fire» дающий возможность бите стрелять. В написанном мной PING PONG GOLD есть 2 приза аналогичного свойства – fireball (огненный шар поражающий биту противника и нанося ей повреждения) и Iceball – заморозка (попав во вражескую биту на время примораживает ее на месте не давая сдвинуться).
Попробуем повторить.
IF KEY(57) THEN SPRITE 12, fire_x, fire_y,0
Это первое что приходит в голову, но… Двигаться огонь (пуля, бомба, лазер) будет только пока вы держите нажатой клавишу SPACE (код 57). Изменим тактику. Какая то команда должна дать сигнал о произведенном выстреле, после чего уже независимо от этого мы выведем изображение огня и станем изменять его координаты. На помощь придут триггеры. Пусть при нажатии на клавишу SPACE триггер (переменная) fire будет получать значение 1.
Пример кода:
Fire=0 //Триггер выстрела в 0, т.е. нет выстрела LOADSPRITE “bita.bmp”,0 //загрузить спрайт биты в 0 LOADSPRITE “fire.bmp”,1 //загрузить спрайт огня в 1 bita_x=320 //координаты биты bita_y=240 fire_x=bita_x //координаты огня те же, что у биты fire_y=bita_y WHILE TRUE //Начало цикла SPRITE 0, bita_x, bita_y,0 //Вывести спрайт биты IF KEY(57) THEN Fire=1 //Если нажат пробел присвоить триггеру 1 IF Fire=1 THEN SPRITE 1, fire_x, fire_y,0 //Если триггер сработал вывести спрайт огня fire_x = fire_x-1 //Изменять координаты спрайта для его движения. SHOWSCREEN WEND
Данная программа будет работать. Бита произведет выстрел. Огонь полетит через экран и исчезнет за его краем. Второй раз мы выстрел сделать не сможем. Очевидно, что триггер так и остался включенным даже когда спрайта огня уже не видно на экране. Необходимо предусмотреть ситуацию обнуления триггера. Это может быть вариант, когда координаты спрайта выходят за границу экрана.
Пример:
IF fire_x <=-50 THEN Fire=0
Кажется все сделано правильно, но мы по-прежнему не видим второго выстрела. Обратимся к отладке (подробнее было в предыдущей главе). Впишем в цикл пару строчек:
PRINT “FIRE = ”+ Fire, 100,100 PRINT “fire_x = ”+ fire_x, 100,140
Запустим программу и видим, что Fire действительно обнуляется, но координаты fire_x продолжают увеличиваться. Т.е. мы не предусмотрели после исчезновения спрайта огня присвоению ему координат биты, для нового выстрела. Огонь начинает движение от биты.
IF fire_x <=-50 Fire=0 fire_x=bita_x //координаты огня те же, что у биты fire_y=bita_y ENDIF
Все здорово, но так мы можем производить только один выстрел. Пока изображение огня не исчезнет с экрана. Вариант применения триггера присвоения переменной к нажатию клавиши, не приведет ни к чему хорошему:
IF KEY(57) fire_x=bita_x //координаты огня те же, что у биты fire_y=bita_y ENDIF
Огонь при нажатии клавиши пробел будет появляться возле биты, даже не долетев до конца и начинать свой путь сначала. Как видите произвести удачный выстрел задача не тривиальная. Но где вы видели стрелялки или арканоиды с одной единственной пулей? Во всех играх стреляют очередями или регулируя частоту выстрелов бесконечным нажатием клавиши пробела. Чем быстрее, тем лучше. Мы рассмотрим упрощенный вариант, который без труда можно усложнить. Позволим игроку произвести 2 выстрела. Т.е. на экране может быть до двух изображений огня. Удобно для этого использовать массивы, но я для простоты от них откажусь.
Fire=0 //Триггер выстрела в 0, т.е. нет выстрела Fire2=0 //Триггер выстрела в 0, т.е. нет выстрела LOADSPRITE “bita.bmp”,0 //загрузить спрайт биты в 0 LOADSPRITE “fire.bmp”,1 //загрузить спрайт огня в 1 bita_x=320 //координаты биты bita_y=240 fire_x=bita_x //координаты огня те же, что у биты fire_y=bita_y fire2_x=bita_x //координаты огня те же, что у биты fire2_y=bita_y WHILE TRUE //Начало цикла SPRITE 0, bita_x, bita_y,0 //Вывести спрайт биты IF KEY(57) IF Fire=0 fire_x=bita_x //координаты огня те же, что у биты fire_y=bita_y Fire=1 ENDIF IF KEY(57) IF Fire2=0 fire2_x=bita_x //координаты огня те же, что у биты fire2_y=bita_y Fire2=1 ENDIF IF Fire=1 THEN SPRITE 1, fire_x, fire_y,0 //Если триггер сработал вывести спрайт огня IF Fire2=1 THEN SPRITE 1, fire_x, fire_y,0 //Если триггер сработал вывести еще один спрайт огня fire_x = fire_x-1 //Изменять координаты спрайта для его движения. Fire2_x = fire2_x-1 //Изменять координаты спрайта для его движения. IF fire_x <=-50 Fire=0 ENDIF IF fire2_x <=-50 Fire2=0 ENDIF SHOWSCREEN WEND
Этот вариант очень хорош. На его основе можно создать любые комбинации выстрелов – очереди, автофайр и т.д. В вышеприведенный пример желательно добавить массивы:
DIM Fire[2] DIM fire_x[2]
А также выделить в подпрограммы логические конструкции. Но об этом уже неоднократно рассказывалось в предыдущих главах.
(Продолжение следует)