Статьи

Разверните танк на задании в зоне изометрической войны

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


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

Переместите мышь, чтобы нацелить башню, и щелкните в любом месте, чтобы танк подъехал к этой точке.

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

Сначала я создал танк в целом. Затем я переключил режим просмотра программы на «параллельную проекцию», расположив камеру под углом 45 ° к резервуару, чтобы создать иллюзию изометрии в игре.

Пожалуйста, не судите меня за ужасную графику, я действительно могу сделать намного лучше, но это только для объяснения 🙂

Затем я спрятал турель, оставив видимым только корпус танка, и повернул корпус на 45 ° восемь раз, представляя каждую позицию отдельно. Таким образом, я достиг 8 различных видов тела. Я сделал то же самое с башней, пока танк был спрятан. Я сохранил все 16 фото в формате PNG 24 с альфа-каналом. Вы можете увидеть окончательный результат ниже. (На самом деле этого недостаточно для такого движения, было бы лучше иметь вдвое больше просмотров танка, но этого достаточно для целей данного урока.)

,

Конечно, вам не обязательно использовать Google SketchUp, вы можете использовать 3ds Max или Maya или что угодно, вы также можете использовать мою графику на практике, если вы не хотите или не можете создавать свою собственную графику.

Теперь откройте Flash (я использую Adobe Flash CS4) и выберите «Создать новый Flash-файл» (Actionscript 3.0). Нам понадобится только сделать MovieClip танка и подключить к нему класс Game позже.

,

Щелкните правой кнопкой мыши по сцене и перейдите к пункту «Свойства документа». Сделайте это 600 x 400 (или как хотите) и 21 кадр в секунду (эта частота кадров кажется мне оптимальной, поэтому я почти всегда использую ее. Хотя это не имеет значения).

Нажмите ОК. Перейдите в File> Save as и сохраните этот файл как tank.fla в какой-то папке на вашем компьютере (я рекомендую вам создать папку Tank и поместить файл внутрь).

Теперь перейдите в File> Import> Import to library . Найдите папку, в которой вы сохранили свои восемь изображений танков, выберите их все и импортируйте в библиотеку.

,

Создайте новый пустой символ, нажав на этот маленький значок в библиотеке:

Выберите тип MovieClip и назовите символ «танк». Поместите точку регистрации в центр (точка регистрации — это крошечный черный квадрат в сетке белых квадратов для тех, кто не знает).

После того, как символ создан, он появляется в библиотеке (его имя «tank» — это просто косметическое имя, которое используется исключительно в библиотеке, поэтому не имеет значения, как вы его называете). Откройте его, дважды щелкнув его значок. Затем возьмите 1.png из библиотеки и перетащите его на сцену символа. Совместите изображение с точкой регистрации символа, как на этом скриншоте:

Вы хотите, чтобы точка регистрации находилась в центре круга поворота танка.

Перейти на временную шкалу символа. Переименуйте «Слой 1» в «Танк». Изображение тела вашего танка (1.png) должно быть в первом кадре этого слоя. Щелкните второй кадр и, не отпуская кнопку мыши, перетащите курсор на восьмой кадр, выбирая кадры со 2 по 8. Затем щелкните правой кнопкой мыши эту выбранную область и выберите «Преобразовать в пустые ключевые кадры».

Когда 7 пустых ключевых кадров созданы, выберите второй кадр и перетащите 2.png к нему, выровняв изображение с точкой регистрации (так же, как вы сделали с 1.png); воображая, что точка регистрации — это ось, по которой танк будет вращаться при повороте. Сделайте то же самое с остальными кадрами. Вам не нужно выравнивать его очень точно, но чем точнее вы выровняете его, тем лучше будет выглядеть движение, когда танк пытается следовать за курсором по ходу игры.

После того, как вы перетащили каждое изображение на сцену символа и выровняли их, выберите первый кадр и нажмите F9, чтобы открыть панель действий. Введите единственный метод «stop ();» в нем и закройте панель. Это важный шаг, потому что мы не хотим, чтобы наш танк автоматически начал вращаться, как только он будет добавлен на сцену.

Перейдите в библиотеку и создайте новый символ MovieClip. Назовите это турель . Дважды щелкните значок символа и сделайте то же самое, что вы сделали с танковым MovieClip (шаги 4–8) к башне, но используя изображения башни. Выровняйте его по точке регистрации таким образом, в точке, вокруг которой турель естественно повернет:

Обратите внимание, что я назвал изображения башен следующим образом: 1-.png, 2-.png и т. Д., Чтобы они не заменяли изображения танка при импорте в библиотеку. Вы можете использовать папки для размещения ваших изображений. В этом случае ваши изображения башни и танка могут иметь одинаковые имена.

