Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Программирование игр на Flash/Flex


Добрый день, уважаемые читатели!

В этом выпуске рассылки мы разработаем простую игру, в которой будет один подвижный объект и несколько препятствий. Задача играющего - объехать препятствия, и добраться до цели. Целью является неподвижный объект.

Желающие могут получить архив с полным текстом модулей проекта здесь.

Мы рассмотрим следующие приемы разработки программ (игр) на языке ActionScript 3.0:

  • Разработка компонента для ввода числовой информации, содержащего поле ввода и две кнопки.
  • Задание ограничений множества вводимых символов.

Условия игры

Как и в игре SimpleMove, описанной в одном из предыдущих выпусков, будет использоваться подвижный компонент, управляемый вектором из четырех составляющих, например:
private var _drive:Array = [.1,-.2,5,0];
Где первый компонент управляет движением по оси OX, второй - по оси OY, третий управляет вращением. Четвертый компонент используется для кодирования информации о том, что нужно делать при столкновении и в данной игре не используется (равен 0).
В качестве подвижного компонента используем экземпляр класса Sprite. При нажатии на кнопку Start он устанавливается в исходное положение и вектор _drive получает случайные значения первых трех компонентов. Пользователь может изменять значения этого вектора с помощью компонентов - экземпляров класса NumberField, описанного ниже. Задача играющего - попасть подвижным объектом в неподвижный объект _aim, не задев при этом имеющиеся препятствия.

Управление движением объекта

В данном варианте имеется 5 препятствий - барьеры наружной рамки, и один дополнительный барьер:
_border1 = border(BORDER,BORDER,WIDTH1+BORDER,BORDER);
_border2 = border(BORDER,HEIGHT1+BORDER,WIDTH1+BORDER,HEIGHT1+BORDER);
_border3 = border(BORDER,BORDER,BORDER,HEIGHT1+BORDER);
_border4 = border(WIDTH1+BORDER,BORDER,WIDTH1+BORDER,HEIGHT1+BORDER);
_border1.alpha = _border2.alpha = _border3.alpha = _border4.alpha = 0;
_border5 = border(WIDTH1-BORDER*2,BORDER*4,WIDTH1-BORDER*2,HEIGHT1);

Возникает вопрос: как анализировать столкновение с каждым из этих объектов? Можно, конечно, написать примерно так, как в предыдущем варианте:
var c1:Boolean = !_auto.hitTestObject(_border1);
var c2:Boolean = !_auto.hitTestObject(_border2);
var c3:Boolean = !_auto.hitTestObject(_border3);
var c4:Boolean = !_auto.hitTestObject(_border4);

Тогда каждая булева переменная примет значение "Истина", если не произошло столкновение. Но что, если препятствий не 4 и не 5, а гораздо больше? Скучный и громоздкий код получится! Поэтому давайте поместим указатели на объекты - препятствия в массив. Опишем его так:
private var _borders:Array = new Array();
и после создания всех объектов заполним:
_borders.push(_border1,_border2,_border3,_border4,_border5);
Обратите внимание на следующие два обстоятельства:

  • Метод push() имеет произвольное количество аргументов, что очень удобно.
  • Нельзя заполнять массив раньше, чем будут получены указатели.
Теперь, код для проверки столкновений укладывается в 4 строки, независимо от числа препятствий:
var cc:Boolean = true;
for each (var border:Sprite in _borders){ // Если обнаружено столкновение, сс примет значние Ложь
cc &&= !_auto.hitTestObject(border); // логическая операция И (конъюнкция)
}

С учетом всего сказанного, рассмотрите немного модифицированный по сравнению с предыдущим вариантом вид функции - обработчика события "Тик таймера":
private function tick(e:TimerEvent):void{
if(_auto.hitTestObject(_aim)){ // Если столкновение с объектом-целью
Inform ="Успех!";
_timer.stop();
}else{
var cc:Boolean = true;
for each (var border:Sprite in _borders){ // Если обнаружено столкновение, сс примет значние Ложь
cc &&= !_auto.hitTestObject(border); // логическая операция И (конъюнкция)
}
with (_auto)
if (cc){
x += _drive[0];
y -= _drive[1]; //Отрицательное значение - чтобы было привычное направление по оси Y
rotation += _drive[2];
}else{
_timer.stop();
Inform ="Неудача";
}
}
}

Компонент для ввода числовой информации

Данный компонент состоит из следующих элементов:
private var _field:TextField = new TextField;
private var __caption:TextField = new TextField;
private var _upButton:SimpleButton;
private var _downButton:SimpleButton;
Как видите, два текстовых поля и две кнопки: одна для увеличения, другая для уменьшения значения. В общем, довольно обычный класс. Хотелось бы обратить внимание на решение следующей задачи: При вводе текста в поле _field с клавиатуры, следует ограничить множество допустимых символов. Число может содержать знак "-" и "." (минус и точку), а также цифры. Вот как этого можно добиться:
Назначим слушатель события:
_field.addEventListener(TextEvent.TEXT_INPUT,onInput);
и опишем его так:
private function onInput(e:TextEvent):void{ // Ввод чисел с проверкой
var perm:Array = ["0","1","2","3","4","5","6","7","8","9",".","-"];//Допустимые символы
var cs:String = e.text; // Последний введенный символ
var b:Boolean = false;
for (var i:uint = 0; i < perm.length; i++){
b ||= cs == perm[i]; // Операция ИЛИ. Переменная b примет значение ИСТИНА,
// если введенный символ = одному из элементов массива
}
if ( !b ){
e.preventDefault(); // Если введен недопустимый символ, то ввод игнорируется.
} else{
(e.target as TextField).setTextFormat(Constants.VFORMAT);
}
}
Видите, какая замечательная функция preventDefault().

Рекомендации

Игру следует докрботать, добавив счетчики числа успехов и неудач. Полагаю, не составит труда разработать игру, в которой целевой объект также будет подвижным. Полезно также поупражняться в описании объектов с помощью файла формата XML.
По всем вопросам прошу обращаться по почте, или через любой Интернет-браузер. Мой адрес и другие контактные данные доступны зарегистрированным пользователям сайта. Желаю успехов!


В избранное