Laserbrain Studios

Games Forum Blog Contact

Author Topic: The basics of isometric programming  (Read 4943 times)

Christian Knudsen

  • Administrator
  • Ace
  • *****
  • Posts: 3014
    • View Profile
The basics of isometric programming
« on: January 25, 2012, 02:20:00 PM »

When I started work on Hostile Takeover, I had only admired existing isometric games and never thought about programming one myself. So when I decided that isometric would be the graphical style I’d go for, I had to do a lot of reading up on the subject and wrap my head around this way of “faking” a 3D presentation with 2D graphics. I thought I might as well share some of the basics I’ve come to understand – maybe you’re gearing up for your own isometric game, but if not, I hope you still find this somewhat interesting.


There were two main issues I had to figure out to get the most basic stuff up and running: drawing the tile sprites in an isometric grid and calculating which tile the mouse cursor is over. As with pretty much everything in programming, the answers to both issues were some surprisingly simple mathematical formulas.


Drawing an isometric grid

 An isometric tile is basically a square tile rotated 45 degress around the z-axis and tilted around the x-axis so it’s twice as wide as it is high:


Rectangular tile to isometric tile


When drawing a grid made up of non-isometric tiles, it’s pretty easy as all the tiles on the same row have the same y-value, but with an isometric grid all tiles are offset half a tile both vertically and horizontally:


Non-isometric and isometric grid

 Image borrowed from this article


This is where basic math came to the rescue. The algorithm I use for drawing tiles is:



   FOR Y := 1 TO SizeY DO BEGIN
      FOR X := 1 TO SizeX DO BEGIN
         DrawX := ((X - Y) * 38) + 400;
         DrawY := (X + Y) * 19;
      END;
   END;


My tiles are 76 pixels wide and 38 pixels high, which is why I multiple with 38 (half of 76) and 19 (half of 38). I add 400 to the x-value to keep the left half of the grid from being drawn at negative x-coordinates (i.e. beyond the left edge of my computer screen). This gives me the x and y coordinates for blitting the tile sprite to the screen. Simple!


Calculating tile mouse over

 When it comes to figuring out which tile the mouse is over (so that the game will know which tile the player character should move to when the player clicks the mouse button!), it was slightly harder to figure out, but, again, some simple math came to the rescue.


I already knew what the screen coordinates of the mouse cursor is, since I used that for actually drawing the mouse cursor. The screen coordinate is just which pixel on the screen the mouse cursor is currently at. My screen resolution is 1280×800, so the mouse cursor’s x-coordinate will be 1 – 1280 and the y-coordinate 1 – 800. I also already know where my tiles are on the screen, since I just previously figured out the algorithm for drawing them to the screen. Combining this, I can make an algorithm for translating the mouse cursor’s screen coordinates to an isometric tile coordinate:




   ScreenX := ScreenX - 438;
   TileX := Trunc((ScreenY / 38) + (ScreenX / 76));
   TileY := Trunc((ScreenY / 38) - (ScreenX / 76));


So if I know that my mouse is at, say, [410, 235] on the screen, calculating which tile the mouse is over is as easy as:


TileX = (235 / 38) + (-28 / 76) = 5 (rounded down)

 TileY = (235 / 38) – (-28 / 76) = 6 (rounded down)


You’ll notice that I start with subtracting 438 from the mouse cursor’s x-coordinate. This is because I added 400 to the x-coordinate when drawing the tiles, so I have to subtract this again (as well as half a tile width) before calculating which tile the mouse is over.


Scrolling map

 Now, this is all well and good for a map that isn’t larger than the computer monitor’s resolution. What do you do if you want a map that’s larger than that and want to allow the player to scroll the map? Easy, you just add an offset x and y value to the algorithms:




   FOR Y := 1 TO SizeY DO BEGIN
      FOR X := 1 TO SizeX DO BEGIN
         DrawX := (((X - Y) * 38) + 400) - OffsetX;
         DrawY := ((X + Y) * 19) - OffsetY;
      END;
   END;


and:




   ScreenX := (ScreenX - 438) + OffsetY;
   ScreenY := ScreenY + OffsetY;
   TileX := Trunc((ScreenY / 38) + (ScreenX / 76));
   TileY := Trunc((ScreenY / 38) - (ScreenX / 76));


When the player scrolls the map horizontally, just increase or decrease the OffsetX value accordingly, and do the same with the OffsetY value when the player scrolls vertically.


And there you have it. The basics of drawing and interacting with an isometric map. I had to play around with the values a bit, though, so when I for example add 400 to the DrawX value, that number is just something I arrived at with trial and error. It would differ for different monitor resolutions and depending on where you want the default map position to be at (i.e. before the player does any scrolling).


If you want to read more about isometric programming theory, there’s a bunch of enlightening articles over at GameDev.Net.


Oh, and in case you’re wondering, the code snippets are Pascal. I program in FreePascal with SDL and OpenGL for cross-platform development.



William Hales

  • Guest
The basics of isometric programming
« Reply #1 on: January 25, 2012, 02:26:17 PM »

If you continue to blog your development regularly in a little time more people will probably be attracted here, with hopefully the same popularity as the Wolfiregames blog.


