# Should be easy find Z on a ramp with x and y (SOLVED)

## Recommended Posts

MikeKan13    102
I need to find the players z if he was standing on an isometric ramp. I know the isometric tiles width and height (if it was square) and using Pythagorean I can get the ramps length. I just cant figure out what his given z would be.

##### Share on other sites
zacaj    667
If you know the Z of both the top and the bottom of the slope, you can do simple linear interpolation. Note that if your slope is parallel to one of the axes (X or Y), you don't need the other one for the equation

[CODE]minZ+(maxZ-minZ)*((X-minX)/(maxX-minX))[/CODE]

At least I think that's right off the top of my head. You use the X position to find the percent (0-1) across the tile you are, and multiply it by the height of the tile. The adding of minZ and subtracting of minX are just because the tile isn't located at (0,0,0). Hopefully that made sense...

##### Share on other sites
MikeKan13    102
Hrmm not sure exactly what you are saying. I shouldn't need a minx miny or minz. I guess my drawing is kind of confusing. Let me try to explain better. All of this is within one block. Think completely local coordinates. So the far top left (outside the isometric square) would be 0,0. For the sake of simplicity lets say the max x for the block is 88 the max y is 44 and the max z is 60. again for simplicity lets say the player is at 88,22(the right tip of the diamond) how do I find his z. obviously his z would be 60 but I need an algorithm that considers any possible point in the diamond.

##### Share on other sites
zacaj    667
Is there any reason youre working with screen coordinates instead of block coordinates? If the sides of the block were parallel to the X/Y axes thhe math is much simpler.

##### Share on other sites
MikeKan13    102
The game is 2d and the entire engine is written that way.

##### Share on other sites
zacaj    667
I'd recommend you split the diamond into two triangles and interpolate the height across it. I haven't done this sorta thing in a while, but I can probably find the code in a few hours... I'm having trouble remembering how it worked off the top of my head. Google how colors are interpolated over triangles in renderers.

##### Share on other sites
MikeKan13    102
There has to be an equation to find the z. I can find the length of the ramp and any length of any lines in the block. Do i need to get the angle of the ramp and do something with that?

##### Share on other sites
zacaj    667
Sorry I cant find the code, but the idea should still work. Find the Z at both sides of the diamond for whatever Y value you have by interpolating the Z at the corners, and then interpolate between the two sides depending on the X value.

##### Share on other sites
MikeKan13    102
sorry I don't understand can you give me an example equation.

##### Share on other sites
zacaj    667
Finding height along top left edge:

Leftsidez=TopZ+ (leftz-topz) *(y/midY) ;

Top right:
Rightsidez=Topz+ (rightz-topz) *(y/midy) ;

Interpolate between left side and right side:

Z=Leftsidez+ (rightsidez-leftsidez) *(x/maxX)

(midy=maxy/2)

I think that's all right, off the top of my head. If y> midy, switch top with mid and mid with bottom.

##### Share on other sites
MikeKan13    102
I couldn't get yours to work but I did find someone who had a trig alogorithm. I won't pretend to understand it but I plugged in my values and it sort of works. I might have done it wrong but it works if the player is near the left side of the diamond but then messes up towards the right.(left and right if block was viewed with your head tilted to the right.) here is the code

[CODE] a = GetDistance(Player.localX, 0, Player.localY, 22, 0, BLOCK_Z)
b = GetDistance(Player.localX, 0, Player.localY, 22, 0, 0)
c = BLOCK_Z
s = (a + b + c) / 2
ar = (s * (s - a) * (s - b) * (s - c)) ^ 0.5
distance = ar / (c * 0.5)
Player.z = distance
......
Public Function GetDistance(ByVal x1 As Long, ByVal x2 As Long, _
ByVal y1 As Long, ByVal y2 As Long, ByVal z1 As Long, ByVal z2 As Long) As Long

GetDistance = ((x2 - x1) ^ 2 + (y2 - y1) ^ 2 + (z2 - z1) ^ 2) ^ 0.5

End Function
[/CODE]

##### Share on other sites
zacaj    667
I have no idea how that code would work. Can you post a link to where you found it? How does my algorithim mess up?

##### Share on other sites
MikeKan13    102
[url="http://gmc.yoyogames.com/index.php?showtopic=386179"]http://gmc.yoyogames...howtopic=386179[/url] it is on the second page. He also mentions another very simple one of just turning the coordinates to their isometric coordinates. I tried this one and it worked very well except sometimes I would fall through my floor near the bottom of ramps. I might be able to rework my own code to use this one. I think if I could get the trig equation to work it would be the best though I do not understand it completely and I might be using incorrect values. Like I said It works for the left side of the ramp but at the bottom of the right side the player pops up instead of smoothly gliding onto it like the right side. Then at the top of the ramp on the right side he is higher than he should be. i tried using your code and It made the player jump in random places on the ramp. I might take another look at it though.

