MichaelAquilina / Some-2D-RPG

Tinkering with Game Development
MIT License
28 stars 5 forks source link

Translating mouse coordinates to a world position #9

Closed behindcurtain3 closed 11 years ago

behindcurtain3 commented 11 years ago

Hey, I've got another question. I want to get the tile that is clicked on by the mouse but I'm having trouble translating the mouse coordinates into world coordinates. Each time I do it seems to be off a little, possibly related to the zoom?

MichaelAquilina commented 11 years ago

There isnt any method currently within the engine that does this (but will definitely be a feature i plan on adding). Could you show me the code your using to translate your coordinates to see if i catch anything that is off? The current zoom code can sometimes cause problems due to loss of information when converting float values to integers, so there are a number of workarounds used to fix this.

behindcurtain3 commented 11 years ago

I don't have the exact line on me right now but its something like this

worldX = mouseState.X - (viewPort.pxDispX * viewPort.ActualZoom);
worldY = mouseState.Y - (viewPort.pxDispY * viewPort.ActualZoom);

Edit: I have tried with and without the zoom but to no avail.

MichaelAquilina commented 11 years ago

That seems to be relatively correct. However, you would probably need to multiply the mouse coordinate with the mouseState too:

worldX = (mouseState.X - viewPort.pxDispX) * viewPort.ActualZoom;
worldY = (mouseState.Y - viewPort.pxDispY) * viewPort.ActualZoom;

If this doesnt work either, then there is probably a bug in some part of the code that is causing this inaccuracy.

behindcurtain3 commented 11 years ago

Hmm that doesn't work either. Here is the closest I've come (doesn't work on all zoom levels):

float worldX = mouseState.X + viewPort.pxTopLeftX + viewPort.pxDispX;
float worldY = mouseState.Y + viewPort.pxTopLeftY + viewPort.pxDispY;

int tileX = (int)(worldX / viewPort.pxTileWidth);
int tileY = (int)(worldY / viewPort.pxTileHeight);

This gets really close to the correct tile / world position but isn't exact (half the time it does get the correct tile). I tried to multiply by the ActualZoom and it makes it further off. What exactly does the Displacement represent?

behindcurtain3 commented 11 years ago

Actually scratch the above post, this works better but its off by just enough to mess the tile detection up in some cases:

float worldX = (mouseState.X + viewPort.pxTopLeftX + viewPort.pxDispX) / viewPort.ActualZoom;
float worldY = (mouseState.Y + viewPort.pxTopLeftY + viewPort.pxDispY) / viewPort.ActualZoom;

int tileX = (int)(worldX / engine.Map.TileWidth);
int tileY = (int)(worldY / engine.Map.TileHeight);
MichaelAquilina commented 11 years ago

Your code is actually correct in using pxTopLeftX/Y rather than pxDispX/Y because i forgot what its use was for (the current zoom code is a bit messy admittedly). Here is an overview of what each value in ViewPortInfo represents:

From revising the above, the code you require probably needs to look something like this:

worldX = (mouseState.X *ActualZoom) + pxTopLeftX + pxDispX;

I do not have the ability to test that theory right now because i dont have the application accessible at the moment but you could try see if that gets you any closer.

Hope that helped.

MichaelAquilina commented 11 years ago
float worldX = (mouseState.X + viewPort.pxTopLeftX ) / viewPort.ActualZoom + viewPort.pxDispX;
float worldY = (mouseState.Y + viewPort.pxTopLeftY ) / viewPort.ActualZoom + viewPort.pxDispY;

int tileX = (int)(worldX / engine.Map.TileWidth);
int tileY = (int)(worldY / engine.Map.TileHeight);

Try that. I think pxDispX and pxDispY are already affected by ActualZoom as far as i remember.

MichaelAquilina commented 11 years ago

Hi, please take a look at my latest commits, they should solve your problem :)

There is now a method in ViewPortInfo called GetWorldCoordinates() which accepts a Point location on the viewport which will be translated accordingly.

Using these resultant coordinates you can just do:

int tileX = (int) (worldCoord.X / engine.Map.TileWidth);
int tileY = (int) (worldCoord.Y / engine.Map.TileHeight);

I also added detailed docstrings for each property in ViewPortInfo so that they can be more easily understood.

Hope this helps!

behindcurtain3 commented 11 years ago

Cheers, it works perfectly!

behindcurtain3 commented 11 years ago

Hey, wanted this implemented so bad because I added AStar pathfinding. Check the commits here: 7e41a77 and 2565445

MichaelAquilina commented 11 years ago

Cool stuff, i was planning on starting an implementation sometime soon but i was sidetracked by other things (the todo list seems endless!). Is there a branch on your fork where i can pull your changes form to see what youve done and test it?