на главную почта поиск
 
поиск
Диона Холдинг
   
   
FLASH-версия 
 Версия для печати 
  Новости
 

   
Новости  
   

Глава 12. Платформы и лифты

Свистать всех наверх, мальчики и девочки, сегодня, я собираюсь рассказать вам маленькую историю о перемещении плиток. Некоторые из вас может быть знают об этом под названием «латформа» (или лифт), пусть вас не смущает название, это все также интересно.

Однажды, много лет тому назад, в стране игр жила юная плитка. Она была счастлива.

В один прекасный день, Герой подошел к ней и спросил: «Юная плитка, почему ты не летаешь?»

("…как птица, вот, так раскрыла бы руки и полетела", - говорили в одном старом кино.)

«Я не знаю, что такое летать» - ответила маленькая плитка.

«Это грустно» - вздохнул Герой – «Сейчас я хотел бы вступить на вас и полететь вместе с вами к звездам (солнцу, счастью и богатству).

Этот день изменил жизнь юной плитки, она перестала быть счастливой.

Но мы можем помочь ей обрести счастье.

Прежде чем начнем кодировать, напишем несколько правил. Правила, они, обычно, только раздражают, но, как ни странно, очень полезны. Что делать? Куда идти? В чем смысл жизни? Правила отвечают:

  • перемещающиеся плитки – плитки типа «облако» (для примера посмотрите здесь)
  • перемещение плиток может быть по горизонтали и вертикали
  • когда Герой вступает на перемещающуюся плитку, он перемещается вместе с плиткой
  • Герой по прежнему не может проходить сквозь стену.

Шаги в перемещении плитки

Итак, как Герой вступает на двигающуюся плитку? Первое и простое решение – прыгает на нее.

На картинке Герой движется вниз и на следующем шаге должен быть внутри двигающейся плитки. Мы будем размещать его, стоящим на плитке.

Примечание. Герой НА плитке или ПОД плиткой. В любом случае, Герой приземляется на плитку.

Но это не единственный способ перехода на платформу. На следующей картинке, Герой стоит на куске стены и ему некуда податься.

А тут плитка движется вверх и на следующем шаге, Герой уже на плитке (как будто зацепился лифтом). Да, нам нужно отследить момент, когда Герой будет подхвачен плиткой, и начнет перемещаться вместе с ней.

(Единственный вопрос – а, иде Герой - внутри или сверху плитки? Его подхватывает верхний край или нижний? А это второй вопрос, но, судя по всему, - верхний край.)

Спрыгивание

Раз Герой стоит на движущейся плитке, нужны способы для Героя, как сойти с нее. Первое, он может спрыгнуть. Он может идти по краю плитки, а потом прыгнуть. Другие возможные критические и опаные для Героя ситуации представлены на картинках ниже.

На этих картинках, Герой при движении плитки должен, либо уменьшится в росте, чтобы его не раздавило, либо сплющиться (резко похудеть), чтобы остаться на плитке. Здесь, правда, Герою лучше прыгнуть вниз или вверх, чтобы избежать столкновения. Если же этого не происходит, то Герою капут, в первом случае, а во втором, он падает, а дальше как получится (высоко ли низко, а успели ли что подложить, подушечку, например).

На этой картинке, Герой вместе с лифтом движется вниз и его цепляет стена, далее плитка движется уже без Героя.

Подготовка

Нарисуем клип движущейся плитки. Вы можете нарисовать разные движущиеся плитки. Назовем кадры клипа "movingtiles". А в библиотеке клипу пропишем имя в свойстве "Linked"- "movingtiles".

Объявим объект движущейся плитки:

// Плитка – тип 1 движущаяся, скорость -2, направление движения и мин-макс перемещения
game.MovingTilep1= function () {};
game.MovingTilep1.prototype.speed=2;
game.MovingTilep1.prototype.dirx=0;
game.MovingTilep1.prototype.diry=1; // Движется по вертикали
game.MovingTilep1.prototype.miny= 0;
game.MovingTilep1.prototype.maxy=2;
game.MovingTilep1.prototype.width=game.tileW/2; // Размеры «лифта»
game.MovingTilep1.prototype.height=game.tileH/2;

