In this article, I will show you how to make a rotatable IsoGroup
in As3Isolib. Well, I don’t actually rotate the group but instead, I reposition the group’s children so that the group appears to be rotated. 🙂
If you’re new to As3Isolib, you can learn a bit about the basics here. If you know the library already, you might want to skip step 1.
Basic steps:
- Subclass the
IsoGroup
- Map the group’s children’s positions to a 2d array
- Add rotation logic
- Rotate the array
- Use the array to reposition the children
- Render
What I need:
- as3ds Array2 class
- an algorithm to rotate a 2d rectangular array. Just google it. It’s everywhere 🙂
Step 1 – Set up my world
I’m going to make a world ( IsoView
) that contains 2 scenes. One at the bottom to contain an instance of IsoGrid
and on top of that, another scene to contain isometric objects. So I’ll start a document class with just a few methods as follows:
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 { private var _world:IsoView; private var _grid:IsoGrid; private var _groupScene:IsoScene; 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); createWorld(); } private function createWorld():void { _world = new IsoView(); _world.setSize(400, 400); addChild(_world); ///////// GRID _grid = new IsoGrid(); _grid.setGridSize(10, 10); _grid.cellSize = 20; var gridScene:IsoScene = new IsoScene(); gridScene.addChild(_grid); _world.addScene(gridScene); ///////// GROUP SCENE _groupScene = new IsoScene(); _world.addScene(_groupScene); _world.addEventListener(Event.ENTER_FRAME, render); } private function render(e:Event):void { _world.render(true); } } }

Empty World
IsoView
.
Line 38 – 45: Creates an IsoGrid
and an IsoScene
to contain it. And then adds the scene to the IsoView
.
Line 48 – 49: Creates a scene to contain the IsoGroup
and adds it to the IsoView
.
The last line sets ENTER_FRAME
listener to render the world.
If I compile the class now, I’ll get something like the picture on the left.
Step 2 – Write a custom IsoGroup
Now I’m going to extend IsoGroup and add some cool stuff. First, some basic stuff just to set things up.
package { import as3isolib.display.IsoGroup; import as3isolib.display.scene.IsoGrid; public class Group extends IsoGroup { protected var _grid:IsoGrid; public function Group(grid:IsoGrid, descriptor:Object = null) { super(descriptor); _grid = grid; } } }
Then I add a method through which I can send a 2d array to the Group
and let it build a bunch of IsoBox
.
public function setMap(map:Array):void { if (children.length > 0) { removeAllChildren(); } //make NxN array that represents the group's layout //this is the array we'll rotate var w:Number = Math.max(map[0].length, map.length); _layout = new Array2(w,w); _layout.fill(0); for (var row:int = 0; row < map.length; row++) { var r:Array = map[row]; for (var col:int = 0; col < r.length; col++) { if (map[row][col] != 0) { var box:IsoBox = new IsoBox(); box.fills = [new SolidColorFill(0x00FFFF, 1), new SolidColorFill(0x8080C0, 1), new SolidColorFill(0xFF8040, 1)]; box.setSize(_grid.cellSize, _grid.cellSize, 40); box.moveTo(_grid.cellSize * col, _grid.cellSize * row, 0); box.name = map[row][col]; addChild(box); _layout.set(col, row, box); } } } }
Line 4 - 7: Removes all previous children in the group if there's any.
Line 11 - 13: make a square Array2
based on the number of columns or rows in the passed array -- whichever the largest to make sure that when I move its elements, they will not fall out of bounds. I use the array as a reference to the positions of the group's children (IsoBox
) and I call it _layout
.
Line 15 - 33: Loop through the Array2
and create IsoBox
instances. Note that I'll use 0
in the array to mark places that I want to be empty. So in the loop, I check if an element is a 0
or not. If it is not a 0
, I create an IsoBox
there. And store a reference to it in the _layout
array.
Back to the Main
class. I add a new method to create my group and I also define the group's map.
private var _map:Array = [ [0, 'A', 'B', 'C'], ['D', 'E', 'F', 'G'] ]; private function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); createWorld(); createGroup(); } private function createGroup():void { _group = new Group(_grid); _group.setMap(_map); _group.moveTo(60, 60, 0); _groupScene.addChild(_group); }
So far I get this when I compile the codes :

Basic Group
Pretty, eh? 🙂
Step 3 - Make the group rotatable
Now that I have the basic group in place it's time to make it rotatable. So I add a new method rotate()
that takes a boolean flag to indicates if the rotation is clockwise (true
) or counter-clockwise (false
).
public function rotate(clockWise:Boolean = true):void { //make a new NxN array for the new layout ( after rotation ) var w:Number =_layout.width; var newLayout:Array2 = new Array2(w, w); newLayout.fill(0); for (var r:int = 0; r < w; r++) { for (var c:int = 0; c < w; c++) { //found this array-rotation algo somewhere on the web var c0:int = (clockWise == true) ? w - 1 - r : r; var r0:int = (clockWise == true) ? c : w - 1 - c; newLayout.set(c0, r0, _layout.get(c, r)); } } _layout = newLayout; updateChildren(); } protected function updateChildren():void { for (var r:int = 0; r < _layout.height; r++) { for (var c:int = 0; c < _layout.width; c++) { if (_layout.get(c, r) is IsoBox) { _layout.get(c, r).moveTo(c * _grid.cellSize, r * _grid.cellSize, 0); } } } }
Line 5 - 7: Makes an empty array for the new layout
Line 13 -14: Using the algorithm, I figure out where each box should end up
Line 15: Set the box to a corresponding position in the new layout
Line 21: replace the old layout with the new one
Line 26 - 39: move the boxes to their new positions using the new layout as a reference
Back to the Main class again, I add some buttons to set the group's rotation and I have something like this (click the black buttons):
So that's basically all the steps to make a rotatable IsoGroup. Pretty simple, right?
Extra - A group that can be rotated over a pivot
As an extra, here's a Group
subclass that allows you to rotate it around a selected box (pivot). What different in this new class from the Group
is the way it handles the rotation. Look at rotate()
and updateChildren()
. Basically, what this class does is move itself so that the pivot box stays at the same position as it was before rotation.
Here's the demo. Click a box to select a pivot. Click it again to deselect. When there's no box selected, the group can rotate just like the one above.
And here's the class:
package { import as3isolib.display.primitive.IsoBox; import as3isolib.display.scene.IsoGrid; import as3isolib.graphics.SolidColorFill; import eDpLib.events.ProxyEvent; import flash.events.MouseEvent; /** * ... * @author Anggie Bratadinata | www.masputih.com */ public class GroupWithPivot extends Group { public var selectedBox:IsoBox; private var _selectedBox_oldX:Number; private var _selectedBox_oldY:Number; public function GroupWithPivot(grid:IsoGrid, descriptor:Object = null) { super(grid, descriptor); } override public function setMap(map:Array):void { super.setMap(map); for each (var isoBox:IsoBox in children) { isoBox.addEventListener(MouseEvent.CLICK, onBoxClick); } } private function onBoxClick(e:ProxyEvent):void { var newBox:IsoBox = e.target as IsoBox; if (selectedBox != null) { //reset color selectedBox.fills = [new SolidColorFill(0x00FFFF, 1), new SolidColorFill(0x8080C0, 1), new SolidColorFill(0xFF8040, 1)]; } if (newBox != selectedBox) { //set new color newBox.fills = [new SolidColorFill(0x804040, 1), new SolidColorFill(0x400000, 1), new SolidColorFill(0x804040, 1)]; selectedBox = newBox; } else { selectedBox = null; } } override public function rotate(clockWise:Boolean = true):void { if (selectedBox != null) { _selectedBox_oldX = selectedBox.x; _selectedBox_oldY = selectedBox.y; } super.rotate(clockWise); } override protected function updateChildren():void { super.updateChildren(); if (selectedBox != null) { var dx:int = selectedBox.x - _selectedBox_oldX; var dy:int = selectedBox.y - _selectedBox_oldY; moveTo(x - dx, y - dy, 0); } } } }
Download
Here's a zip containing all of those classes : [download id="13"]
Also in this category ...
- » Flexbox
- » Mengenal Hook di ReactJS
- » Rust 101: Hello Rust
- » JS : Pemrograman Asinkron
- » End-to-end Testing dengan The Intern
[…] This post was mentioned on Twitter by Sunil A.Nair, as3isolib and Anggie Bratadinata, Anggie Bratadinata. Anggie Bratadinata said: Making Rotatable IsoGroup http://goo.gl/fb/8cQlW […]
Hi there,
just want to thumb up for your work around as3isolib.
Really hope to know something more on the new as3isolib v2 version. In the meanwhile i really enjoy integrating v1 with your useful class!