Question

I'm writing an isometric game, but unfortunately I've got stuck writing with the algorithm used to map back to world coordinates from screen coordinates (or possibly vice versa). Anyway I can't figure out the implementations which are the inverse of my GetScreenX/Y methods. Here's some code. width and height represent the width/height of the viewport area in tiles.

With the correct implementation, this should run through without any trouble. You can run it in Linqpad.

void Main()
{
    for(int width = 1;width<15;width++)
    {   
        for(int height = 1;height<10;height++)
        {
            for(int x = -50;x<50;x++){          
                for(int y = -50;y<50;y++){
                    var screenX = GetScreenX(x, y, width, height);
                    var screenY = GetScreenY(x, y, width, height);
                    var worldX = GetWorldX(screenX, screenY, width, height);
                    var worldY = GetWorldY(screenX, screenY, width, height);
                    if (worldX != x || worldY != y)
                    {
                        throw new Exception("Algorithm not right!");    
                    }
                }   
            }
        }
    }
}

protected int GetScreenX(int x, int y, int width, int height)
{
    return WrappingMod(x + y, width);
}

protected int GetWorldX(int x, int y, int width, int height)
{
    return 1; //needs correct implementation
}

protected int GetWorldY(int x, int y, int width, int height)
{
    return 1; //needs correct implementation
}

protected int GetScreenY(int x, int y, int width, int height)
{
    return WrappingMod((int) ((y - x)/2.0), height);
}

static int WrappingMod(int x, int m)
{
    return (x % m + m) % m;
}

Sorry to have to ask but I'm at my wits end!

Was it helpful?

Solution

I don't understand your WrappingMod function. You seem to calculate the screen coordinate, and then take it modulo viewport dimension (twice) just for the hell of it. That makes your world->screen mapping non-bijective, so it has no inverse.

Why are you drawing several tiles ontop of each other to begin with?

Instead of taking the modulus, you should be wanting to raise an exception when the world coordinate doesn't fit in the viewport.

OTHER TIPS

You need two matrices: one to convert from view to world coordinates, and its inverse to convert the other way.

// my matrices are in 4x4 column-major format

// projection matrix (world -> view)
this.viewTransform.identity()
    .translate(this.viewOrigin)
.scale(1, 0.5, 1)
.rotate(this.viewRotation, 2); // 2 = Z axis

var m = this.viewTransform.current().m;
this.context.setTransform(m[0], m[1], m[4], m[5], m[12], m[13]);

// construct inverse projection matrix (view -> world)
this.viewTransformInv.identity()
    .rotate(-this.viewRotation, 2)
    .scale(1, 2, 0)
    .translate(new Vect4(-this.viewOrigin.x, -this.viewOrigin.y));

// calculate world and map coordinates under mouse
this.viewTransformInv.project(this.mousePos, this.worldPos);

// convert coordinates from view (x, y) to world (x, y, z)
this.worldPos.z = this.worldPos.y;
this.worldPos.y = 0;
this.mapPos[0] = Math.floor(this.worldPos.x / this.TileSideLength);
this.mapPos[1] = Math.floor(this.worldPos.z / this.TileSideLength);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top