Anthill Game Framework

Tiny framework for creating Flash games.

Инструменты пользователя

Инструменты сайта


guide:use_objects

Работа с объектами

Создавая свои объекты и работая с объектами и группами, вам следует знать некоторые простые и полезные вещи, которые позволят вам лучше понимать, как устроен Anthill.


Жизнь игровых объектов

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

  • exists — определяет существование объекта. Если exist == false, значит объект не получает вызов метода update() и вызов метода draw(). При таком раскладе объект может существовать в памяти приложения, но при этом на обработку и отрисовку этого объекта не тратятся ресурсы;
  • alive — определяет, живой объект или нет. Данное свойство для Anthill не учитывается, и в большей степени рассчитано на использование в игре;
  • visible — определяет, видим объект или нет. Если visible == false то для объекта вызывается метод update() и не вызывается метод draw(), таким образом объект не будет виден на экране.

Для того, чтобы убивать, но не удалять объекты из игровой логики, рекомендуются использовать метод kill(). При вызове данного метода для объекта устанавливаются флаги alive и exist равными false, и объект выбывает из игры до того времени, пока он вам вновь не понадобится.

Чтобы вернуть убитый ранее игровой объект в игровую логику, вам следует вызвать для него метод revive(). Вызывая данный метод, вы воскрешаете объект, и он снова в игре.


Переработка объектов

В Anthill существует простой способ переработки ранее использованных объектов, который был успешно позаимствован у Flixel — данный подход позволяет избегать создания своих пулов для переиспользования объектов.

Внимание: Для создания нового экземпляра класса тратится намного больше времени, чем при переиспользовании уже существующего. Происходит это за счет перевыделения памяти и некоторых других трудоемких процессов. Поэтому рекомендуется использовать переработку объектов или пулы.

Реализация переработки объектов встроена непосредственно в AntEntity. Для использования переработки вам необходимо использовать метод recycle(). Например, это классический код создания нового объекта:

var actor:AntActor = new AntActor();
defGroup.add(actor);

А с использованием метода переработки код будет выглядить следующим образом:

var actor:AntActor = defGroup.recycle(AntActor) as AntActor;

Принцип работы метода переработки заключается в поиске не существующих (убитых ранее объектов свойство exists которых равно false) и соответствующих указанному классу. Если будет найден такой объект, то будет возвращен указатель на него, а если доступного для переиспользования объекта не нашлось, то будет создан новый экземпляр объекта указанного класса. При автоматическом создании нового объекта он тут же будет добавлен в текущую группу, поэтому при вызове метода recycle() добавлять полученный объект в группу уже не нужно.

Конечно, в случае использования AntActor — все объекты окажутся подходящим для нашего условия, поэтому нам следует создавать свои классы объектов унаследованными от AntActor и работать непосредственно с ними, а не с актерами. Тогда мы всегда будем уверены в том, что получили тот объект, который заказывали. Например:

var box:Box = defGroup.recycle(Box) as Box;
var enemy:Zombie = defGroup.recycle(Zombie) as Zombie;

Самое важное при переработке объектов — это следить за восстановлением и воскрешением объектов. Например, если мы получили ранее использованный объект, предположим, что это враг, который вероятно был убит игроком ранее, то скорее всего у него будет потрепанный вид и его конечно же следует привести в божеский вид, прежде чем снова отдать на растерзание игроку. Для этого вам следует проверить его существование. Например:

var enemy:Zombie = defGroup.recycle(Zombie) as Zombie;
if (enemy.alive == false)
{
  // Если возвращенный объект убит.
  // Тут нам следует его воскресить и сбросить состояние.
  enemy.revive();
}
else
{
  // Иначе это новый объект, тут нам нужно его инициализировать.
  init();
}

Конечно же, для таких целей следует завести специальный метод init() внутри нашего класса врага, чтобы проверка на новый объект проводилась непосредственно в нем, и выполнялись инициализация или сброс характеристик объекта. Рассмотрим пример реализации метода init() для нашего зомби:

public function init():void
{
  if (alive)
  {
    // Новый экземпляр зомби, добавляем анимашки.
    addAnimationFromCache("ZombieStand");
    addAnimationFromCache("ZombieWalk");
    addAnimationFromCache("ZombieAttack");
    // Скорость движения.
    speed = 5;
    // и т.п.
  }
  else
  {
    // Старый экземпляр зомби.
    revive();
    // тут еще что-нибудь делаем.
  }

  // Объем жизни устанавливаем.
  health = 2;
	// Переключаем анимацию.
  switchAnimation("ZombieStand");
  // Включаем мозг...
  // и т.п.
}

Теперь, чтобы создать такого монстра в игре, нам понадобится всего пара строчек, или даже одна:

var zombie:Zombie = defGroup.recycle(Zombie) as Zombie;
zombie.init();

// Или, если кроме init() больше ничего не нужно, то..
(defGroup.recycle(Zombie) as Zombie).init();

Внимание: Вызывая метод kill() для группы, все вложенные объекты так же будут убиты. Но при воскрешении сущности вложенные объекты не будут воскрешены автоматически. Если вам необходимо воскрешать вложенные объекты при воскрешении сущности, то установите флаг entity.autoReviveChildren равным true.

