Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Isometric Tile engine

This thread is locked; no one can reply to it. rss feed Print
Isometric Tile engine
Ariesnl
Member #2,902
November 2002
avatar

I'm gonna write an isometric tile engine, and I decided to make it a public project so anyone can help, learn from it , use it.
Good idea's are most welcome.

starting code:

HEADER

#SelectExpand
1/* 2Copyright (C) 2011 E.J.M. Martens 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12GNU General Public License for more details. 13 14You should have received a copy of the GNU General Public License 15along with this program; if not, write to the Free Software 16Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 18 19 20================================================================================ 21 22This file defines a basic tile and tileengine for isometric drawing 23 24 25 26History: 27 2808-11-2011 First Setup 29 30 31 32*/ 33 34 35#ifndef _ISOENGINE 36#define _ISOENGINE 37 38#include <vector> 39#include <allegro5/allegro.h> 40#include <allegro5/allegro_image.h> 41#include <allegro5/allegro_primitives.h> 42 43 44class BasicEngine; 45 46class BasicTile 47{ 48 private: 49 // pointer to engine 50 BasicEngine * m_pEngine; 51 52 // Pointer to a bitmap for this tile 53 // This can be a tilesheet or a single tile; 54 ALLEGRO_BITMAP * m_pBitmap; 55 56 // A drawing offset 57 int m_nOffsetX; 58 int m_nOffsetY; 59 60 // offset in a tilesheet -1 if bitmap is a single tile 61 int m_nBitmapOffsetX; 62 int m_nBitmapOffsetY; 63 64 protected: 65 // draw the tile, this is used by Basic Engine 66 // draws placeholders if no bitmap was set 67 virtual void Draw(int a_nMapX,int a_nMapY); 68 69 public: 70 // set the bitmap for this tile 71 void SetBitmap(ALLEGRO_BITMAP * a_pBitmap); 72 void SetOffset(int a_nOffsetX,int a_nOffsetY); 73 74 // constructor 75 BasicTile(); 76 77 // destructor 78 virtual ~BasicTile(); 79 80 friend class BasicEngine; 81}; 82 83 84class BasicEngine 85{ 86 private: 87 88 // nested vector to hold the tiles 89 std::vector<std::vector< BasicTile * > >m_lstCell; 90 91 // the width of every tile 92 int m_nTilewidth; 93 94 // the height of every tile 95 int m_nTileHeight; 96 97 // The Y distance between two rows of tiles (usually 1/4 tileheight) 98 int m_nYStep; 99 100 // the screencenter 101 int SCREENCENTER_X; 102 int SCREENCENTER_Y; 103 104 protected: 105 106 public: 107 108 // Draw the tilemap looking at centerpoint a_nCamX, a_nCamY 109 virtual void Draw(int a_nCamx,int a_nCamy); 110 111 // Generate a testmap 112 virtual void GenerateTest(int a_nWidth, int a_nHeight, ALLEGRO_BITMAP * a_pBitmap); 113 114 // constructor 115 BasicEngine(); 116 117 // destructor 118 virtual ~BasicEngine(); 119 120 friend class BasicTile; 121 122}; 123 124#endif

CPP

