Уроки Flash: Pac-Man

Источник: demiart
Ra1nbow

В этом уроке я расскажу Вам, как сделать легендарную игру - Pac-Man.

Будет показано, как делать уровни с помощью двумерного массива, как заставить пак-мана бегать по уровню, будет код искусственного интеллекта, то есть будет код перемещения врага по уровню, но сразу хочу предупредить, что здесь на рассказано, как сделать несколько уровней, и как организовать подсчет очков.

Подготовка.

Теперь преступим к подготовке нашей сцены. Для начала зададим размер сцены. Сделаем ширину 300 пикселей, и высоту 300(см. рис.1).

Pac-Man *

Рис. 1. Параметры сцены.

Теперь создадим на сцене квадрат со стороной 30(в качестве заливки я выбрал светло-серый цвет, а обводку сделал черным). Затем выделите квадрат и нажмите F8. Дальше сделайте, как показано на рис. 2.

Pac-Man *


Рис. 2. Создание квадрата.

На сцене теперь лежит Movie Clip, два раза щелкните по нему. Вы оказались внутри объекта square. Слой, который там уже есть, назовите - square, а затем создайте еще два слоя - "sc" и "object". Затем в слое "square" и "sc" сделайте еще по два keyframe’а, а в слое "object" только в третьем кадре(см. рис. 3).

Pac-Man *


Рис. 3. Timeline объекта square.

После этого в каждом кадре слоя "sc" пропишите stop(). Затем во втором кадре слоя "square" залейте квадрат черным цветом, а в третьем кадре слоя "object" нарисуйте оранжевый кружок размера приблизительно 13x13 посредине квадрата. То есть в первом кадре у вас должно получиться серый квадрат, во втором черный, а в третьем серый квадрат, с оранжевым кружочком посредине.

Теперь настало время нарисовать самого Pac-man’а. Для этого нажмите Ctrl+F8. И в поле name напишите hero

Слой "Layer 1" переименуйте в "hero", нарисуйте желтенький кружок размера 25x25, и задайте ему координаты по x и y 0. Затем нажмите два раза F5, а затем F6, с делайте "надрез", как показано на рисунке ниже, после чего нажмите F5 еще раз.

Pac-Man *

В итоге timeline объекта "hero" должна выглядеть как на рис. 4.

Pac-Man *


Рис. 4. Timeline объекта "hero"

Далее нажмите Ctrl+F8, и заполните форму Creating New Symbol, как показано на рисунке 5.

Pac-Man *


Рис. 5. Создание объекта "hero_dyn".

Слой "Layer 1" переименуйте в "hero". И перетащите из библиотеки объект "hero" и задайте ему координаты по x и y 0. Затем нажмите F6, выделите наш кружок, далее нажмите Modify -> Transform -> Fip Horizontal. Затем нажмите F6 два раза. Затем перейдите в 3 кадр нажмите один раз на наш кружок и нажмите Ctrl+Shift+7(поворот на 90 градусов против часовой стрелки), затем перейдите в 4 кадр и нажмите один раз на наш кружок и нажмите Ctrl+Shift+9(поворот на 90 градусов по часовой стрелке).

Затем сделайте объект "enemy", также как делали "hero", а заем ‘enemy_dyn" так же как "hero_dyn". Значение поля Indetifier должно быть enemy

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

Теория.

Теперь я расскажу Вам, как будем делать уровни. А делать будем их просто - с помощью двумерной матрицы(массива). И матрица каждого уровня будет выглядеть примерно вот так:

[1, 1, 1, 1, 1, 1, 1, 1, 3, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 2, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1].

Где 1 - это стена, 2 - это наш герой, 3- это враг, а 0 - проход.

Написание кода.

Выйдите на сцену, у вас там должен быть один квадратик, если есть удалите его. Теперь нажмите F9.

CODE
function number_not(a:Number, b:Number) {
if (a>b // a<b) {
 return true;
}
}
//Переменные posx и posy - это коэффециенты координат, для простоты дальше называются координатами
function creatinglevel():Void {
// функция, которая загружает уровень
// увеличиваем число отвечающее за место клетки
// m,r - место, ряд
// присваиваем месту и ряду соответствующие значения
var r:Number = j;
var m:Number = i;
// начинем загружать уровень. "square" - имя клетки в блиотеке(linkage). ["r_"+j+"_m_"+i]  - новое имя клетки (r_ряд_m_место). Координата по х расчитывается место*30, по у: ряд*30
this.attachMovie("square", ["r_"+j+"_m_"+i], (10*j+i), {_x:m*30, _y:r*30});
// проверяем что должно быть: кружок(0) или барьер(1)
switch (map[j][i]) {
case 2 :
 // Достаем игрока из библиотеки и ставим по центру клетки
 this.attachMovie("hero", "hero", (max*max+1), {_x:m*30+2.5, _y:r*30+2.5});
 //posx и posy позиция игрока по х и у соответственно
 hero.posx = i;
 hero.posy = j;
 hero.stop();
 break;
case 3 :
 //Достаем компьютера из библиотеки и ставим по центру клетки
 this.attachMovie("enemy", "enemy", (max*max+2), {_x:m*30+2.5, _y:r*30+2.5});
 //posx и posy позиция компьютера по х и у соответственно
 enemy.posx = i;
 enemy.posy = j;
 //lastx и lasty предидущая позиция компьютера по х и у соответственно, служит при алгоритме движения компьютера
 enemy.lastx = i-1;
 enemy.lasty = j;
 enemy.stop();
 break;
case 1 :
 _root["r_"+j+"_m_"+i].gotoAndStop(2);
 break;
case 0 :
 _root["r_"+j+"_m_"+i].gotoAndStop(3);
 break;
}
i++;
// Переключаемся на следующий ряд, при том условии, что место равно максмальное -1
if (i == max) {
 i = 0;
 j++;
}
// Выходим из функции(очищая интервал),  если кол-во рядов равно максимальному      
if (j>=max) {
 // Убираем блок функции game
 _root.block = 0;
 // очищаем интервал
 clearInterval(creatingInterval);
}
}
function game():Void {
// функция, отвечающая за движение игрока и компьютера и следящая за выигрышем, проигрышем
if (block == 0) {
 // работает только в том случае,если снята блокировка
 // Если герой млм враг коснулись кружочка, то убираем его.
 for (var i = 0; i<max; i++) {
  for (var j = 0; j<max; j++) {
   if (map[j][i] == 0 && (hero.posx == i && hero.posy == j) // (enemy.posx == i && enemy.posy == j)) {
    _root["r_"+j+"_m_"+i].gotoAndStop(1);
    _root.map[j][i] = 4;
   }
  }
 }
 //__________Движение__________    
 //=-=-=-=-=-=ИГРОК=-=-=-=-=-=
 if (Key.isDown(Key.LEFT)) {
  // при нажатии левой стрелки смотрим, можем ли мы пойти налево(проверяем, чтобы значение map[ряд][место-1] не было равно 1 с помощью функции number_not)
  if (number_not(map[_root.hero.posy][_root.hero.posx-1], 1)) {
   //Если учлове выполняется, то мувик игрока идет во второй кадр
   _root.hero.gotoAndStop(2);
   // координата игрока по x уменьшается
   _root.hero.posx--;
   // перемещаем игрока
   _root.hero._x = _root.hero.posx*30+2.5;
  }
 }
 //Остальные стрелки обрабаываются так же как и левая стрелка      
 if (Key.isDown(Key.RIGHT)) {
  if (number_not(map[_root.hero.posy][_root.hero.posx+1], 1)) {
   _root.hero.gotoAndStop(1);
   _root.hero.posx++;
   _root.hero._x = _root.hero.posx*30+2.5;
  }
 }
 if (Key.isDown(Key.DOWN)) {
  if (number_not(map[_root.hero.posy+1][_root.hero.posx], 1)) {
   _root.hero.posy++;
   _root.hero.gotoAndStop(4);
   _root.hero._y = _root.hero.posy*30+2.5;
  }
 }
 if (Key.isDown(Key.UP)) {
  if (number_not(map[_root.hero.posy-1][_root.hero.posx], 1)) {
   _root.hero.posy--;
   _root.hero.gotoAndStop(3);
   _root.hero._y = _root.hero.posy*30+2.5;
  }
 }
 //=-=-=-=-=-=Компьютер=-=-=-=-=-=  
 //лево      
 //Смотрим может ли компьютер пойти налево(проверяем, чтобы значение map[ряд][место-1] не было равно 1)
 if (number_not(map[_root.enemy.posy][_root.enemy.posx-1], 1)) {
  //И смотрим, чтоб координата по х куда идет компьютер не была равна предидущей коорденате по х
  if (number_not(_root.enemy.posx-1, _root.enemy.lastx)) {
   // если всеудовлетворяет условию, то в массив moveenemy добовляем 1 - это значит, что компьютер может пойти на лево. Это будет использовано дальше, когда будет расчитываться следующее передвижение компьютера
   moveenemy.push(1);
  }
 }
 //Аналогично рассматриваем и остальное    
 //право  
 if (number_not(map[_root.enemy.posy][_root.enemy.posx+1], 1)) {
  if (number_not(_root.enemy.posx+1, _root.enemy.lastx)) {
   moveenemy.push(2);
  }
 }
 //Низ        
 if (number_not(map[_root.enemy.posy+1][_root.enemy.posx], 1)) {
  if (number_not(_root.enemy.posy+1, _root.enemy.lasty)) {
   moveenemy.push(3);
  }
 }
 //Верх        
 if (number_not(map[_root.enemy.posy-1][_root.enemy.posx], 1)) {
  if (number_not(_root.enemy.posy-1, _root.enemy.lasty)) {
   moveenemy.push(4);
  }
 }
 //Если длинна массива равна 0, тогда ы понимаем, что компьютер попал в тупик    
 if (moveenemy.length == 0) {
  //для этого мы ввели переменные lastx0 и lasty0. Они служат буффером. в них кидаем значения posx и posy соответственно
  _root.enemy.lastx0 = _root.enemy.posx;
  _root.enemy.lasty0 = _root.enemy.posy;
  //Затем координате компьютера posy и posx присваиваем координаты lasty и lastx
  _root.enemy.posy = _root.enemy.lasty;
  _root.enemy.posx = _root.enemy.lastx;
  //Затем перемещем компьютера на эти координаты
  _root.enemy._x = _root.enemy.posx*30+2.5;
  _root.enemy._y = _root.enemy.posy*30+2.5;
  //Затем предидущем значениям координат присваиваем значения из буффера
  _root.enemy.lasty = _root.enemy.lasty0;
  _root.enemy.lastx = _root.enemy.lastx0;
 }
 //Если длинна массива больше 0    
 if (moveenemy.length>0) {
  //переменной napr присваиваем значение рандом от длинны массива
  napr = random(moveenemy.length);
  //теперь проверяем чему равно знаение массива moveenemy от napr
  switch (moveenemy[napr]) {
   //Если 1, то компьютера перемещаем налево
  case 1 :
   //Пердидущем координатам присваиваем нынешне
   _root.enemy.lasty = _root.enemy.posy;
   _root.enemy.lastx = _root.enemy.posx;
   //Теперь изменяем координату по х
   _root.enemy.posx--;
   // и перемещаем компьютера на его новые координаты
   _root.enemy._x = _root.enemy.posx*30+2.5;
   _root.enemy._y = _root.enemy.posy*30+2.5;
   //так же мувик enemy перемещаем во второй кадр
   _root.enemy.gotoAndStop(2);
   break;
   //Если 2, то компьютера перемещаем направо
  case 2 :
   _root.enemy.lasty = _root.enemy.posy;
   _root.enemy.lastx = _root.enemy.posx;
   _root.enemy.posx++;
   _root.enemy._x = _root.enemy.posx*30+2.5;
   _root.enemy._y = _root.enemy.posy*30+2.5;
   _root.enemy.gotoAndStop(1);
   break;
   //Если 3, то компьютера перемещаем вниз
  case 3 :
   _root.enemy.lasty = _root.enemy.posy;
   _root.enemy.lastx = _root.enemy.posx;
   _root.enemy.posy++;
   _root.enemy._x = _root.enemy.posx*30+2.5;
   _root.enemy._y = _root.enemy.posy*30+2.5;
   _root.enemy.gotoAndStop(4);
   break;
   //Если 4, то компьютера перемещаем наверх
  case 4 :
   _root.enemy.lasty = _root.enemy.posy;
   _root.enemy.lastx = _root.enemy.posx;
   _root.enemy.posy--;
   _root.enemy._x = _root.enemy.posx*30+2.5;
   _root.enemy._y = _root.enemy.posy*30+2.5;
   _root.enemy.gotoAndStop(3);
   break;
  }
  //Очищаем массив moveenemy
  moveenemy = [];
 }
}
}
//Матрица уровеня
var map:Array = [[1, 1, 1, 1, 1, 1, 1, 1, 3, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 2, 1], [1, 1, 1, 1, 1, 1, 1, 1, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 1]];
// размер поля(ширина, высота)
var max:Number = 10;
//Массив отвечающий за передвижение компьютера(в нем храняться направления)
moveenemy = new Array();
i = 0;
j = 0;
// интервал функции game
var gameDuration:Number = 95;
// интервал функции creatinglevel
var loadDuration:Number = 0;
//Запускаем функции creatinglevel и game с помощью интервала
var creatingInterval:Number = setInterval(this, "creatinglevel", loadDuration);
var gameInterval:Number = setInterval(this, "game", gameDuration);

Вот что должно у нас получиться, только без кнопки start

Вот вобщем и конец.

Если еще часик другой посидеть, то можно сделать такое


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=9523