Статьи

Легкое, плавное движение клавиатуры в AS3 с классом ввода

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


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


Это прямое руководство, поэтому настройка также будет прямой.

Создайте новый проект FlashScript 3.0. Размер сцены и цвет не имеют значения, просто используйте то, что вам удобно.

Я использую FlashDevelop для кодирования, но это также можно сделать в любом редакторе AS, например, в Flash Pro (или любом текстовом редакторе, может быть, Notepad;)) Итак, создайте файл Class, убедитесь, что ваш код очень похож на мой; см. ниже. Я назвал мое «Движение». (Если вы используете Flash Pro, ознакомьтесь с этим руководством по созданию класса .)

01
02
03
04
05
06
07
08
09
10
11
package {
    import flash.display.Sprite;
     
    public class Movement extends Sprite {
         
        public function Movement():void {
             
        }
    }
     
}

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


Поэтому после того, как вы связали класс Movement со своим документом, определите переменные, как я сделал ниже

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
package {
    import flash.display.Sprite;
    import flash.events.Event;
     
    public class Movement extends Sprite {
         
        //The object that will move
        private var square:Sprite;
         
        //The maximum speed
        private var _max:Number = 10;
         
        //The variables that are going to be applied to move the square
        private var dx:Number = 0;
        private var dy:Number = 0;
     
        public function Movement():void {
            //Listen for added to stage event
            addEventListener(Event.ADDED_TO_STAGE, init);
        }
         
        private function init(e:Event):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
             
            //Creating a new Sprite and draw inside a square
            square = new Sprite();
            square.graphics.beginFill(0x333333);
            square.graphics.drawRect(0, 0, 30, 30);
            square.x = stage.stageWidth / 2 — square.width / 2;
            square.y = stage.stageHeight / 2 — square.height / 2;
            addChild(square);
        }
    }
     
}

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


Привет, ребята, это класс Input.as; Input.as Класс это парни, о которых я тебе говорил — будь к ним добр! 🙂

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

Примечание. Класс Input.as не принадлежит мне. Он был создан Мэтью Бушем, который портировал Box2D на Flash .

01
02
03
04
05
06
07
08
09
10
11
12
//Example of Input.as Class usage
 
//You have to always initialize it as this with the stage parameter
Input.initialize(stage);
 
//After initializing, you can use kd(), kp() or ku() methods, which
//return a Boolean value if the conditions are met.
//These methods accept multiple arguments,
//so for one event you can use multiple keys.
//This makes it a lot easier to give a boost of accessibility to your app.
//eg See below as I use one call for detecting UP arrow or W for going up.
Input.kd(«UP», «W»);

Итак, теперь, когда вы знакомы с классом Input.as, мы собираемся импортировать его в наш класс Movement и инициализировать его.

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 {
    import flash.display.Sprite;
    import flash.events.Event;
    import Input;
     
    public class Movement extends Sprite {
         
        //The object that will move
        private var square:Sprite;
         
        //The maximum speed
        private var _max:Number = 10;
         
        //The variables that are going to be applied to move the square
        private var dx:Number = 0;
        private var dy:Number = 0;
     
        public function Movement():void {
            //Listen for added to stage event
            addEventListener(Event.ADDED_TO_STAGE, init);
        }
         
        private function init(e:Event):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
             
            //Creating a new Sprite and draw inside a square
            square = new Sprite();
            square.graphics.beginFill(0x333333);
            square.graphics.drawRect(0, 0, 30, 30);
            square.x = stage.stageWidth / 2 — square.width / 2;
            square.y = stage.stageHeight / 2 — square.height / 2;
            addChild(square);
             
            //Initialize the Input.as Class with handler on stage
            Input.initialize(stage);
             
            //Add the refresh loop
            addEventListener(Event.ENTER_FRAME, refresh);
        }
         
        private function refresh(e:Event):void {
             
        }
    }
     
}

Я использую цикл на основе ENTER_FRAME для обнаружения ключевых вводов; ниже приведен метод refresh() который является функцией-обработчиком этого события.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private function refresh(e:Event):void {
    //Key Handler
    if (Input.kd(«A», «LEFT»)) {
        //Move to the left
    }
    if (Input.kd(«D», «RIGHT»)) {
        //Move to the right
    }
     
    if (!Input.kd(«A», «LEFT», «D», «RIGHT»)) {
        //If there is no left/right pressed
    }
     
    if (Input.kd(«W», «UP»)) {
        //Move up
    }
    if (Input.kd(«S», «DOWN»)) {
        //Move down
    }
     
    if (!Input.kd(«W», «UP», «S», «DOWN»)) {
        //If there is no up/down action
    }
}

