![]() |
|
Isometric Tile engine |
Ariesnl
Member #2,902
November 2002
![]() |
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. starting code: HEADER 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 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}
Perhaps one day we will find that the human factor is more complicated than space and time (Jean luc Picard) |
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 Agui GUI API -> https://github.com/jmasterx/Agui |
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
![]() |
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. They all watch too much MSNBC... they get ideas. |
Neil Walker
Member #210
April 2000
![]() |
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. wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie |
Elias
Member #358
May 2000
|
Arthur Kalliokoski said:
It seems to me that if you had a Z (depth) component, it wouldn't be effectively 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. -- |
Neil Walker
Member #210
April 2000
![]() |
Good luck with a painters/basic ordering algorithm getting this to show: Tried to include it, but the site still fails miserably with FF or IE to upload files for me. Neil. wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie |
Arthur Kalliokoski
Second in Command
February 2005
![]() |
Neil Walker said: 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. They all watch too much MSNBC... they get ideas. |
Oscar Giner
Member #2,207
April 2002
![]() |
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
![]() |
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. wii:0356-1384-6687-2022, kart:3308-4806-6002. XBOX:chucklepie |
Arthur Kalliokoski
Second in Command
February 2005
![]() |
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. They all watch too much MSNBC... they get ideas. |
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 -- |
Oscar Giner
Member #2,207
April 2002
![]() |
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
![]() |
We have stacked tiles.... Perhaps one day we will find that the human factor is more complicated than space and time (Jean luc Picard) |
Timorg
Member #2,028
March 2002
|
Will you be hosting the code anywhere? ____________________________________________________________________________________________ |
Ariesnl
Member #2,902
November 2002
![]() |
As I said, the project ( and code) will be public I hope it will evolve into something usefull Perhaps one day we will find that the human factor is more complicated than space and time (Jean luc Picard) |
|