// Плитка – тип 2 движущаяся, скорость -2, направление движения и мин-макс перемещения
game.MovingTilep2= function () {};
game.MovingTilep2.prototype.speed=2;
game.MovingTilep2.prototype.dirx=1; // Движется по горизонтали
game.MovingTilep2.prototype.diry=0;
game.MovingTilep2.prototype.minx= -2; // Задается в плитках
game.MovingTilep2.prototype.maxx=2;
game.MovingTilep2.prototype.width=game.tileW/2;
game.MovingTilep2.prototype.height=game.tileH/2;

У нас 2 типа плиток: MovingTilep1 будет перемещаться вертикально (свойство diry – 1) и MovingTilep2 будет перемещаться горизонтально (свойство dirх также имеет значение 1). Плитка имеет свойство скорости перемещения, как уже догадались, - количество пикселов, на которые перемещается плитка за шаг.

Свойства miny/maxy/minx/maxx будут устанавливать границу перемещения. Здесь можно указывать абсолютные значения, но это может привести к чистому волшебству или конфузу. Поэтому будем устанавливать относительные координаты начальной позиции двигающейся плитки. В этом случае плитку можно устанавливать в пределах границ где угодно, она будет правильно отображаться на экране. Нужно только помнить, движущаяся плитка не проверяет наличие препятствий и соответственно размещать ее нужно так, чтобы ей не мешали стенки.

(Хотя почему, стенка может выступать в качестве тормоза для смены направления движения плитки, да и из стенки она (плитка) тоже может вылезти, вот такая у нас волшебная стенка. Здесь, твори выдумывай и пробуй. Я думаю, что в игре мы выступаем в качестве бога. Другое дело, сейчас это значительно усложнит код и наши письмена. У нас другая задача.)

Посмотрим на пример. Движущаяся плитка начинает с позиции x=2, y=5. Она перемещается вертикально, свойства miny=-1, maxy=4. Как далеко она будет перемещаться? (Тут, все путается от знаков, терминов и т.п.) Минимальная позиция по У от начала - y-miny=5+(-1)=4 равна x=2, y=4. Максимальная позиция по У - 5+4=9 - x=2, y=9.

Для хранения позиции двигающейся плитки будем использовать массив аналогичный массиву Врагов:

//moving tiles array is in the order [tile type, xtile, ytile]
myMovingTiles = [ [0], [[1, 4, 2]], [[2, 4, 4]] ];

На карте 1 мы объявили 1 движущуюся плитку – 1-ого типа ( созданная на базе шаблона MovingTile1), с начальной позицией x=4, y=2. На карте 2 - также 1 плитка. Можно описать и больше движущихся плиток на каждой карте.

Далее, добавим движущиеся плитки в функцию buildMap. Код напишем после блока кода Врагов:

// Блок кода для движущихся плиток
// Как и для Артефактов, скопируем массив платформ текущей карты
game.movingtiles = myMovingTiles[game.currentMap];
// Цикл по массиву описания платформ
for (var i = 0; i<game.movingtiles.length; ++i) {

// Формируем имя
var name = "movingtile"+i;
// Создаем объект с учетом имени
game[name]= new game["MovingTilep"+game.movingtiles[i][0]];
// Присоединяем клип из библиотеки под нужным именем и кладем его на уровень - 12001+i
game.clip.attachMovie("movingtiles", name, 12001+i);
// Запомним клип в общей структуре клипов
game[name].clip=game.clip[name];
// Показываем клип с нужного кадра
game[name].clip.gotoAndStop(game.movingtiles[i][0]);
// Стартовую позицию запомним
game[name].xtile = game.movingtiles[i][1];
game[name].ytile = game.movingtiles[i][2];
// Вычислим координаты Х / У размещения клипа
game[name].x = game[name].xtile *game.tileW+game.tileW/2;
game[name].y = game[name].ytile *game.tileH+game.tileH/2;
// Запомним их в свойствах клипа
game[name].clip._x = game[name].x;
game[name].clip._y = game[name].y;
// Запомним и размах движения платформы
game[name].minx=game[name].minx+game[name].xtile;
game[name].maxx=game[name].maxx+game[name].xtile;
game[name].miny=game[name].miny+game[name].ytile;
game[name].maxy=game[name].maxy+game[name].ytile;
}

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

