ООП и флеш. Программная реализация

Аватар пользователя flahhi
flahhi
Не в сети
Регистрация: 23.08.2012
Баллы: 284
ООП и флеш. Программная реализация

Вы думали, мы уже много чего запрограммировали? На самом деле мы только начали :) Но прогресс на самом деле на лицо. Мы уже вырастили морковь и теперь, стало быть, нужно заняться добавлением кроликов и других тварей ))) Рассмотрим классы Animals, RabbitMale и RabbitFemale. Да, все три сразу. Дело в том, что RabbitMale  и RabbitFemale наследуют Animals. Классы для волков аналогичны классам для кроликов. Их рассмотрим позже. Напишем в класс Animals следующее: 

package 
{
     import flash.display.MovieClip;
     import flash.events.Event;

     public class Animals extends MovieClip
     {
          public var clip:MovieClip;
          public var st:Object;
         
          public function Animals(st:Object, AnimalClass:Class)
          {
               this.st = st;
               clip = new AnimalClass();
               st.addChild(clip);
               clip.x = 50 * Math.floor(Math.random() * 16 + 1) - 25;
               clip.y = 50 * Math.floor(Math.random() * 12 + 1) - 25;
               clip.rotation = 0;
          }
     }
}


Структура, пока, очень похожая на класс Plants. Нужно отдельно оговорить конструкцию this.st = st. Этой строчкой мы глобальной переменной st присваиваем значение st переданное в конструктор. Классы зайцев просты до безобразия:
для мальчиков:
package 
{
     public class RabbitMale extends Animals
     {
          public function RabbitMale(st:Object, RabbitClass:Class)
          {
               super(st, RabbitClass);
          }
     }
}

и для девочек:
package 
{
     public class RabbitFemale extends Animals
     {
          function RabbitFemale(st:Object, RabbitClass:Class)
          {
               super(st, RabbitClass);
          }
     }
}

Как видим пока они идентичны. Обратите внимание на extends Animals. Это и означает, что они наследники класса Animal. Конструкция  super(st, RabbitClass); означает, что мы используем конструктор родительского класса (т.е. Animals). 
Теперь в класс Main мозно добавить две строчки:
new RabbitFemale(stage, RabbitClipFemale);
new RabbitMale(stage, RabbitClipMale);

И, запустив мы увидим что-то такое:
Каждый раз, когда запускаем проект, добавляются два кролика - мальчик и девочка. Это всё хорошо, но до сих пор мы получаем статическую картинку. Пора добавить динамики. Сделаем нашим кроликам функцию для передвижения. Итак в классе Animal добавляем следующую функцию:
// функцич передвижения животных
public function step():void 
{
       cell = Math.floor(Math.random() * 8 + 1);
       if (clip.y + dy > 12*50 || clip.y + dy < 0) dy = -dy;
       if (clip.x + dx > 16*50 || clip.x + dx < 0) dx = -dx;
       clip.rotation =  Math.atan2(dy, dx)*180/Math.PI;
       clip.x += dx;
       clip.y += dy;
       switch(cell)
       {
             case 1: dy = -50; dx = -50;break;
             case 2: dy = -50; dx = 0;break;
             case 3: dy = -50; dx = 50;break;
             case 4: dx = 50; dy = 0;break;
             case 5: dy = 50; dx = 50;break;
             case 6: dy = 50; dx = 0;break;
             case 7: dy = 50; dx = -50;break;
             case 8: dx = -50; dy = 0;break;
        }
 }

Предварительно добавив декларацию dx,dy и cell как глобальные переменные. 
public var cell:int;
public var dx:int = 0, dy:int = 0;

Суть функции в следующем. Случайным образом генерируется значение cell от 0 до 8. Это не что иное, как номер клетки на которую нужно перейти животному. С учётом того что клетки вокруг животного нумеруются по кругу вправо, начиная с левого верхнего угла, мы выбрали значение dx  и dy, - того смешения на которое переместится клип. Так же поменяли значение rotation, вычнслив его через арктангенс точки по координатам и переведя значение из радианов в градусы. На данном этапе функция step() нигде не используется. Чтобы заставить всё таки зайца передвигаться добавим обработчик события:
В конструктор пишем:
clip.addEventListener(Event.ENTER_FRAME, Update);
Не забываем пользоваться комбинацией ctrl+shift+1. Добавляем метод:
public function Update(e:Event):void 
{
          if (++count % 10 == 0)
          {
               step();
          }
 }

