TowerDefence #10. Полоса жизни

Вместе с порой отспусков и каникул лето подходит к концу. Пора возвращатся к работе и к новой серии уроков. Начнем с плавного погружения в дальнейшую разработку и сегодня реализуем только отображение жизни врагов.

Так уж получилось, что с весны я очень мало писал в блог и практически забросил ведение уроков, но унывать не стоит ведь в переди зима, а значит и новый сезон уроков! Чтобы не погружаться сразу в пучину кода и объяснений, первый урок нового сезона будет небольшим и достаточно легким.

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

Способ первый

Самый простой способ который как правило приходит начинающим разработчикам на ум — это количество кадров в клипе полосы жизни равно количеству жизни объекта для которого она предназначена. Способ прост тем что для демонстрации текущего объема здоровья не нужно делать дополнительных рассчетов. А для клипа с полосой жизни достаточно просто установить текущим тот кадр который равен текущему объему здоровья героя.

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

hero.health -= damage;
hero.healthBar.currentFrame = hero.health;

Но преимущество этого способа не такое уж и преимущество. На самом же деле вся простота обманчива и обязательно накажет разработчика, выбравшего этот способ где-нибудь в конце или в середине разработки игры. А недостатки заключаются в следующем:

  1. Если вдруг вам понадобится сделать врагов с разным уровнем здоровья, то для каждого врага вам прийдется рисовать свою полосу жизни.
  2. К врагам или героям нельзя будет применять бонусы, которые смогут произвольно увеличивать здоровье объекта на N единиц, так как полоса жизни не сможет демонстрировать произвольное количество здоровья. Либо для всех бонусов прийдется рисовать свои полосы жизни.

В общем отнесем этот способ рисования полосы жизни к делитантскому подходу и рассмотрим второй способ.

Способ второй

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

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

Простая полоса жизни.

Первый клип — это текущее здоровье, а второй клип — это полный объем здоровья (задний фон полосы жизни). Пусть у нашего героя полный объем здоровья равен 100 единицам, а текущее здоровье 70 единиц. Теперь чтобы отобразить это здоровье в полосе жизни, мы первому клипу установим ширину 100, а второму клипу 70 единиц:

hero.health -= damage;
totalHealthClip.width = 100;
currentHealthClip.width = hero.health;

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

  1. Если враги будут с разным объемом здоровья, то и полоса жизни для них будет разной длины — в некоторых случаях это хорошо, так как можно наглядно увидеть какой враг имеет больше всего здоровья, а какой по меньше. Но с сильно разным объемом жизни юнитов такой прием может оказаться не очень хорошим, так как в итоге полоски жизни разной длины над врагами могут устроить кашу на экране, и игра может потерять в наглядности.
  2. Растягиваемую полосу жизни не нарисовать красиво с завитушками или не сделать такой интересной, как например в StarCraft.

Полосы жизни в игре StarCraft2

Полосы жизни в игре StarCraft 2.

Поэтому давайте рассмотрим наиболее универсальный способ отображения полосы жизни, лишенный вышеперечисленных недостатков.

Способ третий

Предположим, что нам хочется сделать одинаковые по размеру полосы жизни для юнитов с разным количеством здоровья. ?ли же вовсе нарисовать одну красивую полосу жизни как, например в игре StarCraft и использовать для всех юнитов — возможно некоторые удивятся, но сделать это не так сложно, как может показаться на первый взгляд.

Для примера я быстренько нарисовал полосу жизни, отдаленно напоминающую полоску жизни для юнитов в StarCraft. Предположим, что в ней получилось 50 кадров, и как же теперь этой полосой жизни можно отобразить 100 единиц здоровья и больше!?

Сложная полоса жизни.

Самый простой способ конвертировать любое значение из одного масштаба в другой — это использовать проценты! Как это работает: у нас есть юнит, полный объем здоровья которого равен 100, но сейчас его здоровье равно 75 единицам. А полоса жизни равна 50 кадрам. Чтобы выяснить на какой кадр переключить полосу жизни, чтобы она точно показывала текущее здоровье героя, мы вначале вычислим сколько процентов здоровья имеет герой:

(75 / 100) * 100 = 75%

Теперь мы вычисляем, какой кадр будет равен 75% процентам. В данной полосе жизни 50-ый кадр равняется 100% здоровью юнита:

(75% * 50) / 100 = 37,5 кадр

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