Примечание, плитка типа 1 показывается с кадра 1, плитка типа 2 – с кадра 2.

Последня часть кода рассчитывает значение границ для каждой движущейся плитки, свойства miny/max/minx/maxx пока еще расчитываются в абсолютных координатах. Почему? Да, потому. Нам не нужно каждый раз при переходе к новой карте (или возврате на старую карту) вычислять координаты границ.

(Чего там считать то? Крохи.)

В функции moveChar добавим 1 строку в начало для сохранения текущей позиции по У.

ob.lasty=ob.y;

Также перепишем код в той же функции для движения вниз:

if (diry == 1) {

if (ob.downleft and ob.downright and !checkMovingTiles(speed*diry)) {

ob.y += speed*diry;
} else {

ob.jump = false;
if(ob.onMovingTile){

ob.y=ob.onMovingTile.y-ob.onMovingTile.height-ob.height;
}else{

ob.y = (ob.ytile+1)*game.tileH-ob.height;
}

}

}

Добавлен вызов функции checkMovingTiles, которая возвращает true, в случае, когда Герой вспрыгивает на движущуюся плитку. Если он вспрыгнул на нее, то установим У координату Героя, таким образом Герой останется сверху на плитке.

Герой на платформе?

Вы уже догодались о характере дополнений в функции moveChar, да. Самое время создать новую функцию для проверок нахождения объекта (Героя) на движущейся плитке. Функция checkMovingTiles ответит не только на этот вопрос, но и сохранит плитку, на которую встал Герой в его собственных свойствах.

//****************
// Функция: checkMovingTiles
// Назначение: Проверка вспрыгивания объекта на движущуюся плитку
// Параметры:
// у – координата по У
// Возвращает:
// true - объект есть
// false - плитка пуста
// ****************************
function checkMovingTiles (y) {

// Проверим (Объект идет вниз)?
if(char.diry<>-1){

// ДА – вычислим мин-макс параметры движения
var heroymax=char.y+char.height+y;
var heroxmax=char.x+char.width;
var heroxmin=char.x-char.width;
// Результат функции - пока плитка пуста
foundit=false;
// Цикл (по платформам)
for (var i = 0; i<game.movingtiles.length; i++) {

// Запомним текущую платформу
var ob=game["movingtile"+i];
// Вычислим мин-макс координаты движения платформы
var tileymax=ob.y+ob.height;
var tileymin=ob.y-ob.height;
var tilexmax=ob.x+ob.width;
var tilexmin=ob.x-ob.width;
// Проверим (Координаты У объекта < мин платформы)?
// Странный способ проверки вспрыгивания объекта на плитку
if(char.lasty+char.height<=tileymin){

// ДА - Проверим (попадание У координат объекта в интервал движения плитки)?
// Еще одна странная проверка, как все здесь запущено…
if (heroymax<=tileymax and heroymax>=tileymin) {

// ДА – Проверим (попадание Х координат объекта в интервал движения плитки)?
// И еще не менее странный способ проверки
if (heroxmax>tilexmin and heroxmax<tilexmax) {

// ДА – в свойство запищем объека платформу, на которой он движется
char.onMovingTile=ob;
// Запомним результат функции – Да, на платформе торчит кто-то
foundit=true;
// Конец цикла
break;
// НЕТ – Проверим (может по Х координате что-то попадется)?
} else if (heroxmin>tilexmin and heroxmin<tilexmax) {

// ДА – запишем в свойство объекта платформу на которой он движется
char.onMovingTile=ob;
// Запомним результат функции – Да, на платформе торчит кто-то
foundit=true;
// Конец цикла
break;
}

}

}

}

// Возвращаем - Результат функции
return(foundit);
}

}

Посмотрим, что здесь произошло. Если объект не движется вверх (diry = 1), рассчитываем границы для объекта. Затем, открываем цикл по всем движущимся плиткам. Переменная ob содержит объект – текущей движущейся плитки. Вычислим для текущей плитки возможные препятствия.

Если условия размещения объекта соответствуют корректному вспрыгиванию на движущуюся плитку, то объект присоединяется к плитке в свойстве onMovingTile .

