Что такое изометрия, простым, человеческим языком, — это псевдо трехмерная проекция, при которой все объекты повернуты к нам под углом в 45 градусов, так, что мы видим три стороны фигуры. При этом масштаб фигур не изменяется в зависимости от их удаленности. Доступных к общему пользованию изометрических движков на AS3 на самом деле не так уж и много, можно пересчитать на пальцах и двух рук хватит. Расскажу про один из них — as3Isolib.
Библиотека с открытым исходным кодом. Легко допиливается под свои нужды. Глюков особо замечено не было. Скоростью, правда, не хвастается, но и жутко не тормозит. В либе присутствует только базовый функционал по отображению и сортировке, все прочие навороты придется допиливать самому. Из недостатков могу подметить, что последнее обновление на Google Code было в 2010 году. Скачать саму либу можно здесь.
Итак как ее использовать. Весь «изометрический мир» представляет собой одну (для простых проектов) или несколько изометрических сцен IsoScene, которые отображаются через вьюпорт IsoView. Создадим простейшую изометрическую сцену.
|
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 |
package { import as3isolib.display.IsoView; import as3isolib.display.scene.IsoGrid; import as3isolib.display.scene.IsoScene; import flash.display.Sprite; import flash.events.Event; public class Main extends Sprite { 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 view:IsoView = new IsoView(); // Задаем ему размеры равные нашей флешке view.setSize(stage.stageWidth, stage.stageHeight); // Добавляем его на сцену addChild(view); // Создаем изометрическую сцену var scene:IsoScene = new IsoScene(); // Добавляем сцену во вьюпорт view.addScene(scene); // Для наглядности добавим на сцену сетку scene.addChild(new IsoGrid()); // Рендерим сцену scene.render(); } } } |
Собственно сетку IsoGrid можно было и не добавлять, но тогда бы мы увидели просто пустой экран, что было бы не очень наглядно.
В библиотеке присутствуют стандартные примитивы например IsoBox, которые больше подходят для тестирования и отладки, чем для практического использования, но для примера вполне подойдут. Кроме того имеется IsoSprite, это уже более полезный объект, сам он не имеет внешнего представления и является контейнером для DisplayObject-ов. Проще говоря помещаем DisplayObject или набор нескольких в IsoSprite и они становятся частью «изометрического мира». Добавим на сцену примитив IsoBox, IsoHexBox и IsoSprite.
|
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 |
package { import as3isolib.display.IsoSprite; import as3isolib.display.IsoView; import as3isolib.display.primitive.IsoBox; import as3isolib.display.primitive.IsoHexBox; import as3isolib.display.scene.IsoScene; import as3isolib.graphics.SolidColorFill; import flash.display.Sprite; import flash.events.Event; public class Main extends Sprite { 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 view:IsoView = new IsoView(); // Задаем ему размеры равные нашей флешке view.setSize(stage.stageWidth, stage.stageHeight); // Добавляем его на сцену addChild(view); // Создаем изометрическую сцену var scene:IsoScene = new IsoScene(); // Добавляем сцену во вьюпорт view.addScene(scene); // Создаем примитив IsoBox var box:IsoBox = new IsoBox(); // Устанавливаем ему размер (ширина, длина, высота) box.setSize(50, 50, 50); // Добавляем его на сцену scene.addChild(box); // Создаем примитив IsoHexBox var hexBox:IsoHexBox = new IsoHexBox(); // Задаем ему размер hexBox.setSize(50, 50, 40); // Перемещаем его (x, y, z) hexBox.moveTo( -50, 0, 0); // Зальем его красным цветом, чтоб не сливался с коробкой hexBox.fill = new SolidColorFill(0xFF0000, 1); // Добавляем на сцену scene.addChild(hexBox); // Создаем контейнер IsoSprite var sprite:IsoSprite = new IsoSprite(); // Добавлем в него спрайты (массив DisplayObject'ов) sprite.sprites = [new Tree()]; // Задаем размеры контейнера sprite.setSize(50, 50, 50); // Перемещаем его sprite.moveTo(60, 25, 0); // И добавляем на сцену scene.addChild(sprite); // Рендерим сцену scene.render(); } } } |
О чем здесь следует сказать. Устанавливать размеры объекта (setSize(width, length, height) нужно обязательно. Иначе он не будет принимать участия в сортировке. Это не размер DisplayObject‘a, а размер объекта в изометрическом мире.
Перемещать объекты по изометрической сцене не сложнее, чем по обычной, у всех изометрических объектов имеются методы moveTo(x, y, z) и moveBy(x, y, z). Первый перемещает объект в указанные координаты. Второй смещает объект на указанное количество пикселей относительно текущей позиции. Координаты конечно нужно указывать в изометрической проекции, а не в экранной. Самим ничего естественно пересчитывать не придется, для этого в библиотеке есть класс IsoMath с соответствующими статическими методами isoToScreen() и screenToIso(). Кроме того у объекта IsoView есть удобные методы для перевода координат isoToLocal(), localToIso().
Напишем код, который будет перемещать объект IsoBox в координаты клика.
|
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 |
package { import as3isolib.display.IsoSprite; import as3isolib.display.IsoView; import as3isolib.display.primitive.IsoBox; import as3isolib.display.primitive.IsoHexBox; import as3isolib.display.scene.IsoGrid; import as3isolib.display.scene.IsoScene; import as3isolib.geom.Pt; import as3isolib.graphics.SolidColorFill; import eDpLib.events.ProxyEvent; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; public class Main extends Sprite { private const GRIDSIDE:int = 25; private const GRIDSIZE:int = 10; private var _view:IsoView; private var _scene:IsoScene; private var _box:IsoBox; private var _hexBox:IsoHexBox; public function Main():void { // Создаем вьюпорт _view = new IsoView(); // Создаем изометрическую сцену _scene = new IsoScene(); // Создаем примитив IsoBox _box = new IsoBox(); // Создаем примитив IsoHexBox _hexBox = new IsoHexBox(); if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); // Задаем вью размеры равные нашей флешке _view.setSize(stage.stageWidth, stage.stageHeight); // Добавляем его на сцену addChild(_view); // Добавляем сцену во вьюпорт _view.addScene(_scene); // Устанавливаем примитиву IsoBox размер (ширина, длина, высота) _box.setSize(GRIDSIDE, GRIDSIDE, GRIDSIDE); // Добавляем его на сцену _scene.addChild(_box); // Задаем примитиву IsoHexBox размер _hexBox.setSize(GRIDSIDE, GRIDSIDE, GRIDSIDE); // Перемещаем его (x, y, z) _hexBox.moveTo(GRIDSIDE*2, 0, 0); // Зальем его красным цветом, чтоб не сливался с коробкой _hexBox.fill = new SolidColorFill(0xFF0000, 1); // Добавляем на сцену _scene.addChild(_hexBox); // Создаем сетку var grid:IsoGrid = new IsoGrid(); // устанавливаем ей размер grid.setGridSize(GRIDSIZE, GRIDSIZE, 0); // сдвигаем на 100 пикселей для удобства grid.moveTo( -100, -100, 0 ); // добавляем ее на сцену _scene.addChild(grid); // Рендерим сцену _scene.render(); // вешаем слушатель клика на сцену _scene.addEventListener(MouseEvent.CLICK, handlerClick); } private function handlerClick(e:ProxyEvent):void //ловим клики { // Преобразуем координаты клика из экранных в изометрические var pt:Pt = _view.localToIso(new Pt(stage.mouseX, stage.mouseY)); // Округляем точку x по клетке pt.x = Math.round(pt.x / GRIDSIDE) * GRIDSIDE; // Округляем точку y pt.y = Math.round(pt.y / GRIDSIDE) * GRIDSIDE; // Перемещаем примитив Box в новые координаты _box.moveTo(pt.x, pt.y, pt.z); // рендерим сцену _scene.render(); } } } |
Как можно увидеть я беру не точные координаты клика, а округленные до ближайшего кратного GRIDSIDE (25), т.е. до ширины / длины ячейки. Хитрости никакой здесь нет, это делается чтобы объекты не пересекались, просто некрасиво.
Ну вот впрочем и все, остальное дело техники, переписывать сюда документацию особого смысла не вижу. Вводный экскурс по использованию библиотеки я вам дал, те кто заинтересуется может продолжить изучение либы в доках и ее исходниках.
И примерчик самого простенького редактора изометрической карты: