Senin, 27 Juli 2009

Isometric Graphic

Some of the above screenshot using Reiner Prokelein's Tileset

The above screenshot shows that Flash Player 10 can achieve 100 frames per second width 50 X 50 tiles and hundrends of characters.
Next I will tell you the way.

Sample how to put graphics in a tileset


To avoid some problems in putting graphics in Isometric cordinate system, we better apply the following principle:

Put the center in the lower tile square

If the height of your graphics (or bitmap) is more than the height of your isometric tile dimension,
put the center in isometric at isometric point.

For example, if you have a tree,
- put the tree in a tile (cell) center
- the grahic's height must be times of the tile height

Now you can put it by this function example in your IsometricObject:

public function addGraphic(b:Bitmap):void
{
bitmap.x = -bitmap.width/2;
bitmap.y = isometricHeight/2 - bitmapHeight;
}

It's requires to apply isometric point as the center of a tile (cell).






Isometric Projection in Flash Player 10

Much people asking about how to manage collision in isometric.
The eassy way is using ordinary coordinate system (everybody already familiar with it) and do project - unproject, using a matrix, to show on screen.

The Isometric coordinate system is:
- ordinary cartessian system
- rotate it 45 degree
- scale the y to whatever you want. Usually 0.5

So we can create a projection matrix like this:

public function updateProjectionMatrix(tileSquare:Number, yScale:Number):void
{
// Assumed: tile width = tile height = tileSquare
var tLength:Number = Math.sqrt(tileSquare * tileSquare * 2);
projectionMatrix = new Matrix();
projectionMatrix.translate(-tileSquare/2, -tileSquare/2);
projectionMatrix.rotate(45 * Math.PI/180);
projectionMatrix.scale(tileSquare/tLength, tileSquare * yScale/tLength);

// We also prepare a matrix for unprojection:
unprojectionMatrix = projectionMatrix.clone();
unprojectionMatrix.invert();
}

Another way is by defining the tile's dimension:

public function updateProjectionMatrix(tileWidth:Number, tileHeight:Number):void
{
var tLength:Number = Math.sqrt(tileWidth * tileWidth + tileHeight * tileHeight);
projectionMatrix = new Matrix();
projectionMatrix.translate(-tileWidth/2, -tileWidth/2);
projectionMatrix.rotate(45 * Math.PI/180);
projectionMatrix.scale(tileWidth/tLength, tileHeight/tLength);

// We also prepare a matrix for unprojection:
unprojectionMatrix = projectionMatrix.clone();
unprojectionMatrix.invert();
}

Having those matrices making the collision handling more easy.
For example:
If you have more than 1 DisplayObject and wants to recognize the collission
try it:
- put originPosition as property
- put isoPosition as property
in your IsometricObject

public static function isCollide(objA:IsometricObject, objB:IsometricObject):Boolean
{
return objA.getOriginBound().intersects(objB.getOriginBound());
}

Of course you need a getOriginBound() function.

// Assumed you put the graphics in center:
public function getOriginBound():Rectangle
{
return new Rectangle(this.originPosition.x - this.originWidth/2,
this.originPosition.y - this.originHeight/2,
this.originWidth,
this.originHeight);
}

This is the complete IsometricObject for a base object to extends:

package
{
import flash.display.MovieClip;
import flash.geom.Point;
import flash.geom.Rectangle;

public class IsometricObject extends MovieClip
{
public var originPosition:Point = new Point();
public var isoPoint:Point;
public var originWidth:Number;
public var originHeight:Number;

public function IsometricObject(ox:Number=0, oy:Number=0, ow:number=0, oh:Number=0)
{
originWidth = ow;
originHeight = oh;
setOrigin(ox, oy);
}

public function setOrigin(xx:Number, yy:Number):void
{
originPosition.x = xx;
originPosition.y = yy;
isoPoint = MyIsoEngine.project(originPosition);
}
}
}

You also create an MyIsoEngine by including these:

package
{
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;

import IsometricObject;

public class MyIsoEngine
{
public static var tileWidth:Number;
public static var tileHeight:Number;

public static var projectionMatrix:Matrix;
public static var unprojectionMatrix:Matrix;

public static function project(p:Point):Point
{
return projectionMatrix.transformPoint(p);
}

public static function unproject(p:Point):Point
{
return unprojectionMatrix.transformPoint(p);
}

public static function isCollide(objA:IsometricObject, objB:IsometricObject):Boolean
{
return objA.getOriginBound().intersects(objB.getOriginBound());
}
// Initing the engine requires at least:

public static function initEngine(tileW:Number, tileH:Number):void
{
tileWidth = tileW;
tileHeight = tileH;
updateProjectionMatrix();
}

protected static function updateProjectionMatrix():void
{
var tLength:Number = Math.sqrt(tileWidth * tileWidth + tileHeight * tileHeight);
projectionMatrix = new Matrix();
projectionMatrix.translate(-tileWidth/2, -tileWidth/2);
projectionMatrix.rotate(45 * Math.PI/180);
projectionMatrix.scale(tileWidth/tLength, tileHeight/tLength);

// We also prepare a matrix for unprojection:
unprojectionMatrix = projectionMatrix.clone();
unprojectionMatrix.invert();
}

}
}


easy?....
yeah!

See my engine at http://www.icesflash.com/iso.index.html