Кстати, данный способ очень хорошо работает и для создания мини карт или радаров! Представьте, что у вас есть игровое поле размером 2000x1500 пикселей, и вам бы хотелось для него сделать мини карту размерами 150x113 пикселей. Допустим у нас есть объект, который должен отображаться на мини карте, и который имеет реальные координаты в игровом мире x:856 y:345. Давайте переведем координаты объекта из реального игрового масштаба в масштаб мини-карты с использованием процентов.

Вначале вычислим положение объекта на мини-карте в процентах по x и по y:

(856 / 2000) * 100 = x:42,8%
(345 / 1500) * 100 = y:23%

Теперь согласно полученным процентам посчитаем, какие это будут координаты на мини карте:

(42,8% * 150) / 100 = x:64,2 pix
(23% * 113) / 100 = y:25,99 pix

? так, объект с координатами x:856 y:345 в реальном игровом масштабе, на мини карте должен имеет координаты x:64,2 y:26,99. Чтобы пиксели на миникарте не размазывались, результат вычислений, конечно же, стоит округлять, а точность отображения от округлений сильно не пострадает.

Но что-то я отвлекся от нашей основной темы. Давайте все же вернемся к полоскам жизни и добавим их в наш проект.

От теории к делу

Чтобы не держать формулы вычисления процентов в голове, я добавил их в виде отдельных методов в наш полезный класс Amath.as:

Amath.toPercent(current:Number, total:Number):Number

— В качестве параметров передается: current — это текущее значение чего-либо, total — это максимальное значение чего-либо. Метод возвращает процентное соотношение current от total.

Amath.fromPercent(percent:Number, total:Number):Number

— В качестве параметров передается: percent — это процентное значение чего-либо, total — это максимальное значение чего-либо. Метод возвращает текущее значение процента от total.

В нашей игре при реализации отображения полосы жизни я решил совместить первый способ с третьим. То есть в нашей игре будет заранее нарисованная полоса жизни для всех врагов.

Первым делом вам следует подготовить клип полосы жизни. Количество кадров в клипе, как и его размеры, не принципиальны. Например, у меня получилось всего 13 кадров. Первый кадр должен демонстрировать нулевую жизнь, последний кадр должен показывать полную жизнь. Но рисовать можно в любую сторону, ведь благодаря функции «Reverse Frames» вы всегда можете поменять порядок кадров.

Чтобы изменить порядок кадров, выделите все нужные кадры на Timeline и откройте контекстное меню правой кнопкой мыши, найдите и выберите пункт «Reverse Frames» и для выделенных кадров будет применен метод обратной сортировки.

Когда клип с полосой жизни будет готов, не спешите экспортировать его в код, мы сделаем это позже. А первым делом мы напишем класс, который будет расширять обычный MovieClip и добавит нужный нам функционал для удобной работы с полосой жизни. Я решил, что все объекты управления и информации такие как кнопки, полосы жизни и прочее будут располагаться у нас в папке «gui», поэтому первым делом создадим новую папку (пакет): com.towerdefence.gui и сразу добавим в нее новый класс HealthBar.as. Класс должен быть унаследован от MovieClip и содержать одну приватную переменную:

private var _fullHealth:Number;

В конструкторе класса напишем строчку:

this.stop();

При создании экземпляра класса эта строчка остановит анимацию нашего класса, ведь мы его унаследовали от MovieClip. Теперь добавим публичный метод reset():

public function reset(fullHealth:Number):void
{
  _fullHealth = fullHealth;
  this.gotoAndStop(this.totalFrames);
}

Этот метод устанавливает нашему классу максимальное количество жизни, которое он может отображть и за одно устанавливает состояние полосы жизни, как полное здоровье. Далее мы напишем метод update():

public function update(health:Number):void
{
  var percent:Number = Amath.toPercent(health, _fullHealth);
  this.gotoAndStop(Math.round(Amath.fromPercent(percent, this.totalFrames)));
}

Этот метод будет вызываться, когда у врага изменилось здоровье и необходимо обновить состояние полосы жизни. Как можно заметить здесь скрыта вся магия с использованием процентов. В первой строчке мы высчитываем текущую жизнь юнита в процентах от его полной жизни, а во второй строчке переводим проценты в текущий кадр и применяем его к нашему клипу с полосой жизни. На этом с классом HealthBar.as мы заканчиваем.

