Going Isometric

Exclusive offer: get 50% off this eBook here
Starling Game Development Essentials

Starling Game Development Essentials — Save 50%

Develop and deploy isometric turn-based games using Starlin with this book and ebook

$17.99    $9.00
by Juwal Bose | December 2013 | Games Open Source

This article by Juwal Bose, author of the book Starling Game Development Essentials, helps you to understand the isometric projection and details the relationship between the Cartesian and isometric coordinates.

The topics covered in this article are as follows:

  • Cartesian to isometric equations
  • An isometric view via a matrix transformation
  • Implementing the isometric view via isometric art
  • Level data structure
  • Altering registration points
  • Depth sorting
  • Understanding isometric movement
  • Detecting isometric collision

(For more resources related to this topic, see here.)

Cartesian to isometric equations

A very important thing to understand here is that the level data still remains the same 2D array, and we will be altering only the rendering process. Later on, we will need to update the level data to accommodate large tiles, which will contain items that are bigger than the current tile size. Our two-dimensional top-down coordinates for a tile can be called Cartesian coordinates. The relationship between Cartesian and isometric coordinates is shown in the following code:

//Cartesian to isometric: x_Iso = x_Cart - y_Cart; y_Iso = ( x_Cart + y_Cart ) / 2; //Isometric to Cartesian: x_Cart = ( 2 * y_Iso + x_Iso ) / 2; y_Cart = ( 2 * y_Iso – x_Iso ) / 2;

Now that is very simple isn't it? We will use an IsoHelper class for this conversion where we can pass through a point and get back to the converted point.

An isometric view via a matrix transformation

Although the equations are simple and straightforward, the art needed for an isometric tile is a bit complicated. The artist needs to create the rhombus-shaped tile art with pixel precision and mostly tileable in all four directions. An alternative approach is to use the square tile itself and skew them dynamically using the corresponding code. Let us try to create the isometric view for the level data with the same tiles using this approach.

The transformation matrix for isometric transformation is as follows, which is essentially a rotation of 45 degrees and scaling by half in Y axis:

var m:Matrix = new Matrix(1,0.5,-1,0.5,0,0);

The code for the IsometricLevel class, is shared as follows. You should initialize this class from the Starling document class using new Starling (IsometricLevel, stage). The following approach just applies the isometric transformation matrix to the RenderTexture image. Minor changes in the init function are shown in the following code:

var m:Matrix = new Matrix(1,0.5,-1,0.5,0,0); for(var i:int=0;i<levelData.length;i++){ for(var j:int=0;j<levelData[0].length;j++){ img=new Image(texAtlas.getTexture(paddedName(levelData[i][j]))); img.x=j*tileWidth+borderX; img.y=i*tileWidth+borderY; rTex.draw(img); } } m.translate( 300, 0 ); rTexImage.transformationMatrix = m;

We apply the transformation matrix to the RenderTexture image and translate it by 300 pixels so that the whole of it is visible. Skewing will make a part of the image to be out of the visible area of the screen. We will get the following result:

An alternate approach is to apply the transformation matrix to each individual tile image, find the corresponding isometric coordinates, and move and place individual tiles accordingly as shown in the following code:

var m:Matrix = new Matrix(1,0.5,-1,0.5,0,0); var pt:Point=new Point(); for(var i:int=0;i<levelData.length;i++){ for(var j:int=0;j<levelData[0].length;j++){ img = new Image(texAtlas.getTexture(paddedName(levelData[i][j]))); img.transformationMatrix = m; pt.x=j*tileWidth+borderX; pt.y=i*tileWidth+borderY; pt=IsoHelper.cartToIso(pt); img.x=pt.x+300; img.y=pt.y; rTex.draw(img); } }

Here, we use the convenient cartToIso(pt) conversion function of our IsoHelper class to find the corresponding isometric coordinates to our Cartesian coordinates. We are offsetting the drawing by 300 pixels to handle the skewing offset for the image.

This approach will work in some cases, but not all top-down tiles can be simply skewed and made into an isometric tile. For example, consider a tree in the top-down view, it will simply look like a skewed tree graphic after we apply the isometric transformation. So, the right approach is to create an isometric tile art specifically and use isometric equations to place them correctly. Let us use the isometric tiles provided in the assets pack to create a sample level.

Implementing the isometric view via isometric art

Please refer to the SampleIsometricDemo source folder, which implements a sample level of our game using isometric art and the previously mentioned equations. There are some differences in the approach that I will be explaining in the following sections. Most of it has to do with the change in level data, altering the registration point of larger tiles, and handling depth. We also need to offset the image drawing so that it fits in the screen area. We use a variable called screenOffset for this purpose.

The render code is as follows:

