Глава 10. Убей его
Поговорим об уничтожении Врага. Можно использовать бластер, пистолет, палку, слово ( экстремально мощное оружие, но требует длительного обучения, чтобы стать мастером). Мы будем использовать клавишу SHIFT, чтобы стрелять во Врага. Когда я говорю «Снаряд», я считаю, что это любой объект, летящий от Героя в направлении Врага. Это может быть шар, стрела, мороженное, пингвин, что угодно. Первое, давайте поразмышляем над тем, что надо сделать, чтобы выстрелить, и каково поведение нашего Снаряда. Когда нажимаем клавишу SHIFT, объект Снаряд и его изображение в виде клипа должно быть создано корректно на стороне Героя. После чего Снаряд начинает автоматически перемещаться по направлению движения Героя. Если Снаряд сталкивается со стеной или Врагом, он (снаряд) разрушает препятствие. Скорость Снаряда должна быть выше скорости Героя, иначе Герой сам падет «дручком пропертый» (так говорят на Украине, но, по русски, очень даже понятно). Обычно глупый Враг не видит летящий снаряд, но можно создать Врага, который будет уворачиваться от снаряда. Можно создать Врага, стреляющего в Героя. (Здесь есть поле, где может развернуться фантазия разработчика.)
Подготовка к стрельбеНарисуем клип Снаряда и дадим ему имя "bullet" для присоединения клипа к объекту при показе на экране. Графика внутри клипа должна быть выровнена относительно центра картинки. Объявим снаряд: game.Bullet= function () {}; game.Bullet.prototype.speed=5; game.Bullet.prototype.dirx=0; game.Bullet.prototype.diry=-1; game.Bullet.prototype.width=2; game.Bullet.prototype.height=2;
Снаряды будут лететь со скростью 5 пикселов за тик. Они имеют width/height (ширину/высоту) - 2 пиксела и наносят достаточное повреждение Врагу. Свойства dirx/diry будут определять направление полета Снаряда. Их смысл такой же, как и в других объектах. Возьмем текущее направление полета Снаряда от свойств объекта (Героя), но в начале игры, когда Герой еще никуда не двигается, а игрок хочет пальнуть, то Снаряд полетит вверх - по умолчанию. (Как говорится Попал пальцем в небо.) Добавим два новых свойства объекту game: game={tileW:30, tileH:30, currentMap:1, bulletcounter:0}; game.bullets= new Array();
Свойство bulletcounter будет хранить число использованных Снарядов и поможет создавать новый объект Снаряд с новым именем. Первый объект Снаряд будет называться bullet0 и далее по возрастанию. Максимальное количество - 100, после счетчик сбрасывается в 0. В теории, число Снарядов бесконечно, но кто знает, что при этом может случиться. Свойство game.bullets массив, сохраняющий информацию о выпущенных снарядах. Сначала игры массив выстрелов пуст. Для объекта (Героя) добавим свойство shootspeed (скорострельность) - обеспечивает паузу между выстрелами. В этот период, сколько не жми на курок, в ответ тишина. char={xtile:2, ytile:1, speed:4, shootspeed:100};
Высокое значение свойства скорострельности говорит о медленной стрельбе, уменьшение значения скорость стрельбы увеличивается. Значение 1000 говорит о задержке в 1сек. между выстрелами. (Здесь надо назвать свойство не скорострельность, а скорее «тихострелльность».) Убитый Враг удаляется из игры. Изменим часть кода, связанного с Врагом, в функции buildMap: game.currentEnemies = new Array(); for (var i = 0; i<enemies.length; ++i) { var name = "enemy"+i; game[name]= new game["Enemyp"+enemies[i][0]](); game[name].id=i; game.currentEnemies.push(game[name]);
А функции соображалки Врага enemyBrain заменим строку: var name = "enemy"+i;
На var name = "enemy"+game.currentEnemies[i].id;
Будем использовать свойство currentEnemies объекта game для сохранения данных о всех Врагах на поле боя. Когда Враг убит, удалим его из массива. Новое свойство "id" поможет нам удалить объект Враг из массива. Кроме этого, там же, пересчет Врагов делаем в цикле: for (var i = 0; i<game.currentEnemies.length; ++i) {
В функции detectKeys добавим код после проверки нажатия клавиш: if (Key.isDown(Key.SHIFT) and getTimer()>ob.lastshot+ob.shootspeed) { _root.shoot(ob); }
Если нажата клавиша SHIFT и времени прошло больше, чем пауза между выстрелами, то вызываем функцию shoot. В начале , добавим две строки в функцию moveChar, чтобы сохранить направление движения объекта. ob.dirx=dirx; ob.diry=diry;
Будем использовать эти данные для определения направления полета cнаряда. ВыстрелДля создания Cнарядов и обеспечения их полета создаем функцию shoot: //**************** // Функция: shoot // Назначение: Выстрел объекта (Героя или Врага) // Параметры: // ob - объект // Возвращает: // **************************** function shoot (ob) { // Получаем число милисекунд, прощедших после последнего вызова Таймера ob.lastshot=getTimer(); // Счетчик выстрелов + 1 game.bulletcounter++; // Проверим (Выстрелов перебор)? if (game.bulletcounter>100) { // ДА Счетчик выстрелов в 0 game.bulletcounter=0; }
// Формируем имя объекта снаряд var name = "bullet"+game.bulletcounter; // Создаем новый объект game[name]= new game.Bullet(); // Запомним номер выстрела в свойстве объекта game[name].id=game.bulletcounter; // Добавим объект в массив Снарядов game.bullets.push(game[name]); // Проверим (Объект двигался)? if (ob.dirx or ob.diry) { // ДА запомним нарпавление движения в свойствах Снаряда game[name].dirx= ob.dirx; game[name].diry= ob.diry; }
// Запоминаем для Снаряда позицию Х / У по позиции объекта (Героя или Врага) game[name].xtile= ob.xtile; game[name].ytile= ob.ytile; // Присоединяем клип снаряда из библиотеки по именем и // кладем его на уровень 10100+game.bulletcounter game.clip.attachMovie("bullet", name, 10100+game.bulletcounter); // Клип запоминаем в общей структуре game[name].clip=game.clip[name]; // Вычисляем координаты Х / У клипа game[name].x = (ob.x+game[name].dirx*ob.width); game[name].y = (ob.y+game[name].diry*ob.height); // Запоминаем их в свойствах клипа game.clip[name]._x = game[name].x; game.clip[name]._y = game[name].y;
}
Первое, кто стрелял? Это может быть, как Герой, так и Враг, все определяется параметром ob и местом вызова функции выстрела. Мы используем функцию getTimer(), чтобы сохранить время выстрела в свойстве lastshot и в нужном месте проверить возможность выстрела с учетом паузы. Далее, увеличиваем счетчик выстрелов game.bulletcounter на 1 и проверяем, если их больше 100, то обнуляем счетчик. Теперь создаем новый объект bullet с именем по счетчику выстрелов, все эти данные сохраняются в объекте game. Снаряд добавляется в массив снарядов game.bullets. Далее проверяем наличие свойств dirx/diry для объекта и сохраняем значения, либо объекта, либо по умолчанию (т.е. в небо идет из шаблона объекта). Чтобы показать Снаряд, нам нужно сохранить позицию объекта (Героя) на карте. Свойства объекта ob.xtile / ob.ytile копируются в объект bullet. Последняя часть кода присоединяет клип Снаряда, рассчитывает его координаты для показа. Интерсен способ расчета начальной позиции Снаряда. game[name].x = (ob.x+game[name].dirx*ob.width);
Первое, берется позиция объекта, это центр объекта. Т.к. Снаряд не может вылететь из Героя, то добавим ширину Героя с учетом направления его движения. Когда Герой стоит, снаряд полетит из точки его центра выше или ниже. Убит!В конце функции detectKeys добавим строку, вызывающую вторую новую функцию, которая будет перемещать Снаряд и следить за тем в кого он попал. _root.moveBullets();
А вот и сама функция: //**************** // Функция: moveBullets // Назначение: Полет снаряда (Героя или Врага) Вот пуля полетела и, ага! // Параметры: // // Возвращает: // **************************** function moveBullets () { // Цикл по снарядам for (var i = 0; i<game.bullets.length; ++i) { // Запомним объект Снаряд var ob=game.bullets[i]; // Получим препятствия getMyCorners (ob.x+ob.speed*ob.dirx, ob.y+ob.speed*ob.diry, ob); // Проверим (Препятствий НЕТ)? if (ob.downleft and ob.upleft and ob.downright and ob.upright) { // ДА Как летит пуля? - Пуля (с ударением на последнем слоге) летит по дуге. moveChar(ob, ob.dirx, ob.diry);
} else { // НЕТ Вот пуля попала удаляем клип Снаряда, а как же Стена ob.clip.removeMovieClip(); // Удаляем объект Снаряд delete game["bullet"+game.bullets[i].id]; // Удаляем Снаряд из массива снарядов game.bullets.splice(i,1); // Нужно добавить функции удаления стены // … }
// Цикл по Врагам (Считается, что пуля попала во Врага. // Здесь должна быть проверка В кого попал Снаряд for (var j = 0; j<game.currentEnemies.length; ++j) { // Формируем имя Врага var name = "enemy"+game.currentEnemies[j].id; // Запомним объект текущего Врага var obenemy = game[name]; // Вычислим Х / У расстояние между Врагом и Снарядом var xdist = ob.x - obenemy.x; var ydist = ob.y - obenemy.y; // Проверим (Снаряд попал)? if (Math.sqrt(xdist*xdist+ydist*ydist) < ob.width+obenemy.width) { // ДА Удаляем клип Врага obenemy.clip.removeMovieClip(); // Удаляем объект Врага delete game["enemy"+game.currentEnemies[j].id]; // Удаляем убиенного из массива Врагов game.currentEnemies.splice(j,1); // Удаляем клип Снаряда из промежуточного объекта ob.clip.removeMovieClip(); // Повторно удаляем Снаряд из структуры и массива (А зачем, его уж там и нет) // delete game["bullet"+game.bullets[i].id]; // game.bullets.splice(i,1); }
}
}
}
Функция в цикле просматривает все Снаряды по массиву снарядов. Используем функцию getMyCorners для определения препятствий для Снаряда. Если препятствий нет, то функцией moveChar перемещаем Снаряд. Теперь, если снаряд попадает в стену, то нужно разрушить ее. Это требует 3 действий с использованием id снаряда и еще 3 действий для стенки: - Удалить клип снаряда (используем функцию removeMovieClip)
- Удалить объект снаряд (используем функцию удаления)
- Удалить текущий снаряд из массива снарядов.
(А как же сама стенка? А кампот?) Мы не можем оставить объект Снаряд в игре, т.к. он все равно не виден, да и из массива будет удален. Когда Снаряд удален, стенка еше стоит, теперь пришла пора проверить, а может это Враг. В цикле проверим Врагов из массива currentEnemies и посчитаем рассотяние между Врагом и снарядом. Если оно очень маленькое, значит снаряд встретил Врага и обоих можно кирдык. Если мы хотим в игре уничтожить Врага навсегда, даже после смены карты, то нужно разместить строку после расчета расстояния между снарядом и Врагом: myEnemies[game.currentMap][obenemy.id]=0;
Можно сделать стрельбу более интересной: - Ограничить количество снарядов. Можно установить номер снаряда, а затем уменьшать на 1, а условие возможности выстрела проверять по > 0.
- Ограничиться только одним снарядом на период пока он с кем-нибудь не встретится. Это осуществляется проверкой массива снарядов game.bullets по условию > 0.
- Создать стреляющих Врагов. Да еще чтобы они стреля случайным образом и в случайное время.
- Создать разное оружие с возможностью его выбора. Можно объявить разные типы снарядов разной опасности.
(Здесь также есть место, где может развернуться фантазия разработчика.) Счастливой охоты . Можно загрузить исходные коды и клипы отсюда. Можно реализовать стрельбу в прыжке. Сначала изменим в функции moveChar строки сохранения направления движения объекта по горизонтали: if (dirx<>0) { ob.dirx = dirx; }
Исходник с примером можно взять отсюда. (Там, правда, про стрельбу в прыжке (или стрельба по «македонски») ничего нет, но стрельба в прыжке есть.) Исправление ошибок. 20.12.2003. В функции moveBullets строка: var name = "enemy"+j;
Должна быть заменена строкой: var name = "enemy"+game.currentEnemies[j].id;
Кто увидит старую версию, поправьте. Благодарности Christian и Travis, нашедшим ошибку. Ошибка 01.03.2004. В функции enemyBrain строка: var name = "enemy"+i;
Должна быть: var name = "enemy"+game.currentEnemies[i].id;
Глупый я, глупый благодарности Ian, указавшему на нее. Есть вопросы - пишите мне на semikin@dionaholding.ru Читаем дальше - Глава 11. Подарки и сокровища Возвращаемся на Начало учебника
|