После того, как мы закончили с символом башни, снова откройте символ танка, создайте новый слой над слоем «Танк» и перетащите фрагмент ролика из библиотеки на этот слой. Совместите башню с корпусом резервуара. Результат должен выглядеть так:

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

… затем перейдите в свойства и дайте ему имя экземпляра mTurret (для башни MovieClip):

Нажмите на ссылку «Сцена 1», чтобы выйти из режима редактирования символов.

Щелкните правой кнопкой мыши символ резервуара в библиотеке, выберите «Свойства» (или «Связывание», если вы используете Flash CS3) в раскрывающемся меню (убедитесь, что вы находитесь в расширенном режиме), выберите «Экспорт для Actionscript» и для класса Имя типа в «Танк» (с большой буквы). Этот шаг позволит нам в будущем подключить наш Tank MovieClip к экземплярам, ​​созданным с использованием нашего класса Tank.

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

В инструменте Flash Authoring перейдите в « Файл»> «Создать» и создайте новый файл ActionScript.

Перейдите в папку, в которой вы сохранили файл tank.fla, и создайте новую папку с именем «main» внутри. Сохраните файл ActionScript в этой папке как TankMaker.as . Поэтому местоположение этого файла должно быть: tank / main / TankMaker.as

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

1
2
3
4
5
6
package main {
 
    import flash.display.*;
    import flash.events.*;
 
}

Слово «основной» здесь означает расположение этого файла относительно нашего tank.fla.

Нам понадобятся классы «display» для отображения наших активов на экране и «events» для отслеживания событий мыши.

Теперь нам нужно объявить открытый класс TankMaker (в соответствии с именем файла Actionscript) и необходимые переменные:

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
package main {
     
    import flash.display.*;
    import flash.events.*;
 
    public class TankMaker extends Sprite {
         
        // the instance of our Tank class (which we exported for actionscript before)
        private var tank:Tank;
 
        // the vars to keep the coordinates of the point where we want our tank to move
        private var moveTankToX:Number;
        private var moveTankToY:Number;
 
        // coordinates of the point at which the tank aims its turret
        private var turnTurretToX:Number;
        private var turnTurretToY:Number;
 
        // current position of the tank
        private var currentTankPositionX:Number;
        private var currentTankPositionY:Number;
         
        private var tankSpeed:Number = 2;
 
        // the point at which the tank moves after a mouse click
        private var clickPoint:Object;
         
        // the angle of tank and turret rotation in radians
        private var Atan2:Number;
        private var turretAtan2:Number;
    }
}

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

Непосредственно под последней переменной создайте публичную функцию и назовите ее TankMaker. Это будет конструктор класса. Затем добавьте в него прослушиватель событий для Event.ADDED_TO_STAGE, чтобы мы могли создать наш объект-танк только после этапа. Затем передайте это событие методу addStage.

1
2
3
4
5
public function TankMaker() {
     
    addEventListener(Event.ADDED_TO_STAGE, addStage);
 
}

После того, как этап создан и событие ADDED_TO_STAGE вызвало метод addStage (), самое время создать экземпляр танка.