Возможно некоторые из читателей не поняли всей этой простоты и задались вопросом о том, где же мы работаем непосредственно с клипом UnitHealthBar_mc!? На самом деле класс HealthBar.as будет родительским классом для клипа UnitHealthBar_mc. Чтобы установить родительский класс для клипа отображающего здоровье, откройте библиотеку во Flash IDE, выберите клип UnitHealthBar_mc и откройте его свойства. В свойствах мы как обычно экспортируем клип в код, но в место базового класса flash.display.MovieClip напишите com.towerdefence.gui.HealthBar и нажмите OK. Теперь когда мы создадим клип UnitHealthBar_mc в коде, он будет унаследован от HealthBar.as, который в свою очередь будет унаследован от MovieClip, и таким образом мы получим функционал MovieClip и функционал нашего класса HealthBar.as. Теперь дело осталось за малым, добавить использование новой возможности в игре.

Связываем клип полосы жизни с классом HealthBar

Связываем клип полосы жизни с классом HealthBar.as.

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

protected var _healthBar:HealthBar;

Далее в методе init() класса EnemyBase добавим её инициализацию:

// Если полоса жизни не инициализирована, создаем её
if (_healthBar == null)
{
  _healthBar = new UnitHealthBar_mc();
  addChild(_healthBar);
}
_healthBar.reset(_health); // Устанавливаем максимальное здоровье

Теперь найдем метод addDamage() в классе EnemyBase и добавим в него обновление состояния полосы жизни.

 public function addDamage(damage:Number):void
{
  _healthBar.update(_health);
}

На этом внедрение полосы жизни в класс EnemyBase.as закончено. Но поскольку у потомков класса EnemyBase родительский метод addDamage() перекрывается и метод родительского класса (скорее всего) не вызывается, то для полноценной работы нам следует в классе EnemySoldier добавить вызов родительского addDamage(), чтобы тот обновил полосу жизни.

override public function addDamage(damage:Number):void
{
  _health -= damage;

  // Вызываем метод родителя для обновления полосы жизни
  super.addDamage(damage); 
            
  //... дальнейший код в этом методе оставляем без изменений ...
}

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

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

Домашнее задание

На первом уроке нового учебного года я решил предложить вам простое домашнее задание, чтобы голова с лета сразу не гудела :) Если вы активно играете в игры и в Товер Дефенсы в частности, то наверное могли заметить, что для абсолютно здоровых врагов полосы жизни порой не показываются, чтобы не нагружать игрока лишней бесполезной информацией. То есть, если полосы жизни у врага нет, значит он еще совсем свежий. Так вот, подумайте и сделайте так, чтобы полосу жизни можно было бы удобно прятать от игрока, когда у юнита 100% здоровья.

Так же хочу напомнить про домашнее задание в прошлом уроке — его результаты для вражеских единиц нам понадобятся уже в следующем уроке! :)

Заключение

Сегодня мы рассмотрели простой и эффективный пример работы с процентами, который нам, как игровым разработчикам, в будущем позволит создавать не только универсальные полосы жизни, но и радары или миникарты для наших замечательных игр.

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

Ссылка на исходники — CS4, *.zip, 161кб.

Результат

Дополнение

Дружище Claymore подсказал небольшое упущение которое в некоторых случаях может приводить к неприятностям. Проблема заключается в том, что шкала жизни переносится в кадры 1 к 1, что может привести к получению нулевого кадра, а нулевого кадра не существует. Поэтому метод update() для класса HealthBar.as следует переделать следующим образом:

 

public function update(health:Number):void
{
  var percent:Number = Amath.toPercent(health, _fullHealth);
  this.gotoAndStop(Math.round(Amath.fromPercent(percent, this.totalFrames - 1)) + 1);
}

Если вы используете масштабирование клипов или иной способ отображения полосы жизни, то этот недостаток не является проблемой.

Содержание

  1. Вступление
  2. Структура игры
  3. Карта проходимости
  4. Первый враг
  5. Готовимся к поиску пути
  6. Поиск пути
  7. Редактор уровней
  8. Движение врагов
  9. Первая башня
  10. Кэширование объектов
  11. Полоса жизни
  12. Вражеские волны
  13. Загрузка вражеских волн
  14. Продолжение следует...

 

 

Спасибо большое!
Как раз то, что было нужно)

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

Dyrk
31 Августа 2011
— 15:50
#

Хороший урок, спасибо.))

Ivobobul
31 Августа 2011
— 15:57
#

Ура новый Урок!!!!!!!!!! Спасибо!

?ван
31 Августа 2011
— 15:59
#

