![]() |
|
Isometric Graphics |
Neil Roy
Member #2,229
April 2002
![]() |
I'm sitting here doing some more work on isometrics, which is still relatively new to me. I've done 3D and lots of 2D, just never Isometrics. As long as I can recall I have always read you need a mouse map when it comes to selecting a tile with your mouse so you know which tile you are clicking on. Well, I found some nice code on selecting isometric tiles without using a mouse map so after some of my own adjustments to it, I thought I would share what I have here. // get the map x & y positions // Note: with these calculations you don't need a colour mouse map! tile_mx = (int)((((float)mouse_y + (float)scroll_y) / (float)TILE_Y) + (((float)mouse_x + (float)scroll_x) - ((float)MAPSIZE * (float)TILE_X/2)) / (float)TILE_X); tile_my = (int)((((float)mouse_y + (float)scroll_y) / (float)TILE_Y) - (((float)mouse_x + (float)scroll_x) - ((float)MAPSIZE * (float)TILE_X/2)) / (float)TILE_X); I have a lot of (float)'s in there because it is very important that the calculation's floating point precision is retained before it is finally converted to an int. Here's an explanation of the variables: And a screenshot of my editor as it is so far (the hilltops are brown because I plan to add in more layers later on, not added yet): And for completeness sake, here's code for plotting your tiles on screen: screen_x = (iso_x - iso_y + MAPSIZE) * (TILE_X / 2); screen_y = (iso_x + iso_y) * (TILE_Y / 2); iso_x & iso_y being the isometric map co-ordinates, top most position being 0,0 for example. if you have a large scrolling map, I would add scroll_x and scroll_y to screen_x and screen_y respectively. --- |
GullRaDriel
Member #3,861
September 2003
![]() |
Interesting. Does the selection works fine on all the layers ? (I mean also on tile that are higher than the basic floor) "Code is like shit - it only smells if it is not yours" |
Neil Roy
Member #2,229
April 2002
![]() |
I haven't added layers yet, but I can't see why not, you just need to adjust for the vertical offset, should be simple enough. WHat I will probably do is just check for where on the grid you have clicked (on the base layer), then check the height of that layer and simply select the top most tile. For my layering I plan to have each tile have a height, rather that separate maps for each layer, this will make it more flexible with less wasted space. Something like: map[y][x].height Only the top most tile will matter the way I am doing it. If you need to have separate tiles on the same location at differing heights I would just add a linked list with all the tiles at that location. Edit: Of course, for editing layers, I would probably have an option to only show one specific layer, or hide all layers above a certain point, especially if you have layers sandwiched between others. Edit2: An additional note about my editor. I started out using PNGs with Allegro 4.4 and man alive were they slow to draw! At least with transparency. I ended up switching back to magic pink BMPs. The frame rate with the screen full of map was 9FPS with PNGs, as you can see in t his screenshot it's well over 200... I guess I'll save using PNGs for allegro 5. --- |
Slartibartfast
Member #8,789
June 2007
![]() |
I'm not really sure how to explain it, but your solution won't work when you add variable heights to your tiles because you can't know in advance what the height of the tile will be. For example, a tile in (x,y,z) = (0,0,0) and a tile in (x,y,z)=(1,1,2) should be drawn in exactly the same space on the screen, the same for (2,2,4) and (3,3,6). (it might be different numbers depending on how exactly your solution works, but nevermind that.) EDIT: Yeah, alpha blending in A4 is incredibly slow. Just switch to A5 ---- |
Neil Roy
Member #2,229
April 2002
![]() |
Sure it will work, it is working for me now. I select that tile, get the height of it, adjust the selector image I draw to indicate which tile I am pointing at and voila. This is a selection issue, the tiles all still have the same base location, when you select them, you're selecting that grid location no matter what the height is. getting the height of the tile and adjusting the actual drawing of the selector on it is trivial. I'll just have to add layers in (which I am planning on anyhow) and post the program when done. Edit: At this time my map is scroll-able as well, in the image above it is a 50x50 map, fairly large with 64x32 tiles. A layer above is no different than scrolling up whatever the offset is. And currently I scroll all over and have no problems selecting a tile, I just add in the offset to the calculation for the scrolling. It's no different for layers, just add in a vertical offset for the layer's height and select away. How else would you select these tiles with a colour map? You still need to account for a vertical offset before you can select a grid location and then use the colour tile to see how much you need to adjust for, there is no difference, you need to offset for the layer then use the math to get the co-ordinates, you're just replacing a colour image with calculations. Edit2: I think I see what you are talking about though. Selecting a high layer's tile just by pointing at the map could be difficult, but it is the same no matter what method you use, colour map or the above calculations. If you use a colour map, you'll still end up pointing at a grid location of say a tile higher than what you wish, how do you determine the layer you're pointing at seems to me to be the same problem for both methods. All I can think of is checking the layers for the surrounding tiles, but as I said, this is a problem to consider no matter which method you use. --- |
Slartibartfast
Member #8,789
June 2007
![]() |
Lets put it like this, I have a tile in (0,0,0), it is drawn on the screen in coordinate (300,0). What happens when I click (300,1), do I get the tile in (0,0,0) or the tile in (3,3,6)? ---- |
Neil Roy
Member #2,229
April 2002
![]() |
I see that problem, but I don't see how using a coloured tile makes any difference, the problem is the same, and I haven't tackled it yet. In each case you need to determine if what you're pointing at is a higher level or not. Of course, you could simply edit by layer which is what I had in mind as well. IN either case, you have the same problem as with colour tiles or the calculations. I am new to isometrics so I haven't dealt with layers much yet, but this is an interesting discussion and I thank you for bring it up, I'll look into this and see what I can find. I was thinking about checking surrounding tiles to see what their heights were though, I guess you would only have to check the tiles immediately south of where you are pointing at. I wonder if you kept a separate index of tiles that are drawn on a certain point? hmmm..... Note: on my map a tile would never go from being at a height of 0 on one tile to being at a height of 6 on the next one down. Tiles would only be one layer difference at most the way I am doing things, but still, it's an interesting problem no matter how you do selecting. --- |
Slartibartfast
Member #8,789
June 2007
![]() |
Here's how it works: ---- |
Neil Roy
Member #2,229
April 2002
![]() |
I'm curious how games like Transport Tycoon and Simcity 2000 solved this? You can have some pretty high hills on both these games and even larger maps. I am thinking that a separate bitmap could end up eating a lot of memory for these really huge maps. I know Transport Tycoon (renamed "Locomotion") has maps that are about 400 square, Simcity 2000 is around 256 square I think, something like that, in either case, some pretty big maps. I know in my game, which will use the same style maps as these two games the heights between tiles won't be greater than 1, so if you select a tile, you should only need to check the tile you think you are on, then check the tile to the north and south of it to see if there is a height difference. But I can't foresee much of a problem now that I think of it. We'll see. I'm reallu anxious to add in layers now. You have an interesting solution though, I just wonder how effective it will be for really large maps... --- |
Slartibartfast
Member #8,789
June 2007
![]() |
You have two possible approaches: ---- |
Neil Roy
Member #2,229
April 2002
![]() |
Perhaps a scaled down version of the larger tiles? If the tiles are 64x32 as mine are, they could be scaled down to 16x8 or so, even half size would work, then just apply the same algorithm for selecting to the smaller tiles which you would use to colourize for the height selection.... Edit: Seeing as how I am still new to Isometrics and I am not finding ANY tutorials online about selecting tiles at really high heights, I'll just stick to 1 layer above the ground like I have now. I think I may create a seperate project just to experiment with this problem and see what I can come up with. Your ideas about colour maps is a good one, but I am not convinced that's the best idea. I am determined to find out how games like SimCity 2000 did it. When I tested that game it runs extremely fast, scrolling etc... but that may be just due to it using 8bit graphics too. I should check on how much RAM it uses and see if perhaps they use something like what you suggested... Edit2: I found an interesting document on the SimCity2000 file format. It doesn't answer my question about how they select tiles, but it is interesting how data is organized and the info contained in a SC2000 level. --- |
Hyena_
Member #8,852
July 2007
![]() |
I'm thinking of an isometric view too for the world map.. However, I'm thinking of fake-isometrics instead of the one you are discussing here. By fake I mean using rectangular coordinates as a normal 2d game would use but tiles are 16*8. I guess diablo 2 uses that method. 1 rectangle contains 4 triangles.
|
J-Gamer
Member #12,491
January 2011
![]() |
@Neil Roy: for some reason or another, I can't seem to be able to click the link... " There are plenty of wonderful ideas in The Bible, but God isn't one of them." - Derezo |
Neil Roy
Member #2,229
April 2002
![]() |
@J-Gamer: Sorry, typo, I corrected it. @Hyena: It seems to me that this could have more problems than a normal isometric view. In a normal isometric map you're basically just rotating a square map 45 degrees, but figuring out the grid location is just about the same. One note about Diablo levels, they don't have the problems with height because Diablo levels are flat, they don't have any height at all, you won't see a hill in Diablo, go ahead and look. I have considered not even bothering to worry about having hills in my game as most of the really successful games I have noticed have been flat isometric games, they get away with this by having a lot more detail in their game so you're so busy admiring how nice it all looks you don't even notice how flat everything is. I may just stick to a flat map with small hills like I posted, there isn't really any big need for large hills anyhow when I start thinking about it. It's certainly not something I wish to stress over. Edit: If anyone's curious, here's what I have created so far: isomed.zip {"name":"604028","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/4\/9\/493bc326fe32f4666ba1e467e44e9506.png","w":800,"h":600,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/4\/9\/493bc326fe32f4666ba1e467e44e9506"} it's fairly basic at the moment, you scroll the map around with your cursor keys, left clicking and dragging around the terrain defaults to "drawing hills", right click flattens them again. Road drawing mode is similar, just left and and drag your mouse around the terrain to draw roads, it will automatically connect up the roads similar to the way Simcity 2000 does it. Right clicking will erase roads and automatically "disconnect" adjacent roads. I haven't added in code to put roads on top of the hills yet, you can put one on the side of a hill. I'll get to that next. The map is currently 50x50, although it can be any size, this is just one I made up for now. I want to make all this configurable from a menu in the future. --- |
Hyena_
Member #8,852
July 2007
![]() |
I hope you've looked that page too: http://www.yarrcade.com/2010/09/19/terrain-modificatio-in-grid-based-games-part-1-isometric-landscape/ Yesterday I checked it out.. It is cool but if you start seeing the flaws of this system, it doesn't seem to fit so well to your game. Even when bitmap texture is blitted on the isometric tiles of different angles. However, I downloaded your zip because I am building a random world generator based on random noise -> heightmap conversion and I was looking for a system to display my results. Age of empires and red alert 2 used your system but still you don't see many hills in these games for some reason. In the other hand, games like Settlers use a lot of hills and they are totally cool looking there: So I personally am very tempted to try out the settlers' hexagonal landscape just because it looks a lot more realistic than all the isometric ones. I guess it's the case of choosing a right system for a right kind of a game EDIT: EDIT2: {"name":"604044","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/e\/e\/eeaed3eea3ba6f8a4d4150b4a42b23c2.jpg","w":806,"h":625,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/e\/e\/eeaed3eea3ba6f8a4d4150b4a42b23c2"}
|
Neil Roy
Member #2,229
April 2002
![]() |
That interesting because I was playing Locomotion (newer version of Transport Tycoon for Windows) and I noticed they had an option to toggle gradients on/off to "smooth" out the edges and that got me to thinking about trying that myself. I also want to redo my graphics so there aren't grid lines and make them something you can toggle on/off. I'll also probably redo my roads so they're done more the way Locomotion does theirs. I', also thinking about making the tiles so that they are higher when you raise them, but I'm not certain about that yet. I'm thinking about just allowing the hills to be only a couple layers high, they don't really need to be too high anyhow. I had noticed that the tops of hills being the same shade as the land really took away from the look of them being higher, I may just program it to have lighter colours for height, not sure how I will implement this yet, but it does look nicer, now that you have done something up, I really like the looks of that. Add in some trees, brush, real looking grass etc... and it could get quite nice looking I think. I originally had the editor so you clicked on a tile, then places it, but when trying to make large maps this got VERY tedious so I looking into ways to automate the process so you could just draw them. What I do is have the tiles organized so the corners of the tiles are like a binary... 1 8/\2 \/ 4 The main base tile is tile #0, zero meaning no corners are raised. If the top corner is raised, it is tile #1, the right corner, it is #2, if the top and right are raise, you guessed it, #3 (1 + 2). Etc... this way, when I raise a tile up by left clicking it, obviously all 4 corners are raise, all I need to do is take the value of the surrounding tiles and logically OR them with the corner that gets raised, so if I click a tile, the tile above it (Y-1, X-1) has the southern most corner raised up to match, so I take the value of that tile, OR it with 4, and the result is the new tile# that goes there, this makes it really simple to raise all the surrounding tiles up and make a hill. The code to do that is very simple: I check to make sure the tile the mouse is over is greater than zero (I set tile_mx and tile_my, the tile the mouse is pointing at to -1 if it is pointing off the border of the map). Tile #15 is all four corners raised as you may have guessed. I want to change that part of this so it instead sets the "height" of that map tile. The rest of this simply checks to make sure it stays within bounds (less than MAPSIZE, greater than zero) and then ORs it with the appropriate number for the corners effected. Road tile pieces are all greater than 19, which is why it returns if the tile # is >19. And of coure, lowering the terrain is similar, you lower the main tile (set it to zero) then logically AND all the surrounding tiles so the connected corners are all lowered, which leads to the proper tile #s being drawn. I do something similar for the roads as well, except with them I call a recursive function which adjusts surrounding roads so they automatically connect up. The road pieces are organized in a "binary" fashion like the terrain. I may redo the tiles so that they are all WATER at the base location, and you raise up LAND when you click, so you see islands when you click, otherwise it's all water when you start. 1void raise_terrain()
2{
3 if(tile_mx>=0 && tile_my>=0) {
4 if(map[tile_my][tile_mx]>19) return; // don't touch terrain with roads... yet
5 map[tile_my][tile_mx]= 15;
6 if((tile_my-1>=0 && tile_mx-1>=0) && (map[tile_my-1][tile_mx-1]<20))
7 map[tile_my-1][tile_mx-1] |= 4;
8 if((tile_mx-1>=0) && (map[tile_my][tile_mx-1]<20))
9 map[tile_my][tile_mx-1] |= 6;
10 if((tile_my-1>=0) && (map[tile_my-1][tile_mx]<20))
11 map[tile_my-1][tile_mx] |= 12;
12 if((tile_mx+1<MAPSIZE) && (map[tile_my][tile_mx+1]<20))
13 map[tile_my][tile_mx+1] |= 9;
14 if((tile_my+1<MAPSIZE) && (map[tile_my+1][tile_mx]<20))
15 map[tile_my+1][tile_mx] |= 3;
16 if((tile_my+1<MAPSIZE && tile_mx-1>=0) && (map[tile_my+1][tile_mx-1]<20))
17 map[tile_my+1][tile_mx-1] |= 2;
18 if((tile_my-1>=0 && tile_mx+1<MAPSIZE) && (map[tile_my-1][tile_mx+1]<20))
19 map[tile_my-1][tile_mx+1] |= 8;
20 if((tile_my+1<MAPSIZE && tile_mx+1<MAPSIZE) && (map[tile_my+1][tile_mx+1]<20))
21 map[tile_my+1][tile_mx+1] |=1;
22 }
23}
That could probably be improved, but it's just my first draft of that function, I don't like all those "if"s in there, but... --- |
Arthur Kalliokoski
Second in Command
February 2005
![]() |
Hyena_ said: EDIT2: It just looks like normals to the light source to me. Height doesn't matter, just the angle. They all watch too much MSNBC... they get ideas. |
Neil Roy
Member #2,229
April 2002
![]() |
Oh I seen what you meant. My scenes are lit by the game though, could be interesting to try though. Edit: While looking over some other websites a possible solution came to me with regard to selecting tiles that are several layers high. Once you select a tile, you could then compare where it is drawn on screen with where the mouse is pointing, then maybe do some maths on the distance and esimate how many tiles "south" of where the program selected you are actually pointing, perhaps "walking" one tile at a time until you get the correct one. Or in the case of valleys, walk north. I guess you would test one tile to the south, one to the north, whichever brings you closer you would continue to "walk" in that direction until you get the correct grid location... I'll have to play around with this idea, I was going to not bother with higher terrain, but it bugs me too much to just drop it like that. Edit: Upon further reflection, I have come up with a better solution that I think will work (I don't think the above solution will). I based it off of the ray casting concept where you draw a line from the viewer into the scene and see what it intersects with. Well, with isometrics the best way I could come up with that is similar would be to start a fixed number of tiles below the mouse position, then test that location to see if the tile position matches. If not, then move one tile north and test it again. Keep doing this while the top of the tile being tested is below the mouse_y position. Once the top of the tile is above the mouse_y than you have the right tile. If you start at the bottom of the map and work your way up, you will always get the right tile. The number of tiles you start below the mouse position will depend on the maximum height of the hills on your map. You could of course start at the very bottom of the map, but this would probably just waste time. If you have really large maps like I have, you could also just start at the bottom of the visible map. --- |
|