В этом уроке вы научитесь создавать платформенную игру на основе физики как можно быстрее с помощью World Construction Kit.
Окончательный результат предварительного просмотра
Давайте посмотрим на конечный результат, к которому мы будем стремиться:
Это немного шатко, но это можно исправить — и подождите, пока не увидите, как быстро и легко это сделать!
Шаг 1: Скачать
Загрузите библиотеки Box2D Alchemy Port и WCK. Получите исходный код от github, а дополнительную информацию смотрите на сайте www.sideroller.com .
Шаг 2: Новый проект FlashDevelop
Нажмите «Проект» и выберите «Новый проект» из списка. Выберите AS3 Project в качестве шаблона проекта, назовите свой проект, укажите его в пустой директории и нажмите OK.
Найдите библиотеки Box2D / WCK, которые вы скачали на шаге 1, и поместите следующие папки в папку lib вашего нового проекта: Box2D , Box2DAS , дополнения , гравитация , разное , формы и wck .
Снова нажмите «Проект» и выберите «Свойства». Нажмите на вкладку «Classpaths» и добавьте свою папку lib.
Откройте Main.as в исходном файле и добавьте выделенный код. FlashDevelop должен автоматически генерировать все остальное.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
public class Main extends WCK
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
}
}
|
Шаг 3: Установите Flash IDE
Откройте Flash Professional. Нажмите Ctrl + Shift + F12, чтобы открыть Параметры публикации. Нажмите вкладку Flash. Выберите опцию «Экспортировать SWC»
…. а затем нажмите кнопку « Параметры» рядом с полем со списком ActionScript 3.0 .
На вкладке «Исходный путь» нажмите на значок «Перейти к пути» и выберите свою папку lib . Затем нажмите на вкладку «Путь к библиотеке» и выберите значок «перейти к SWC». Выберите файл lib / Box2DAS / Box2D.swc .
Нажмите кнопку «ОК» в разделе «Дополнительные параметры ActionScript 3» и снова в окне «Параметры публикации». Сохраните ваш FLA в папке \ src \ вашего проекта FlashDevelop (в той же папке, что и Main.as).
Наконец, нажмите Ctrl + F3, чтобы открыть свойства документа и установить класс документа на Main.
Шаг 4: Ваш первый объект в мире
Начните с использования инструмента прямоугольник, чтобы нарисовать прямоугольник на сцене.
Преобразуйте прямоугольник в символ, выделив его и нажав F8.
Установите точку регистрации в центре. * Примечание: очень важно, чтобы вы регистрировали все игровые символы таким образом. Невыполнение этого условия повлияет на то, как ваш объект реагирует на гравитацию и столкновения.
Нажмите «Экспорт для Actionscript» и установите базовый класс в shapes.Box
Шаг 5: Создайте мир
Может показаться нелогичным, что вы создали объект мира до того, как создали свой мир. Вы могли бы сделать это в любом случае, но вы увидите, что это сделать быстрее.
Выберите объект Static Box на сцене и нажмите F8.
Как и в случае со Static Box, установите точку регистрации мира в центре и установите флажок « Экспорт для ActionScript» .
Установите базовый класс на wck.World
Шаг 6: Определите мировой компонент
Щелкните правой кнопкой мыши по вновь созданному символу мира в библиотеке.
Выберите «Определение компонента …»
В поле Class введите wck.World
Это главная точка продажи для World Construction Kit. Если вы теперь щелкнете по объекту World на сцене и откроете панель свойств, нажав Ctrl + F3, вы можете отредактировать набор проверяемых свойств компонента World под заголовком «Параметры компонента».
Шаг 7: Определите компонент статического объекта
Хорошо, теперь мы собираемся сделать то же самое с нашим статическим объектом.
Щелкните правой кнопкой мыши по вашему символу Static Box в библиотеке.
Выберите «Определение компонента …»
В поле Класс введите wck.BodyShape
Откройте панель свойств, выбрав объект Static Box на сцене и нажав Ctrl + F3.
Прокрутите окно «Параметры компонента» вниз и измените «тип» с динамического на статический. Если вы забудете это сделать, ваши статические компоненты (стены, полы, платформы) станут подвержены гравитации и упадут с экрана во время выполнения.
Шаг 8: Построить пол и стены
Выберите ваш статический объект внутри мира. Скопируйте и вставьте его пару раз.
Выберите каждый экземпляр статического объекта и, используя функцию «Свободное преобразование», растяните, наклоните и переместите статические объекты вокруг, чтобы сформировать стены и пол. Вам не нужно держать границы на сцене.
Вот пример одной из моих попыток:
Очевидно, что «быть художником» не является обязательным условием для этого урока.
Шаг 9: Построй своего героя!
Какой хороший платформер без убедительного главного героя?
Находясь внутри объекта World, нарисуйте прямоугольник. Не стесняйтесь проявлять творческий подход здесь. Это лучшее, что я смог сделать:
Преобразуйте своего персонажа в символ, но пока не объявляйте базовый класс.
Щелкните правой кнопкой мыши по вашему новому символу Героя в библиотеке.
Выберите «Определение компонента …»
В поле Класс введите wck.BodyShape
Шаг 10: создайте класс Player
Откройте FlashDevelop.
Убедитесь, что ваш проект открыт. В папке \ src \ создайте новую папку с именем «View». В «View» создайте новую папку с именем «Characters».
Щелкните правой кнопкой мыши «View» и добавьте новый класс.
Назовите свой класс как-нибудь как HeroCharacter.as и установите базовый класс на shapes.Box
.
Ваша структура папок теперь должна выглядеть так:
Шаг 11: переопределить метод создания
Это точка входа для добавления функциональности вашим персонажам.
Добавьте следующий код в наш новый класс:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
public class HeroCharacter extends Box {
private var contacts:ContactList;
public override function create():void {
reportBeginContact = true;
reportEndContact = true;
contacts = new ContactList();
contacts.listenTo(this);
fixedRotation = true;
listenWhileVisible(world, StepEvent.STEP, world_stepEventHandler, false, 0, true);
listenWhileVisible(this, ContactEvent.BEGIN_CONTACT, this_beginContactHandler, false, 0, true);
super.create();
}
}
|
Установив для reportBeginContact
и reportEndContact
значение true
, мы устанавливаем свойства BodyShape
класса BodyShape
. Мы указываем, что мы хотели бы, чтобы BodyShape
отправлял ContactEvents
когда столкновения начинаются и когда конфликты заканчиваются. Затем мы создаем экземпляр ContactList
и просим его « listenTo
this
». ContactList.listenTo(this)
создает прослушиватели для ContactEvent.BEGIN_CONTACT
и ContactEvent.END_CONTACT
. Затем он создает обработчики для каждого из них, которые хранят информацию о столкновении. Вы можете увидеть все это, поместив курсор на ContactList
и нажав Ctrl + F4 в FlashDevelop.
Установив fixedRotation
в true
, мы гарантируем, что наш герой не будет вращаться вперед или назад при столкновении с объектами.
listenWhileVisible
— это еще один способ добавления прослушивателей событий. Мы могли бы использовать addEventListener(StepEvent.STEP, parseInput, false, 0, true);
но добавленная функциональность здесь заключается в том, что listenWhileVisible
удалит прослушиватели событий и назначит их для сборки мусора, когда Entity
будет удалена из игры. Для наших целей listenWhileVisible
является более оптимизированной версией addEventListener
. * Примечание. Как и в случае с addEventListener
, всегда используйте слабые ссылки, чтобы неиспользуемые объекты могли быть использованы для сборки мусора.
Используя super.create()
мы вызываем метод create()
для BodyShape
. Это позволяет нам расширить функциональность метода create()
вместо его замены.
Шаг 12: обработать ввод игрока
Давайте начнем с создания нашего обработчика StepEvent
для ввода игрока.
1
2
3
4
|
private function world_stepEventHandler(e:StepEvent):void
{
}
|
В каждый интервал времени StepEvent
будет отправляться из класса b2World
в Box2D. Шаг по умолчанию составляет 0,05 секунды. Вы можете легко изменить параметр timeStep
, вернувшись во Flash Professional и открыв параметры компонента World.
Далее мы будем использовать утилиту ввода, чтобы определить, какие клавиши в данный момент нажимаются пользователем.
1
2
3
4
5
6
|
private function world_stepEventHandler(e:StepEvent):void
{
var left:Boolean = Input.kd(‘LEFT’);
var right:Boolean = Input.kd(‘RIGHT’);
var jump:Boolean = Input.kp(‘UP’);
}
|
Метод Input.kd может принимать несколько аргументов. Итак, если мы хотим позволить пользователю иметь возможность управлять HeroCharacter с помощью WASD и пробела, мы можем изменить код следующим образом:
1
2
3
4
5
6
|
private function world_stepEventHandler(e:StepEvent):void
{
var left:Boolean = Input.kd(‘LEFT’, ‘A’);
var right:Boolean = Input.kd(‘RIGHT’, ‘D’);
var jump:Boolean = Input.kp(‘UP’, ‘ ‘, ‘W’);
}
|
Input.kd()
прослушивает Input.kd()
клавиши, а Input.kp()
прослушивает нажатие клавиши.
Шаг 13: примени импульс для перемещения игрока
Когда импульс применяется к твердому телу, импульс тела изменяется. Импульс — это произведение массы на скорость. Поэтому, когда мы хотим изменить скорость (скорость и направление) нашего игрока, мы будем использовать метод на b2body
называемый ApplyImpulse()
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
private function world_stepEventHandler(e:StepEvent):void
{
var left:Boolean = Input.kd(‘LEFT’, ‘A’);
var right:Boolean = Input.kd(‘RIGHT’, ‘D’);
var jump:Boolean = Input.kp(‘UP’, ‘ ‘, ‘W’);
if (jump) {
b2body.ApplyImpulse(new V2(0, -2), b2body.GetWorldCenter());
}
else if(left) {
b2body.ApplyImpulse(new V2(-2, 0), b2body.GetWorldCenter());
}
else if(right) {
b2body.ApplyImpulse(new V2(2, 0), b2body.GetWorldCenter());
}
}
|
ApplyImpulse()
принимает два параметра: мировой импульсный вектор и точку приложения импульса. На данный момент мы передадим новый 2D-вектор в качестве первого параметра для прыжка, перемещения влево и вправо (нам нужно будет отрегулировать, как мы справимся с прыжком чуть позже). Второй параметр для каждого метода b2body.GetWorldCenter()
— это b2body.GetWorldCenter()
. Этот метод возвращает мировое положение центральной массы нашего героя. Это важно, потому что ApplyImpulse
изменит угловую скорость нашего героя, если он не ApplyImpulse
на его центральную массу (именно поэтому мы использовали регистрацию центра для героя во Flash).
Шаг 14: Разобраться с нормальной силой
Вернитесь в Flash Professional и установите класс символа героя на «view.characters.HeroCharacter» и оставьте базовый класс пустым. Затем установите имя экземпляра вашего героя на «герой».
В параметрах компонента компонента World отмените выбор параметра «allowDragging» и выберите «прокрутка». Таким образом, пользователь не сможет перемещать вашего персонажа с помощью мыши, и камера будет следовать за вашим игроком, когда он будет двигаться. Наконец, в поле ‘focusOn’ введите ‘hero’, имя экземпляра вашего героя.
Нажмите Ctrl + Enter, чтобы проверить фильм. Вы заметите, что можете перемещать своего персонажа, нажимая влево и вправо, и можете прыгать с пробелом. Но если вы продолжите нажимать пробел, вы будете продолжать прыгать до бесконечности.
Причина, по которой мы не можем продолжать прыгать до бесконечности, заключается в том, что, как только мы в воздухе, нашим ногам уже нечего толкать, чтобы нас подтолкнуть. Нет равных сил у наших ног отталкивания. Когда мы твердо посажены на землю, сила, которая помогает нам прыгать вверх и удерживает нас от падения через пол, называется нормальной силой. Что нам нужно сделать, это определить, какая нормальная сила действует на ноги наших игроков. Если нет нормальной силы, то он не может сделать прыжок. Мы сделаем это, используя наш ContactList.
Вернитесь в FlashDevelop. Давайте еще раз изменим наш обработчик событий шага:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
private function world_stepEventHandler(e:StepEvent ):void
{
var manifold:b2WorldManifold = null;
if(!contacts.isEmpty()) {
manifold = getNormalForce();
}
var left:Boolean = Input.kd(‘LEFT’, ‘A’);
var right:Boolean = Input.kd(‘RIGHT’, ‘D’);
var jump:Boolean = Input.kp(‘UP’, ‘ ‘, ‘W’);
if (jump && manifold) {
var v:V2 = manifold.normal.multiplyN( -3);
b2body.ApplyImpulse(v, b2body.GetWorldCenter());
}
else if(left) {
b2body.ApplyImpulse(new V2(-.5, 0), b2body.GetWorldCenter());
}
else if(right) {
b2body.ApplyImpulse(new V2(.5, 0), b2body.GetWorldCenter());
}
}
|
Мы напишем код для getNormalForce()
всего за секунду. Здесь мы хотим найти контакты (касается ли наш игрок чего-нибудь?), Получить коллектор, описывающий, где наш игрок касается контакта (сбоку или снизу), и ускорить игрока вверх, если он вступает в контакт с землей. Если нет контактов, наш герой должен быть в воздухе. В этом случае коллектор будет нулевым, и игрок не сможет прыгнуть.
Теперь давайте напишем метод getNormalForce()
.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
private function getNormalForce():b2WorldManifold
{
var manifold:b2WorldManifold = null;
contacts.forEach(function(keys:Array, contactEvent:ContactEvent) {
var tempManifold:b2WorldManifold = contactEvent.getWorldManifold();
if (tempManifold.normal.y > 0) {
tempManifold.normal = new V2(0, tempManifold.normal.y);
manifold = tempManifold;
}
});
contacts.clean();
return manifold;
}
|
Перед вызовом getNormalForce()
мы проверяем, находится ли наш игрок в контакте с чем-либо. Если нет, то мы знаем, что он в воздухе. Причина, по которой эта функция существует, состоит в том, чтобы не дать игроку совершить второй прыжок со стены или сбоку от платформы.
Сначала мы объявляем локальную переменную с именем manifold
и устанавливаем ее в null
. Это параметр, который мы будем возвращать. Если персонаж героя находится в контакте с чем-то справа или слева от него (но не на земле), эта функция вернет нулевой коллектор.
Используя метод contacts.forEach()
, мы можем проверить каждый ContactEvent в нашем ContactList. Все ContactEvents имеют свойство worldManifold. Поэтому мы создаем другую локальную переменную с именем tempManifold и устанавливаем для нее значение, возвращаемое каждым contactEvent.GetWorldManifold. Затем мы проверяем, больше ли temp.normal.y больше нуля. Здесь мы спрашиваем, есть ли нормальная сила оси Y?
Если герой находится на земле или платформе, мы обнуляем любую нормальную силу оси X. Невыполнение этого условия приводит к прыжкам с багги, когда игрок толкается к стене. Не стесняйтесь экспериментировать с этим. Если вы не обнуляете x, игрок получает классную (но ненадежную) способность Metroid к прыжкам со стены.
Наконец, очистите список контактов. Мы не хотим обрабатывать одни и те же контакты более одного раза.
Шаг 15: добавь монеты
Теперь, когда у нас есть главный герой, который может бегать и прыгать, давайте добавим несколько предметов, которые он может подобрать. Вернитесь в Flash Professional, нарисуйте круг или эллипс для монеты и преобразуйте его в символ. Установите класс и базовый класс, как показано:
Положите на сцену столько экземпляров класса монет, сколько вы хотите. В параметрах компонентов я устанавливаю static
тип каждой монеты, чтобы гравитация не влияла на них и могла плавать на месте, как в Марио, но решать вам.
Шаг 16: обрабатывать столкновения с монетами
Прямо сейчас монеты являются неподвижными, статичными объектами. Мы хотели бы изменить это. Вернитесь к FlashDevelop и откройте класс HeroCharacter
. Добавьте обработчик событий для таких столкновений:
1
2
3
4
|
private function this_beginContactHandler(e:ContactEvent):void
{
}
|
Это обработчик для слушателя, который мы создали на шаге 11. Добавьте следующий код:
1
2
3
4
5
6
7
|
private function this_beginContactHandler(e:ContactEvent):void
{
var coin:Coin = e.other.m_userData as Coin;
if(coin) {
coin.remove();
}
}
|
Сначала мы создаем локальную переменную с именем coin
того же типа, что и класс монет, созданный вами во Flash. ContactEvent отслеживает другой прибор Box2D, участвующий в столкновении. Если это монета, мы удаляем ее со сцены, создавая иллюзию, что она была собрана.
Шаг 17: Сохраняйте счет
Создайте папку в каталоге \ src \ под названием «модель». Внутри «model» создайте папку с именем «Scoreboard» и создайте новый класс « ScoreBoard
который расширяет EventDispatcher
. Так как мы хотим, чтобы за один раз был только один экземпляр табло, мы будем следовать шаблону проектирования Singleton. В начале этого года был краткий совет по шаблону Singleton на Activetuts +, если вы хотите получить ссылку.
Напишите следующий код в классе ScoreBoard:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
package model.scoreboard
{
import flash.errors.IllegalOperationError;
import flash.events.Event;
import flash.events.EventDispatcher;
public class ScoreKeeper extends EventDispatcher
{
private static var _instance:ScoreKeeper;
public function ScoreKeeper()
{
if (_instance != null)
{
throw new IllegalOperationError(«Use ScoreBoard.getInstance() to get a reference to the Singleton ScoreKeeper.»);
}
else
{
initialize();
}
}
private function initialize():void
{
}
public static function getInstance():ScoreKeeper
{
if (_instance == null) _instance = new ScoreKeeper();
return _instance;
}
}
}
|
Это паттерн Синглтон. Мы ожидаем, что любой класс, который хочет получить доступ к ScoreKeeper, будет использовать статическую функцию getInstance()
. Если экземпляр уже существует и кто-то (например, другой разработчик в вашей команде) пытается создать экземпляр ScoreKeeper через его конструктор, они получат наше сообщение об ошибке, сообщающее, что к ScoreKeeper следует обращаться только через getInstance()
.
ScoreKeeper расширяет EventDispatcher, чтобы он мог отправлять события при изменении оценки. Мы создадим табло в качестве компонента просмотра, который будет подписываться на события ScoreKeeper.
Теперь нам нужно ScoreKeeper, чтобы фактически начать вести счет. Нам нужна переменная для хранения счета, метод, который увеличивает счет, метод получения для оценки, чтобы другие классы могли получить к нему доступ, и public static const
для хранения нашего типа события.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
package model.scoreboard
{
import flash.errors.IllegalOperationError;
import flash.events.Event;
import flash.events.EventDispatcher;
public class ScoreKeeper extends EventDispatcher
{
public static const SCORE_CHANGED:String = «SCORE_CHANGED»;
private var _score:uint;
private static var _instance:ScoreKeeper;
public function ScoreKeeper()
{
if (_instance != null)
{
throw new IllegalOperationError(«Use ScoreBoard.getInstance() to get a reference to the Singleton ScoreKeeper.»);
}
else
{
initialize();
}
}
private function initialize():void
{
_score = 0;
}
public function incrementScore():void
{
_score++;
dispatchEvent(new Event(«SCORE_CHANGED»));
}
public static function getInstance():ScoreKeeper
{
if (_instance == null) _instance = new ScoreKeeper();
return _instance;
}
public function get score():uint { return _score;
}
}
|
И это все, что нам нужно для нашего ScoreKeeper. Теперь давайте создадим компонент вида для отображения номера счета. Войдите во Flash и на сцене (не внутри символа мира) вытащите табло. Здесь важно только то, что вы используете Text Tool для рисования TextField с именем экземпляра ‘ score
‘. Преобразуйте TextField в символ видеоклипа с именем ScoreBoard
.
Вернувшись в FlashDevelop, в папку world, создайте класс «ScoreDisplay», который расширяет MovieClip. Все, что нам нужно сделать здесь, это получить экземпляр ScoreKeeper и подписаться на его события. Это должно выглядеть так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package view.world
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.text.TextField;
import model.scoreboard.ScoreKeeper;
public class ScoreDisplay extends MovieClip
{
private var _scoreKeeper:ScoreKeeper = ScoreKeeper.getInstance();
public function ScoreDisplay()
{
this.score.text = «0»;
_scoreKeeper.addEventListener(ScoreKeeper.SCORE_CHANGED, scoreBoard_ScoreChangedHandler, false, 0, true);
}
private function scoreBoard_ScoreChangedHandler(e:Event):void
{
this.score.text = _scoreKeeper.score.toString();
}
}
}
|
Вернитесь во Flash и откройте свойства символа ScoreBoard в библиотеке. Измените класс на view.world.ScoreDisplay
.
У вас есть последний шаг. Вернитесь в класс HeroCharacter и добавьте две строки кода:
1
2
3
4
5
6
7
8
|
private function this_beginContactHandler(e:ContactEvent):void
{
var coin:Coin = e.other.m_userData as Coin;
if(coin) {
coin.remove();
scoreBoard.incrementScore();
}
}
|
1
2
3
4
|
public class HeroCharacter extends Box {
private var contacts:ContactList;
private var scoreKeeper:ScoreKeeper = ScoreKeeper.getInstance();
|
Шаг 18: Добавьте статические платформы
Перейдите во Flash Professsional и поместите экземпляр StaticBox
(тот же, который мы использовали для создания стен и пола) внутри экземпляра World. Убедитесь, что вы установили его тип на static
в Component Parameters и что платформа достаточно низкая, чтобы ваш игрок мог перейти к нему.
Шаг 19: добавь приостановленные платформы с соединениями Box2D
WCK делает создание качающихся платформ очень простым. Мы можем сделать все это во Flash IDE без написания кода.
Начните с рисования круга. Преобразуйте круг в символ с именем Joint
и установите для базового класса значение wck.Joint
. Затем щелкните правой кнопкой мыши символ «Соединение» в библиотеке и перейдите к « Определение компонента» . Установите класс как wck.Joint
. На панели «Свойства» установите имя экземпляра в качестве anchor
а в параметрах компонента измените type
на « Revolute
. Это соединение, которое придаст нашей платформе маятниковое действие.
Нарисуйте платформу с помощью инструмента «Прямоугольник». Выберите его и конвертируйте в символ. Установите базовый класс на extras.Platform
. Щелкните правой кнопкой мыши на символе в библиотеке и в определении компонента установите для Class значение extras.Platform
.
Вытащите еще два экземпляра Объединенного класса в Мир и поместите каждый из них на любом конце Платформы. Макет должен выглядеть так:
Для каждого нового экземпляра Joint перейдите в Параметры компонента и измените type
на « Distance
», а в поле target2Name
напишите « anchor
». Протестируйте свой фильм, и у вас должна быть качающаяся платформа.
Шаг 20: добавь врагов
В FlashDevelop добавьте новый класс в папку \ characters \ EnemyCharacter
. Вот код, который мы собираемся написать (это будет выглядеть очень знакомо):
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
package view.characters
{
import Box2DAS.Common.V2;
import Box2DAS.Dynamics.ContactEvent;
import Box2DAS.Dynamics.StepEvent;
import shapes.Box;
import wck.ContactList;
public class EnemyCharacter extends Box {
private var contacts:ContactList;
private var left:Boolean = true;
private var right:Boolean;
public override function create():void {
fixedRotation = true;
reportBeginContact = true;
super.create();
contacts = new ContactList();
contacts.listenTo(this);
listenWhileVisible(world, StepEvent.STEP, world_stepEventHandler, false, 0, true);
listenWhileVisible(this, ContactEvent.BEGIN_CONTACT, this_beginContactHandler, false, 0, true);
}
private function world_stepEventHandler(e:StepEvent ):void
{
if(left) {
b2body.ApplyImpulse(new V2(-.1, 0), b2body.GetWorldCenter());
}
else if(right) {
b2body.ApplyImpulse(new V2(.1, 0), b2body.GetWorldCenter());
}
}
private function this_beginContactHandler(e:ContactEvent):void
{
var wall:StaticBox = e.other.m_userData as StaticBox;
if(wall) {
left = !left;
right = !right;
}
}
}
}
|
Единственное, что здесь происходит, это то, что каждый раз, когда объект сталкивается со стеной, он меняет направление. И на каждом шаге события вражеский персонаж будет применять импульс в том направлении, в котором он стоит.
Вернитесь во Flash и нарисуйте вражеского персонажа и преобразуйте его в символ с базовым классом, для которого установлено значение view.characters.EnemyCharacter
а для класса — Enemy
.
Последнее, что нам нужно сделать, это обработать контакт между персонажем игрока и вражеским персонажем. В классе HeroCharacter
добавьте следующий код:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
private function this_beginContactHandler(e:ContactEvent):void
{
var coin:Coin = e.other.m_userData as Coin;
trace(coin);
if(coin) {
coin.remove();
scoreKeeper.incrementScore();
}
else {
var enemy:EnemyCharacter = e.other.m_userData as EnemyCharacter;
if (enemy)
{
var tempManifold:b2WorldManifold = e.getWorldManifold();
if (tempManifold.normal.y > 0)
{
Util.addChildAtPosOf(world, new BadGuyFX(), enemy);
enemy.remove();
}
}
}
}
|
Если наш герой соприкасается с чем-то, а это не монета, мы проверим, не является ли это EnemyCharacter
. Если это так, мы проверим коллектор ContactEvent
чтобы определить, ударили ли мы плохого парня сверху или сбоку. Если мы прыгнем на него сверху, он будет удален со сцены.
Я хотел добавить анимацию раздавливания EnemyCharacter, поэтому во Flash я сделал ролик с анимацией временной шкалы, когда враг сокрушен. Я установил для базового класса этого объекта BadGuyFX
значение misc.FX
, класс в библиотеке WCK, который один раз воспроизводит собственную анимацию временной шкалы, а затем устанавливает себя в null
. Затем я добавил его в рабочую область с помощью метода Util
addChildAtPosOf()
. Благодаря анимации удаление врага не кажется таким внезапным.
Вывод
Теперь, когда у вас есть рабочий прототип платформера, я призываю вас продолжать исследовать то, что может предложить WCK. Я особенно рекомендую поиграть в Component Parameters ваших игровых объектов. Это действительно забавный и быстрый способ изменить физику игрового мира без написания кода. Я надеюсь, вам понравился этот урок! Спасибо за прочтение!