Eli Delventhal
« League of Dukes » JGO Kernel      Posts: 3573 Medals: 44
Game Engineer
|
 |
«
on:
2009-02-16 20:06:42 » |
|
Hey all,
I'm messing around with a game and having a hell of a time trying to get 2D isometric working happily. Basically the game logic all happens using a square unrotated 2D grid, then after drawing the background I'm trying just to rotate/translate everything else to match the background image. This isn't working.
Aside from the fact that the dimensions of a space at a given position are completely different than those at another point, there's a lot of other annoying crap to consider which is giving me a massive headache.
The easiest thing would obviously be to have a bunch of isometric sprites and then draw them at the correct locations and just translate/rotate/scale everything the same amount. Doing so would obviously make the background match up exactly with the active sprites.
However, I've got a 2D isometric background image drawn by an artist, so I've got to somehow match to that. It seems like a fool's errand. Does anyone have any pointers or methods they do when writing a game using 2.5d? If your advice is "there's no way to really match up with an artist's image unless you know the exact skew it had," then that of course makes sense. But I'm curious if anyone has done 2D isometric using backgrounds, rather than systematically placed tiles.
Thanks.
|
See my work:OTC Software<br /> Currently Working On:Secret project... I edit JGO in production, because I simply don't waste time writing bugs
|
|
|
Markus_Persson
JGO Kernel      Posts: 2092 Medals: 10
Mojang Specifications
|
 |
«
Reply #1 on:
2009-02-17 04:29:45 » |
|
If you don't know the transform of the background images, you're fairly boned. Ask the artist, or try to calculate it yourself. One way would be to place a grid along the floor plane of the original background image, then calculating the tilt/rotation/skew/whatever from that. OR you could just hack it until it looks good enough. 
|
|
|
|
|
|
Games published by our own members! Go get 'em!
|
|
Eli Delventhal
« League of Dukes » JGO Kernel      Posts: 3573 Medals: 44
Game Engineer
|
 |
«
Reply #3 on:
2009-02-17 14:07:37 » |
|
If you don't know the transform of the background images, you're fairly boned. Ask the artist, or try to calculate it yourself. One way would be to place a grid along the floor plane of the original background image, then calculating the tilt/rotation/skew/whatever from that. OR you could just hack it until it looks good enough.  I've been trying to hack it with little success because of various issues, most prevalent of which is that I'm not very good at 3D. Pretty much I've tried getting away with it just by applying a rotation along the center, which kinda sorta works but doesn't really line up properly. Maybe if I better explain exactly what I've got that'll help. Here's what I've been working with: 1) The artist draw a simple grid-based "floor plan" that had no perspective at all - i.e. was completely from a top-down view. 2) The artist applied Adobe Illustrator's 3D transform function to the grid, with the rotations of these values along the axes: (30,26,-37). 3) I've got my game in ortho mode, so if I try to simply apply that same rotation to everything it goes fairly nuts, and my sprites are squeezed in a fairly screwed up way. The only thing it appears I can do are rotations, translations, and scales along the X and Y axes only. Therefore it becomes impossible to directly emulate this viewpoint. So, any ideas, anyone? It seems like since I've got these coordinates I should be all set, but that's unfortunately not the case because the transformations applied are not ortho like my game. Any way to easily get that matching?
|
See my work:OTC Software<br /> Currently Working On:Secret project... I edit JGO in production, because I simply don't waste time writing bugs
|
|
|
Riven
« League of Dukes » JGO Kernel      Posts: 5862 Medals: 255
Hand over your head.
|
 |
«
Reply #4 on:
2009-02-17 14:52:14 » |
|
Did you try the matrix I gave you?
Isometric projection is simply: 1. looking at the world top-down 2. rotating the world 45deg (both FLAT axis... either X,Y or X,Z... affect eachother) 3. subtracting UP axis (in modelspace) from Y (in screenspace) to make higher units go to the top of the screen 4. scaling the screenspace X or Y, to make the tiles look stretched horizontally.
My projection matrix does just that.
If your unit is at XYZ, pass the vector through the matrix and you get the XY (and depth) coordinates.
Just to clarify: you'd pass in 1 vector per unit/item. You'd never need to do any transforms in java.awt.Graphics
|
Hi, appreciate more people! Σ ♥ = ¾ Learn how to award medals... and work your way up the social rankings
|
|
|
Eli Delventhal
« League of Dukes » JGO Kernel      Posts: 3573 Medals: 44
Game Engineer
|
 |