Обьявив public var count:int = 0; - переменную счётчик. Запускаем:
Так, как тут swf отображается с масштабом, не все клеточки могут быть видны. Ссылка на оригинал.
Вот,зайцы прыгают как угорелые, но на морковку им плевать. Исправим?!) Для этого немного модифицируем класс Plants. Добавим глобальную переменную (вернее, правильно говорить поле класса) public static var plantsarr:Array = new Array();. Вы заметили? Она статик... Это значит что для всех обьектов этот массив будет единый. И в конструкторе, после инициализации clip пишем: plantsarr.push(this); , то есть добавляем обьект в данный массив. Итого имеем, когда создаётся новый обьект он сразу же добавляется в массив. Таким образом мы в любой момент имеем доступ ко всем созданным объектам. Возникает естественный вопрос, зачем это нужно? А затем, что мы будем проверять пересечение всех растений с нашим зайцем. Вот смотрите. Давайте добавим следующий метод в класс Animals:
// функция питания животных
public function eat(eater:Object, foodarr:Array):void
{
     for (var i:int = 0; i < foodarr.length; i++)
     {
          if (eater.clip.hitTestObject(foodarr[i].clip))
          {
               dx = - eater.clip.x + foodarr[i].clip.x;
               dy = - eater.clip.y + foodarr[i].clip.y;
               if (eater.clip.x == foodarr[i].clip.x && eater.clip.y == foodarr[i].clip.y)
               {
                    st.removeChild(foodarr[i].clip);
                    foodarr.splice(i, 1);
               }
          }
     }
}
Метод принимает два параметра: первый - это обьект, который ест, едок, так сказать, а второй - тот самый массив еды. Внутри мы пробегаем по элементам массива и проверяем, не пересекаются ли они с eater, если пересекаются, то dx и dy меняем таким образом, чтобы едок следующим ходом попал на клетку с едой. Если же они пересекаются и координаты едока равны координатам еды, то удаляем еду с экрана и с массива.
Где же теперь вызвать эту функцию? Так как для волков и зайцев - разная еда, то добавляем вызов метода следует осуществлять внутри классов наследников. Тем более нам нужно, чтобы за каждой итерацией проверка пересечений повторялась. То есть нужен обработчий события Enter_Frame. Оно уже есть в родительском классе так что его можно просто переопределить. Это делается так. В классы RabbitMale  и RabbitFemale добавляем override метод:
override public function Update(e:Event):void
{
     eat(this, Plants.plantsarr);
     super.Update(e);
}
Где  super.Update(e); выполняет Update  из родительского класса. Запускаем, смотрим, как кролики трескают морковку)))
Для очень ленивых положу исходник тут :)

 

Аватар пользователя LeeTovetz
LeeTovetz
Не в сети
Регистрация: 24.08.2012
Баллы: 401

Крутые кролики.

моя радость тут ))) http://leetovetz.deviantart.com/gallery/

Аватар пользователя Arven992
Arven992
Не в сети
Регистрация: 08.11.2012
Баллы: 1

"Вы думали, мы уже много чего запрограммировали?..."
наивные рабы)))))))) вас ждет еще пол тонны строчек кода))))))))

Аватар пользователя LeeTovetz
LeeTovetz
Не в сети
Регистрация: 24.08.2012
Баллы: 401

Вот поэтому мне больше нравится рисовать.

моя радость тут ))) http://leetovetz.deviantart.com/gallery/

Аватар пользователя flahhi
flahhi
Не в сети
Регистрация: 23.08.2012
Баллы: 284

Оно лишним не будет. Но каждому своё :) 

Аватар пользователя Алексей89
Алексей89
Не в сети
Регистрация: 07.12.2015
Баллы: 2

Круто получилось.

Пожалуйста, оставьте ваш комментарий. Спасибо!

Для комментирования войдите или зарегистрируйтесь