Антон у тебя в статье кусок тествтта с кодом 2 раза написан
"
Amath.fromPercent(percent:Number, total:Number):Number

— В качестве параметров передается: percent — это процентное значение чего-либо, total — это максимальное значение чего-либо. Метод возвращает текущее значение процента от total.

"

?ван
31 Августа 2011
— 16:18
#

Появился вопрос по уроку. Какое функциональное значение создание для полосы жизни именно многокадрового мувиклипа? Разве не проще создать однокадровый спрайт и менять его параметр scaleX в соответствии с оставшимся количеством жизней.

?ли все же у полос жизни которые базируются на кадрах мувиклипа есть какие-то преимущества?

jarofed
31 Августа 2011
— 17:36
#

Класс, огромное спасибо за урок, я кстати как новичек, пока небыло уроков, тоже додумался уменьшать полоску жизни с помощью scaleX. тоже хотелось бы узнать о приимуществах данного метода

Marik
31 Августа 2011
— 18:01
#

Полоска прячетс под другим мобом - это баг.

shaman4d
31 Августа 2011
— 18:27
#

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

Claymore
31 Августа 2011
— 18:39
#

Shaman4d, используйте спрайт контейнер и все будет путем :)

?ван
1 Сентября 2011
— 08:56
#

@?ван, это на первый взгляд кажется что один и тот же кусок с кодом два раза написан, но на самом деле там речь идет о двух разных методах.

Ant.Karlov
1 Сентября 2011
— 10:51
#

@jarofed, да, в большинстве случаев намного проще менять параметр клипа scaleX чтобы получить нужный эффект и не рисовать ручками много кадров. Но бывают и такие случаи, например, о которых я написал — нужно нарисовать такую полосу жизни для которой изменение масштаба не годится.

Обратите внимание на те же полосы жизни в игре StarCraft — там по мимо того, что полоса разбита на квадратики она еще и меняет цвет в зависимости от количества здоровья. Конечно можно рисовать полосу жизни программно с изменением цвета, но тут в любом случае с точки зрения производительности оптимальнее будет заранее «отрендеренная» полоса жизни нежели программно рисуемая :)

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

Ant.Karlov
1 Сентября 2011
— 11:03
#

@shaman4d, то что полосы жизни проваливаются под других врагов — это не столько баг сколько не доделка. Если нужно сделать так чтобы они не проваливались и всегда были поверх всех, то необходимо немного переделать класс HealthBar.as и сам визуальный образ полосы жизни добавлять не в единицу, а в отдельный клип (слой).

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

Ant.Karlov
1 Сентября 2011
— 11:08
#

@Claymore, согласен, возможный переход на не существующий кадр я упустил. По хорошему дополнительно следует сделать проверку чтобы значение было не менее 1 и не более totalFrames. Но если я не ошибаюсь, то при попытки переключить MovieClip на несуществующий кадр он переключает на ближайший доступный кадр, то есть у него есть своя проверка на выход из диапазона кадров. Надо проверить :)

Ant.Karlov
1 Сентября 2011
— 11:11
#

в документации конечно написано, что будет ошибка при попытке перейти на несуществующий кадр, но на практике я ее пока не отловил :)

по поводу "прятания" полоски здоровья, что есть просто добавить еще один пустой кадр в HealthBar. Тогда метод reset() будет выставлять последний кадр после своего вызова, и полоску будет не видно, имхо самый простой спобоб

archi
1 Сентября 2011
— 12:52
#

@archi, Бинго! Давай дневник поставлю пять! :D

Ant.Karlov
1 Сентября 2011
— 14:33
#

Антон смотри какие баги есть сейчас.
http://s61.radikal.ru/i172/1109/69/5a061960e8c0.png
Возможность расставлять башни в любом месте. После того как перекроешь вход юнитам, они начинают двигаться через любые препятствия.

Bziks
1 Сентября 2011
— 14:57
#

Вот так чем дальше читаешь эти уроки, тем больше понимаешь, насколько же Антон пока дилетант в программировании. :)

Вместо scaleX самого спрайта нужно использовать scaleX для маски, тогда можно и старкрафтоподобные лайфбары делать в одном кадре.
Ну а разделение на слои с самого начала надо было определить - для HUD в любом случае нужен свой слой. А то теперь при добавлении волн придется искусственно ограничивать себя, постоянно держа в уме мысль, что враги не должны перекрывать чужие лайфбары, плохо это.

Max
1 Сентября 2011
— 15:41
#