Также вы можете работать напрямую с умершими или несуществующими объектами, используя следующие методы:

  • getAvailable(aClass:Class) — Извлекает первую попавшуюся свободную сущность, соответствующую указанному классу (exists == false);
  • getExtant(aClass:Class) — Извлекает первую попавшуюся существующую сущность, соответствующую указанному классу (exists == true);
  • getAlive(aClass:Class) — Извлекает первую попавшуюся живую сущность (alive == true);
  • getDead(aClass:Class) — Извлекает первую попавшуюся мертвую сущность (alive == false);
  • getRandom(aClass:Class, aExistsOnly:Boolean) — Извлекает случайную вложенную сущность. Второй флаг определяет, следует ли выбирать только из существующих объектов;
  • getByTag(aTag:int) — Извлекает первую сущность, тэг которой соответствует указанному тэгу. Для сравнения используется свойство tag, которое предназначено для произвольного использования разработчиком;
  • getQueryByTag(aTag:int) — Извлекает все объекты в виде массива, тэги которых соответствуют указанному тэгу.

Быстро посчитать количество вложенных в сущность объектов, соответствующим определенным состояниям, вы можете, используя следующие методы:

  • numLiving() — Возвращает количество живых объектов (alive == true);
  • numDead() — Возвращает количество мертвых объектов (alive == false).

Также у сущности существует два полезных метода, которые могут устанавливать для всех вложенных объектов определенные свойства или вызывать указанные методы:

  • setAll(aVariableName:String, aValue:Object, aRecurse:Boolean = true) — Устанавливает для всех вложенных объектов свойству aVariableName значение aValue. Атрибут aRecurse определяет, будет ли вызван метод setAll() для вложенных групп;
  • callAll(aFunctionName:String, aArgs:Array = null, aRecurse:Boolean = true) — Вызывает для всех вложенных объектов метод aFunctionName и передает в него аргументы из массива aArgs. Атрибут aRecurse определяет, будет ли вызван метод callAll() для вложенных групп.

Пример использования:

// Устанавливаем все вложенные объекты в позицию 10
defGroup.setAll("x", 10);

// Воскрешаем все вложенные объекты
defGroup.callAll("revive");

// Альтернативная установка позиции для всех объектов вызовом метода callAll
defGroup.callAll("reset", [ 10, 10 ]);


Доступ к вложенным объектам

Все вложенные объекты находятся в массиве сущности children, количество же вложенных объектов доступно в свойстве numChildren. Если вам необходимо перебрать все вложенные объекты, то вы можете использовать следующий код:

var i:int = 0;
var obj:AntEntity;
while (i < numChildren)
{
  obj = children[i++];
  if (obj != null)
  {
    // Тут делаем что-то с объектом
  }
}

Внимание: По умолчанию при удалении вложенных объектов размер массива children не изменяется, и вместо удаленных объектов записывается null. Поэтому при работе напрямую с массивом children следует проверять полученное содержимое на null, прежде чем пытаться обратиться к его свойствам или методам.

Если вам необходимо обработать только существующие объекты и проигнорировать при этом несуществующие, то в условие проверки следует добавить наличие флага exists.

if (obj != null && obj.exists)
{
  // Тут делаем что-то с объектом
}


Сортировка вложенных объектов

Для сортировки вложенных объектов следует использовать метод sort(), который в качестве аргументов принимает два параметра: имя свойства, по которому выполняется сортировка и тип сортировки, по убыванию или по возрастанию. В следующем примере мы сортируем все объекты по полю y по убыванию.

// Сортировка объектов по убыванию
myMap.sort("y", AntEntity.DESCENDING);

Для сортировки объектов рекомендуется использовать свойство z — фактически это третья координата наравне с x и y, но специально созданная для того, чтобы вы могли помещать туда свои значения и выполнять по ним сортировку. Свойство z как и tag не используется фреймворком и предназначено исключительно для пользовательского использования.


Простое движение объектов

В Anthill реализована простая система движения объектов, которая может использоваться на ваше усмотрение. Для реализации движения используется несколько переменных, которые определяют все необходимые параметры:

  • velocity:AntPoint — Скорость движения сущности;
  • acceleration:AntPoint — Сила ускорения сущности;
  • drag:AntPoint — Сила торможения (трения) сущности;
  • maxVelocity:AntPoint — Максимально допустимая скорость сущности.

Аналогичные параметры есть и для вращения:

  • angularVelocity:Number — Скорость вращения сущности;
  • angularAcceleration:Number — Сила ускорения вращения сущности;
  • angularDrag:Number — Сила торможения (сопротивления) вращения сущности;
  • maxAngularVelocity:Number — Максимально допустимая скорость вращения сущности.

По умолчанию стандартная система движения отключена, чтобы её активировать необходимо установить флаг moves равным true. Пример использования:

// Создаем актера
var actor:AntActor = new AntActor();
actor.addAnimationFromCache("MySuperHero");
add(actor);

// Задаем ему скорость движения
actor.velocity.x = 10;
actor.moves = true;

Особенно удобно использовать данный подход в связке с AntKeyboard, например:

override public update():void
{
  if (AntG.keys.LEFT)
  {
    actor.velocity.x = -10;
  }
  else if (AntG.keys.RIGHT)
  {
    actor.velocity.x = 10;
  }
  else
  {
    actor.velocity.x = 0;
  }
}

Более подробно об обработке нажатия клавиш и мыши читайте в разделе «Обработка действий с клавиатуры» и «Обработка действий с мыши».


guide/use_objects.txt · Последние изменения: 11.05.2013 12:05 — Илья Уткин