Архивы: по дате | по разделам | по авторам

DiNGS – программирование игр в домашних условиях. Часть 15

АрхивПрограммазм (архив)
автор : Александр Супрунов   18.04.2003

Клавиши в игре, метеоры и другие эффекты...

Многие играли в космические стрелялки, где маленький отважный истребитель выносит с экрана полчища врагов ураганным огнем лазерных пушек, но мало кто задумывался как это реализовано. Ах, какая ерунда! Как бы не так. Все это достаточно сложно и есть много методов решения этой проблемы.

Но как это соотносится с программированием Понга? Во многих играх, даже не стрелялках используются выстрелы. Вспомните тот же «Арканоид», где часто встречается приз «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]

А также выделить в подпрограммы логические конструкции. Но об этом уже неоднократно рассказывалось в предыдущих главах.

(Продолжение следует)

© ООО "Компьютерра-Онлайн", 1997-2024
При цитировании и использовании любых материалов ссылка на "Компьютерру" обязательна.