@Max, я оставляю вам возможность раскрыться в комментариях как настоящему профессионалу. Уверен, профессионал вроде вас раскроет все аспекты игростроения в одном уроке за пару дней в отличии от меня мурыжащего эту тему уже второй год.

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

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

Ant.Karlov
1 Сентября 2011
— 16:56
#

Спасибо за уроки, Антон! Очень помогают при создании игры. Если интересно вот скриншот
Пытаюсь перенять и твой стиль рисования, хотя пока не очень выходит)

AntonSK
1 Сентября 2011
— 17:38
#

Сори поздно заметил что там есть отличия :) а тут ты уже ответил :(

?ван
1 Сентября 2011
— 17:40
#

@Bziks, возможность расставлять башни — это не баг, это просто недоделка. К этой проблеме мы еще обязательно вернемся и сделаем проверку на возможное закрытие пути для вражеских единиц и запрета установки башни если она закрывает дорогу.

Ant.Karlov
1 Сентября 2011
— 18:22
#

@AntonSK, скриншот не открылся, ссылка не работает. Но в любом случае полностью перенять стиль наверное все равно не получится :P

Ant.Karlov
1 Сентября 2011
— 18:24
#

Ладно, Антон, прости за наезд. Мне просто этот урок живо напомнил древний туториал AsteroidStorm, там тоже про лайфбары было. ? я не смог удержаться от сравнения: там код явно писал программист, а тут явно пишет художник. Я почему-то ожидал от этого блога уроков в духе Феронато, а получаются уроки в духе Хитри (хорошо хоть не на AS2).
А я в своих проектах вообще не использую DisplayList, у меня ручной рендер, для лайфбаров используется copyPixels с изменяемым sourceRectangle. Получается очень быстро, хоть 10000 юнитов пускай. Естественно, при портировании на другие платформы такой подход тоже лучше всего - растр он и в Африке растр.

Короче, Антон, советую тебе забить на этих мелких дармоедов и вместо сомнительных уроков сосредоточиться на своих разработках. Потому что даже история фриланса с Арморами гораздо более интересна и поучительна, чем этот школьный урок про проценты.

Max
1 Сентября 2011
— 19:00
#

Max, тут недавно был еще один гуру-учитель жизни, только из цеха художников. Вы бы шли свои блоги вели, а не учили других.

Алексашка
1 Сентября 2011
— 19:15
#

@Ant.Karlov, я и не пытаюсь полностью скопировать стиль, просто беру на вооружение некоторые моменты) У меня вообще с графикой не очень, никаких худ. школ не заканчивал и это самый тяжелый момент при создании игры (тем более первой). Надо было на кого то ориентироваться просто, а твой арт один из лучших в мире флеш игр)
Сори за битую ссылку) Вот норм - http://fotkidepo.ru/?id=photo:683156

AntonSK
1 Сентября 2011
— 21:23
#

@AntonSK, отлично получается! Только вот с травой какая-то беда...

@Max, а выложите-ка свой код или покажите ссылку на блог. Хочется увидеть код такого человека, как Вы.

f-duck
2 Сентября 2011
— 00:50
#

Какой код? Парой строчек же не отпишешься, тем более, что у меня лайфбары не привязаны к объектам юнитов, а рисуются смекалистым менеджером HUD.
Блога нет, если и появится, то будет на английском. Аудитория, понимаешь ли.

Max
2 Сентября 2011
— 23:37
#

@Max, на 10000 юнитах будет тормозить, каким бы вывод быстрым не был.

pro11
2 Сентября 2011
— 23:54
#

@Max, ну если не код, то скиньте хотя бы пару ссылочек на свои проэкты. Думаю, мы наверняка о них слышали и не раз в них играли. Просто очень интересно увидеть, на что способны столь великий мастер, ка вы))
Ждемс)

Xcite
3 Сентября 2011
— 13:50
#

@Xcite непонятно к чему это все "сперва добейся"? Все правильно Max сказал. В смысле программирования, у автора на протяжении всех уроков огрехи, на которые ему не раз указывали. По поводу конечного продукта вроде никто и не высказывался отрицательно, качество игры зависит не только от качества кода.
З.Ы. поражает, что кто-то до сих пор не знает как пишется слово проЕкт

Jakimushka
3 Сентября 2011
— 14:45
#

Jakimushka, это всего лишь уроки. Какие еще огрехи? Этот код не для создания полноценной игры, а для изучения основ. К тому же многие вещи намеренно упрощаются для понимания ключевых моментов.