Edit: Help to find that post: It is halfway down on the second page posted by [url="http://gmc.yoyogames.com/index.php?showuser=106214"]althing06[/url][color=#EEEEEE] [/color]

##### Share on other sites
MikeKan13    102
NM his simple one does the relatively same thing as the complex one and neither work. This is ridiculously difficult.

##### Share on other sites
zacaj    667
If theyre both giving the same results, is it possible youre sending your data in wrong?

##### Share on other sites
MikeKan13    102
It is possible I guess but
[CODE]
a = point_distance character x,y to right top edge (of slope sprite)
b= point_distance character x,y to right bottom edge
c = point_distance right top corner to right bottom corner
s = (a+b+c)/2
ar = sqrt(s*(s-a)*(s- b )*(s-c))
distance = ar / (c * .5)
[/CODE]
the descriptions he gives for the points are vague. I am not sure if by right top edge he means the ztop of the ramp or the y of the sprite or the y of the diamond or what. I have tried many different combinations and no luck. It is giving me like a corner of a pyramid. I am searching on the internet but can't seem to find anything else.

##### Share on other sites
For clarity:
[attachment=7430:isometric_ramp.png]
The problem seems to be that you need to find the distance 'into the ramp' - that is, the distance in the up-right direction on the tile. On the illustration above, it's the length of the red vector. Once you have that, you can do a simple linear interpolation between 0 and maxZ.

The purple vector p in the illustration gives the position of the player relative to point D. You can easily calculate it in terms of its x- and y-components, but you need it written as a sum of the red vector and the blue vector; that way you can just take the length of the red vector component, and that will be the distance 'into the ramp'.

The green and pink vectors e1 and e2, shown coming out of point D, should be normalized. They are easy to calculate; just subtract D from A and normalize to get the green vector, and subtract D from C and normalize to get the pink vector.

The red vector is proportional to e1 and the the blue vector is proportional to e2, so all you need to do is find the scaling factors to scale them up to the correct size:

redVector = c1*e1
blueVector = c2*e2

so

p = redVector + blueVector
p = c1*e1 + c2*e2
p.x = c1*e1.x + c2*e2.x
p.y = c1*e1.y + c2*e2.y

Now you have two equations for c1 and c2, so it's easy to solve for them; you should come out with:

c1 = (p.x*e2.y - p.y*e2.x)/(e1.x*e2.y - e1.y*e2.x)

We said that e1 was normalized, so, since redVector = c1*e1, the length of redVector - and therefore the distance 'into the ramp' - is just c1. The height, then, is a linear interpolation:

where |AD| is the length of side AD. I haven't tried this in game code of any sort, but I've graphed the c1 function and gotten sensible results. Hopefully if you decide to use it it works for you!

##### Share on other sites
MikeKan13    102
confused...

[left]p = redVector + blueVector[/left]

[left][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]p = c1*e1 + c2*e2[/font][/color][/left]

[left][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]p.x = c1*e1.x + c2*e2.x[/font][/color][/left]

[left][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]p.y = c1*e1.y + c2*e2.y[/font][/color][/left]

[left][font=helvetica, arial, verdana, tahoma, sans-serif][color=#282828]c1 is used in these equations and then [/color][/font][/left]
[left]You find the value of c1 using the previous values you just found using c1?!?![/left]
[left][color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]c1 = (p.x*e2.y - p.y*e2.x)/(e1.x*e2.y - e1.y*e2.x)[/font][/color][/left]

[left]Also I am not a very strong math person. What does normalize mean?[/left]
[left]Edit: I am trying to go through and understand. are e1 and e2 cordinates, lines, distances? you have e2.y and ect so it makes me think they are coordinates. Sorry I am very bad with math. I looked up normalizing numbers and it is simple enough. what I don't understand is am I getting a set of coordinates for the line or is it a set of lengths. Also is p.x and p stuff the players x or do you mean the line p in the picture. Please clarify and dumb it down for me. Things like this : [color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif][size=3]p = redVector + blueVector <-- how do you add two lines together? They consist of 4 sets of different cords.[/size][/font][/color][/left]

##### Share on other sites
[quote name='Mikekan13']
c1 is used in these equations and then
You find the value of c1 using the previous values you just found using c1?!?![/quote]
In retrospect I see how my setup might have mislead you there; I was writing out a derivation, not lines of code to be evaluated sequentially. I don't know c1 until the end. I [i]do[/i] know p, though; that's the location of the player, as described above. I write down an equation that contains what I do know - p, e1, and e2 - as well as what I don't know - c1 and c2. It's just chance that p ended up all by itself on the left like a variable that's getting a value assigned. The lines that you were curious about are just me playing around with the equation until I have c1, the number I want, by itself where I can calculate it. The only bit that's relevant to the actual code is the line where c1 is defined.

[quote name='Mikekan13']are e1 and e2 cordinates, lines, distances? you have e2.y and ect so it makes me think they are coordinates.
...
what I don't understand is am I getting a set of coordinates for the line or is it a set of lengths. Also is p.x and stuff the players x or do you mean the line p in the picture.[/quote]
e1 and e2 are vectors, as is p1. In this case, that means that each one has an x and a y component. You could think of the components as coordinates [i]or[/i] lengths here; after all, a coordinate is just the length away from zero. You represent a vector graphically by drawing a line with length and direction corresponding to the components. That is, if you have the vector (3, 4), you would draw the end with the arrowhead 3 units to the right and four units above the other end.

When I drew the line p, then, I meant p to be the location at the tip of the arrowhead. It's a line that [i]represents[/i] a position. In this case I drew the line from point D, meaning that the coordinates of the location should be measured from point D, not from the origin of the entire game map.

[quote name='Mikekan13']Things like this : p = redVector + blueVector <-- how do you add two lines together? They consist of 4 sets of different cords.[/quote]
An important thing to understand about vectors is that their length and direction is important, but their overall position doesn't matter. If I have the vector (1, 1), I can draw it from world position (0, 0) to world position (1, 1), or from world position (12, -3) to world position (13, -2); those two drawings represent exactly the same vector. When you're using vectors to represent positions it's often clearer to draw them from (0, 0), but that's not the only correct way.

The end of the vector with the arrowhead is called the head, and the back end is called the tail. Graphically, you add two vectors by lining up the head of one with the tail of the other; you can do that because, as I said, the overall position of a vector doesn't matter. The sum is then the vector from the tail of the first vector to the head of the second vector. I don't have the red and the blue vector lined up that way, but note that if you shift the blue vector down and left until its head is on the red vector's tail, the purple vector goes from the blue tail to the red head.

You can get the same result by adding the vectors' components separately; if you have three vectors a, b, and c so that a + b = c, then ax + bx = cx and ay + by = cy. That's how I got the x and the y equation from the redVector + blueVector sum. A more concrete example might be 'If I move 3 meters left and 2 meters up and then I move 1 meter right and 5 meters down, all together my position will have moved 2 meters left and 3 meters down.'

You're adding a two-component vector to another two-component vector. These vectors are stored with two components instead of four because, again, the start and end positions don't matter, just the difference between them. The result is one two component vector; two of the original components form one of the new components, and the other two form the other. Adding vectors component-by-component is usually how it's done in code.

I've written some C++ code that I hope will help clarify what I mean; instead of explicit vectors it uses separate coordinates, which might be more familiar to you. A, B, C, and D are the locations of the corners of the diamond, as defined in the image in my previous post. pxWorld and pyWorld are the two-dimensional coordinates of the player using the same coordinate system that you used to measure A, B, C and D - meaning if you measure A, B, C and D from the bottom-left of the entire map, you should measure pxWorld and pyWorld from the bottom-left of the entire map as well:
[code]float getHeight(float Ax, float Ay, float Bx, float By, float Cx, float Cy, float Dx, float Dy, float pxWorld, float pyWorld, float maxZ)
{
//calculate player position relative to point D
float px = pxWorld - Dx;
float py = pyWorld - Dy;

//calculate e1 and e2, including normalization
float e1x = (Ax - Dx)/Sqrt((Ax - Dx)*(Ax - Dx) + (Ay - Dy)*(Ay - Dy));
float e1y = (Ay - Dy)/Sqrt((Ax - Dx)*(Ax - Dx) + (Ay - Dy)*(Ay - Dy));
float e2x = (Cx - Dx)/Sqrt((Cx - Dx)*(Cx - Dx) + (Cy - Dy)*(Cy - Dy));
float e2y = (Cy - Dy)/Sqrt((Cx - Dx)*(Cx - Dx) + (Cy - Dy)*(Cy - Dy));

//calculate c1
float c1 = (px*e2y - py*e2x)/(e1x*e2y - e1y*e2x);

//do the linear interpolation and return the result
float AD = Sqrt((Ax - Dx)*(Ax - Dx) + (Ay - Dy)*(Ay - Dy));
}[/code]

I should say that I haven't tried to compile or run it. It's not at all optimized, of course - A, B, C, D, and maxZ presumably don't change, so a lot of things could be precalculated - but I hope it makes the method I describe more clear.

Edit: added Bx and By to the function's arguments; whoops!

##### Share on other sites
MikeKan13    102
I just got home from working a 12 hour day and I am really tired. I skimmed it and it makes more sense to me now. I will try and implement it after work tomorrow. Thank you.

##### Share on other sites
MikeKan13    102
YES! You sir or ma'am are a genius and I love you to the power of 100. Works perfectly!

##### Share on other sites
MikeKan13    102
Can't get it for the reverse. I just switched the variables around so that b would be d. I also tried switching all the y subtraction math around cause I thought maybe it was giving negative values.

##### Share on other sites
As you seemed to be thinking, you can indeed change the ramp direction by switching around where A, B, C, and D are. Note that the vectors e1 and e2 that point along the sides of the tile are defined to point from D to A and D to C; e1 is the 'up the ramp' vector, so moving from D to A should move you up the ramp, and moving from D to C should move you along the base or the top of the ramp without changing your height.

All you need to do, then, is look at the ramp orientation, choose D and C to be at low corners of the ramp, and choose A to be at the high corner that shares an edge with D. An easy way to do that is to take the corners as I defined them and rotate the point labels through as many quarter-turns as you rotate the ramp itself. For the first new picture you posted, where you increase in height as you move down and to the left, the ramp is rotated by two quarter-turns counterclockwise; that would make the left point A, the bottom B, the right C, and the top D.