суббота, 17 сентября 2011 г.

Экспресс программирование 1: космо шутер







 Итак, начинается новый раздел - экспресс программирование. Здесь я буду писать как и что можно быстро сделать на флэше. Также здесь же будут разные эксперименты.
Сейчас же я расскажу как быстро сделать игру на флэш - космический шутер (что-то вроде invaders). Цель на сегодня - сделать одноуровневую игру меньше чем за час.

1. Создаю новый документ, делаю несколько мувиклипов: себя (треугольничек-мувиклип, имя - hero), врага (треугольничек-мувиклип, повёрнутый в другую сторону, имя - alien), свою пулю (её я решил сделать отдельно от вражеских пуль, пусть различаются хоть как-нибудь, имя - myBullet), вражескую пулю (alBullet).
2. Делаю два кадра: в первом будет надпись "Нажмите пробел для старта", во втором будет происходить весь игровой процесс. Все мувиклипы, созданные в пункте 1, должны быть на втором кадре!
3. Теперь время писать код. Сначала переменные: shoot - флажок, обозначает выстрелил ли я уже или нет (если false, то могу выстрелить, если true - нет), d и d2 - depth врагов. Тоже самое с bulletd и bulletd2 - depth пуль. Теперь поподробнее про это: во Flash нужно, чтобы все объекты, создаваемые в процессе игры, имели свою глубину. Если у двух или более объектов одинаковая глубина, флэш начинает тупить. Чтобы легче было контролировать все эти объекты, они будут пронумерованы. Например: alien0, alien1, alien2 ... Я предпочитаю for(i=d2;i<d;i++){ - получается проход по всем объектам от d2 до d. Чтобы, например, пройтись по aliens0,aliens1,aliens2,...,aliens19, нужно ввести:for(i=0;i<20;i++){ , затем в теле цикла достаточно будет написать _root["aliens"+i] , чтобы ссылаться поочерёдно на все объекты (aliens0,aliens1,aliens2,...,aliens19).
4. Объявляем переменные и заполняем экран врагами:
stop();

d = d2 = 0;
bulletd = bulletd2 = 100;
shoot = false;
for (i=0; i<10; i++) {
 for (i2=0; i2<5; i2++) {
  alien.duplicateMovieClip("al"+d,d);
  _root["al"+d]._x = i*50+50;
  _root["al"+d]._y = i2*50+50;
  _root["al"+d].xSpeed = 1;
  d++;
 }
}

5. Затем нужно прописать _root.onEnterFrame = function(){ /*тело функции*/ }. Тогда то, что находится в теле функции будет выполняться 24 раза в секунду (по умолчанию, чтобы изменить - измените fps ролика). Теперь нужно реализовать стрельбу. Принцип такой: у вас всего одна пуля. Выстрелив, вы не можете стрелять, пока она во что-нибудь не врежется (или не улетит за пределы).
_root.onEnterFrame = function() {
 if (shoot == false && Key.isDown(Key.SPACE)) {
  shoot = true;
  myBullet._x = hero._x;
  myBullet._y = hero._y;
 }
 if(shoot == true){
  myBullet._y -= 10;
 }else{
  myBullet._x = -100;
 }
 if(myBullet._y < -50){
  shoot = false;
 }
}
6. Описываем поведение врагов:
if (d != d2) {
 for (i=d2; i<d; i++) {
  if (_root["al"+i]) {
   _root["al"+i]._x += _root["al"+i].xSpeed*5;
   if(_root["al"+i].hitTest(myBullet)){
    _root["al"+i].removeMovieClip();
    shoot = false;
   }
   if (_root["al"+i]._x>530) {
    _root["al"+i].xSpeed = -1;
   }
   if (_root["al"+i]._x<20) {
    _root["al"+i].xSpeed = 1;
   }
   //random(200) - означает, что действие (здесь - стрельба врагов) будет выполняться
   //в среднем раз в 200 проходов (при 24fps - один раз в 8.3 секунд)
   if (random(200) == 0) {
    bullet.duplicateMovieClip("bullet"+bulletd,bulletd);
    _root["bullet"+bulletd]._x = _root["al"+i]._x;
    _root["bullet"+bulletd]._y = _root["al"+i]._y;
    _root["bullet"+bulletd].ySpeed = random(5)+3;
    bulletd++;
   }
  }
 }
}
7. Описываем поведение вражеских пуль:
if (bulletd != bulletd2) {
 for (i=bulletd2; i<bulletd; i++) {
  if (_root["bullet"+i]) {
   if (_root["bullet"+i]._x<0 || _root["bullet"+i]._x>550 || _root["bullet"+i]._y<0 || _root["bullet"+i]._y>400) {
    _root["bullet"+i].removeMovieClip();
   }
   _root["bullet"+i]._x += _root["bullet"+i].xSpeed;
   _root["bullet"+i]._y += _root["bullet"+i].ySpeed;
   if (_root["bullet"+i].hitTest(hero)) {
    DELETE();
    prevFrame();
   }
  }
 }
}
8. Теперm нужно сделать функцию очистки, т.е. DELETE();
function DELETE () {
 myBullet.removeMovieClip();
 for(i=bulletd2;i<bulletd;i++){
  _root["bullet"+i].removeMovieClip();
 }
 for(i=d2;i<d;i++){
  _root["al"+i].removeMovieClip();
 }
}
9. И немного оптимизации. Дело в том, что пуль будет много, и правая граница for'а будет постоянно уведичиваться. И спустя некоторое время игра начнёт сильно тормозить. Поэтому я всегда делаю проверку, и если на левой границе уже никого не осталось, то и не надо её считать :)
if (bulletd2 != bulletd && !_root["bullet"+bulletd2]) {
 bulletd2++;
}
if (d2 != d && !_root["al"+d2]) {
 d2++;
}
10. И последние штрихи в этом кадре: условие победы и движение главного героя.
if (Key.isDown(Key.LEFT)) {
 hero._x -= 7;
}
if (Key.isDown(Key.RIGHT)) {
 hero._x += 7;
}
if(d2 == d){
 DELETE();
 prevFrame();
}
11. Вернёмся к первому кадру: Пишем всю необходимую информацию (управление - влево, вправо, пробел. Чтобы начать игру, нажмите энтер. И пишел следующий код:
stop();
_root.onEnterFrame=function  () {
 if(Key.isDown(Key.ENTER)){
  nextFrame();
 }
}
Итак, вот полный код этой игры. Поэксперементируейте, попробуйте изменить какие-нибудь значения.
stop();
function DELETE () {
 myBullet.removeMovieClip();
 for(i=bulletd2;i<bulletd;i++){
  _root["bullet"+i].removeMovieClip();
 }
 for(i=d2;i<d;i++){
  _root["al"+i].removeMovieClip();
 }
}
d = d2 = 0;
bulletd = bulletd2 = 100;
shoot = false;
for (i=0; i<10; i++) {
 for (i2=0; i2<5; i2++) {
  alien.duplicateMovieClip("al"+d,d);
  _root["al"+d]._x = i*50+50;
  _root["al"+d]._y = i2*50+50;
  _root["al"+d].xSpeed = 1;
  d++;
 }
}
_root.onEnterFrame = function() {
 if (shoot == false && Key.isDown(Key.SPACE)) {
  shoot = true;
  myBullet._x = hero._x;
  myBullet._y = hero._y;
 }
 if(shoot == true){
  myBullet._y -= 10;
 }else{
  myBullet._x = -100;
 }
 if (Key.isDown(Key.LEFT)) {
  hero._x -= 7;
 }
 if (Key.isDown(Key.RIGHT)) {
  hero._x += 7;
 }
 if(d2 == d){
  DELETE();
  prevFrame();
 }
 if (d != d2) {
  for (i=d2; i<d; i++) {
   if (_root["al"+i]) {
    _root["al"+i]._x += _root["al"+i].xSpeed*5;
    if(_root["al"+i].hitTest(myBullet)){
     _root["al"+i].removeMovieClip();
     shoot = false;
    }
    if (_root["al"+i]._x>530) {
     _root["al"+i].xSpeed = -1;
    }
    if (_root["al"+i]._x<20) {
     _root["al"+i].xSpeed = 1;
    }
    if (random(200) == 0) {
     bullet.duplicateMovieClip("bullet"+bulletd,bulletd);
     _root["bullet"+bulletd]._x = _root["al"+i]._x;
     _root["bullet"+bulletd]._y = _root["al"+i]._y;
     _root["bullet"+bulletd].ySpeed = random(5)+3;
     bulletd++;
    }
   }
  }
 }
 if (bulletd != bulletd2) {
  for (i=bulletd2; i<bulletd; i++) {
   if (_root["bullet"+i]) {
    if (_root["bullet"+i]._x<0 || _root["bullet"+i]._x>550 || _root["bullet"+i]._y<0 || _root["bullet"+i]._y>400) {
     _root["bullet"+i].removeMovieClip();
    }
    _root["bullet"+i]._x += _root["bullet"+i].xSpeed;
    _root["bullet"+i]._y += _root["bullet"+i].ySpeed;
    if (_root["bullet"+i].hitTest(hero)) {
     DELETE();
     prevFrame();
    }
   }
  }
 }
 if (bulletd2 != bulletd && !_root["bullet"+bulletd2]) {
  bulletd2++;
 }
 if (d2 != d && !_root["al"+d2]) {
  d2++;
 }
};
P.s. Вообще, эту игру я делал достаточно давно. Цель моя была тогда несколько другая: написать играбельную игру как можно меньшего размера. В оригинальной игре код немного изменён (например, мувиклипы создаются когда игра уже запушена. Таким образом в библиотеке всего один мувиклип: главный герой. Это сделано из-за того, что создание мувиклипы едят много памяти). Swf файл игры весит 1,394 байт :D

Комментариев нет:

Отправить комментарий