var pt:Point=new Point(); for(var i:int=0;i<groundArray.length;i++){ for(var j:int=0;j<groundArray[0].length;j++){ //draw the ground img=new Image
(texAtlas.getTexture(String(groundArray[i][j]).split(".")[0])); pt.x=j*tileWidth; pt.y=i*tileWidth; pt=IsoHelper.cartToIso(pt); img.x=pt.x+screenOffset.x; img.y=pt.y+screenOffset.y; rTex.draw(img); //draw overlay if(overlayArray[i][j]!="*"){ img=new Image(texAtlas.getTexture
(String(overlayArray[i][j]).split(".")[0]));])); img.x=pt.x+screenOffset.x; img.y=pt.y+screenOffset.y; if(regPoints[overlayArray[i][j]]!=null){ img.x+=regPoints[overlayArray[i][j]].x; img.y-=regPoints[overlayArray[i][j]].y; } rTex.draw(img); } } }

The result is shown in the following screenshot:

Level data structure

The level data for our isometric level is not just a simple 2D array with index numbers any more, but a combination of multiple data structures. We have a 2D array for the ground tiles, another 2D array for overlay tiles, and a dictionary to store altered registration points of the overlay tiles. Ground tiles are those tiles which exactly fit the isometric tile dimensions, which in this case is 80 x 40, and makes up the bottom-most layer of the isometric level. These tiles won't take part in any depth sorting as they are always rendered below all other items that populate the level.

Overlay tiles are items which may not fit into the isometric tile dimensions and have height, for instance, buildings, trees, bushes, rocks, and so on. Some of these can be fit into tile dimensions, but are kept as such that we have various advantages using the following approach:

  • We are free to place an overlay tile over any ground tile, which adds to flexibility
  • We would need a lot of tiles if we try to fit overlay tiles and ground tiles together for all permutations and combinations
  • Effects such as tinting can be applied independently to the overlay tiles
  • Depth handling becomes much easier
  • Overlay tiles which are smaller than the tile size reduce the game size

Altering registration points

Starling considers all images as rectangular blocks with their registration point at the top-left corner. The registration point is the point which can be considered as the (0,0) of that image. Traditional Flash had given us the capability to alter the registration points by embedding images inside Sprite or MovieClip. We can still do the same, but it will require unnecessary creation of a lot of Sprites. Alternately, we can use the pivotX and pivotY properties of Starling objects for the same result too. In our isometric level, we will need to precisely place overlay tiles inside the isometric grid space. An overlay tile does not have any standard size as it can be any item— a tree, building, character, and so on. So, placing them correctly is a tricky thing and very specific to the tile concerned.

This leads us to have independent registration points for each overlay tile. We use a dictionary structure to save these values and use those values as offsets while placing overlay tiles. For example, we need to place a bush image, nonwalk0009.png, exactly at the middle of an isometric grid, which means moving it 12 pixels to the left and 19 pixels to the top for proper alignment. We save (12,19) as a new point inside our dictionary for ID nonwalk0009.png, as follows:

regPoints["nonwalk0009.png"]=new Point(12,19);

Finding a tile's precise placement point needs to involve visual interaction; hence, we will build a level editor, which makes this easier.

Depth sorting

An isometric view needs us to handle the depth of items manually. For ground tiles, there is no depth issue as they always form the lowest layer over which all the overlay items and characters are drawn. But overlay tiles and characters need to be drawn at specific depths for it to look appropriate. By depth, I mean the order at which the images are drawn. An image drawn later will overlap the one drawn earlier, thereby making it seem in front of the latter. For a level which does not change or without any moving items, we need to find the depth only once for the initial render. But for a level with moving characters or vehicles, we need to find every frame in the game loop and render.

The current sample level does not change over time, so we can simply render the level by looping through the array. Any overlay item placed at a higher I or J value will be rendered later, and hence will be shown in front, where I and J are array indices. Thus, items placed at higher indices appear closer to the camera, that is, for the same I, a higher J is closer to the camera and vice versa.

When we have a moving item, we need to find the corresponding array position it occupies based on its current screen position. By using these new found array indices, we can compare with the overlay tile's indices and decide on the drawing sequence. The code to find array indices from the screen position is as follows:

//capture screen position var screenPos:Point=new Point(hero.x,hero.y); //convert to cartesian coordinates var cartPos:Point=IsoHelper.isoToCart(screenPos); //find tile indices from cartesian values var tilePos:Point=IsoHelper.getTileIndices(screenPos,tileWidth);

Understanding isometric movement

Isometric movement is very straightforward to implement. All we need to do is move the item in top-down Cartesian coordinates and draw it on the screen after converting into isometric coordinates. For example, if our character is at a point, heroCart in the Cartesian system, then the following code moves him/her to the right:

heroCart.x+=heroSpeed; //convert to isometric coordinates heroIso=IsoHelper.cartToIso(heroCart); heroImage.x=heroIso.x; heroImage.y=heroIso.y; rTex.draw(heroImage);

Detecting isometric collision