«
Reply #5 on:
2009-02-17 14:57:22 » |
|
Did you try the matrix I gave you?
Isometric projection is simply: 1. looking at the world top-down 2. rotating the world 45deg (both FLAT axis... either X,Y or X,Z... affect eachother) 3. subtracting UP axis (in modelspace) from Y (in screenspace) to make higher units go to the top of the screen 4. scaling the screenspace X or Y, to make the tiles look stretched horizontally.
My projection matrix does just that.
If your unit is at XYZ, pass the vector through the matrix and you get the XY (and depth) coordinates.
I didn't try it because I wouldn't know what to do with it  . Here's the extent of my OpenGL transformation knowledge: 1 2 3
| glTranslatef(); glRotatef(); glScalef(); |
So if you tell me to "apply a matrix" I won't really know how.  Similarly, I don't know if an exact isometric matrix transformation would work, because the grid got moved by (30,26,-37), which isn't exact. I might need a little babying here, or you can just tell me to sod off and read an OpenGL book. I wouldn't mind some babying, though. 
|
See my work:OTC Software<br /> Currently Working On:Secret project... I edit JGO in production, because I simply don't waste time writing bugs
|
|
|
Riven
« League of Dukes » JGO Kernel      Posts: 5862 Medals: 255
Hand over your head.
|
 |
«
Reply #6 on:
2009-02-17 15:27:21 » |
|
<babying>  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
| import java.awt.Color; import java.awt.Graphics;
import javax.swing.JFrame; import javax.swing.JPanel;
public class Isometric extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(); frame.getContentPane().add(new Isometric()); frame.setSize(640, 480); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }
@Override protected void paintComponent(Graphics g) { super.paintComponent(g);
g.setColor(Color.WHITE);
final int tileCount = 16; final int tileSize = 8;
Color[] colors = new Color[3]; colors[0] = Color.RED; colors[1] = Color.GREEN; colors[2] = Color.BLUE;
Color[] tileColors = new Color[tileCount * tileCount]; float[][] tileMidPoints = new float[tileCount * tileCount][3];
for (int y = 0; y < tileCount; y++) { for (int x = 0; x < tileCount; x++) { int i = y * tileCount + x;
tileColors[i] = colors[(int) (Math.random() * colors.length)];
float[] point = tileMidPoints[i]; point[0] = x; point[1] = 0.0f; point[2] = y; } }
for (int i = 0; i < tileCount * tileCount; i++) { int x = i % tileCount; int y = i / tileCount;
g.setColor(tileColors[i]); g.fillRect(x * tileSize, y * tileSize, tileSize, tileSize); }
Matrix4 iso = Isometric.createIsometricMatrix();
for (int i = 0; i < tileCount * tileCount; i++) { float[] model = tileMidPoints[i]; float[] view = new float[3];
iso.transform(model, view);
float x = view[0]; float y = view[1];
x *= 10.0f; y *= 10.0f;
x += this.getWidth() / 2; y += this.getHeight() / 2;
int xi = (int) x; int yi = (int) y; int r = 4;
g.setColor(tileColors[i]); g.fillRect(xi - r, yi - r, r * 2 + 1, r * 2 + 1); } }
private static Matrix4 createIsometricMatrix() { Matrix4 iso = new Matrix4(); iso.m00 = iso.m33 = 1.0f; iso.m10 = iso.m12 = 0.5f; iso.m11 = 2.0f; iso.m02 = -1.0f; iso.m21 = -0.05f; return iso; }
public static class Matrix4 { public float m00, m01, m02, m03; public float m10, m11, m12, m13; public float m20, m21, m22, m23; public float m30, m31, m32, m33;
public void transform(float[] in, float[] out) { float x = in[0]; float y = in[1]; float z = in[2];
out[0] = m00 * x + m01 * y + m02 * z + m03; out[1] = m10 * x + m11 * y + m12 * z + m13; out[2] = m20 * x + m21 * y + m22 * z + m23; } } } |
|
Hi, appreciate more people! Σ ♥ = ¾ Learn how to award medals... and work your way up the social rankings
|
|
|
Riven
« League of Dukes » JGO Kernel      Posts: 5862 Medals: 255
Hand over your head.
|
 |
