Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (495)
Games in Android Showcase (114)
games submitted by our members
Games in WIP (563)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  2.5d Isometric view?  (Read 5922 times)
0 Members and 1 Guest are viewing this topic.
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Posted 2009-02-17 01: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
Offline Markus_Persson

JGO Wizard


Medals: 15
Projects: 19


Mojang Specifications


« Reply #1 - Posted 2009-02-17 09: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. Wink

Play Minecraft!
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 798
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #2 - Posted 2009-02-17 14:00:48 »

This is my OpenGL projection matrix for isometric transforms:

http://www.java-gaming.org/topics/isometric-engine-rct-style-major-update-14-sep/10237/msg/82081/view.html#msg82081 (scroll to the screenshot)
http://www.java-gaming.org/topics/isometric-engine-rct-style-major-update-14-sep/10237/msg/83479/view.html#msg83479

You can probably use your own Matrix classes to do this operation in software.

Just feed modelspace 3d points and you'll get (normalized) 2d screen coords.
Scale and translate until it fits your artists image.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #3 - Posted 2009-02-17 19: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. Wink

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
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 798
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #4 - Posted 2009-02-17 19: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
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #5 - Posted 2009-02-17 19: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  Tongue.

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. Smiley 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. Wink

See my work:
OTC Software
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 798
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #6 - Posted 2009-02-17 20:27:21 »

<babying> Wink

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];

      // create random world
     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;
         }
      }

      // render top down
     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);
      }

      // render isometric
     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];

         // scale
        x *= 10.0f;
         y *= 10.0f;

         // translate
        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()
   {
      // --> 1.0, 0.0, -1.0, 0.0 // x
     // --> 0.5, 2.0, 0.5, 0.0 // y
     // --> 0.0, -0.05, 0.0, 0.0 // depth
     // --> 0.0, 0.0, 0.0, 1.0 // [nothing]

      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
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 798
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #7 - Posted 2009-02-17 20: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>();

      // create tile grid
     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);
         }
      }

      // nice arcs (3d)
     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);
         }
      }

      // render top down
     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);
      }

      // render isometric
     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();

               // translate to tile corners in model space
              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)
   {
      // --> 1.0, 0.0, -1.0, 0.0 // x
     // --> 0.5, 2.0, 0.5, 0.0 // y
     // --> 0.0, -0.05, 0.0, 0.0 // depth
     // --> 0.0, 0.0, 0.0, 1.0 // [nothing]

      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
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #8 - Posted 2009-02-17 21:05:43 »

Thanks for the babying, I'll try that out.  Smiley

See my work:
OTC Software
Offline Riven
« League of Dukes »

JGO Overlord


Medals: 798
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #9 - Posted 2009-02-17 21: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
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

Dwinin (29 views)
2014-09-12 09:08:26

Norakomi (57 views)
2014-09-10 13:57:51

TehJavaDev (78 views)
2014-09-10 06:39:09

Tekkerue (38 views)
2014-09-09 02:24:56

mitcheeb (58 views)
2014-09-08 06:06:29

BurntPizza (45 views)
2014-09-07 01:13:42

Longarmx (30 views)
2014-09-07 01:12:14

Longarmx (35 views)
2014-09-07 01:11:22

Longarmx (36 views)
2014-09-07 01:10:19

mitcheeb (40 views)
2014-09-04 23:08:59
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!