Methods for 3D tilemaps

Monkey Forums/Monkey Programming/Methods for 3D tilemaps

QWeb(Posted 2016) [#1]
Hi,

I'm considering building a fairly retro-feeling 3D tilemap game. The character and NPC's will be sprites, the ground will be a tile, walls will be flat textures between the tiles, and objects will ideally be 3D...

I'm not fussed for fancy lighting or perspective. An isometric layout would actually be quite cool, except that I want 360deg camera rotation which obviously isn't possible with traditional isometrics. Not fussed either for zoom ability, just left/right camera rotation would be perfect.

For anybody who played the original Runescape, that's basically the result I'm looking for.

I was considering the MiniB3D module for this as B3D's terrain commands would, I think, be perfect but a) it looks like this isn't yet in the MiniB3D module, b) it looks like the module isn't maintained much any more, c) I'm worried this would actually be overkill for lower end devices, and d) I'm not actually sure if this would give enough per-tile control to set the walls up etc.

I've also been looking at the Mojo graphics functions, particularly DrawImageRect which incorporates height and rotation values... Perhaps drawing a vertically squashed, rotated tile would work, using pseudo-camera-angle based math to position all of the tiles around each other. This wouldn't give any level of perspective though (again, I'm not too fussed about that) and if I'm simply using rotated images I wouldn't be able to have hills in the grid, which would be a shame. This also wouldn't work for the walls.

To the point, does anybody have thoughts as to where I should be concentrating my thoughts here? What would the "proper" method for this kind of a set-up be? Not much is set in stone in terms of the game itself, so I'm totally open to "This would work but you'd have to ditch idea X" type thoughts.

If it makes any difference, initially (and potentially indefinitely) the target will be HTML5. I'd like to support mobile eventually, but if nothing else I could just wrap the resulting HTML5 in a Phonegap app for that.

All comments much appreciated.


Gerry Quinn(Posted 2016) [#2]
If you want 360 degrees rotation, you need 3D. Simple as that. If you are organising everything isometrically, the 3D library can probably be as primitive as you like, though. Even a non-maintained one would probably do so long as the camera stays working.

Pure isometric 2D graphics can only give you a 4-perspective view (like many old games from c.1990 - retro is an option here). Trying to rotate or shear graphics will just look ugly.


QWeb(Posted 2016) [#3]
Thanks Gerry,

Since posting the above, I've actually been tinkering with isometrics. I'd still prefer proper 3D rotation, but this approach actually feels quite cool too. I'm beginning to see the advantages.

If I decide to scrap this approach and go for 3D after all, would you have any recommendations? It seems MiniB3D hasn't been updated for some time and isn't a complete representation of the original B3D commands, which is a shame.

If I stick with isometrics, my current issue is that the scale params of DrawImage don't appear to work as I originally expected. The scale seems to happen before the rotation so rather than a 45deg rotated square being squashed vertically into a diamond, I'm seeing a square squashed vertically into a rectangle and then rotated... I assume there's a method for instead rotating and outputting into a canvas of some sort, which can then be squashed vertically and drawn to the screen, but I'm having a hard time finding any kind of functionality for this in the documentation... actually I'm having a hard time finding much at all in the documentation if I'm totally honest... The language seems powerful but the explanations of it aren't much good :-/


Gerry Quinn(Posted 2016) [#4]
Word of God is here - read Mark's post in:

http://www.monkey-x.com/Community/posts.php?topic=2412

I figured out where to put in Shear once, but I can't remember right now... anyway, as I said shearing etc. is of very limited use.

You're right about the docs, but a google search for discussions in these forums will help you out with most things!


bitJericho(Posted 2016) [#5]
Isometric graphics are usually just drawn in isometric style. You can see my Tiled map editor library showing off isometric maps in Monkey out of the box.

https://github.com/bitJericho/bit.tiled

This library and map editor would also be fine for 3d grid maps too, depending on how you wanted to render it.


QWeb(Posted 2016) [#6]
Crazy week - finding the time for this isn't easy!

Since my above post, I did temporarily give up on the idea of automatically generating the rotated tiles, and got a crude isometrics map working that renders with the tile corresponding to the players location in the center of the screen, + moving the player x/y does adjust the map render appropriately, however my math was trial and error and now that it's working, I'm not totally sure why! Most frustratingly, x appears to be reversed so my array of tiles when rendered as an isometric results in a flipped map, so while this first attempt does work, I'm wanting to start again and try to make this more logically.

Code: http://pastebin.com/27JhymHF
Files: http://development.qweb.co.uk/isometric-test/isometric-test.zip

If you download the files + run, you'll see the array has a vertical path running down the left hand side of the map, but when rendered this runs down the right hand side. Additionally, increasing player X moves the map further away instead of further towards. Technically working, just not in the direction that makes sense to me. I'd expect 0,0 to be the top left of my array, not the top right.

I could work with this, in theory, but in practice getting things like pathfinding and converting player clicks on a 2D x/y screen into map tile co-ordinates is going to be hugely difficult with a reversed map! Also, as above what I'm really wanting to do is have the code take a single, large image and slice it up into tiles by itself, but for this I need to be able to rotate and then scale each tile, rather than using pre-rendered rotated tile images. If I use the rotate and scale params of DrawImage() though, the scale seems to happen first so the result isn't useful. Gerry, I had a look over the post you linked to but this didn't make much sense to me I'm afraid...

Any tips as to where I'm going wrong here, i.e. why the map is reversing, would be appreciated. And any examples for rotating and then scaling an image would be even more appreciated.


QWeb(Posted 2016) [#7]
Oh, and also if you run the above you'll notice there's a faint gap between the tiles, which isn't intentional. My tile images are 128x128 and I'm rendering them 128x128 apart, so I'm not sure what's going on here. I'm hoping it's because of the aliasing in the images themselves and that rotating + scaling in code would give a more seamless result?

My thought, basically, is that if I can make this work from a single top-down image, I can then have our designers draw something really nice for a ground texture without having to use any special map editor software. Then we can pre-render vegetation graphics to sit on top of specific tiles, using a second array, which should give some depth to the ground without anything fancy having to be coded in. This method would mean we have individually handled tiles but not the conventional repetitive render that a tilemap usually results in. The map itself could be broken into blocks so that the entire world doesn't need loading as I can see this being a fairly big strain on device memory, but we can cross that bridge later...


Gerry Quinn(Posted 2016) [#8]
"Also, as above what I'm really wanting to do is have the code take a single, large image and slice it up into tiles by itself, but for this I need to be able to rotate and then scale each tile, rather than using pre-rendered rotated tile images."

You can use GrabImage to split an image into lots of tile images with handles in the centre - that's probably closest to what you want. Remember your map coordinates will have to scale as well as the objects.

I would guess the lines are indeed probably due to antialiasing, two partially transparent edges on top of each other won't add up to the original colour, I don't have much expertise with such things, but making images a little larger has worked for me at times. Maybe a background of the approximate colour or similar tricks would work too. It's also possible that padding of some kind is needed, i.e. you might not be able to get the right results simply by chopping up an image and rotating square sections that have no transparent edges. In short, I don;t know, and probably different ways of doing things need different tricks.

As for the geometry, there's no choice but to get it right, whether by trial and error, design, or a combination of both, Mark's page describes how the code works. Maybe there are some isometric examples you could look at - even if you can't find them in Monkey there are probably tutorials on the web using other languages, and the principles will be the same.


QWeb(Posted 2016) [#9]
Thanks Gerry.

Your last comment ref the principles being the same as with other languages is spot on. I should really stop looking for Monkey-x specific examples and just look for the math. I suppose at the end of the day, that's what I really need some guidance with here and that's what's currently causing the flipped map, not any specific code use.

As soon as I get chance to play around with GrabImage I will do, thanks for this also. I'd noticed it in the docs but must confess I've not tinkered yet.