Объявите приватную функцию и назовите ее addStage. Тип данных функции будет: Событие. И возвращаемый тип будет «void», потому что мы не собираемся ничего возвращать из него.

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
private function addStage (e:Event):void {
     
    //create a new tank instance of the movie clip
    // which you had exported for actionscript
    tank = new Tank();
     
    // now a little trick, I scaled my tank down
    // to the size of about one fourth of its original size
    // so that is wasn’t so huge
    tank.scaleX = 0.25;
    tank.scaleY = 0.25;
     
    // set the initial position of the tank right
    // in the center of the stage
    tank.x = stage.stageWidth / 2;
    tank.y = stage.stageHeight / 2;
    // and add it to the display list
    addChild(tank);
     
    // now add event listeners for mouse down and mouse move
    // events to the stage
    stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownListener);
    stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveListener);
     
}

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

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
private function mouseMoveListener(e:MouseEvent):void {
     
    // create a variable to keep the relative angle
    // between mouse’s current position in degrees
    // and the tank’s current position
    var angle:Number;
 
    // the next 2 variables are gonna be
    // equal to the the mouse’s current position
    turnTurretToX = e.stageX;
    turnTurretToY = e.stageY;
     
    // calculate the relative angle in radians
    // between the mouse’s curent position
    // and the tank’s current position
     
    turretAtan2 = Math.atan2(turnTurretToY — currentTankPositionY, turnTurretToX — currentTankPositionX);
 
 
    // calculate the same angle in degrees.
    // to get degrees out of radians we have to
    // multiply radians by 180 and divide the result by PI
    // But here are some specifics of Flash
    // it calculates the angle not from 0 thru 360
    // but from 0 thru 180 and from — 180 thru 0
     
    // so let’s add some conditional to get rid of this problem
    if (Math.round(turretAtan2 * 180 / Math.PI) < 0) {
        // if angle is between 0 and -180 add 360 to it
        angle = Math.round(turretAtan2 * 180 / Math.PI) + 360;
    } else {
        // if not, calculate it as usual
        angle = Math.round(turretAtan2 * 180 / Math.PI);
    }
     
 
    // having our angle value stored in a variable
    // let’s rotate our turret towards the mouse pointer
     
    // I’ve done a lot of calculations trying to
    // figure it all out, so you may try to undestand my logic
     
    // I’m just picking the right frame of the turret MC depending
    // on the angle of the mouse from the turret
     
    if (angle > 240 && angle < 300) {
        // go inside the tank MovieClip then inside mTurret
        // go to the frame 1 and stop
        tank.mTurret.gotoAndStop(1);
    }
    if (angle > 300 && angle < 340) {
        tank.mTurret.gotoAndStop(2);
    }
    if ((angle >= 0 && angle < 20) || (angle > 340 && angle <= 360)) {
        tank.mTurret.gotoAndStop(3);
    }
    if (angle > 20 && angle < 60) {
        tank.mTurret.gotoAndStop(4);
    }
    if (angle > 60 && angle < 120) {
        tank.mTurret.gotoAndStop(5);
    }
    if (angle > 120 && angle < 160) {
        tank.mTurret.gotoAndStop(6);
    }
    if (angle > 160 && angle < 200) {
        tank.mTurret.gotoAndStop(7);;
    }
    if (angle > 200 && angle < 240) {
        tank.mTurret.gotoAndStop(8);
    } // end
     
}

Ниже конца нашей функции mouseMoveListener () создайте закрытую функцию mouseDownListener () с типом данных MouseEvent и передайте ее методу moveTankOnEnterFrame:

01
02
03
04
05
06
07
08
09
10
private function mouseDownListener(e:MouseEvent):void {
     
    // when click occurs assign the next variable
    // the coordinates of the mouse pointer’s current position
    moveTankToX = e.stageX;
    moveTankToY = e.stageY;
    // and add event listener to move the tank frame by frame
    addEventListener(Event.ENTER_FRAME, moveTankOnEnterFrame);
     
}

Создайте новую частную функцию с именем moveTankOnEnterFrame () и внутри нее вызовите метод moveToCoordinates () с 3 параметрами:

1
2
3
private function moveTankOnEnterFrame(e:Event) {
    moveToCoordinates(tank, moveTankToX, moveTankToY);
}

Это, в конце концов, заставит танк двигаться к точке щелчка, в каждом кадре.

Теперь мы вызвали метод moveToCoordinates (), но мы еще не создали его. Давайте сделаем это сейчас.

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

1
private function moveToCoordinates(tank_mc:Tank, tX:Number, tY:Number) { // create a variable to keep the relative angle // between mouse’s current position in degrees // and the tank’s current position // this variable exists only inside this function so // you we can use the same name as we used before var angle:Number;

Зачем использовать расстояние 15? Ну, я обнаружил, что он никогда не выходит за пределы 15, просто проследив его так:

1
trace(Math.abs(tank_mc.x — clickPoint.x));

… вы можете сделать то же самое, если хотите;)

Поскольку наш класс готов, давайте посмотрим на него в целом:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package main {
     
    import flash.display.*;
    import flash.events.*;
 
    public class TankMaker extends Sprite {
 
        private var tank:Tank;
 
        private var moveTankToX:Number;
        private var moveTankToY:Number;
 
        private var turnTurretToX:Number;
        private var turnTurretToY:Number;
        private var currentTankPositionX:Number;
        private var currentTankPositionY:Number;
         
        private var tankSpeed:Number = 2;
 
        private var clickPoint:Object;
         
        private var Atan2:Number;
        private var turretAtan2:Number;
 
        public function TankMaker() {
             
            addEventListener(Event.ADDED_TO_STAGE, addStage);
 
        }
         
        private function addStage (e:Event):void {
             
            tank = new Tank();
            tank.scaleX = 0.25;
            tank.scaleY = 0.25;
            tank.x = stage.stageWidth / 2;
            tank.y = stage.stageHeight / 2;
            addChild(tank);
             
            stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownListener);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveListener);
             
        }
 
        private function mouseMoveListener(e:MouseEvent):void {
             
            var angle:Number;
 
            turnTurretToX = e.stageX;
            turnTurretToY = e.stageY;
             
            turretAtan2 = Math.atan2(turnTurretToY — currentTankPositionY, turnTurretToX — currentTankPositionX);
 
             
            if (Math.round(turretAtan2 * 180 / Math.PI) < 0) {
                angle = Math.round(turretAtan2 * 180 / Math.PI) + 360;
            } else {
                angle = Math.round(turretAtan2 * 180 / Math.PI);
            }
 
             
            if (angle > 240 && angle < 300) {
                tank.mTurret.gotoAndStop(1);
            }
            if (angle > 300 && angle < 340) {
                tank.mTurret.gotoAndStop(2);
            }
            if ((angle >= 0 && angle < 20) || (angle > 340 && angle <= 360)) {
                tank.mTurret.gotoAndStop(3);
            }
            if (angle > 20 && angle < 60) {
                tank.mTurret.gotoAndStop(4);
            }
            if (angle > 60 && angle < 120) {
                tank.mTurret.gotoAndStop(5);
            }
            if (angle > 120 && angle < 160) {
                tank.mTurret.gotoAndStop(6);
            }
            if (angle > 160 && angle < 200) {
                tank.mTurret.gotoAndStop(7);;
            }
            if (angle > 200 && angle < 240) {
                tank.mTurret.gotoAndStop(8);
            }
             
        }
         
         
        private function mouseDownListener(e:MouseEvent):void {
             
            moveTankToX = e.stageX;
            moveTankToY = e.stageY;
            addEventListener(Event.ENTER_FRAME,moveTankOnEnterFrame);
             
        }
         
        private function moveTankOnEnterFrame(e:Event) {
             
            moveToCoordinates(tank, moveTankToX, moveTankToY);
        }
 
        private function moveToCoordinates(tank_mc:Tank, tX:Number, tY:Number) {
             
            var angle:Number;
         
            if (Math.round(Atan2 * 180 / Math.PI) < 0) {
                angle = Math.round(Atan2 * 180 / Math.PI) + 360;
            } else {
                angle = Math.round(Atan2 * 180 / Math.PI);
            }
 
            if (angle > 240 && angle < 300) {
                tank.gotoAndStop(1);
            }
            if (angle > 300 && angle < 340) {
                tank.gotoAndStop(2);
            }
            if ((angle >= 0 && angle < 20) || (angle > 340 && angle <= 360)) {
                tank.gotoAndStop(3);
            }
            if (angle > 20 && angle < 60) {
                tank.gotoAndStop(4);
            }
            if (angle > 60 && angle < 120) {
                tank.gotoAndStop(5);
            }
            if (angle > 120 && angle < 160) {
                tank.gotoAndStop(6);
            }
            if (angle > 160 && angle < 200) {
                tank.gotoAndStop(7);
            }
            if (angle > 200 && angle < 240) {
                tank.gotoAndStop(8);
            }
 
            clickPoint = {x:moveTankToX, y:moveTankToY};
            Atan2 = Math.atan2(clickPoint.y — tank_mc.y, clickPoint.x — tank_mc.x);
 
            tank_mc.x += Math.cos(Atan2) * tankSpeed;
            tank_mc.y += Math.sin(Atan2) * tankSpeed;
             
            currentTankPositionX = tank_mc.x;
            currentTankPositionY = tank_mc.y;
             
            if (Math.abs(tank_mc.x — clickPoint.x) < 15 && Math.abs(tank_mc.y — clickPoint.y) < 15) {
 
                removeEventListener(Event.ENTER_FRAME,moveTankOnEnterFrame);
            }
        }
    }
}

Перейдите в File> New и создайте новый файл ActionScript. Сохраните его как «Game.as» в той же папке, что и файл tank.fla. Это будет наш класс документов .

Вот код для класса Game.as:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
package {
     
    import flash.display.*;
    // import the contents of our main folder
    import main.*;
     
    public class Game extends MovieClip {
         
        private var newTank:TankMaker;
         
        public function Game () {
             
            // create a new instance of our tank maker class
            newTank = new TankMaker();
            // and add it to the stage of course
            addChild(newTank);
        }
    }
}

Сохраните файл. Все, что он делает, это создает танк и добавляет его на основную сцену, готовую к контролю.

Откройте tank.fla и перейдите на панель свойств. Для класса введите «Игра» и сохраните файл.

Ага! Вот и мы. Теперь вы можете нажать CTRL + ENTER на ПК (CMD + RETURN на Mac) и протестировать игру.

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