Collision detection for any tile-based game is done based on tiles. When designing, we will make sure that certain tiles are walkable while certain tiles are nonwalkable, which means that the characters can move over some tiles but not over others. So, when we calculate the movements of any character, we first make sure that the character won't end up on a nonwalkable tile. Thus, after each movement, we check if the resulting position falls in a nonwalkable tile by finding array indices as mentioned previously. If the result is true, we will ignore the movement, else we will proceed with the movement and update the on-screen character position.

heroCart.x+=heroSpeed; //find new tile point var tilePos:Point=IsoHelper.getTileIndices(heroCart,tileWidth); //this checks if new tile position is occupied, else proceeds if(checkWalkable(tilePos)){ //convert to isometric coordinates heroIso=IsoHelper.cartToIso(heroCart); heroImage.x=heroIso.x; heroImage.y=heroIso.y; rTex.draw(heroImage); }

You may be wondering that the hero character should need some special considerations to be drawn correctly as the right depth, but by the way we draw things, it gets handled automatically. We do not allow the hero to move onto a nonwalkable tile, that is, bushes, trees, and so on. So, any tile remains walkable or nonwalkable. The character gets drawn on top of a walkable tile, which does not contain any overlay items, and hence it will occupy the right depth.

In this method, a full tile has to be made either walkable or nonwalkable, but this may not be the case for all games. We may need to have tiles, which block entry from a specific direction or block exit in a particular direction as a fence along one border of a tile. In such cases, the tile is still walkable, but valid movement is also checked by tracking the direction in which the character is moving. For our game, the first method will be used along with the four-way freedom of movement.

In an isometric view, movement can be either in four directions or eight directions, which in turn is called a four-way movement or an eight-way movement respectively. A four-way movement is when we move along the X or Y axis alone on the Cartesian space. An eight-way movement happens when, in addition to four - way, we also move the item diagonally. Logic still remains the same.

Summary

In this article, we learned about the isometric projection and the equations that help us to implement it based on the simpler Cartesian system. We implemented a sample isometric level using isometric art as well as learned about matrix-based fake isometric rendering. We analyzed the IsoHelper class, which facilitates easy conversion between Cartesian and isometric coordinates and also helps in finding array indices.

We learned why altering the registration points is essential for perfectly placing the overlay tiles and we found that our level data needs to track these registration points as well. We also learned how depth sorting, collision detection, and isometric movement are done based on our tile-based approach.

Resources for Article:


Further resources on this subject:


Starling Game Development Essentials Develop and deploy isometric turn-based games using Starlin with this book and ebook
Published: December 2013
eBook Price: $17.99
Book Price: $29.99
See more
Select your format and quantity:

About the Author :


Juwal Bose

Juwal Bose is a game developer, game designer, and technology consultant from the incredibly beautiful state of Kerala in India. He is an active figure in social media and game development SIGs, and never misses a chance to speak at technical conferences and barcamps. He conducts technical workshops for engineering students at professional colleges as a part of open source initiatives. Juwal is the Director at Csharks Games and Solutions Pvt Ltd, where he manages research and development, as well as training and pipeline integration in his area of expertise.

Juwal has been actively involved with Adobe technologies, manages the Adobe user group for his state, and maintains a close relationship with the experts at Adobe in the Indian subcontinent. He has been developing games since 2004 using multiple technologies including ActionScript, Objective-C, Java, Unity, LibGDX, Cocos2D, OpenFL, Blender, and Starling. His team has created more than 350 online Flash games to date, and many of the job management games are listed at the top of leading portals worldwide.

Juwal writes game development tutorials for GameDevTuts+ and manages the blog of Csharks games. His isometric tutorial for GameDevTuts+ is well received and is considered a thorough guide for developing tile-based isometric games. Juwal also takes part in game jams and recently won the Nasscom GDC's game jam with is Starling-based game, Mosquito Defense. This is Juwal's first book, but he aims to keep writing and sharing his nine years of game development experience through more books.

Juwal is a voracious reader and likes to travel. His future plans also include writing fiction

Books From Packt


 Marmalade SDK Mobile Game Development Essentials
Marmalade SDK Mobile Game Development Essentials

Corona SDK Mobile Game Development: Beginner's Guide
Corona SDK Mobile Game Development: Beginner's Guide

 Building your First Mobile Game using XNA 4.0
Building your First Mobile Game using XNA 4.0

 Developing Mobile Games with Moai SDK
Developing Mobile Games with Moai SDK

 LiveCode Mobile Development Hotshot
LiveCode Mobile Development Hotshot

Learning ShiVa3D Game Development
Learning ShiVa3D Game Development

 HTML5 Game Development with GameMaker
HTML5 Game Development with GameMaker

GameSalad Beginner’s Guide
GameSalad Beginner’s Guide


Your rating: None Average: 1.7 (3 votes)

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
S
6
p
Z
D
x
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software