Всем привет!
Во многих играх нам необходимо, чтобы какой-либо игровой объект поворачивался в сторону нашего курсора.
Давайте сделаем что-нибудь такое, чтобы это тоже было в нашей копилке наработок)
Что будем делать?
Я решил сделать 2 вида объекта для примера.
1-й объект — это лук со стрелой, будет с ограниченным поворотом по углам, поворачиваться будет моментально за мышкой.
2-й объект — это башня танка, у неё нет ограничений по углам поворота и она будет поворачиваться с определённой скоростью.
В результате мы хотим получить вот такую картину:
Графика
Графику мы будем использовать по такому же принципу как описано в статье Рисуем в IDE, а кодим в FD. Я заранее подготовил графику в виде 4-х png файлов:
Далее импортировал эти файлы в библиотеку созданного .fla файла. Лук и стрелу объединил в один клип, а корпус танка и башню в разные, т.к. башня будет поворачиваться отдельно от корпуса.
Все объекты в графике изначально повёрнуты вправо, т.к. это совпадает с углом флеш-объекта = 0 градусов.
Пушка танка на png повёрнута вниз, поэтому я повернул её вправа уже в самом клипе пушки.
Далее я объединяю клипы лука, корпуса танка и пушки в 1 клип (mcScene), располагаю их там как хотел бы видеть их в игре и даю имена клипам лука (bow) и пушки (tower), чтобы потом легко определить их в коде.
Паблишим библиотеку в swc и всё, на этом с графикой закончили.
Код
Создаём новый проект в FD, подключаем библиотеку swc и кодим.
Приведу результат трудов в виде листинга кода главного класса:
1 2 3 4 5 6 7 8 9 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 91 92 93 94 95 96 97 98 99 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 |
package { import flash.display.MovieClip; import flash.display.Sprite; import flash.events.Event; import flash.geom.Point; import monax.MyMath; /** * Пример поворота объектов за курсором мыши. Специально для cyber-code.ru * @author Monax */ [Frame(factoryClass="Preloader")] public class Main extends Sprite { private var _bow: MovieClip; private var _tower: MovieClip; // текущее положение мыши на нужном объекте. // пример: если нужно чтобы танк поворачивал дуло туда, куда указывает мышь, то этот объект - это земля, на которой находится танк // в нашем случае - это родительский объект - этот класс private var _mousePosX: Number; private var _mousePosY: Number; // параметры поворота лука private var _bowMaxAn: Number = 60; // максимальный угол поворота = 60 градусов private var _bowMinAn: Number = -90; // минимальный угол поворота = -90 градусов // параметры поворота башни private const TOWER_TURN_SPD: Number = 45; // скорость поворота башни, (градус / сек) 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); // создаём сцену var scene: MovieClip = new Scene_mc(); scene.x = stage.stageWidth / 2; scene.y = stage.stageHeight / 2; addChild(scene); // записываем клипы лука и башни танка _bow = scene.getChildByName("bow") as MovieClip; _tower = scene.getChildByName("tower") as MovieClip; addEventListener(Event.ENTER_FRAME, onEnterFrame); } private function turnTankTower(aDT: Number):void { /** * можно было бы просто ориентироваться по координатам текущей сцены, * НО это было бы справедливо только для той игровой области, которая не смещалась (например по причине двигающейся камеры в игре) * поэтому я сделаю расчёт на это сразу. т.е. алгоритм будет универсальным и более общим, а не частным. * * Мы переведём сначала все координаты в глобальные, там найдём угол поворота и будем к нему стремиться - вертеть пушку */ // получаем глобальные координаты мыши (это координаты относительно левого верхнего угла плеера, независимо от смещений родительских спрайтов) var mousePos: Point = localToGlobal(new Point(_mousePosX, _mousePosY)); // глобальные координаты центра пушки var towerPos: Point = _tower.localToGlobal(new Point()); // новый угол поворота пушки // силами своей функции нахождения угла между двумя точками, вершина угла в (0;0) var nRot: Number = MyMath.getAngle2Deg(1, 0, mousePos.x - towerPos.x, mousePos.y - towerPos.y); // обрезаем угол согласно максимальному(180) и минимальному(-180) углам флеш-объектов while (nRot > 180) nRot -= 360; while (nRot < -180) nRot += 360; // текущий угол поворота пушки var tRot: Number = _tower.rotation; // рассчитываем направление поворота пушки, выбирая минимальный угол поворота, тем самым кротчайшую дугу var towerTurnDir: int = nRot - tRot <= 180 ? 1 : -1; if (nRot - tRot < 0) towerTurnDir = -1; if (nRot - tRot < -180) towerTurnDir = 1; // дельта-поворот за данный тик времени var dtTowerTurn: Number = towerTurnDir * TOWER_TURN_SPD * aDT; // поворачиваем if (_tower.rotation != nRot) { // меры для того, чтобы пушка не дёргалась, когда достигнет нужного угла взгляда var rotAbs: Number = Math.abs(nRot - _tower.rotation); var dtAbs: Number = Math.abs(dtTowerTurn); // смягчения при достижении целевого угла if (rotAbs <= dtAbs / 2) { dtTowerTurn = nRot - _tower.rotation; } else if (rotAbs <= dtAbs) { dtTowerTurn *= 0.5; } _tower.rotation += dtTowerTurn; } } private function turnBow():void { // получаем глобальные координаты мыши (это координаты относительно левого верхнего угла плеера, независимо от смещений родительских спрайтов) var mousePos: Point = localToGlobal(new Point(_mousePosX, _mousePosY)); // глобальные координаты центра пушки var bowPos: Point = _bow.localToGlobal(new Point()); // новый угол поворота пушки // силами своей функции нахождения угла между двумя точками, вершина угла в (0;0) var nRot: Number = MyMath.getAngle2Deg(1, 0, mousePos.x - bowPos.x, mousePos.y - bowPos.y); // применяем ограничения if (nRot < _bowMinAn) nRot = _bowMinAn; if (nRot > _bowMaxAn) nRot = _bowMaxAn; _bow.rotation = nRot; } private function onEnterFrame(e:Event):void { update(1 / stage.frameRate); } private function update(aDT:Number):void { // записываем координаты, куда башне надо смотреть - это координаты мышки на земле // земля - это родитель танка, в нашем случае родитель - это текущий класс. _mousePosX = mouseX; _mousePosY = mouseY; turnTankTower(aDT); turnBow(); } } } |
Всё уместилось в 1 файле и + 1 функция (MyMath.getAngle2Deg()) из моих личных запасов, которая находит угол между двумя точками с вершиной в координатах (0;0).
Я хорошо прокомментировал код, поэтому непоняток должно быть минимум.
Вся соль заключается в формулах и алгоритмах расчёта правильного угла поворота.
Материалы
Архив с исходниками: rotateToMouse.rar