#SelectExpand
1 2/* 3Copyright (C) 2011 E.J.M. Martens 4 5This program is free software; you can redistribute it and/or 6modify it under the terms of the GNU General Public License 7as published by the Free Software Foundation; either version 2 8of the License, or (at your option) any later version. 9 10This program is distributed in the hope that it will be useful, 11but WITHOUT ANY WARRANTY; without even the implied warranty of 12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 19 20 21================================================================================ 22 23This file implements a basic tile and tileengine for isometric drawing 24 25 26History: 27 2808-11-2011 First Setup 29 30 31 32*/ 33 34 35 36 37#include "stdafx.h" 38#include <allegro5/allegro.h> 39#include <allegro5/allegro_image.h> 40#include <allegro5/allegro_primitives.h> 41#include "IsoEngine.h" 42 43 44 45//-------------------------------------------------------------- 46// Constructor : BasicTile.BasicTile 47// Description : Constructs a tile 48//------------------------------------------------------------- 49BasicTile::BasicTile() 50{ 51 m_nOffsetX = 0; 52 m_nOffsetY = 0; 53 m_nBitmapOffsetX = -1; 54 m_nBitmapOffsetY = -1; 55 m_pBitmap = NULL; 56} 57 58 59//-------------------------------------------------------------- 60// Destructor : BasicTile.~BasicTile 61// Description : Destroys a tile 62//------------------------------------------------------------- 63BasicTile::~BasicTile() 64{ 65 66 67} 68 69//-------------------------------------------------------------- 70// Function : BasicTile.SetOffset 71// Description : Set's the grabbing offset for a tile 72// Virtual : No 73//------------------------------------------------------------- 74void BasicTile::SetOffset(int a_nOffsetX,int a_nOffsetY) 75{ 76 m_nBitmapOffsetX = a_nOffsetX; 77 m_nBitmapOffsetY = a_nOffsetY; 78} 79 80 81//-------------------------------------------------------------- 82// Function : BasicTile.SetBitmap 83// Description : Set's the bitmap for a tile 84// Virtual : No 85//------------------------------------------------------------- 86void BasicTile::SetBitmap(ALLEGRO_BITMAP * a_pBitmap) 87{ 88 m_pBitmap = a_pBitmap; 89} 90 91 92//-------------------------------------------------------------- 93// Function : BasicTile.Draw 94// Description : Draws a tile at position a_nScreenX, a_nScreenY 95// Virtual : Yes 96//------------------------------------------------------------- 97void BasicTile::Draw(int a_nScreenX,int a_nScreenY) 98{ 99 a_nScreenX+=m_nOffsetX; 100 a_nScreenY+=m_nOffsetY; 101 102 if (m_pBitmap == NULL) 103 { 104 // No bitmap, draw a placeholder 105 106 ALLEGRO_COLOR Fill = al_map_rgb(255,0,0); 107 ALLEGRO_COLOR Border = al_map_rgb(0,255,0); 108 109 al_draw_filled_triangle(a_nScreenX,a_nScreenY+m_pEngine->m_nYStep, a_nScreenX+m_pEngine->m_nTilewidth, a_nScreenY+m_pEngine->m_nYStep,a_nScreenX+m_pEngine->m_nTilewidth/2,a_nScreenY,Fill); 110 al_draw_filled_triangle(a_nScreenX,a_nScreenY+m_pEngine->m_nYStep, a_nScreenX+m_pEngine->m_nTilewidth, a_nScreenY+m_pEngine->m_nYStep,a_nScreenX+m_pEngine->m_nTilewidth/2,a_nScreenY+m_pEngine->m_nTilewidth/2,Fill); 111 al_draw_line(a_nScreenX,a_nScreenY+m_pEngine->m_nYStep, a_nScreenX+m_pEngine->m_nTilewidth/2,a_nScreenY,Border, 1); 112 al_draw_line(a_nScreenX+m_pEngine->m_nTilewidth/2,a_nScreenY,a_nScreenX+m_pEngine->m_nTilewidth,a_nScreenY+m_pEngine->m_nYStep,Border, 1); 113 al_draw_line(a_nScreenX+m_pEngine->m_nTilewidth,a_nScreenY+m_pEngine->m_nYStep,a_nScreenX+m_pEngine->m_nTilewidth/2,a_nScreenY+m_pEngine->m_nTilewidth/2,Border, 1); 114 al_draw_line(a_nScreenX+m_pEngine->m_nTilewidth/2,a_nScreenY+m_pEngine->m_nYStep*2,a_nScreenX,a_nScreenY+m_pEngine->m_nYStep,Border, 1); 115 116 } 117 else 118 { 119 if ((m_nBitmapOffsetX == -1)&&(m_nBitmapOffsetY == -1)) 120 { 121 // single tile 122 al_draw_bitmap(m_pBitmap, a_nScreenX, a_nScreenY,0); 123 } 124 else 125 { 126 // tilesheet 127 al_draw_bitmap_region(m_pBitmap,m_nBitmapOffsetX, m_nBitmapOffsetY, m_pEngine->m_nTilewidth, m_pEngine->m_nTileHeight, a_nScreenX, a_nScreenY,0); 128 } 129 130 } 131} 132 133 134 135 136 137//-------------------------------------------------------------- 138// Constructor : BasicEngine::BasicEngine 139// Description : Constructs a tileengine 140//------------------------------------------------------------- 141BasicEngine::BasicEngine() 142{ 143 m_nTilewidth=64; 144 m_nTileHeight=64; 145 m_nYStep = m_nTileHeight/4; 146 SCREENCENTER_X = 800; 147 SCREENCENTER_Y = 600; 148} 149 150 151//-------------------------------------------------------------- 152// Destructor : BasicEngine::~BasicEngine 153// Description : frees all used memory 154//------------------------------------------------------------- 155BasicEngine::~BasicEngine() 156{ 157 std::vector<std::vector< BasicTile * > >::iterator p=m_lstCell.begin(); 158 while (p!=m_lstCell.end()) 159 { 160 std::vector< BasicTile * >::iterator q = (*p).begin(); 161 while (q!=(*p).end()) 162 { 163 BasicTile * hulp = *q; 164 (*p).erase(q++); 165 delete hulp; 166 } 167 m_lstCell.erase(p++); 168 } 169} 170 171 172//-------------------------------------------------------------- 173// Function : BasicEngine.Draw 174// Description : Draws a tilemap centered around a_nCamx,a_nCamy 175// Virtual : Yes 176//------------------------------------------------------------- 177void BasicEngine::Draw(int a_nCamx,int a_nCamy) 178{ 179 int DrawX; 180 int DrawY; 181 unsigned int startx,endx,starty,endy; 182 183 184 //Calculate start and end for nested loops 185 startx=(a_nCamx-SCREENCENTER_X)/m_nTilewidth; 186 if (startx>m_lstCell.size()) startx=m_lstCell.size(); 187 188 endx=((a_nCamx+SCREENCENTER_X)/m_nTilewidth)+1; 189 if (endx>m_lstCell.size()) endx=m_lstCell.size(); 190 191 starty=((a_nCamy-SCREENCENTER_Y)/m_nYStep); 192 if (starty>m_lstCell.size()) starty=m_lstCell.size(); 193 194 endy=((a_nCamy+SCREENCENTER_Y)/m_nYStep)+1; 195 if (endy>m_lstCell.size()) endy=m_lstCell.size(); 196 197 int sy=(starty*m_nYStep); 198 int h_sx=startx*m_nTilewidth; 199 int sx; 200 201 for (unsigned int y=starty;y<endy;y++) 202 { 203 sx=h_sx; 204 if (y % 2 == 0) 205 { 206 sx+=m_nTilewidth/2; 207 } 208 for (unsigned int x=startx;x<endx;x++) 209 { 210 DrawX=int(SCREENCENTER_X+(sx-a_nCamx)); 211 DrawY=int(SCREENCENTER_Y+(sy-a_nCamy)); 212 sx+=64; 213 m_lstCell[x][y]->Draw(DrawX,DrawY); 214 } 215 sy+=m_nYStep; 216 } 217 218} 219 220 221//----------------------------------------------------------------------------- 222// Function : BasicEngine.GenerateTest 223// Description : Generates a testmap with Width a_nWidth and height a_nHeight 224// Virtual : Yes 225//----------------------------------------------------------------------------- 226void BasicEngine::GenerateTest(int a_nWidth, int a_nHeight, ALLEGRO_BITMAP * a_pBitmap) 227{ 228 for (int y=0; y<a_nHeight;y++) 229 { 230 std::vector<BasicTile * > tempvector; 231 for (int x=0;x< a_nWidth;x++) 232 { 233 BasicTile * pTile = new BasicTile(); 234 if (a_pBitmap!=NULL) 235 { 236 pTile->SetBitmap(a_pBitmap); 237 if((x==0)||(y==0)) 238 { 239 pTile->SetOffset(0,320); 240 241 } 242 else 243 { 244 pTile->SetOffset(0,256); 245 } 246 } 247 pTile->m_pEngine = this; 248 tempvector.push_back(pTile); 249 } 250 m_lstCell.push_back(tempvector); 251 } 252 253}

- Wisdom is the art of using knowledge
- String theory: There's music in everything

jmasterx
Member #11,410
October 2009

It might be a good idea to abstract drawing and maybe the underlying API so the engine can be used with SDL, SFML, etc

Audric
Member #907
January 2001

The flat map (horizontal tiles) is a no-brainer, challenge is when you introduce vertical shapes and need to make them cover one another with the right priority.

Arthur Kalliokoski
Second in Command
February 2005
avatar

Audric said:

The flat map (horizontal tiles) is a no-brainer, challenge is when you introduce vertical shapes and need to make them cover one another with the right priority.

It seems to me that if you had a Z (depth) component, it wouldn't be effectively changed if you simply tilted the scene at 45 degrees and used the painters algorithm.

“Throughout history, poverty is the normal condition of man. Advances which permit this norm to be exceeded — here and there, now and then — are the work of an extremely small minority, frequently despised, often condemned, and almost always opposed by all right-thinking people. Whenever this tiny minority is kept from creating, or (as sometimes happens) is driven out of a society, the people then slip back into abject poverty. This is known as "bad luck.”

― Robert A. Heinlein

Neil Walker
Member #210
April 2000
avatar

Perhaps use some const correctness and initialisation lists.

You'll probably be wanting some kind of utility class to do conversions, e.g. pixel to tile, etc.

