Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Detecting mouseover on isometric map

This thread is locked; no one can reply to it. rss feed Print
Detecting mouseover on isometric map
Some_Guy
Member #14,362
June 2012

Here we go with another newbie question

I'm rendering my map with 2 nested for loops.
It looks like this:

Quote:

.. .. 01 .. ..
.. 02 06 ..
.. 03 07 11 ..
04 08 12 16
05 09 13 17 21
10 14 18 22
.. 15 19 23 ..
.. 20 24 ..
.. .. 25 .. ..

Now, I've been working in an algorithm that can detect the tile where the cursor is, but failed miserably.
I think the problem is I'm storing the tiles in a way that doesn't help at all.
Currently this is what I have:

#SelectExpand
1 for(int i = 0;i < this->total_tiles;i++) // rows 2 { 3 for(int j = this->total_tiles;j >= 0; j--) // columns 4 { 5 6 // ...the rendering part works just fine 7 8 // I guess this is what i'm doing wrong 9 this->tiles[this->current_tile][0] = j; // column 10 this->tiles[this->current_tile][1] = i; // row 11 this->tiles[this->current_tile][2] = 1; // the ID of the image 12 } 13 }

How would you guys do this?

Thomas Fjellstrom
Member #476
June 2000
avatar

I based my design on something I read on one gamedev site that I'm not sure still has the article.

But basically, I had a couple lookup tables. something like the following:

#SelectExpand
1// assuming our tiles are 8x8 pixels 2int tile_map_table[8][8] = { 3 { 1, 1, 1, 0, 0, 2, 2, 2 }, 4 { 1, 1, 0, 0, 0, 0, 2, 2 }, 5 { 1, 0 0, 0, 0, 0, 0, 2 }, 6 { 0, 0, 0, 0, 0, 0, 0, 0 }, 7 { 0, 0, 0, 0, 0, 0, 0, 0 }, 8 { 3, 0, 0, 0, 0, 0, 0, 4 }, 9 { 3, 3, 0, 0, 0, 0, 4, 4 }, 10 { 3, 3, 3, 0, 0, 4, 4, 4 }, 11}; 12 13int tile_loc_map[5][2] = { { 0, 0 }, { -1, -1 }, { 1, -1 }, { -1, 1 }, { 1, 1 } }; 14 15int mouse_x = 100, mouse_y = 100; 16int tile_x = mouse_x / 8; 17int tile_y = mouse_y / 8; 18int loc_tile_x = mouse_x & 7; 19int loc_tile_y = mouse_y & 7; 20int iso_tile_x = tile_x + tile_loc_map[tile_map_table[loc_tile_y][loc_tile_x]][0]; 21int iso_tile_y = tile_y + tile_loc_map[tile_map_table[loc_tile_y][loc_tile_x]][1];

It's something like that anyhow. iso_tile_x and iso_tile_y is the coords of the selected tile.

I'd have pulled out my old iso engine code, but Its all stuck on a backup CD somewhere.

Hope that helps.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Aikei_c
Member #14,871
January 2013
avatar

Another way would be to use transformations.
Edit: I could elaborate further on that if you showed me your tile.
Edit: On wikipedia there is an article on how to do that without transformations: http://en.wikipedia.org/wiki/Video_games_with_isometric_graphics#Mapping_screen_to_world_coordinates

Some_Guy
Member #14,362
June 2012

@Thomas
In your example are you filling the array pixel by pixel?

@Aike
So far I've been working with 32x32 tiles.
Based on what is explained in your link I made this

// tiles are 32x32
// map is 30x30 

int virtualTileX = x / 32;
int virtualTileY = y / 32;

int numberOfTilesInX = 30;

int isoTileX = virtualTileX - (numberOfTilesInX / 2);
int isoTileY = virtualTileX - (numberOfTilesInX / 2);

It doesn't work 100% but the pattern is there.
It just takes as 0,0 the tile #2 in the picture, instead the one in the top corner.

(My map is 30x30, this one is just an example)

{"name":"11392040083_c62b99616a_o.jpg","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/6\/86cd6d81989d9344399b4313512f240b.jpg","w":700,"h":369,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/8\/6\/86cd6d81989d9344399b4313512f240b"}11392040083_c62b99616a_o.jpg

I guess I just need to figure how to make that correction and it will be working.

EDIT: mmm now I check better the 0 in the X axis is not exactly in the middle of the row, but int the tile #13.

Thomas Fjellstrom
Member #476
June 2000
avatar

Some_Guy said:

@Thomas
In your example are you filling the array pixel by pixel?

Yes. tile_map_table is a map of each pixel in a tile to the offset needed to adjust the tile index location.

just doing a division and modulo of the mouse position only works for square tiles. You need to adjust those positions based on where the point is on the diamond shape.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Aikei_c
Member #14,871
January 2013
avatar

If you use 32x32 tiles, they must be just 45 degrees rotated squares, right? In this case you just need to apply rotational transformation.

ALLEGRO_TRANSFORM transform;
al_identity_transform(&transform);
al_rotate_transform(&transform,ALLEGRO_PI/4);

//later
float isox=mousex;
float isoy=mousey;
al_transform_coordinates(&trans,&isox,&isoy);

But that would be pure coordinates, if you need tile coordinates, you would need to divide that by your tile size in isometry, which in your case should be about 22.6272:

int tilex = isox/22.6272;
int tiley = isoy/22.6272;

This should probably work. There might be some inconsistencies since your world coordinate grid and screen coordinate grid do not start at the same point.

Some_Guy
Member #14,362
June 2012

Can you please explain how to do it in A4?

Aikei_c
Member #14,871
January 2013
avatar

I'm not sure, but I believe you do it like this:

float isox = (cos(PI/4)*mousex)+(sin(PI/4)*mousey);
float isoy = (-sin(PI/4)*mousex)+(cos(PI/4)*mousey);

Or you could just use Thomas's method. You do this by just dividing your map into squares by dividing mouse coordinates by tile size (32), in this square one isometric tile is in the center and four others are in the corners. You need to figure out which one is in the center, this will depend on where your coordinate grid starts. And then compare the (mousex/32; mousey/32) with the tile map table. This approach should be less computation intensitive, I think I heared that it mattered in the past but shouldn't matter now.

Ariesnl
Member #2,902
November 2002
avatar

This can be done much easier..
when the mouse ison the map, hide the mouse and enable a special tile selector.
place the tile selector on the tile closest to the mouse.

then move the tile selector according to the delta mouse movement

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

Some_Guy
Member #14,362
June 2012

Ariesnl said:

place the tile selector on the tile closest to the mouse.

Am I missing something or I would be facing exactly the same problem than now? :o

taronĀ 
Member #10,584
January 2009
avatar

http://stackoverflow.com/questions/6915555/how-to-transform-mouse-location-in-isometric-tiling-map

A way to transform coordinates to tile is given here in the accepted answer. I think it may be helpful.

Some_Guy
Member #14,362
June 2012

I don't know what is the problem but nothing seems to work for me.
Tried what your guys suggested plus everything in the first 6 or 7 google pages, I disabled everything cameras related to keep it simpler, but still can't get it working.
I will try to extract the relevant part of the code and post it here.

GullRaDriel
Member #3,861
September 2003
avatar

I use the following function wich works if you give it the right mousemap for your tiles.

#SelectExpand
1/*!\fn ScreenToMap( int mx, int my, int *Tilex,int *Tiley,BITMAP *mousemap) 2 * 3 *\brief Convert screen coordinate to map coordinate 4 * 5 *\param mx The 'x' coordinate in pixel 6 *\param my The 'y' coordinate in pixel 7 *\param Tilex Output for the generated Tilex 8 *\param Tiley Output for the generated Tiley 9 *\param mousemap A mousemap with colors for one tile 10 * 11 *\return TRUE 12 */ 13 14int ScreenToMap( int mx, int my, int *Tilex, int *Tiley, BITMAP *mousemap ) 15 { 16 17 /* SCREEN TO MAP VARIABLES */ 18 int RegionX, RegionY, 19 RegionDX = 0, RegionDY = 0, 20 MouseMapX, MouseMapY, 21 MouseMapWidth, MouseMapHeight, c; 22 23 MouseMapWidth = mousemap -> w; 24 MouseMapHeight = mousemap -> h; 25 26 /* First step find out where we are on the mousemap */ 27 RegionX = ( mx / MouseMapWidth ); 28 RegionY = ( my / MouseMapHeight ) << 1; /* The multiplying by two is very important */ 29 30 31 /* Second Step: Find out WHERE in the mousemap our mouse is, by finding MouseMapX and MouseMapY. */ 32 33 MouseMapX = mx % MouseMapWidth; 34 MouseMapY = my % MouseMapHeight; 35 36 /* third step: Find the color in the mouse map */ 37 c = getpixel( mousemap, MouseMapX, MouseMapY ); 38 39 if ( c == makecol( 255, 0, 0 ) ) { 40 RegionDX = -1; 41 RegionDY = -1; 42 } 43 44 if ( c == makecol( 255, 255, 0 ) ) { 45 RegionDX = 0; 46 RegionDY = -1; 47 } 48 49 if ( c == makecol( 255, 255, 255 ) ) { 50 RegionDX = 0; 51 RegionDY = 0; 52 } 53 54 if ( c == makecol( 0, 255, 0 ) ) { 55 RegionDX = -1; 56 RegionDY = 1; 57 } 58 59 if ( c == makecol( 0, 0, 255 ) ) { 60 RegionDX = 0; 61 RegionDY = 1; 62 } 63 64 *Tilex = ( RegionDX + RegionX ); 65 *Tiley = ( RegionDY + RegionY ); 66 67 68 return TRUE; 69 70 } /* ScreenToMap( ... ) */

Here is some code for drawing the needed mousemap:

#SelectExpand
1/* Drawing the mousemap */ 2 ( *map ) -> mousemap = create_bitmap( ( *map ) -> TILEW , ( *map ) -> TILEH ); 3 ( *map ) -> colortile = create_bitmap( ( *map ) -> TILEW , ( *map ) -> TILEH ); 4 5 clear_to_color( ( *map ) -> mousemap , makecol( 255 , 255 , 255 ) ); 6 clear_to_color( ( *map ) -> colortile , ( *map ) -> bgcolor ); 7 8 /* drawing mousemap */ 9 line( ( *map ) -> mousemap , 0 , ( TILEH >> 1 ) - 2 , ( TILEW >> 1 ) - 3 , 0 , makecol( 255, 0, 0 ) ); 10 floodfill( ( *map ) -> mousemap , 1 , 1 , makecol( 255, 0, 0 ) ); 11 12 line( ( *map ) -> mousemap , ( TILEW >> 1 ) - 3 , TILEH - 1 , 0 , ( TILEH >> 1 ) + 1 , makecol( 0 , 255 , 0 ) ); 13 floodfill( ( *map ) -> mousemap , 1 , TILEH - 2 , makecol( 0, 255, 0 ) ); 14 15 line( ( *map ) -> mousemap , ( TILEW >> 1 ) + 2 , TILEH - 1 , TILEW - 1 , ( TILEH >> 1 ) + 1 , makecol( 0, 0, 255 ) ); 16 floodfill( ( *map ) -> mousemap , TILEW - 2 , TILEH - 1 , makecol( 0, 0, 255 ) ); 17 18 line( ( *map ) -> mousemap , ( TILEW >> 1 ) + 2 , 0 , TILEW - 1 , ( TILEH >> 1 ) - 2 , makecol( 255, 255 , 0 ) ); 19 floodfill( ( *map ) -> mousemap , TILEW - 1 , 0 , makecol( 255, 255, 0 ) );

Please note that you only need to preload mousemap bitmap one time.

In the code when I need to know which tile I'm on, I'm just doing this (considering it also has scrolling):

ScreenToMap( mouse_x - (buffer -> w - mapbuffer -> w ) + ( map->TILEW ) + map->X, 
mouse_y - (buffer -> h - mapbuffer -> h ) + ( map->TILEH >> 1 ) + map->Y, 
&a , &b , map -> mousemap );

I coded this from some gamedev articles:
http://archive.gamedev.net/archive/reference/list56f4.html?categoryid=198

particularly:
http://archive.gamedev.net/archive/reference/articles/article747.html
http://archive.gamedev.net/archive/reference/articles/article748.html

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

Some_Guy
Member #14,362
June 2012

Thank you GullRaDriel, I will try it next, but I would like to show you guys what I have right now.

According http://stackoverflow.com/questions/6915555/how-to-transform-mouse-location-in-isometric-tiling-map/13838164#13838164

Quote:

{"name":"B0TVn.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/c\/b\/cbec5f1fbb7b29c55bcb7d0cf1363225.png","w":390,"h":202,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/c\/b\/cbec5f1fbb7b29c55bcb7d0cf1363225"}B0TVn.png

I rendered the tiles like above.

the sollution is VERY simple!

first thing:

my Tile width and height are both = 32 this means that in isometric view, the width = 32 and height = 16! Mapheight in this case is 5 (max. Y value)

y_iso & x_iso == 0 when y_mouse=MapHeight/tilewidth/2 and x_mouse = 0

when x_mouse +=1, y_iso -=1

so first of all I calculate the "per-pixel transformation"

TileY = ((y_mouse*2)-((MapHeight*tilewidth)/2)+x_mouse)/2;

TileX = x_mouse-TileY;

to find the tile coordinates I just devide both by tilewidth

TileY = TileY/32; TileX = TileX/32;

DONE!! never had any problems!

My code

int r_y = ((mouse_y*2)-((29*32)/2)+mouse_x)/2;
int r_x = mouse_x - r_y;
r_y = (r_y) / 32;
r_x = (r_x) / 32;

My tiles are 32x32 same as in the example, but they don't change the width/height relation.

This is how I'm rendering them (30x30 map)

for(int i = 0;i < this->total_tiles;i++) 
{
    for(int j = 0;j < this->total_tiles;j++) 
    {
        this->tile_x = (j * (this->tile_w / 2)) + (i * (this->tile_w / 2)); 
        this->tile_y = (i * (this->tile_h / 2)) - (j * (this->tile_h / 2)); 
    }

    draw_sprite(this->buffer, this->tile1, this->tile_x, this->tile_y);
}

And this is what I get
{"name":"11411734803_b0a23afc7a_o.jpg","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/4\/54b523d1eae42e58b4f65f4651730062.jpg","w":973,"h":610,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/5\/4\/54b523d1eae42e58b4f65f4651730062"}11411734803_b0a23afc7a_o.jpg

Screen to map conversion isn't working.
At 0,0 gives me 7,-7.

Edgar Reynaldo
Member #8,592
May 2007
avatar

This should not be that hard.

This can be solved with simple linear equations, transformations, and inequalities. First decide where on your map the isometric coordinate (0.0,0.0) is. For arbitrariness's sake make the positive x-axis going up and to the right, and the positive y axis going up and to the left in isometric space.

These coordinates will be known as isomap_world_x, and isomap_world_y in world space. We need to first change from screen space to world space, and then from world space to iso space.

A brief explanation of the method used - first find the equation of the line of the iso x-axis in real space. (y = (H/W)*x). Replace y by the expression (y - N*H) where N is the x coord in iso space and then solve for N. Repeat for the equation of the line of the iso y-axis in real space. Once you have both solved, combine them and then solve for the xy coords from the iso coords.

#SelectExpand
1float mousex = ev.mouse.x; 2float mousey = ev.mouse.y; 3 4// change from screen space to world space 5mousex -= camerax; 6mousey -= cameray; 7 8// Make mouse position relative to iso 0,0 9mousex -= isomap_world_x; 10mousey -= isomap_world_y; 11 12// invert mouse so it matches iso space 13mousey *= -1; 14 15// mouse space is now +y up and +x right, and relative to iso 0,0 16 17// now convert to iso using these formulas : 18mouseisox = mousex/ISO_TILE_WIDTH + mousey/ISO_TILE_HEIGHT; 19mouseisoy = mousey/ISO_TILE_HEIGHT - mousex/ISO_TILE_WIDTH;

The tricky part is converting back from iso to screen space, but easy enough if you figure out the equations for iso space from screen space.

mousex = (ISO_TILE_WIDTH/2.0f)*(isox - isoy);
mousey = (ISO_TILE_HEIGHT/2.0f)*(isox + isoy));

mousey *= -1;

mousex += isomap_world_x;
mousey += isomap_world_y;

mousex += camerax;
mousey += cameray;

I wanted to solve this so bad I made an example proggie. Here ya go!

IsoMap.7z Binary, source, and data. 7-zip (archiver program for 7z files).

Obligatory screenie :
{"name":"608177","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/c\/7c55485273d058cca25e2de1b1af8b16.png","w":812,"h":632,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/c\/7c55485273d058cca25e2de1b1af8b16"}608177

And the full source code :

#SelectExpand
1 2#include <allegro5/allegro.h> 3#include <allegro5/allegro_image.h> 4#include <allegro5/allegro_primitives.h> 5#include <allegro5/allegro_font.h> 6#include <allegro5/allegro_ttf.h> 7 8#include <cstdio> 9#include <cmath> 10#include <exception> 11 12using std::exception; 13///typedef std::exception GameException; 14 15class GameException : public exception { 16 const char* str; 17public : 18 GameException(const char* s) : str(s) {} 19 20 const char* what() {return str;} 21}; 22 23class POINT { 24public : 25 float x; 26 float y; 27 28 POINT() : x(0.0f) , y(0.0f) {} 29 POINT(float xpos , float ypos) : x(xpos) , y(ypos) {} 30 31 POINT& SetPoint(float xpos , float ypos) { 32 x = xpos; 33 y = ypos; 34 return *this; 35 } 36 37 POINT operator-() { 38 POINT r; 39 r.x = -x; 40 r.y = -y; 41 return r; 42 } 43 POINT operator+(POINT& p) { 44 POINT r = *this; 45 r.x += p.x; 46 r.y += p.y; 47 return r; 48 } 49 POINT& operator+=(POINT& p) { 50 *this = *this + p; 51 return *this; 52 } 53 POINT operator-(POINT& p) { 54 POINT r = *this; 55 r.x -= p.x; 56 r.y -= p.y; 57 return r; 58 } 59 POINT& operator-=(POINT& p) { 60 *this = *this - p; 61 return *this; 62 } 63 64 friend bool OnSameTile(POINT p1 , POINT p2); 65}; 66 67bool OnSameTile(POINT p1 , POINT p2) { 68 return ((floor(p1.x) == floor(p2.x)) && (floor(p1.y) == floor(p2.y))); 69} 70 71class IsometricWorld { 72 73private : 74 ALLEGRO_DISPLAY* display; 75 76 ALLEGRO_EVENT_QUEUE* queue; 77 ALLEGRO_TIMER* timer; 78 79 ALLEGRO_FONT* font; 80 81 ALLEGRO_BITMAP* tile1; 82 ALLEGRO_BITMAP* tile2; 83 84 float SCREENWIDTH; 85 float SCREENHEIGHT; 86 87 float NUMTILESWIDE; 88 float NUMTILESTALL; 89 90 float ISOTILEWIDTH; 91 float ISOTILEHEIGHT; 92 93 POINT l,r,t,b,c; 94 95 POINT camPos; 96 POINT isoWorldPos; 97 98 POINT msPos; 99 100 101public : 102 103 IsometricWorld() : 104 display(0), 105 queue(0), 106 timer(0), 107 font(0), 108 tile1(0), 109 tile2(0), 110 SCREENWIDTH(800), 111 SCREENHEIGHT(600), 112 NUMTILESWIDE(4), 113 NUMTILESTALL(4), 114 ISOTILEWIDTH(SCREENWIDTH/NUMTILESWIDE), 115 ISOTILEHEIGHT(SCREENHEIGHT/NUMTILESTALL), 116 l(),r(),t(),b(),c(), 117 camPos(0.0f , 0.0f), 118 isoWorldPos(SCREENWIDTH/2.0f , SCREENHEIGHT) 119 { 120 if (!al_init()) {throw GameException("Failed to initialize allegro 5.");} 121 if (!al_init_image_addon()) {throw GameException("Failed to init image addon.");} 122 if (!al_init_primitives_addon()) {throw GameException("Failed to init primitives addon.");} 123 if (!al_init_font_addon()) {throw GameException("Failed to init font addon.");} 124 if (!al_init_ttf_addon()) {throw GameException("Failed to init ttf addon.");} 125 if (!al_install_keyboard()) {throw GameException("Failed to install keyboard.");} 126 if (!al_install_mouse()) {throw GameException("Failed to install mouse.");} 127 128 al_set_new_display_flags(ALLEGRO_OPENGL | ALLEGRO_WINDOWED); 129 display = al_create_display(SCREENWIDTH , SCREENHEIGHT); 130 131 if (!display) {throw GameException("Failed to create display.");} 132 133 al_clear_to_color(al_map_rgb(0,0,0)); 134 al_flip_display(); 135 136 timer = al_create_timer(1.0/60.0); 137 if (!timer) {throw GameException("Failed to create timer.");} 138 139 queue = al_create_event_queue(); 140 if (!queue) {throw GameException("Failed to create event queue.");} 141 142 al_register_event_source(queue , al_get_display_event_source(display)); 143 al_register_event_source(queue , al_get_keyboard_event_source()); 144 al_register_event_source(queue , al_get_mouse_event_source()); 145 146 font = al_load_ttf_font("verdana.ttf" , 24 , 0); 147 if (!font) {throw GameException("Failed to load font.");} 148 149 tile1 = al_create_bitmap(ISOTILEWIDTH , ISOTILEHEIGHT); 150 tile2 = al_create_bitmap(ISOTILEWIDTH , ISOTILEHEIGHT); 151 152 l.SetPoint(0.0f , ISOTILEHEIGHT/2.0f); 153 r.SetPoint(ISOTILEWIDTH , ISOTILEHEIGHT/2.0f); 154 t.SetPoint(ISOTILEWIDTH/2.0f , 0.0f); 155 b.SetPoint(ISOTILEWIDTH/2.0f , ISOTILEHEIGHT); 156 c.SetPoint(ISOTILEWIDTH/2.0f , ISOTILEHEIGHT/2.0f); 157 158 159 ALLEGRO_COLOR c1 = al_map_rgb(255,192,0); 160 ALLEGRO_COLOR c2 = al_map_rgb(0,64,255); 161 float thickness = 10.0; 162 163 al_set_target_bitmap(tile1); 164 165 al_clear_to_color(al_map_rgba(0,0,0,0)); 166 al_draw_line(l.x , l.y , t.x , t.y , c1 , thickness); 167 al_draw_line(l.x , l.y , b.x , b.y , c1 , thickness); 168 al_draw_line(r.x , r.y , t.x , t.y , c1 , thickness); 169 al_draw_line(r.x , r.y , b.x , b.y , c1 , thickness); 170 171 al_set_target_bitmap(tile2); 172 173 al_clear_to_color(al_map_rgba(0,0,0,0)); 174 al_draw_line(l.x , l.y , t.x , t.y , c1 , thickness); 175 al_draw_line(l.x , l.y , b.x , b.y , c1 , thickness); 176 al_draw_line(r.x , r.y , t.x , t.y , c1 , thickness); 177 al_draw_line(r.x , r.y , b.x , b.y , c1 , thickness); 178 al_draw_filled_triangle(l.x , l.y , t.x , t.y , c.x , c.y , c2); 179 al_draw_filled_triangle(r.x , r.y , t.x , t.y , c.x , c.y , c2); 180 al_draw_filled_triangle(l.x , l.y , b.x , b.y , c.x , c.y , c2); 181 al_draw_filled_triangle(r.x , r.y , b.x , b.y , c.x , c.y , c2); 182 183 al_set_target_bitmap(al_get_backbuffer(display)); 184 } 185 186 void DrawBitmapCenteredOn(ALLEGRO_BITMAP* bmp , POINT p) { 187 p.x -= al_get_bitmap_width(bmp)/2.0f; 188 p.y -= al_get_bitmap_height(bmp)/2.0f; 189 190 al_draw_bitmap(bmp , p.x , p.y , 0); 191 } 192 193 void Run() { 194 al_start_timer(timer); 195 bool redraw = true; 196 197 while(1) { 198 if (redraw) { 199 al_clear_to_color(al_map_rgb(0,0,0)); 200 POINT isoMsPos = ScreenCoordsToIsoCoords(msPos); 201 for (unsigned int tiley = 0 ; tiley < NUMTILESTALL ; ++tiley) { 202 for (unsigned int tilex = 0 ; tilex < NUMTILESWIDE ; ++tilex) { 203 POINT isoPt((float)tilex + 0.5f , (float)tiley + 0.5f); 204 POINT worldPt = IsoCoordsToScreenCoords(isoPt); 205 206 if (OnSameTile(isoPt , isoMsPos)) { 207 DrawBitmapCenteredOn(tile2 , worldPt); 208 } 209 else { 210 DrawBitmapCenteredOn(tile1 , worldPt); 211 } 212 } 213 } 214 215 al_draw_textf(font , al_map_rgb(255,255,255) , 10 , 10 , 0 , " msPos = %3.1f , %3.1f" , msPos.x , msPos.y); 216 al_draw_textf(font , al_map_rgb(255,255,255) , 10 , 50 , 0 , "isoMsPos = %3.1f , %3.1f" , isoMsPos.x , isoMsPos.y); 217 218 al_flip_display(); 219 redraw = false; 220 } 221 222 do { 223 ALLEGRO_EVENT ev; 224 al_wait_for_event(queue , &ev); 225 if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {return;} 226 227 if (ev.type == ALLEGRO_EVENT_MOUSE_AXES) { 228 msPos.SetPoint(ev.mouse.x , ev.mouse.y); 229 redraw = true; 230 } 231 else if (ev.type == ALLEGRO_EVENT_TIMER) { 232 redraw = true; 233 } 234 235 236 if (ev.type == ALLEGRO_EVENT_KEY_DOWN) { 237 if (ev.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {return;} 238 switch (ev.keyboard.keycode) { 239 case ALLEGRO_KEY_UP : 240 241 break; 242 case ALLEGRO_KEY_DOWN : 243 244 break; 245 case ALLEGRO_KEY_LEFT : 246 247 break; 248 case ALLEGRO_KEY_RIGHT : 249 250 break; 251 default : 252 253 break; 254 } 255 } 256 257 } while (!al_is_event_queue_empty(queue)); 258 } 259 } 260 261/// POINT ScreenCoordsToIsoCoords(POINT p); 262/// POINT IsoCoordsToScreenCoords(POINT p); 263 POINT ScreenCoordsToIsoCoords(POINT scr) { 264 scr -= isoWorldPos; 265 scr.y = -scr.y; 266 POINT iso; 267 iso.x = scr.x/ISOTILEWIDTH + scr.y/ISOTILEHEIGHT; 268 iso.y = scr.y/ISOTILEHEIGHT - scr.x/ISOTILEWIDTH; 269 return iso; 270 } 271 POINT IsoCoordsToScreenCoords(POINT iso) { 272 POINT scr; 273 scr.x = (ISOTILEWIDTH/2.0f)*(iso.x - iso.y); 274 scr.y = (ISOTILEHEIGHT/2.0f)*(iso.x + iso.y); 275 scr.y = -scr.y; 276 scr += isoWorldPos; 277 return scr; 278 } 279}; 280 281int main(int argc , char** argv) { 282 IsometricWorld* world = 0; 283 284 try { 285 world = new IsometricWorld(); 286 world->Run(); 287 } 288 catch (GameException e) { 289 printf("Error - %s\n" , e.what()); 290 } 291 292 return 0; 293}

Aikei_c
Member #14,871
January 2013
avatar

Some_Guy said:

At 0,0 gives me 7,-7.

Well, judging from the picture, (0,0) on the screen does seem likely to be at (7; -7) in isometry...
If you draw it like this:

    for(int j = 0;j < this->total_tiles;j++) 
    {
        this->tile_x = (j * (this->tile_w / 2)) + (i * (this->tile_w / 2)); 
        this->tile_y = (i * (this->tile_h / 2)) - (j * (this->tile_h / 2)) - this->tile_h/2; 
    }

(0; 0) should show (0; 0) for you...

Some_Guy
Member #14,362
June 2012

@Edgar, Thank you! Will check it with more time tonight.

@Aikei_c thanks but it still gives me 7,-7

Edgar Reynaldo
Member #8,592
May 2007
avatar

I cleaned it up a bit and changed the dimensions and added in a camera with the arrow buttons.

Here's an updated exe and src (Needs the data and dlls from the earlier attachment)

Here's an updated exe and src (Needs the data and dlls from the earlier attachment)

{"name":"608181","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/1\/71cf32f7b6d8da2604b3d5371e28862d.png","w":812,"h":632,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/1\/71cf32f7b6d8da2604b3d5371e28862d"}608181

Some_Guy
Member #14,362
June 2012

Edgar, the problem is your code is A5 and mine A4, thank you anyway.

I give up for now, eventually I will start everything from scratch in A5

Thanks everyone.

taronĀ 
Member #10,584
January 2009
avatar

The logic should still remain the same, doesn't matter if it's allegro 4 or 5. Regardless, going with allegro 5 instead of 4 is a good idea.

Edgar Reynaldo
Member #8,592
May 2007
avatar

The formulas and conversion are the same. I never meant to suggest you had to switch to A5. Don't you already have something working in A4? Feel free to continue it.

I really only wrote the demo to demonstrate that my system works.

Aikei_c
Member #14,871
January 2013
avatar

I'm afraid you must be trying to just paste our code into your project, while you need to understand what is going on under the hood. Try to understand what people here told you, maybe do some drawings (and calculations) on paper to help you understand what's going on. That will be so much better than just taking someone else's code literally and hoping it's gonna work.

Some_Guy
Member #14,362
June 2012

Aikei_c said:

I'm afraid you must be trying to just paste our code into your project, while you need to understand what is going on under the hood. Try to understand what people here told you, maybe do some drawings (and calculations) on paper to help you understand what's going on. That will be so much better than just taking someone else's code literally and hoping it's gonna work.

It's exactly the other way around, I don't have any interest on get the code working without understand its logic.
Otherwise I would take Edgar's code and start my project from there.

Edgar Reynaldo
Member #8,592
May 2007
avatar

One thing I didn't say is that you could probably realign 0,0 on the map to be in the top middle. You would have to redo the calculations a bit but then you wouldn't have to invert the y.

What part are you having trouble with? Here are the formulas again, for reference. (This is after having aligned with 0,0 on your iso map).

<math>isox = \frac{x}{w} + \frac{y}{h}</math>
<math>isoy = \frac{y}{h} - \frac{x}{w}</math>

<math>x = \frac{w}{2}*(isox - isoy)</math>
<math>y = \frac{h}{2}*(isox + isoy)</math>

Some_Guy
Member #14,362
June 2012

Edgar, there is something else besides a map positioning / camera issue.
Even when I tried a lot of different approach the isometric numbers never match with the amount of tiles per row/column.
Got busy with something else right now, but when I have some time I will start it from scratch in A5, then I will look again at your code and will let you know.

Thank you.

Go to: