Moving 2D Camera

Started by Setlock, December 01, 2016, 03:26:51

Previous topic - Next topic

Setlock

Hello everyone, I have search through probably 50 articles and help posts for how to do this, but still cannot find a working solution for me. I am current creating a 2D game using LWJGL and need to have the camera always centered on the character. Currently I am creating the player and keeping it in one position then when the user press WASD it moves all other objects that are drawn to the screen to mimic movement.
This is the camera creation I use:
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      glOrtho(0, WIDTH, HEIGHT, 0, 1, -1);
                glMatrixMode(GL_MODELVIEW);
      glEnable(GL_TEXTURE_2D);

I have tried glTranslatef in many different ways and many different places none so far have works. I hope you can help me fix this problem quickly. Thanks in advanced.

Kai

First, decide on a common coordinate system that your player and everything else in the world share.
For example, this could be "world coordinates", where the origin, i.e. the position with coordinates (0, 0) is at some fixed position in the world. Everything else is relative to this fixed position.
That means, when your player moves to the right, its X coordinate increases. And when it stands exactly on the origin with fixed coordinates (0, 0) then its position is (0, 0).
So what you need to do in order to position an object at coordinate (x, y) (where 'x' and 'y' are any numbers) you have to call: glTranslatef(x, y). That's that.
If you leave it at that, then of course your player - as it moves to the right - moves out of the visible viewport/screen.
So, you have to move "the camera" along with the player. Essentially what this means is to translate everything "back" by (-x, -y) so as to nullify/undo the player's own translation. This will have the result of your player always being at the center of the viewport and everything else moving in the opposite direction of the player.
So, before moving and rendering any of your world objects (including the player), you have to glTranslatef(-x, -y) (where 'x' and 'y' are the player's coordinates).

Setlock

Thanks first off for the quick response. I would like to say I have put glTranslatef(-playerX,-playerY) but unfortunately it didn't work as expected. I placed it before rendering any world objects but when I then go into the game and move the playerX one block out of the hundreds I have made will move(I generate blocks that are 25px/25px and save all data about them in an array list. Then have a drawquadtex method to draw the textures. I'm not sure if this has anything to do with it, but it's all I can think of)

Kai

If this does not work for you, then your "camera" and your models use different coordinate systems. This means that you have some glScalef() calls to scale your models but then translate them based on the scaled coordinate system (i.e. calls to glScalef() happen _before_ calls to glTranslafe()).
Since you say you move in units of one "block" and one such block is 25 pixels by 25 pixels, I am assuming now that you do something like glScalef(25, 25, 1).

But in general, it is hard to know what is not working without you describing _exactly_ how your model moving and camera moving looks like and how it should look like.

Setlock

Well right now when WASD is pressed a for loop executes and moves all squares in the array list  left right up or down depending on direction. So I want it to move such as Terraria where the player moves right or left and the camera stays on it at all times. And currently I have no scalef calls

Setlock

Currently these two methods are how I create the squares:
   public static void DrawQuad(float x, float y, float width, float height)
   {
      glBegin(GL_QUADS);
      glVertex2f(x,y);
      glVertex2f(x + width, y);
      glVertex2f(x + width,y + height);
      glVertex2f(x, y+height);
      glEnd();
   }

   public static void DrawQuadTex(Texture tex, float x, float y, float width, float height)
   {
      tex.bind();
      glTranslatef(x, y, 0);
      glBegin(GL_QUADS);
      glTexCoord2f(0,0);
      glVertex2f(0,0);
      glTexCoord2f(1,0);
      glVertex2f(width,0);
      glTexCoord2f(1,1);
      glVertex2f(width,height);
      glTexCoord2f(0,1);
      glVertex2f(0,height);
      glEnd();
      glLoadIdentity();
   }

Setlock

I have just changes where the glTranslate is and now it works but not as well as I had hoped. For placing blocks I have a 25*(x/25) and a 25*(y/25) where x is mouseX and y is mouseY- so the tiles "snap" into a location on the grid that is divisible by 25 but unfortunately when using glTranslate it messes up that system. Furthermore I have create a condition for the block textures in that if they are on on the screen then draw textures to them:
      for(int i =0; i < tiles.size(); i++)
      {
         if(tiles.get(i).getX() >= 0 && tiles.get(i).getX() < WIDTH && tiles.get(i).getY() >= 0 && tiles.get(i).getY() < HEIGHT)
         {   
            DrawQuadTex(tiles.get(i).getTexture(), tiles.get(i).getX(), tiles.get(i).getY(),tiles.get(i).getWidth(), tiles.get(i).getHeight());
         }
      }

But now the glTranslate changes the position which messes that up as well. And even more some specific block types dont load in.
So far a lot is going wrong...

Setlock

Ive finally done it! Well sort of. So I finally put glTranslatef(-playerX,playerY,0) in thew correct place so that all things on screen are translated. But with that comes more issues. I have a method that when the user clicks places a block and it uses 25*(MouseX/25) but when things are translated it messes up that equation since it believes the mouse is somewhere else. How would I go about fixing that?