Уже поехали

Теперь начианется самое трудное, т.к. сейчас нужно будет проверять и движение плитки и опасности для того кто на ней находится. А ведь ему грозят разные опасности – либо его раздавит плиткой сверху, либо он упадет, если не похудеет. Все эти проверки делаем в функции moveTiles.

//****************
// Функция: moveTiles
// Назначение: Самодвижение плитки – включаем и поехали
// Параметры:
//
// Возвращает:
//
// ****************************
function moveTiles () {

// Цикла (по платформам)
for (var i = 0; i<game.movingtiles.length; i++) {

// Запомним текущю платформу
var ob=game["movingtile"+i];
// Вычислим препятствия
getMyCorners (ob.x + ob.speed*ob.dirx, ob.y + ob.speed*ob.diry, ob)
// Проверим (Препятствия ЕСТЬ по вертикали)?
if (ob.miny>ob.upY or ob.maxy<ob.downY) {

// ДА - Меняем на противоположное движение платформы по У
ob.diry=-ob.diry;
}

// Проверим (Препятствия ЕСТЬ по горизонтали)?
if (ob.minx>ob.leftX or ob.maxx<ob.rightX) {

// ДА - Меняем на противоположное движение платформы по Х
ob.dirx=-ob.dirx;
}

// Вычисляем координаты Х / У
ob.x = ob.x + ob.speed*ob.dirx;
ob.y = ob.y + ob.speed*ob.diry;
// Вычисляем позицию платформы Х / У
ob.xtile = Math.floor(ob.x/game.tileW);
ob.ytile = Math.floor(ob.y/game.tileH);
// Вычисляем координаты Х / У для клипа
ob.clip._x = ob.x;
ob.clip._y = ob.y;
// Проверим (Движение вверх по вертикали)
if(ob.diry==-1) {

// ДА - Вызываем проверку подхвата Героя на платформу
checkMovingTiles(0);
}

}

// Проверим (Герой на плитке)?
if(char.onMovingTile) {

// ДА – для него посчитаем препятствия
getMyCorners (char.x, char.y+char.onMovingTile.speed*char.onMovingTile.diry, char);
// Проверим (Герой ползет ВВЕРХ)?
if (char.onMovingTile.diry == -1) {

// ДА – Проверим (Препятствий НЕТ)?
if (char.upleft and char.upright) {

// ДА – меняем координаты Героя
char.y=char.onMovingTile.y-char.onMovingTile.height-char.height;
} else {

// НЕТ – координата Героя
char.y = char.ytile*game.tileH+char.height;
// Герой – прыгает автоматом
char.jumpspeed = 0;
char.jump = true;
// Платформу отсоединяем от Героя
char.onMovingTile=false;
}

}

// НЕТ – Проверим (Герой ползет ВНИЗ)?
if (char.onMovingTile.diry == 1) {

// ДА – Проверим (Препятствий НЕТ)?
if (char.downleft and char.downright) {

// ДА – меняем координаты Героя
char.y=char.onMovingTile.y-char.onMovingTile.height-char.height;
} else {

// НЕТ – Освобождаем платформу
char.onMovingTile=false;
// Герой остался на стене
char.y = (char.ytile+1)*game.tileH-char.height;
}

}

// Посчитаем препятствия по горизонтали
getMyCorners (char.x+char.onMovingTile.speed*char.onMovingTile.dirx, char.y, char);
// Проверим (платформа движется ВЛЕВО)?
if (char.onMovingTile.dirx == -1) {

// ДА – Проверим (Препятствий НЕТ)?
if (char.downleft and char.upleft) {

// ДА – пересчитаем Х координат Героя
char.x += char.onMovingTile.speed*char.onMovingTile.dirx;
} else {

// НЕТ – Герой падает с платформы
char.x = char.xtile*game.tileW+char.width;
fall (char);
}

}

// Проверим (платформа движется ВПРАВО)?
if (char.onMovingTile.dirx == 1) {

// ДА – Проверим (Препятствий НЕТ)?
if (char.upright and char.downright) {

// ДА – пересчитываем Х координату Героя
char.x += char.onMovingTile.speed*char.onMovingTile.dirx;
} else {

// НЕТ – Герой падает
fall (char);
// Пресчитаем Х координату Героя (А после-то зачем?)
char.x = (char.xtile+1)*game.tileW-char.width;
}

}

// Обновим Героя
updateChar (char);
}

}