Это довольно просто. Определите, нажата ли какая-либо из клавиш, и действуйте соответствующим образом.

Я часто использую троичный оператор: value = condition ? true : false; value = condition ? true : false;
Это в основном оператор if, который сжат в одну строку.

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

Ниже вы можете ознакомиться с условиями:

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
private function refresh(e:Event):void {
    //Key Handler
    if (Input.kd(«A», «LEFT»)) {
        //Move to the left
        dx = dx < 0.5 — _max ?
    }
    if (Input.kd(«D», «RIGHT»)) {
        //Move to the right
        dx = dx > _max — 0.5 ?
    }
     
    if (!Input.kd(«A», «LEFT», «D», «RIGHT»)) {
        //If there is no left/right pressed
        if (dx > 0.5) {
            dx = dx < 0.5 ?
        } else {
            dx = dx > -0.5 ?
        }
    }
     
    if (Input.kd(«W», «UP»)) {
        //Move up
        dy = dy < 0.5 — _max ?
    }
    if (Input.kd(«S», «DOWN»)) {
        //Move down
        dy = dy > _max — 0.5 ?
    }
     
    if (!Input.kd(«W», «UP», «S», «DOWN»)) {
        //If there is no up/down action
        if (dy > 0.5) {
            dy = dy < 0.5 ?
        } else {
            dy = dy > -0.5 ?
        }
    }
     
    //After all that, apply these to the object
    square.x += dx;
    square.y += dy;
}

Если вы не знакомы с троичным оператором, возьмите лист бумаги и ручку и запишите несколько из них в формате if … else; Это отличное упражнение, чтобы справиться с происходящим.

Имейте в виду, что я манипулирую переменными dx и dy и в конце устанавливаю только фактические значения x и y. Это помогает нам сделать движение жидкости; это не дергается, поскольку мы изменяем их значения непосредственно во всей функции ..

Давай, проверь это! Видишь, как хорошо он движется?


Ладно. Все правильно, движется плавно — но вне сцены! Ниже я добавил условия обнаружения столкновений.

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
private function refresh(e:Event):void {
    //Key Handler
    if (Input.kd(«A», «LEFT»)) {
        //Move to the left
        dx = dx < 0.5 — _max ?
    }
    if (Input.kd(«D», «RIGHT»)) {
        //Move to the right
        dx = dx > _max — 0.5 ?
    }
     
    if (!Input.kd(«A», «LEFT», «D», «RIGHT»)) {
        //If there is no left/right pressed
        if (dx > 0.5) {
            dx = dx < 0.5 ?
        } else {
            dx = dx > -0.5 ?
        }
    }
     
    if (Input.kd(«W», «UP»)) {
        //Move up
        dy = dy < 0.5 — _max ?
    }
    if (Input.kd(«S», «DOWN»)) {
        //Move down
        dy = dy > _max — 0.5 ?
    }
     
    if (!Input.kd(«W», «UP», «S», «DOWN»)) {
        //If there is no up/down action
        if (dy > 0.5) {
            dy = dy < 0.5 ?
        } else {
            dy = dy > -0.5 ?
        }
    }
     
    //Boundary detection
    if (square.x — dx < 0 || square.x + dx + square.width > stage.stageWidth) {
        //x axis detection
    }
     
    if (square.y — dy < 0 || square.y + dy + square.height > stage.stageHeight) {
        //y axis detection
    }
     
    //After all that, apply these to the object
    square.x += dx;
    square.y += dy;
}

Он ищет границы более точным способом, проверяя, попадают ли края квадрата в границы (до этого он просто проверял центр квадрата относительно границ).

Отлично. Теперь нам нужно добавить код, чтобы заставить квадрат отскочить от границ. Для этого я умножаю на -1 значение оси dx или dy . Но этого недостаточно! Если скорость достаточно высокая, то квадрат пройдет через поля или просто сойдет с ума. Поэтому, прежде чем мы умножим, мы должны установить x или y объекта так же, как и границу, с которой он встречается.

Так что если x object.x = 0; а затем умножьте dx на -1.

01
02
03
04
05
06
07
08
09
10
11
12
//Margin detection
if (square.x — dx < -dx || square.x + dx + square.width > stage.stageWidth) {
    //x axis detection
    square.x = square.x — dx < -dx ?
    dx *= -1;
}
  
if (square.y — dy < -dy || square.y + dy + square.height > stage.stageHeight) {
    //y axis detection
    square.y = square.y — dy < -dy ?
    dy *= -1;
}

Проверьте это сейчас! Бодрая правда? 🙂

Чтобы сделать это еще лучше, продолжайте экспериментировать с различными значениями — например, вместо умножения на -1, попробуйте -0,7 и посмотрите результаты.


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

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

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