Neil.
MAME Cabinet Blog / AXL LIBRARY (a games framework) / AXL Documentation and Tutorial

wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie

Elias
Member #358
May 2000

It seems to me that if you had a Z (depth) component, it wouldn't be effectively
changed if you simply tilted the scene at 45 degrees and used the painters algorithm.

The painters algorithm has the advantage that even transparent shapes will (mostly) work. If you have no transparency you don't even need painters algorithm, draw them in any order and the z-buffer takes care of it all.

--
"Either help out or stop whining" - Evert

Neil Walker
Member #210
April 2000
avatar

Good luck with a painters/basic ordering algorithm getting this to show:

isomot.gif

Tried to include it, but the site still fails miserably with FF or IE to upload files for me.

Neil.
MAME Cabinet Blog / AXL LIBRARY (a games framework) / AXL Documentation and Tutorial

wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie

Arthur Kalliokoski
Second in Command
February 2005
avatar

Good luck with a painters/basic ordering algorithm getting this to show:

Compare that bizarre case with the broken visibility determination in Tomb Raider 1, 2 and 3 (at least) and you'll realize it's not that big of a problem.

“Throughout history, poverty is the normal condition of man. Advances which permit this norm to be exceeded — here and there, now and then — are the work of an extremely small minority, frequently despised, often condemned, and almost always opposed by all right-thinking people. Whenever this tiny minority is kept from creating, or (as sometimes happens) is driven out of a society, the people then slip back into abject poverty. This is known as "bad luck.”

― Robert A. Heinlein

Oscar Giner
Member #2,207
April 2002
avatar

Well, that specific image just doesn't makes sense, but it's true that painter algorithm is not perfect, but is usually good enough (look at games like Roller Coaster Tycoon 1/2, there are minor glitches but overall it looks good). Painters algorithm will render the map without glitches, the problem comes when you have objects that lie between 2 or more tiles (moving objects usually).

But if using Allegro 5, using Z depth is virtually free, so... that makes things simpler and the render doesn't have glitches (you just need to take care of translucent objects).

Neil Walker
Member #210
April 2000
avatar

Of course it makes sense, in a typical isometric game you have moving platform tiles or tiles that do not fit exactly onto the grid, e.g. the player.

In fact, it wasn't drawn, it was a screen capture from an isometric engine that accounted for this by using ordering and masks :)

Neil.
MAME Cabinet Blog / AXL LIBRARY (a games framework) / AXL Documentation and Tutorial

wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie

Arthur Kalliokoski
Second in Command
February 2005
avatar

It doesn't seem to make sense if you assume they're cubes, but if you were to assume the blue box was shorter than the red box, it'd render like that.

“Throughout history, poverty is the normal condition of man. Advances which permit this norm to be exceeded — here and there, now and then — are the work of an extremely small minority, frequently despised, often condemned, and almost always opposed by all right-thinking people. Whenever this tiny minority is kept from creating, or (as sometimes happens) is driven out of a society, the people then slip back into abject poverty. This is known as "bad luck.”

― Robert A. Heinlein

Elias
Member #358
May 2000

With a z-buffer the red/green/blue cubes will render correctly. Just if they were all half-transparent they wouldn't.

It doesn't even matter in which order you draw them - the z-buffer will store a depth value for each pixel. So if you draw red first and then green the obscured parts of green are skipped because they have more depth than the red in front. When now drawing blue it will overwrite red (because blue has less depth) but skip the pixels behind green as they again have more depth.

[edit:] This reminds me of a picture from an isometric engine I attempted a long time ago but which I gave up on back then after encountering this issue :P devils3cubes.png

--
"Either help out or stop whining" - Evert

Oscar Giner
Member #2,207
April 2002
avatar

Aah, now I see how that image makes sense, but then those cubes are not spaced in a grid. I was assuming that.

Ariesnl
Member #2,902
November 2002
avatar

We have stacked tiles....
{"name":"605090","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/3\/b376d2ae2f35b1627fed21ef08a6f571.png","w":800,"h":619,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/3\/b376d2ae2f35b1627fed21ef08a6f571"}605090

- Wisdom is the art of using knowledge
- String theory: There's music in everything

Timorg
Member #2,028
March 2002

Will you be hosting the code anywhere?

____________________________________________________________________________________________
"c is much better than c++ if you don't need OOP simply because it's smaller and requires less load time." - alethiophile
OMG my sides are hurting from laughing so hard... :D

Ariesnl
Member #2,902
November 2002
avatar

As I said, the project ( and code) will be public :)

I hope it will evolve into something usefull

- Wisdom is the art of using knowledge
- String theory: There's music in everything

Go to: