convert Cartesian width and height to Isometric

一世执手 提交于 2019-12-12 01:16:16

问题


I'm trying to create an Isometric game in the SDL graphics library.

When you render in SDL you require a source rectangle and a destination rectangle. The source rectangle is the portion of the texture you have loaded that you wish to render and the destination rectangle is the area on the screen you are rendering to. Rectangles simply consist of 4 properties, X position, Y position, Width, and Height.

Now say I have a Cartesian destination rectangle with these coordinates:

X=20, Y=10, Width=16, Height=16

Now say I wanted to convert this to Isometric. To convert the X and Y coordinates I would use:

isometricX = cartX - cartY;
isometricY = (cartX + cartY) / 2;

Now what I don't understand is what I would do to convert the Cartesian Width and Height to Isometric Width and Height to create the illusion that the view port is being moved 45 degrees to one side and 30 degrees down, creating the Isometric look.

EDIT: I'd like to clarify my question a little, so when I convert the Cartesian Coordinates to Isometric I change this:http://i.stack.imgur.com/I79yK.png to this:http://i.stack.imgur.com/ZCJg1.png. So now I am trying to figure out how to rotate the tiles so they all fit together and how I need to adjust the Height and Width to get this to happen.


回答1:


To start with you'll need these operations to convert to and from isometric coordinates:

isoX = carX + carY;
isoY = carY - carX / 2.0;

carX = (isoX - isoY) / 1.5;
carY = isoX / 3.0 + isoY / 1.5;

right-angled corners in the top-left and bottom-right become 120 degrees, the other two corners become 60 degrees. the bottom-right corner becomes the bottom corner, the top-left corner becomes the top. this also assumes that y increases going up, and x increases going right (if your system is different, flip the signs accordingly). you can verify via substitution that these operations are eachothers inverse.

for a rectangle you need 4 points transformed - the corners - as they will not be 'rectangular' for the purposes of SDL (it will be a parallelogram). this is easier to see numerically.

first, assign the corners names of some sort. i prefer clockwise starting with the bottom-left - this coordinate shall be known as C1, and has an associated X1 and Y1, the others will be C2-4.

C2 - C3
|    |
C1 - C4

then compute their cartesian coordinates...

X1 = RECT.X;
Y1 = RECT.Y;

X2 = X1; // moving vertically
Y2 = RECT.Y + RECT.HEIGHT;

X3 = RECT.X + RECT.WIDTH;
Y3 = Y2; // moving horizontally

X4 = X3; // moving vertically
Y4 = RECT.Y;

and lastly apply the transform individually to each coordinate, to get I1, I2, I3, I4 coordinates...

iX1 = X1 + Y1;
iY1 = Y1 - X1 / 2.0;
// etc

and what you end up with is on-screen coordinates I1-4, that take this shape:

    I2
  /    \
I1      I3
  \    /
    I4

But unlike this shoddy depiction, the angles for I4 and I2 will be ~127 deg, and for I1 and I3 it should be ~53 deg. (this could be fine-tuned to be exactly 60/120, and depends on the 2.0 factor for carX when computing isoY - it should be sqrt(3) rather than 2.0 but meh, close enough)

if you use the inverse transform, you can turn back the I1-4 coordinates into C1-4, or locate a world coordinate from a screen coordinate etc.

implementing a camera / viewport gets a little tricky if only at first but it's beyond what was asked so i won't go there (without further prodding)...

(Edit) Regarding SDL...

SDL does not appear to "play nice" with generalized transforms. I haven't used it but its interface is remarkably similar to GDI (windows) which I've played around with for a game engine before and ran into this exact issue (rotating + scaling textures).

There is one (looks to be non-standard) SDL function that does both scaling and rotating of textures, but it does it in the wrong order so it always maintains the perspective of the image, and that's not what is needed here.

Basic geometry will be fine, as you've seen, because it's fills and lines which don't need to be scaled, only positioned. But for textures... You're going to have to either write code to render the texture one pixel at a time, or use a combination of transforms (scale after rotate), or layering (drawing an alpha-masked isometric square and rendering a pre-computed texture) and so on...

Or of course, if it's an option for you, use something suited for raw geometry and texture data like OpenGL / Direct3D. Personally I'd go with OpenGL / SFML for something like this.




回答2:


Unfortunately I cannot comment to ask for clarification so I must answer with a question: can you not convert all four points then from those points calculate the width and height from the transformed points?

X=20, Y=10, Width=16, Height=16

as you've said

isometricX = cartX - cartY;
isometricY = (cartX + cartY) / 2;

so

isometricX1 = cartX1 - cartY1;
isometricY1 = (cartX1 + cartY1) / 2;

and

isometricWidth = std::abs(isometricY - isometricY1)

There's probably a more efficient route though but as I do not know Cartesian geometry I can't find that solution

EDITisometricWidth found the distance between the two points not the width and hieght another note is you'd need opposite corners (yes I realize the other guy probably as a much better answer :P)



来源:https://stackoverflow.com/questions/31577053/convert-cartesian-width-and-height-to-isometric

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!