Алексашка
3 Сентября 2011
— 15:49
#

@Jakimushka, вначале перед уроками некоторые переживали, что всякие неумехи будут потом брать исходники уроков, менять графику и продавать уроко-клоны без изменений. Теперь вот оказывается, что код не идеален и сплошные огрехи и недоделки. Но я как бы сразу предупреждал, что отполированного и законченного продукта после уроков я не обещаю. Основные темы я объясняю, а как и кто реализовывает отдельно взятые моменты — это уже дело каждого. Кто-то растягивает полосы жизни, кто-то растягивает маску, кто-то предпочитает рисовать их заранее и потом только переключать кадры. ? разве можно судить по таким моментам о профессионализме? Думаю нет. Судя по моему предыдущему комментарию можно сделать вывод, что разные подходы следует использовать в разных случаях и они будут оправданы.

К тому же никто тут и не говорит, что я супер-пупер программист, как впрочем и художник :) В заглавной записи к урокам я написал, что я могу делать ошибки и буду рад вашим конструктивным замечаниям. Конструктива много и меня это радует. Но есть и тролло-профи вроде вас которые готовы только попукать в комментариях о том что автор ламер, а вы вот такие умные и без меня обо всем этом знаете. Но разница наша в том, что я нашел время, силы и желание чтобы рассказать другим о том, что знаю я, а вы нет. Если у вас есть мысли о том как что-то можно улучшить — напишите об этом. А если вы не хотите делится своим опытом и знанием с другими то проходите лучше мимо, так как иначе вы больше похожи на троллей которым все равно никто не поверит. Спасибо за понимание.

Ant.Karlov
3 Сентября 2011
— 16:15
#

@Jakimushka, слушай, а ты, наверное филолог, правда? Так тебе не блоги всякие перечитывать надо, а в школу к детям, тетрадки проверять.
Если уж на то пошло, то ты написал: "@Xcite непонятно к чему это все "сперва добейся"?". Так вот обращение запятыми выделять надо ;-)

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

Xcite
3 Сентября 2011
— 16:27
#

Xcite, ты много знаешь общепризнанных флеш девелоперов с ником Макс ? :) Да еще и уровня Антона Карлова, который один из лучших в России.

Макс обычный тролль, и на его великие достижения в программировании на AS 3.0 даже смотреть не интересно.

@ Ant.Karlov, спасибо за урок :)

stardust
4 Сентября 2011
— 01:55
#

Спасибо за урок =)

Garibaldus
4 Сентября 2011
— 07:55
#

отличный урок! )

not bot
4 Сентября 2011
— 10:03
#

@Ant.Karlov Спасибо за урок! Не подскажешье еще, где можно почитать про проектирование структуры классов игры? Про паттерны и state машины? ?ли может книга какая есть, связанная с этим?

Dumskiy
4 Сентября 2011
— 12:14
#

... а знчаит и новый сезон уроков!...
?справь очепятку)) В глазпопала))
Спасибо за уроки!
Очень интересует вопрос, будет ли урок про создание уровней? ?менно про выбор уровней, переход между ними, и сохранение каких то результатов между переходами. Сейчас учусь и делаю свою первую игру и когда стал вопрос о создании уровней и переходов между ними, мозг встал в ступор(( немного поразмыслев решил что моя 1 игра будет бесконечноц)))

pytachok
5 Сентября 2011
— 00:34
#

@pytachok, на мой взгляд, то что вы перечислили является самым простым и этому не стоит уделять внимания. Для выбора уровня достаточно доработать класс Game, так чтобы его можно было вызывать с параметром идификатора нужного уровня. В классе App создаем меню выбора уровней (генерируем циклом матрицу кнопок, где каждая последующая кнопка будет вызывать i-й уровень). Так же нужно создать класс менеджерра уровней, который при вызове будет возвращать информацию нужного уровня (матрицу игрового поля, бэкграун, волны монстров). Переход между уровнями тоже не сложно сделать - создаем окошко геймовера и пихаем туда кнопки рестарта и след уровня. Для включения след уровня или выход в меню удаляем все объекты и листенеры относящиеся к game и universe, далее добавляем новый (если рестрат, то тот же самый). А хранить данные результаты можно в App с последующей записью в shared.

AntonSK
5 Сентября 2011
— 04:31
#

@AntonSK, спасибо за описание. Просто еще не дошел сам до этого вот и хочеться увидить хоть приблизительный код, чтобы потом на основе него уже двигаться дальше.