«
Reply #7 on:
2009-02-17 15:42:15 » |
|
Oh, and it might look like a hexagonal map, but that's just because I just rectangles instead of polygons to render the isometric tiles. I was too lazy, but well, here you go: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
| import java.awt.Color; import java.awt.Graphics; import java.awt.Polygon; import java.util.ArrayList; import java.util.List;
import javax.swing.JFrame; import javax.swing.JPanel;
public class Isometric extends JPanel { public static void main(String[] args) { JFrame frame = new JFrame(); frame.getContentPane().add(new Isometric()); frame.setSize(640, 480); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }
@Override protected void paintComponent(Graphics g) { super.paintComponent(g);
g.setColor(Color.WHITE);
final int tileCount = 16; final int tileSize = 8;
Color[] colors = new Color[3]; colors[0] = Color.RED; colors[1] = Color.GREEN; colors[2] = Color.BLUE;
List<Color> colorList = new ArrayList<Color>(); List<float[]> quads = new ArrayList<float[]>(); List<Boolean> isTile = new ArrayList<Boolean>();
for (int y = 0; y < tileCount; y++) { for (int x = 0; x < tileCount; x++) { float[] point = new float[3]; point[0] = x; point[1] = 0.0f; point[2] = y;
quads.add(point); colorList.add(colors[(int) (Math.random() * colors.length)]); isTile.add(Boolean.TRUE); } }
for (int k = 0; k <= tileCount; k += 4) { for (int i = 0; i <= 10000; i++) { float v = k / (float)tileCount; float u = i / 10000.0f;
float[] point = new float[3]; point[0] = v * (tileCount-1); point[1] = (float) -Math.sqrt(Math.sin(u * Math.PI)) * 5.0f; point[2] = u * (tileCount-1);
quads.add(point); colorList.add(Color.BLACK); isTile.add(Boolean.FALSE); } }
for (int i = 0; i < quads.size(); i++) { float[] point = quads.get(i);
int x = (int) point[0]; int y = (int) point[2];
g.setColor(colorList.get(i)); g.fillRect(x * tileSize, y * tileSize, tileSize, tileSize); }
Matrix4 iso = Isometric.createIsometricMatrix(10, this.getWidth() / 2, this.getHeight() / 2);
final float[] view = new float[3];
final float[] xRel = new float[] { -0.5f, -0.5f, +0.5f, +0.5f }; final float[] yRel = new float[] { -0.5f, +0.5f, +0.5f, -0.5f };
for (int i = 0; i < quads.size(); i++) { g.setColor(colorList.get(i));
if (!isTile.get(i).booleanValue()) { float[] model = quads.get(i).clone();
iso.transform(model, view);
g.fillOval((int) view[0] - 2, (int) view[1] - 2, 5, 5); } else { Polygon p = new Polygon(); for (int k = 0; k < 4; k++) { float[] model = quads.get(i).clone();
model[0] += xRel[k]; model[2] += yRel[k];
iso.transform(model, view);
p.addPoint((int) view[0], (int) view[1]); }
g.fillPolygon(p); } } }
private static Matrix4 createIsometricMatrix(int scale, int x, int y) { Matrix4 iso = new Matrix4(); iso.m00 = iso.m33 = 1.0f * scale; iso.m10 = iso.m12 = 0.5f * scale; iso.m11 = 2.0f * scale; iso.m02 = -1.0f * scale; iso.m21 = -0.05f * scale; iso.m03 = x; iso.m13 = y; return iso; }
public static class Matrix4 { public float m00, m01, m02, m03; public float m10, m11, m12, m13; public float m20, m21, m22, m23; public float m30, m31, m32, m33;
public void transform(float[] in, float[] out) { float x = in[0]; float y = in[1]; float z = in[2];
out[0] = m00 * x + m01 * y + m02 * z + m03; out[1] = m10 * x + m11 * y + m12 * z + m13; out[2] = m20 * x + m21 * y + m22 * z + m23; } } } |
Sorry for the messy code, but you should get started with that. The arc looks weird, because it is composed out of tiles...
|
Hi, appreciate more people! Σ ♥ = ¾ Learn how to award medals... and work your way up the social rankings
|
|
|
Eli Delventhal
« League of Dukes » JGO Kernel      Posts: 3573 Medals: 44
Game Engineer
|
 |
«
Reply #8 on:
2009-02-17 16:05:43 » |
|
Thanks for the babying, I'll try that out. 
|
See my work:OTC Software<br /> Currently Working On:Secret project... I edit JGO in production, because I simply don't waste time writing bugs
|
|
|
Riven
« League of Dukes » JGO Kernel      Posts: 5862 Medals: 255
Hand over your head.
|
 |
«
Reply #9 on:
2009-02-17 16:18:55 » |
|
I updated the arcs a bit, so that you wouldn't get the idea that they were skewed.
|
Hi, appreciate more people! Σ ♥ = ¾ Learn how to award medals... and work your way up the social rankings
|
|
|
|