I’d recommend you have a look at http://freedroid.sourceforge.net/ .  It’s open source and runs along the same isometric RPG lines as Hostile Takeover.



Christian Knudsen

  • Administrator
  • Ace
  • *****
  • Posts: 3014
    • View Profile
The basics of isometric programming
« Reply #2 on: January 25, 2012, 02:26:17 PM »

Yeah, I’m very much a fan of the Wolfire guys and their blog. And somewhat inspired by them in the way I’ve built and hope to expand my own little blog here. Just remember than I’m one guy while they’re three, I believe, so I probably won’t be able to update my blog quite as often as they are. I’ll try to do it as often as time permits, though. It would also be cool to have guest bloggers here, if it ever gets popular enough.


That FreeDroid game looks fun. I’ll have to check it out!



Kuncoro

  • Guest
The basics of isometric programming
« Reply #3 on: January 25, 2012, 02:26:17 PM »

Why not using matrix so you can easely projecting and unprojecting?



Christian Knudsen

  • Administrator
  • Ace
  • *****
  • Posts: 3014
    • View Profile
The basics of isometric programming
« Reply #4 on: January 25, 2012, 02:26:17 PM »

I made a blog post about my reasons for going 2D isometric instead of 3D, if that’s what you mean:


http://laserbrainstudios.com/2010/08/why-isometric/



Theodore Gifford

  • Guest
The basics of isometric programming
« Reply #5 on: March 01, 2012, 06:54:32 AM »

Hey, this is great, thanks!  I’m in a group making an in-browser multiplayer turn based strategy game as a class project.  We’ve been chugging along fine with our orthogonal grid, intending to move over to isometric soon.  Everything is working great except for mouse control.  This will be really helpful.



Christian Knudsen

  • Administrator
  • Ace
  • *****
  • Posts: 3014
    • View Profile
The basics of isometric programming
« Reply #6 on: March 01, 2012, 02:20:56 PM »

Glad you found it helpful! Good luck with your project! :)



Paul R

  • Guest
The basics of isometric programming
« Reply #7 on: April 02, 2012, 11:22:43 PM »

Very nice, is rather simple to implement and understand,

I’ve yet to get around to the scrolling stage.

Just got to work how to get the current tile selected centre XY coordinates!



Paul R

  • Guest
The basics of isometric programming
« Reply #8 on: April 03, 2012, 12:55:57 AM »

In fact, scratch the last comment, when looking closer, it doesn’t seem to work fully.

if you were to split the tile into 4 bits (visually to understand what is going on, so down and across the middle), clicking in different areas of the tile can result in the incorrect tile X and Y.



Christian Knudsen

  • Administrator
  • Ace
  • *****
  • Posts: 3014
    • View Profile
The basics of isometric programming
« Reply #9 on: April 03, 2012, 01:44:37 AM »

I’m not sure I understand which part you can’t get to work?



Paul R

  • Guest
The basics of isometric programming
« Reply #10 on: April 03, 2012, 09:44:40 AM »

http://localhostr.com/files/03g1MOK/iso.png


Bare in mind I’m doing this on Android and Andengine, which might be doing something unexpected.


The tile 1,1 is a Tile I have picked.

Click on segment A

X = 0  Y  = 1


Click on segment B

X = 1 Y  = 1


Click on segment C

X = 1  Y  = 2


Click on segment D

X = 1 Y  = 2


The grid is one whole PNG,

Top Left placed at 0,0

Width = 360

Height = 180

Tile Height = 45

Tile Width = 90



Paul R

  • Guest
The basics of isometric programming
« Reply #11 on: April 03, 2012, 09:46:43 AM »

float touchX = pSceneTouchEvent.getX();

float touchY = pSceneTouchEvent.getY();

int originWidth = 180


float pScreenX = touchX – 45 – originWidth;

float tileX = (touchY / 45) + (pScreenX / 90);

float tileY = (touchY / 45) – (pScreenX / 90);



Christian Knudsen

  • Administrator
  • Ace
  • *****
  • Posts: 3014
    • View Profile
The basics of isometric programming
« Reply #12 on: April 03, 2012, 10:09:57 AM »

What’s your algorithm for drawing the tiles? Your .png seems to be cropped or moved around the “screen”, so I can’t just pick a random pixel and do the algorithm on that, since I don’t know what modifiers have been applied to the X and Y drawing positions.



Paul R

  • Guest
The basics of isometric programming
« Reply #13 on: April 03, 2012, 09:13:52 PM »

I’ve fixed it now.  I was just drawing a grid as one whole png,

I’m now producing each tile by hand, using the following code, which works quite well,


http://www.athanazio.com/wp-content/uploads/2008/02/isomapjava.txt


Your “Calculating tile mouse over” works, its probably the most quickest way, the above txt file also has the row/col maths but is longer.


All I’ve got to do now is get the centre of the clicked tile!

Sorry for wasting your time and making a mess of the comments!



Christian Knudsen

  • Administrator
  • Ace
  • *****
  • Posts: 3014
    • View Profile
The basics of isometric programming
« Reply #14 on: April 03, 2012, 11:02:01 PM »

No problem. Glad you got it working. :)