Статьи

Создание «Flux»: простая флеш игра с гравитационной механикой

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


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

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

Сама игра очень проста в своем нынешнем состоянии — взгляните на эту критику, чтобы узнать, как превратить ее из простой демонстрации в полноценную игру!


Настройте новый проект AS3 во FlashDevelop и установите его размеры 550x600px.

1
2
3
4
5
6
7
8
9
package
{
    [SWF(width = «550», height = «600»)]
     
    public class Main extends Sprite
    {
     
    }
}

В частице есть шесть объектов, которые вы можете определить по игре выше:

  • Энергоснабжение — представлено белым объектом овальной формы
  • Астероид — представленный в виде камня
  • Потребитель энергии — представлен красной звездой, ограниченной зеленым светом.
  • Звезды — фон
  • Индикатор диапазона — представлен белым кружком
  • Корабль — объект игрока

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


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

Они есть:

  • Звезды
  • Энергоснабжение
  • Потребитель энергии
  • астероид

В этом уроке мы только собираемся сделать объекты «энергообеспечения» из четырех приведенных выше. Итак, давайте начнем с создания этих объектов и их падения со случайной нерестовой позицией и скоростью.

Начните с создания класса Energy :

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
package
{
    import flash.display.MovieClip;
    import flash.events.Event;
 
    public class Energy extends MovieClip
    {
        private var rSpeed:Number = 0;
         
        public function Energy(speed:Number)
        {
            graphics.beginFill(0x321312);
            graphics.drawCircle(0, 0 , 8);
             
            rSpeed = speed;
        }
         
        // we will call this every frame
        public function move():void
        {
            this.y += rSpeed;
            //rotation speed is linked to moving speed
            this.rotation += rSpeed / 8;
        }
    }
}

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

Создайте класс:

01
02
03
04
05
06
07
08
09
10
11
12
package
{
     
    public class GameScreen extends MovieClip
    {
 
        public function GameScreen()
        {
         
        }
    }
}

Это все, что нам нужно на данный момент.


Теперь мы создадим экземпляр GameScreen в Main :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package
{
    import flash.display.Sprite;
    import flash.events.Event;
 
    [SWF(width = «550», height = «600»)]
      
    public class Main extends Sprite
    {
        private var game:GameScreen;
         
        public function Main():void
        {
            // don’t display a yellow rectangle on the screen at startup
            stage.stageFocusRect = false;
             
            game = new GameScreen();
            addChild(game);
             
            // give keyboard focus to the game screen immediately
            stage.focus = game;
        }
    }
}

Зачем беспокоиться? Ну, таким образом, будет проще добавить дополнительные экраны позже, если мы захотим (например, предварительный загрузчик, титульный экран, игра поверх экрана …).


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

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
package
{
    import flash.display.MovieClip;
     
    public class EnergyManager
    {
        // this Vector will store all instances of the Energy class
        private var energyList:Vector.<Energy>
        private var gameScreen:GameScreen;
         
        public function EnergyManager(gs:GameScreen)
        {
            gameScreen = gs;
            energyList = new Vector.<Energy>;
        }
    }
}

Обратите внимание, что мы требуем, чтобы ссылка на GameScreen передавалась в конструктор, и мы храним эту ссылку в закрытой переменной. Мы также настроили Вектор для хранения ссылок на все энергетические объекты.

Пока что класс не содержит других функций; мы добавим их позже.


Добавьте функцию ниже для создания энергии, это просто функция; позже мы вызовем функцию из класса GameScreen :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
public function createEnergy(number:int):void
{
    var energy:Energy;
    for (var i:int = 0; i < number; i++) {
 
        energy = new Energy(4);
             
        gameScreen.addEnergyToScreen(energy);
             
        energyList.push(energy);
 
        energy.x = Calculation.generateRandomValue(30, 520);
        energy.y = Calculation.generateRandomValue( -150, -20);
    }
}

