Isometric mouse troubles in HTML5 Canvas.

Started by Nine Toes, Thu 08/12/2011 06:27:46

Previous topic - Next topic

Nine Toes

I haven't been back here in a while.  I've been working on this little toy of mine off and on for a few months, and I've finally become kind of frustrated with it.  So, I've returned hoping I could get some more good advice from my old, favorite forum.

I've built an isometric field of tiles using HTML5's canvas.  I won't say I built it all by myself, I had to take some hints from a few different sources - namely, some of the calculation algorithms.  The whole project is a mixture of nostalgia and a desire to understand how isometric games work.

http://www.geiertech.com/etc/isometric/phase_3/

So far, it's working just fine (albeit, a little choppy or sluggish).  The only problem I'm having with it is the translation of the mouse coordinates to map coordinates.  The mouse cursor is drawn on the map, and it does move with the mouse.  But if you click the link and look, you'll see (and mind you, you'll have to keep the mouse arrow over towards the left half of the screen so you can see the tile cursor being drawn on the map) that there is a large gap between the mouse arrow and the tile cursor.

The value missing, I'm positive, is the offset value of the map:
Code: ags

var $Map = {
	offset: [0,0]
}


This value is being set as the distance from the 0,0 coordinates of the canvas to the 0,0 coordinates of the map.

Now, you have the mouse coordinates, which are taken directly from the browser, and any borders, margins, or padding of the page or canvas are subtracted.  Below are the calculations I'm currently using to calculate the map coordinates, in psuedocode:
Code: ags

MapX = Round(((MouseY - (TileH / 2)) / TileH) - ((MouseX - (TileW / 2)) / TileW));
MapY = Round(((MouseY - (TileH / 2)) / TileH) + ((MouseX - (TileW / 2)) / TileW));


I've tried adding/subtracting the offset values in various combinations to the above equations, but it always seems to end up throwing the tile cursor position way off in the Delta Quadrant.

If you need to for whatever reason, here are some key controls:
PgUp = zoom in
PgDn = zoom out
Home = reset zoom to default
X = toggle wireframe mode
Arrow keys = move the map in whichever direction by 1px

You can move the map by left-clicking and dragging.  Click the mouse wheel to center again.

I thought I could get this to work on my own, but I'm ready for some suggestions.  So, any ideas about how to make both cursors line up?
Watch, I just killed this topic...

fred

#1
I found this article about isometric projection, which solves the problem with a slightly different formula:

Code: ags
tile_x = (pixel_x/(tile_w/2) + pixel_y/(tile_h/2)) / 2
tile_y = (pixel_y/(tile_h/2) - pixel_x/(tile_w/2)) / 2


Hope it helps - and good job on the demo so far! Are you going to make a full game out of it? Btw. there's also Construct2, which I've been using for rapid game prototyping in HTML5. Not that it deals specifically with isometric projections, afaik.

Khris

#2
Right now, moving the mouse to 0,0 screen puts the cursor at 0,0 map.
The arbitrary offset you have introduced is the position of the map's top left corner in relation to the screen.

So all you need to do is subtract the screen coordinates of 0,0 map from the mouse coordinates before inserting them into the formula to get the map cursor coordinates. This will essentially move the mouse to the right and down, right over the map cursor.

InCreator

Are you sure your XY didn't get swapped at some point?

Nine Toes

Thank you, all of you, for your input and advice.

It took me a while, but I finally figured it out.  Khris' advice was what I was looking for.  The equation now looks like this:
Code: ags

MapX = Round(((MouseY - OffsetY) - TileH / 2) / TileH) - ((MouseX - OffsetX) - TileW / 2)) / TileW));
MapY = Round(((MouseY - OffsetY) - TileH / 2) / TileH) + ((MouseX - OffsetX) - TileW / 2)) / TileW));

I swore I had tried countless combinations with the offset coordinates added/subtracted, but I finally found something that worked.

http://www.geiertech.com/etc/isometric/phase_3/index.php It's purty, isn't it? :D

And, Increator:  Yeah, I think I probably did somewhere, now that you mention it.  I've been looking but I haven't found where just yet.
Watch, I just killed this topic...

Construed

I felt sorry for myself because I had no shoes.
Then I met the man with no feet.

Eigen

#6
If you ever want to implement anything other than a flat isometric ground, then take a look at this rather old article (the example code is messed up but it's not really needed anyway)

What you should be interested in is this .. for the basic flat ground at least:


Basically when you click on the map, you find the first tile thats bounding box (box should be as large as this image is compared to the white part) contains the mouse coordinates, there may be many but any will do. Let's say you clicked a tile in 7-th column and 3-rd row (7,3).

Then imagine you draw this image on the map, over the tile, so that the white area is exactly where the graphical tile is. (You don't need to draw it)

Then you translate the mouse coordinates to bounding box, so that the top-left corner would be (0,0) and so on. Then you check the color of the pixel at that coordinate. Eg. if it's yellow, then in your case you subtract one from column and you get (6,3), which is the actual tile you clicked. If the color is pink, then you add one row and you get (7,4) which is the actual tile you clicked. If it's white, you do nothing because you already clicked the right tile.

Does it make sense? I'm not really good at explaining things.

edit: Oh, okay. I totally mis-read the topic. Nevermind then. Hopefully someone finds it useful nonetheless. :)

SMF spam blocked by CleanTalk