1
\$\begingroup\$

I'm making a 2d top down game in Java using LWJGL(OpenGL, essentially). I recently tried adding a swinging sword mechanism. My coordinate system is set to the bottom left FOR ALL objects. The rotation worked, but it happens with respect to the bottom left corner of the Sword Quad. I want it to rotate with the center of the bottom line as the pivot for rotation. I tried a lot of solutions from the internet like:

  • translating the object to origin(0,0 of the screen), then rotating, then translate to the point of pivot.
  • translating object normally, then rotating, then again translating to the point you want it to pivot at.

But they all yield weird results.

Here's the code:

The Sword Class:

public class Sword extends GameObject {

    private static int speed = 5, deg = 0;;

    private Texture tex;

    public Sword(float x, float y, ObjectId id)  {
        super(x, y, id);

        //tex = ImageLoader.loadTexture(null, null);
    }
    protected void update(ArrayList<GameObject> objects) {
        if(deg < 360) deg += 1;
        else deg = 0;
    }

    protected void render() {
        Draw.rect(x, y, 10, 32, deg, 1, 0, 0);
    }

    public Rectangle getBounds() {
        return null;
    }

}

The Draw.rect method:

public static void rect( float x, float y, float width, float height, 
                         float deg, float r, float g, float b) {
        glDisable(GL_TEXTURE_2D);

        glPushMatrix();
        {
            glTranslatef(0, 0, 0);
            glRotatef(deg, 0, 0, 1);
            glTranslatef(x + (width/2), y, 0);

            glColor3f(r, g, b); 

            glBegin(GL_QUADS); // Specifies to the program where the drawing 
                               // code begins. just to keep stuff neat. 
                               // GL_QUADS specifies the type of shape 
                               // you're going to be drawing.
            {                 
                glVertex2f(0, 0); // Specify the vertices. 0, 0 is on BOTTOM 
                                  // LEFT CORNER OF SCREEN.
                glVertex2f(0, height); // 2f specifies the number of args 
                                       // we're taking(2) and the type 
                                       // (float)
                glVertex2f(width, height);
                glVertex2f(width, 0); 
            }
            glEnd();
        }

        glPopMatrix();

        glEnable(GL_TEXTURE_2D);
    }

EDIT: Here is an image of what "weird result" is. In the pic, I'm translating first to origin[(0, 0) of the WORLD], then rotating(by 90 degrees), then translating to translating to [x - (width/2) , y]. As you can see, the red block that represents the sword is out of the "arena", even though I've set the x, and y of the sword to near the player. The image: enter image description here

\$\endgroup\$
1
\$\begingroup\$

There are multiple issues with this code.

First of all your quad vertices are not centered around the origin, this doesn't have to be a problem but note that it will use the corner of the quad as the pivot to rotate the sprite then.

Secondly, you are rotating on the X-axis. This seems weird since the general direction your camera in looking in is the -Z direction. If you want to rotate a quad that spans the X,Y plane you have to rotate on the Z axis.

Thirdly, and most importantly for your question, you are translating first and then rotating. This will move your sword, and then rotate it in a giant circle around the origin. Note that glTranslate(0, 0, 0); does absolutely nothing. Also note that you want to call these commands in reverse order, since OpenGL uses a matrix stack. So to rotate first and then translate (like you really want to) you would do:

glTranslatef(x + (width/2), y, 0); glRotatef(0, 0, deg, 1);

\$\endgroup\$
0
\$\begingroup\$

For that kind of behaviour you generally Rotate about the origin, then Translate, then Scale.

Since you want to rotate from the center bottom of your quad, from the origin you'd: 1. Translate the image to have its center at the origin ((width/2)) 2. Rotate 3. Translate to the desired location

I'm not familiar with the inner works of OpenGL (I work with a rendering engine), but your first translate (glTranslatef(0, 0, 0); does nothing, it does not translate anything because of the values are zero. I think your intention was to "set the origin at (0, 0, 0)"; to achieve that, I think you need to set the current matrix to identity instead (glLoadIdentity();).

So in the end it would look like:

  1. Reset the transform matrix (glLoadIdentity())
  2. Translate the image to have its center at the origin ((width/2))
  3. Rotate
  4. Translate to the desired location

To get to what you need, I suggest to do one step at a time. ("Ok, is my sword properly centered from the origin? No, ok let's do that... Ok, done, now let's try to rotate it about it's new origin... ok now it works as I'd like it to... ok, finally, let's put it in its final position... and... done!") That's usually what I do, otherwise I get lost and do not fully understand the process.

\$\endgroup\$
  • \$\begingroup\$ Does not work. I tried the steps you mentioned above, but the rectangle that is supposed to be the sword doesn't even show up now. I put glTranslatef((width/2), y, 0) in the first translate, then rotated, then translated to glTranslatef(x, y, 0). Is that what you meant? I will edit the question to add pictures of what "weird results" are as well. Have a look at those too. I think it might be a problem of how OpenGL is translating the objects. Also Note: It is not a single rotation, it is several rotations, that is, deg is increasing, so the sword is in swinging animation. \$\endgroup\$ – user3690770 May 10 '15 at 4:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.