pytachok
5 Сентября 2011
— 09:06
#

@pytachok. Если с английский все нормально то вот тут серия уроков по созданию переходов между экранами, выбора уровня и даже встраивания мочи апи =) Ссылка на следующий урок всегда внизу страницы под комментами.

Dumskiy
5 Сентября 2011
— 10:51
#

не упомянут scale9Grid хотя для прелоадеров он отлично подходит.

Lord_Xaoca
5 Сентября 2011
— 17:18
#

Вопрос Антону не по теме поста:
На видео о создании уровня к МТ2 вы после отрисовки уровня (всякие камни, деревья и прочие декорации), создавали физическую модель уровня, расставляя прямоугольнички.
Хотелось бы услышать про эти прямоугольнички:
что они из себя представляют? как их получить и обработать в коде?

приветкакдела
6 Сентября 2011
— 11:37
#

2приветкакдела:
все очень просто, я делаю так:
1)делаем объект Box (мувиклип или спрайт) внутри которого есть квадратный шейп 100х100
2)вставляем этот объект нf сцену, сжимаем/растягиваем/поворачиваем
3)как в описанном примере считываем объекты Box из уровня, и создаем физический объект 100х100 растянутый/сжатый/повернутый как конкретный объект Box

orbit
6 Сентября 2011
— 15:53
#

orbit, в целом понятно, только в каком описанном примере? как считать именно эти объекты Box.
перебрать детей и каждого проверять на (getChildAt(i) is Box)?

и, если быть наглым, еще один вопрос:
а как организовать разные слои в мувиклипе уровня?
тоесть, есть у меня задний план и передний план, а между ними должен ,бегать игрок.
в Антоновском МТ2 хорошо видны эти слои (к примеру, иногда деревья стоят спереди)

приветкакдела
6 Сентября 2011
— 20:19
#

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

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

var level:MovieClip;
for (var i:int = 0; i < level.numChildren; i++)
{
var mc:MovieClip;
mc = level.getChildAt(i) as Sprite;
if (mc.name == "box")
{
// Создаем тут ящик
}
else if (mc.name == "wheel")
{
// Создаем тут колесо
}
}

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

mc.width и mc.height — ширина и высота объекта;
mc.x и mc.y — положение объекта;
mc.rotation — угол поворота;

Чтобы получить реальные размеры клипа, следует вначале считать угол поворота клипа, потом установить клипу угол поворота == 0 и после этого уже считывать width и height.

Разные слои для уровня обычно реализуются в разных клипах. Например, в моих играх для каждого уровня все объекты хранятся в двух клипах: в первом клипе передний план и расположение физических объектов с персонажами, во втором клипе все объекты для заднего плана.

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

Ant.Karlov
6 Сентября 2011
— 21:28
#

@pytachok, да уроки про создание интерфейса игры и в частности про создание уровней и про переходы между ними — будут обязательно. ? кстати это уже будет достаточно скоро...

Ant.Karlov
6 Сентября 2011
— 21:34
#

@Dumskiy, к сожалению я книжек и статей про проектирование игр толком не встречал и мало что читал про это. Все в основном приходит с опытом или черпается из редко встречающихся источников. Кстати отсутствие толковой информации по этой теме как раз и побудило меня больше рассказывать об этом в блоге, но судя по участившимся агрессивным комментариям к записям — все и так все знают :)

Ant.Karlov
6 Сентября 2011
— 21:44
#

Те, которые оставляют агрессивные комментарии, похоже, как раз мало что знают.

P.S.: тоже очень интересно читать именно о структурировании игры. Где делать меню, как организовать игровые экраны, как заставить взаимодействовать разные уровни и создать переходы между ними и т. п. Очень жду, когда уроки дойдут до этого момента!

jarofed
7 Сентября 2011
— 15:10
#

"но судя по участившимся агрессивным комментариям к записям — все и так все знают "

@Ant.Karlov, те кто пишут, привлекают к себе внимание. Я ничего не знаю. ? таких, как я, еще десять, и еще, и еще. Мы не будем писать всякий раз "Нет, пишите", но мы ждем уроков, даже если не говорим об этом.

Dimuron
7 Сентября 2011
— 15:47
#

Антон, Вы, как инсайдер, подскажите, какие вообще сейчас есть перспективы у TD? Жанр жив? ?ли монстры типа того же GemCraft-a заняли эту нишу, и туда не пробиться маленьким инди... ?бо пишу "неклассическую" TD и не знаю не зря ли. Вообще хотелось бы увидеть что-то типа краткого анализа современного рынка инди-флеш игр. Разумеется без раскрытия "страшных сектретов", но хоть что то=) Спасибо за многие интересные записи в блоге!