Хорошо, о чем мы, это, говорили, а, первая часть движения платформы. Цикл по плиткам и сравнение позиции объекта со свойствами . Если плитка слишком далеко, то движение пойдет в обратном направлении.

(Здесь уж, слишком как-то все запутанно.)

Следующий код:

if(ob.diry==-1){

checkMovingTiles(0);
}

Этим условием проверяем – подобрали мы объект. Это возможно в том случае, если объект стоит на краю стены, а плитка поднимается вверх (diry= -1).
Условие :

if(char.onMovingTile){

касается Героя на плитке. Свойство onMovingTile говорит о нахождении объекта (Героя) на плитке и необходимости проверки для него (объекта) возможных препятствий при движении плитки. Это тот же код, что и в функции moveChar. Нам нужно вычислить препятствия по углам, используем функцию getMyCorners . Если препятствий нет, то перемещаем плитку с Героем . Ну а если есть, то Герой не может оставаться на плитке.

(И че, За этим должен следить игрок, а плитка все одно должна ехать, так и Герою капут. Кстати там так и написано. А вот, не капут, Герой автоматом скатывается с платформы, за этим должен следить игрок. )

Туда и обратно, тебе и мне приятно - качели

В функции detectKeys добавим строку для начала движения платформ, прежде, чем Герой начнет двигаться:

moveTiles();

Если вдруг Герой сиганет куда-нибудь, в свойство onMovingTile запишем false: (Т.е. в прыжке нельзя попасть на движущуюся плитку.)

ob.onMovingTile=false;

Там же, когда Герой перемещается влево/вправо, проверим для движущихся плиток:

if (!checkMovingTiles(1)) {

char.onMovingTile = false;
}

(Здесь наворочено так много условий, что их надо очень внимательно проверять. Как быть с прозрачными плитками при встрече друг с другом? Можно ли переходить с одной движущейся плитки на другую? Почему нельзя прыгать? И т.д. и т.п. Вопросов выше крыши, придется изучать.)

Исправление ошибок. 11.04.2005. Дункан (Dunkan) нашел ошибку при горизонтальном движении плитки. Когда Герой топает по краю стены, объект не может определить движущуюся плитку и продолжает топать. Пожалста, проверьте перемещение плиток только по клавишам лево/право.

Можно загрузить исходный код отсюда.

Есть вопросы - пишите мне на semikin@dionaholding.ru

Читаем дальше - Глава 13. Скроллинг

Возвращение на Начало учебника

 

Всего: 5

Электронные формы от Adobe

14 ноября с.г. компания представила новую версию всем известного средства Adobe Acrobat. 8-ая по счету версия принесла новые возможности по переходу от бумажных документов к электронным.
читать
 

АрмПарк - Универсальная учетная система

Серия материалов о программе - АрмПарк - Универсальная учетная система. Решение для тех кому необходимо быстро создать и внедрить электронную картотеку по учету - документов, матералов, оборудования, ресурсов или зеленых человечков.
читать
 

Программирование игр на основе плиток

Представляется перевод замечательного учебника по созданию движка игры на основе плиток (Tile Based Games). Я благодарен автору Tonypa за разрешение публикации перевода. Если у Вас возникают вопросы, пишите и я постараюсь Вам помочь.
читать
 

Универсальная информационная система-конструктор Учет документов (Доклад на конференции).

Доклад на Третьей практической конференции по Электронному Документообороту - "Программа "Учет документов" ", 9 декабря, Москва, Мэрия Москвы.
читать
 

Интеграция систем с использованием новых технологий

Один из ключевых моментов совершенствования электронного бизнеса - это повышение гибкости процессов за счет ускорения реализации решений в области интеграции.
читать
Всего: 5

Rambler's Top100

   
   

новости

продукты

решения

услуги

о компании

   
   
125315, Москва, Часовая ул., д.30
Телефон: (095)797-32-82; Факс: (095)797-32-81
© 2005 ООО "Диона Холдинг"
Администратор: admin@dionaholding.ru