3

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:https://i.stack.imgur.com/I79yK.png to this:https://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.

deery50
  • 65
  • 1
  • 5
  • [this answer](http://stackoverflow.com/a/893063/5134012) may help. im not familiar with sdl, but it looks like you won't be able to draw an isometric rectangle just knowing its size and width in sdl, you'd need a polygonal-based method where each point's coordinates can be specified. (unless im reading too far into what you're trying to do) – Xeren Narcy Jul 23 '15 at 03:01
  • @Xeren I actually did see that answer before, in that example they have tiles that are already in Isometric form, they have this: http://coobird.net/img/tile-width-height.png whereas I have a flat tile and want to figure out a way to make it Isometric. – deery50 Jul 23 '15 at 03:10
  • ok. so you need a way to turn a cartesian rectangle (from what i assume is world-coordinates) into an isometric one? if so, just need one more thing, which orientation are you using? that is, +y is up and +x is right for cartesian, what do you want each diagonal direction to represent? – Xeren Narcy Jul 23 '15 at 03:36
  • @XerenNarcy If you had a square paper with the Cartesian coordinates in front of you and if you rotated it until the point on the bottom right side of the paper was facing you, that is what I am looking for. I also just figured out that SDL can support rotation when it renders which may be another way of accomplishing this but if I was to use this I would have to figure out the angle that I rotate each sprite as it gets rendered so the tiles fit together nice and tightly and I don't really understand how I would calculate that. – deery50 Jul 23 '15 at 03:53
  • (re recent edit) i see... ok, lastly: in these pics the tiles have been arranged on an isometric grid, so are you after a way to transpose _grid coordinates_ from cartesian to isometric (the positions of the tiles as the orientation of the tiles in this example doesn't change)? – Xeren Narcy Jul 23 '15 at 04:07
  • .... or are you after the tiles being rotated as well as the grid they are on? – Xeren Narcy Jul 23 '15 at 04:14
  • @xeren I'd rather the tiles rotated as well as the grid. – deery50 Jul 23 '15 at 04:26

2 Answers2

3

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.

Xeren Narcy
  • 875
  • 5
  • 15
  • Thanks for all of the help so far. So doing what you have above I am successfully converting each corner of the tiles to isometric, changing this: http://i.imgur.com/tHCpAQi.png to this: http://i.imgur.com/hmKBHcX.png. (I'm using SDL to draw lines in between each point). But when I get to actually rendering the sprites using SDL_RenderCopyEx I still don't understand how to find the angle (relative by default to the center of the tile) to rotate the sprites. – deery50 Jul 23 '15 at 17:27
  • Unfortunately rotation won't be enough because the angles at the corners change under this coordinate transform. You no longer have a square as defined by on-screen coordinates, else it would be possible to define a position and size + a rotation to create the isometric perspective. Problem here is SDL's capacity... Looking for SDL-based solutions, I have only two options: 1, write your own function that renders per-pixel under this transform (i can help with the concept) or 2, use 45 deg, and scale the entire screen afterwards to %50 along height (requires off-screen rendering perhaps)... – Xeren Narcy Jul 23 '15 at 23:18
  • 3, I'm seeing that SDL has _textured polygon_ render methods, I believe that's what you should use but I have no idea how it transforms the texture. For comparison, in OpenGL you can specify the on-texture coordinates for each on-screen coordinate in a polygon. – Xeren Narcy Jul 23 '15 at 23:27
  • Further reading isn't encouraging me that this will work in SDL nicely... For non-rectangular rendering like this I highly suggest considering OpenGL (SFML sets up OpenGL in 2D out of the box). – Xeren Narcy Jul 23 '15 at 23:33
  • Alright, well thanks for your help. I'll take a look at SFML and OpenGL. I have used SDL with OpenGL before but it was a little tedious and I was hoping I wouldn't need to switch for my simple little game.. – deery50 Jul 23 '15 at 23:52
  • @XerenNarcy I'm trying to implement it, but it seems like, there are brackets missing: `isoY = carY - carX / 2.0;` -> `isoY = (carY - carX) / 2.0;` Am I wrong? – Jerry Lundegaard Oct 26 '21 at 13:45
0

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)