Seagull
8 Сентября 2011
— 02:24
#

@Seagull, да, я думаю что жанр TD живее живых. С выходом новых замечательных игр в этом жанре начинают играть даже те, кто раньше не играл в TD. Посмотрите Kingdom Rush — не игра, а сказка просто :) Есть и обратные модификации где игрок должен провести колонну боевых единиц по дороге и попутно разрушить башни. Так же хочется заметить, что одна из последних дорого проданных игр (несколько десятков тыщ долларов) на FGL тоже в жанре TD.

Но помните, что покупают и играют не в жанр — все дело в хорошей игре :)

Анализы мне как-то плохо даются, но я подумаю над этим. Спасибо за предложение!

Ant.Karlov
8 Сентября 2011
— 10:46
#

делаю свою игру, и везде использую moviceclip без анимации (т.е. тока 1 кадр). нужно ли при создании объекта
a1 = new mc_pr();
потом останавливать его?
a1.stop();
как я понял, даже если у меня 1 кадр, он все равно постоянно "прокручивается". так?

имярек
15 Сентября 2011
— 13:45
#

@имярек, а зачем тебе MovieClip с одним кадром?
В АS3 для этих нужд придумали Sprite.

Xcite
18 Сентября 2011
— 20:25
#

я в adobe flash виду тока movieclip, графику и кнопку. как создавать спрайтом?

имярек
18 Сентября 2011
— 22:13
#

Когда экспортируеш клип в ActionScript и у него только один кадр, то базовым классом указывай Sprite, а не MovieClip, у него еще иконка станет не синего цвета, а зеленого. Хотя это не имеет большого смысла как экспортировать, я имею ввиду в коде используй спрайты, а не клипы, это экономит память. Лучше тебе почитать на досуге Essential ActionScript 3.0

Xcite
19 Сентября 2011
— 16:09
#

так это же полезно - экономить память. спасибо.

имярек
19 Сентября 2011
— 17:03
#

Хорошо, что прочитал комментарии, а то домашнее задание начал бы со сложных махинаций в классе EmenyBase c addChild.
Сам бы не догадался, а все так просто. Нужно добавить пустой keyframe и не забыть откорректировать вычисления жизни this.gotoAndStop(Math.round(Amath.fromPercent(percent, this.totalFrames – 2)) + 1);

FirstFlashGame
23 Ноября 2011
— 20:34
#

Антон огромное спасибо за блог!!! Не обращайте внимание на всяких выскочек типа Max. А Max(у) лишь скажу здесь в уроках показано не то как делать игры от начала и до конца, так и только так, а то как решать проблемы встречающиеся при программировании. За основы цикла уроков была взята игра TowerDefence, а по ходу создания была рассмотрена и решена цела куча проблем с которыми встречаются начинающие разработчики(в том числе и я):
1)Карта проходимости
2)Поиск пути
3)Простейший редактор уровней
4)Кэширование объектов
5)Полосы жизни
5)...
На счет полос жизни: а какая разница кто как делает!!!
Тому, кто играет во flash игры, пофигу написана полоса жизни 10 стоками кода или 15 или 100 строками, игроку главное красота игры и ее общее восприятие, да конечно не надо быть быдло-кодером и писать то что можно 2 строками, 30ю, но выторговывать у компьютера пару мегабайт памяти при нынешних-то ее объемах - глупо и смешно!!! ? еще - такик как вы(Max) в инете полно, а таких как Антон единицы!!! ? то что он находит время(отрывая его от своего отдыха, семьи, ...) и делится своими знаниями с такими как я делает Антона на много более продвинутым разработчиком чем вы, ваш СУПЕР код(если он вообще существует) принес пользу только вам, а из уроков Антона я думаю извлекли пользу уже тысячи людей!!!
Еще раз огромное Вам СПАС?БО Антон!!!!!!!!!!!!

Даниил
12 Января 2012
— 01:10
#

As2 (если в екземплярах)
if(enemyhealth1 == 100){
healtbar1._alpha = 0;
}

Dariy
14 Января 2012
— 20:44
#

Я бы рисовал цветную полосу через FillRect, вторую для фона, а сверху стеклянный PNG.

Fear_Factory
5 Апреля 2013
— 14:41
#