Мы создаем новый источник энергии со скоростью 4, добавляем его в список отображения (через GameScreen), добавляем его в вектор всех энергетических объектов, которые мы только что создали, и устанавливаем его положение в случайную точку в определенных пределах.

Calculation.generateRandomValue(#, #) — статическая функция, которую мы еще не написали, поэтому давайте сделаем это сейчас. Создайте новый класс с именем Calculation и добавьте эту функцию:

1
2
3
4
5
6
public static function generateRandomValue(min:Number, max:Number):Number
{
    var randomValue:Number = min + (Math.random() * (max — min));
         
    return randomValue;
}

Эта функция будет генерировать случайное число между двумя значениями, переданными ей. Для получения дополнительной информации о том, как это работает, см. Этот Быстрый совет . Поскольку это статическая функция, нам не нужно создавать экземпляр Calculation для его вызова.

Теперь, что это addEnergyToScreen() функция addEnergyToScreen() ? Мы еще не определили это, поэтому давайте сделаем это сейчас. Добавьте это к GameScreen :

1
2
3
4
public function addEnergyToScreen(energy:Energy):void
{
    addChild(energy);
}

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

1
2
3
4
5
6
7
public function removeEnergyFromScreen(energy:Energy):void
{
    if (energy.parent == this)
    {
        removeChild(energy);
    }
}

Давайте установим таймер, который определяет интервал для каждого нереста. Этот код входит в GameScreen конструктора GameScreen :

1
2
3
4
5
energyM = new EnergyManager(this);
                                 
var spawnTimer:Timer = new Timer(3000, 0);
spawnTimer.addEventListener(TimerEvent.TIMER, spawnEnergy);
spawnTimer.start();

Таким образом, каждые три секунды таймер будет вызывать spawnEnergy() . Давайте напишем эту функцию сейчас:

1
2
3
4
private function spawnEnergy(e:TimerEvent):void
{
    energyM.createEnergy(4);
}

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

1
2
3
4
public function Player()
        {
            graphics.beginFill(0x7ebff1);
            graphics.drawCircle(0, 0, 20);

Добавьте этот код в GameScreen чтобы добавить игрока на экран:

1
2
// in the variable definitions
public var player:Player;
1
2
3
4
5
// in the constructor function
player = new Player;
addChild(player);
player.x = 275;
player.y = 450;

Пока у нас должно быть несколько источников энергии, падающих на несколько секунд, и игрок появляется в середине экрана:

playerandenergy.

Есть два основных способа применения движения:

  1. Использование логических (true / false) значений — true = движется, false = не движется. При нажатии клавиши со стрелкой вправо значение «перемещение вправо» изменится на true . В каждом обновлении фрейма «перемещение вправо» — это true , мы увеличиваем значение x объекта.
  2. Using direct update each frame — когда нажата клавиша со стрелкой вправо, объект получает указание немедленно двигаться вправо, увеличивая его значение x.

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

Для этого есть три простых шага:

  1. Создайте две логические переменные, одну для перемещения вправо и одну для перемещения влево.
    1
    2
    private var moveRight:Boolean = false;
    private var moveLeft:Boolean = false;
  2. Переключить логическое значение при нажатии или отпускании клавиш:
    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
        addEventListener(Event.ENTER_FRAME, update);
        addEventListener(KeyboardEvent.KEY_DOWN, KeyDownHandler);
        addEventListener(KeyboardEvent.KEY_UP, KeyUpHandler);
    }
         
    private function KeyDownHandler(e:KeyboardEvent):void
    {
        if (e.keyCode == Keyboard.RIGHT) {
            moveRight = true;
        }
        if (e.keyCode == Keyboard.LEFT) {
            moveLeft = true;
        }
        if (e.keyCode == Keyboard.SPACE) {
            if (isGravityPushing == true) {
                isGravityPushing = false;
            } else {
                isGravityPushing = true;
            }
        }
    }
         
    private function KeyUpHandler(e:KeyboardEvent):void
    {
        if (e.keyCode == Keyboard.RIGHT) {
            moveRight = false;
        }
        if (e.keyCode == Keyboard.LEFT) {
            moveLeft = false;
        }
    }
  3. Основываясь на этих логических значениях, фактически перемещайте игрока каждый кадр:

    Не забудьте сначала создать функцию прослушивания из события enter frame, «update»:

    1
    2
    3
    4
    5
    6
    7
    8
    //call this function every frame
    private function update(e:Event):void
        if (moveRight == true) {
            player.x += 6;
        }
        if (moveLeft == true) {
            player.x -= 6;
        }

    Держите игрока в пределах экрана:

    1
    2
    3
    4
    5
    6
    if (player.x >= 525) {
        moveRight = false;
    }
    if (player.x <= 20) {
        moveLeft = false;
    }

Вот как все это выглядит на месте:

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package
{
    import flash.display.MovieClip;
    import flash.events.Event;
    import flash.events.TimerEvent;
    import flash.ui.Keyboard;
    import flash.utils.Timer;
    import flash.events.KeyboardEvent;
  
    public class GameScreen
    {
        public var player:Player;
  
        private var energyM:EnergyManager;
  
        private var moveRight:Boolean = false;
        private var moveLeft:Boolean = false;
        private var isGravityPushing:Boolean = true;
  
        private var returnedPower:int = 0;
  
        private var scoreText:Text;
        private var totalScore:int=0;
        private var score:Text;
  
        public function GameScreen()
        {
            scoreText = new Text(«Score :»);
            addChild(scoreText);
  
            energyM = new EnergyManager;
  
            var spawnTimer:Timer = new Timer(3000, 0);
            spawnTimer.addEventListener(TimerEvent.TIMER, spawnEnergy);
            spawnTimer.start();
  
            player = new Player;
            addChild(player);
            player.x = 275;
            player.y = 450;
  
            addEventListener(Event.ENTER_FRAME, update);
            addEventListener(KeyboardEvent.KEY_DOWN, KeyDownHandler);
            addEventListener(KeyboardEvent.KEY_UP, KeyUpHandler);
        }
 
    private function KeyDownHandler(e:KeyboardEvent):void
    {
        if (e.keyCode == Keyboard.RIGHT) {
            moveRight = true;
        }
        if (e.keyCode == Keyboard.LEFT) {
            moveLeft = true;
        }
        if (e.keyCode == Keyboard.SPACE) {
            if (isGravityPushing == true) {
                isGravityPushing = false;
            }else if (isGravityPushing == false) {
                isGravityPushing = true;
            }
        }
    }
         
    private function KeyUpHandler(e:KeyboardEvent):void
    {
        if (e.keyCode == Keyboard.RIGHT) {
            moveRight = false;
        }
        if (e.keyCode == Keyboard.LEFT) {
            moveLeft = false;
        }
    }
 
    private function update(e:Event):void
    {
        if (player.x >= 525) {
            moveRight = false;
        }
        if (player.x <= 20) {
            moveLeft = false;
        }
        if (moveRight == true) {
            player.x += 6;
        }
        if (moveLeft == true) {
            player.x -= 6;
        }
    }
    }
}

На данный момент источники энергии нерестятся, но не движутся. Мы будем использовать GameScreen.update() чтобы заставить их двигаться, так как она запускает каждый кадр.

Добавьте этот код в GameScreen.update() :

1
energyM.moveAll();

Теперь, конечно, нам нужно сделать EnergyManager.moveAll() , поэтому добавьте это в EnergyManager.as :

1
2
3
4
5
6
7
public function moveAll():void
{
    for (var i:int = 0; i < energyList.length; i++) {
        var energyS:Energy = energyList[i];
        energyS.move();
    }
}

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

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

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

Мы можем написать функцию как ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public function checkCollision(p:Player):int
{
    // energy transferred due to collision
    var energyTransfer:int = 0;
     
    for (var i:int = 0; i < energyList.length; i++) {
        var energyS:Energy = energyList[i];
         
        var newX:Number = px — energyS.x;
        var newY:Number = py — energyS.y;
             
        var distance:Number = Math.sqrt(newX * newX + newY * newY);
             
        if (distance <= 28) {
            gameScreen.removeEnergyFromScreen(energyS);
            energyList.splice(i, 1);
            // for this simple game, we’ll always transfer 1 unit
            // but you could alter this based on speed of collision
            // or any other factor
            energyTransfer = 1;
        }
    }
    return energyTransfer;
}
  • Строка 32: обратите внимание, что мы передаем ссылку на игрока, чтобы мы могли получить доступ к его позиции.
  • Строка 38: EnergyS является коротким для энергоснабжения.
  • Строки 40 и 41: найти разницу в координатах x и y между игроком и источником энергии, который мы сейчас проверяем.
  • Строка 43: вычислите расстояние между объектами через Пифагора.
  • Строка 45: проверка на столкновение; 28 — сумма радиусов двух объектов (радиус игрока равен 20, радиус энергии равен 8).
  • Строки 46 и 47: убрать подачу энергии с экрана и из вектора.
  • Строка 51: добавьте максимум одну единицу энергии на кадр.

Вы можете изменить energyTransfer += 1 51 на energyTransfer += 1 , чтобы позволить игроку поглощать более одного энергетического объекта одновременно. Это зависит от вас — попробуйте и посмотрите, как это влияет на игру.


Нам нужно проверять наличие коллизий в каждом кадре, поэтому мы должны вызвать функцию, которую мы только что написали из GameScreen.update() .

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

1
private var returnedPower:int = 0;
1
returnedPower = energyM.checkCollision(player);

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

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

G — это просто число, и мы можем установить его на то, что нам нравится. Точно так же мы можем установить массы каждого объекта в игре на любые значения, которые нам нравятся. Гравитация возникает на бесконечных расстояниях, но в нашей игре у нас будет точка отсечения (обозначенная белым кружком в демонстрационной версии с начала урока).

Об этой формуле следует отметить две наиболее важные вещи:

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

Прежде чем мы начнем кодировать игровую механику для функций «Push» и «Pull», давайте выясним, что мы хотим, чтобы она делала:

фреймворк

По сути, мы хотим, чтобы A (игрок) оказывал определенную силу на B (кристалл) и двигал B к A на основе этой силы.

Мы должны пересмотреть несколько концепций:

  • Вспышка работает в радианах, а не в градусах.
  • Система координат Flash имеет реверсированную ось Y: спуск означает увеличение y.
  • Мы можем получить угол линии, соединяющей А с В, используя Math.atan2(By - Ay, Bx - Ax) .
  • Мы можем использовать тригонометрию, чтобы выяснить, насколько нам нужно переместить B вдоль каждой оси, основываясь на этом угле и силе:
    • Bx += (Force*Math.cos(angle));
    • By += (Force*Math.sin(angle));
  • Мы можем использовать теорему Пифагора, чтобы выяснить расстояние между двумя объектами:

Для получения дополнительной информации см. Учебные пособия Gravity in Action и Trigonometry для разработчиков Flash-игр .


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

  1. Найдите разницу в x и y между кораблем и данным кристаллом.
  2. Найдите угол между ними в радианах.
  3. Найдите расстояние между ними, используя Пифагора.
  4. Проверьте, находится ли объект в гравитационном поле корабля.
  5. Если так, вычислите гравитационную силу и …
  6. … применить силу, изменяя значения х и у кристалла.

Образец кода:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
public function gravityPull(p:Player): void
{
    for (var i:int = 0; i < energyList.length; i++) {
        var energyS:Energy = energyList[i];
             
        var nX:Number = (px — energyS.x);
        var nY:Number = (py — energyS.y);
         
        var angle:Number = Math.atan2(nY, nX);
             
        var r:Number = Math.sqrt(nX * nX + nY * nY);
             
        if (r <= 250) {
            var f:Number = (4 * 50 * 10) / (r * r);
            energyS.x += f * Math.cos(angle);
            energyS.y += f * Math.sin(angle);
        }
    }
}
  • Строка 53: получить ссылку на игрока.
  • Строка 55: мы проходим через каждый энергетический объект.
  • Строка 61: найдите угол между кораблем и энергией.
  • Строка 63: найдите расстояние между ними тоже.
  • Строка 65: проверьте, находится ли энергия в силовом поле корабля.
  • Строка 67: используйте формулу:
    • 4 = G, «гравитационная постоянная», которую я выбрал.
    • 50 = m1, масса корабля игрока.
    • 10 = м2, масса энергетического объекта.
  • Строка 69: применить движение.

Вот интервал времени, показывающий, как это выглядит:

Обратите внимание, что энергия движется тем быстрее, чем ближе к кораблю, благодаря термину r-квадрат.

Мы можем реализовать функцию толкания, просто сделав силу отрицательной:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
public function gravityPull(p:Player): void
{
    for (var i:int = 0; i < energyList.length; i++) {
        var energyS:Energy = energyList[i];
             
        var nX:Number = (px — energyS.x);
        var nY:Number = (py — energyS.y);
         
        var angle:Number = Math.atan2(nY, nX);
             
        var r:Number = Math.sqrt(nX * nX + nY * nY);
             
        if (r <= 250) {
            var f:Number = (4 * 50 * 10) / (r * r);
            energyS.x -= f * Math.cos(angle);
            energyS.y -= f * Math.sin(angle);
        }
    }
}

Здесь объект движется медленнее по мере удаления от игрока, так как сила ослабевает.


Конечно, вам понадобится эта функция для запуска каждого кадра с помощью GameScreen — но перед этим нам нужно будет использовать логическую функцию для переключения между двумя функциями:

1
private var isGravityPushing:Boolean = true;

Мы будем использовать true для «Push» и false для «Pull».

Внутри KeyDownHandler() :

1
2
3
4
5
6
7
if (e.keyCode == Keyboard.SPACE) {
    if (isGravityPushing == true) {
        isGravityPushing = false;
    } else if (isGravityPushing == false) {
        isGravityPushing = true;
    }
}

После этого вам придется проверять логическое значение каждого кадра. Добавьте это для update() :

1
2
3
4
5
6
if (isGravityPushing == true) {
    energyM.gravityPull(player);
}
if (isGravityPushing == false) {
    energyM.gravityPush(player);
}

Вы можете обнаружить, что движение не выглядит так хорошо. Это может быть из-за того, что сила не совсем идеальна, или из-за r-квадрата.

Я хотел бы изменить формулу следующим образом:

1
var f:Number = (0.8 * 50 * 10) / r;

Как видите, я уменьшил значение «G» до 0,8 и изменил силу, чтобы она зависела просто от расстояния между объектами, а не от квадрата расстояния.

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


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

Для этого мы создадим новый класс Text :

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
package
{
    import flash.display.MovieClip;
    import flash.text.TextField;
    import flash.events.Event;
    import flash.text.TextFormat;
 
    import flash.text.TextFormatAlign;
 
    public class Text extends MovieClip
    {
        public var _scoreText:TextField= new TextField();
         
        public function Text(string:String)
        {
            var myScoreFormat:TextFormat = new TextFormat();
            myScoreFormat.size = 24;
             
            myScoreFormat.align = TextFormatAlign.LEFT;
            myScoreFormat.color = (0x131313);
             
            _scoreText.defaultTextFormat = myScoreFormat;
             
            _scoreText.text = string;
             
            addChild(_scoreText);
        }
 
        public function updateText(string:String)
        {
            _scoreText.text = string;
        }
    }
}

Это очень просто; это в основном мувиклип с текстовым полем внутри.


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

Чтобы сила корабля появилась на самом корабле, мы можем просто добавить экземпляр Text в список отображения объекта корабля.

Объявите эти переменные в классе Ship :

1
2
public var totalPower:Number = 100;
private var powerText:Text;

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

Сначала в конструкторе:

1
2
3
4
5
6
7
// add a new text object if it doesn’t already exist
if (!powerText) {
    powerText = new Text(String(int(totalPower)));
    addChild(powerText);
    powerText.x -= 20;
    powerText.y -= 16;
}

А потом…

1
2
3
4
5
6
public function updatePower():void
    {
        // fps = 24, so this makes power decrease by 1/sec
        totalPower -= 1 / 24;
        powerText.updateText(String(int(totalPower)));
    }

Мощность будет уменьшаться каждый кадр на 1/24 единицы, то есть уменьшаться на одну полную единицу каждую секунду.

Нам нужно, чтобы это запускалось каждый кадр, поэтому добавьте эту строку в GameScreen.update() :

1
player.updatePower();

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

В GameScreen.update() добавьте выделенную строку:

1
2
returnedPower = energyM.checkCollision(player);
player.totalPower += returnedPower;

Помните, что вы можете изменить мощность, возвращаемую EnergyManager.checkCollision() .


Опять же нам понадобится текстовый класс. На этот раз мы отобразим «Оценка», а затем значение.

Здесь нам понадобятся еще три переменные:

  • Текст «Оценка».
  • Текст значения оценки .
  • Переменная для хранения фактической оценки.

GameScreen это в классе GameScreen :

1
2
3
private var scoreText:Text;
private var totalScore:int = 0;
private var score:Text;

В конструкторе добавьте этот код:

1
2
3
4
5
6
7
scoreText = new Text(«Score :»);
addChild(scoreText);
 
score = new Text(String(totalScore));
addChild(score);
score.x = scoreText.x + 100;
score.y += 2;

Теперь добавьте в функцию update() :

1
score.updateText(String(totalScore));

Вот и все — мы создали базовую версию вышеописанной игры!

Посмотрите (вам может понадобиться перезагрузить страницу):


Может быть, вы также хотели бы фон со встроенным изображением и звездами. Добавьте это в ваш Main класс:

1
2
3
4
5
[Embed(source = «/../lib/SpaceBackground.jpg»)] //embed
        private var backgroundImage:Class;
 
        private var bgImage:Bitmap = new backgroundImage();
        private var numOfStars:int = 70;

Теперь создайте класс Star :

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
package assets
{
    import flash.display.MovieClip;
    import flash.events.Event;
 
    public class Star extends MovieClip
    {
        private var speed:Number;
         
        public function Star(alpha:Number, size:Number, speed1:Number)
        {
            graphics.beginFill(0xCCCCCC);
            graphics.drawCircle(0, 0, size);
             
            speed = speed1;
        }
         
        // make sure you call this every frame
        private function moveDown():void
        {
            this.y += speed;
             
            if (this.y >= 600) {
                this.y = 0;
            }
        }
    }
}

В конструкторе Main() добавьте это, чтобы создать звезды:

1
2
3
for (var i:int = 0; i < numOfStars; i++) {
        createStars();
}

Вот фактическая createStars() :

01
02
03
04
05
06
07
08
09
10
11
12
13
private function createStars():void
{
    var star:Star = new Star(
        Math.random(),
        Calculations.getRandomValue(1, 2),
        Calculations.getRandomValue(2, 5)
    );
             
    addChild(star);
             
    star.x = Calculations.getRandomValue(0, 550);
    star.y = Calculations.getRandomValue(0, 600);
}

При случайной альфе, размере, положении и скорости можно создать псевдо-3D фон.

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

Добавьте прозрачность (альфа-значение) к кружку с кодом ниже:

1
graphics.beginFill(0xCCCCCC, 0.1);

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


Я надеюсь, вам понравился этот урок! Пожалуйста, оставьте свои комментарии.

Далее: Прочтите эту критику, чтобы получить руководство по переходу Flux с простого демо на полноценную игру!