Make square walk by rotating around corners

I in the very beginning of making a small game, and I'm having some problems getting the basic movement of my character.

My character is a square that can be moved by rotating around a corner. The user chooses what corner to rotate around by pressing a button. Here is the (malfunctioning) code I've come up with this far(Java and slick2d):

    // square is an org.newdawn.slick.Image and is rendered by calling square.draw()

@Override
public void update(GameContainer container, int delta) throws SlickException {
Input input = container.getInput();
if (input.isKeyDown(Input.KEY_W))
{
square.setCenterOfRotation(0, 0);
square.setRotation(square.getRotation() + 1);
}
else if (input.isKeyDown(Input.KEY_E))
{
square.setCenterOfRotation(square.getWidth(), 0);
square.setRotation(square.getRotation() + 1);
}
else if (input.isKeyDown(Input.KEY_S))
{
square.setCenterOfRotation(0, square.getHeight());
square.setRotation(square.getRotation() + 1);
}
else if (input.isKeyDown(Input.KEY_D))
{
square.setCenterOfRotation(square.getWidth(), square.getHeight());
square.setRotation(square.getRotation() + 1);
}
}


This will rotate the square correctly, but when I switch rotation direction, the square jumps two times its lenght to the side I switched to. I think the problem is that I never really move the square, just rotate it away from its original position. I think this will also make collision detection difficult.

How would I prevent this 'jumping', and how will I later do collision detection on the image? Or asked in another way, how should I be doing the 'rotation walking'?

• Can you post a picture of what you mean by "square that can be moved by rotating around a corner" – user55564 Dec 19 '14 at 19:24
• I hope this gives some context: i.imgur.com/ihtaeY3.png i.imgur.com/fR1dEwJ.png i.imgur.com/OiRkIJ9.png There I have turned the square around one corner, and then switched corner. As you can see, the square has 'jumped' to the other side of itself. – totokaka Dec 19 '14 at 19:28
• It seems the rotation is kept when I change the center of rotation, so it's the position I need to update. I'm having a hard time figuring out how to calculate the position, and where I should be setting it. I think the centerOfRotation should always be the center of the square, and rather change the position each time I update the rotation, but I can't seem to figure out an algorithm for this. – totokaka Dec 19 '14 at 19:42

Im not sure this works 100% but here is an idea to get you started. Let your square have x,y as center and r as its current rotation value. Let dx and dy be the displacement from center to one corner of the square when r is 0;

On rotate-moving the square on the said corner:

First get the corner's position:

 cx = x + rotated(dx, r);
cy = y + rotated(dy, r);


Find the new correct center location after rotation dr:

 x = cx + rotated(-dx, r + dr);
y = cy + rotated(-dy, r + dr);


See http://en.wikipedia.org/wiki/Rotation_matrix for implementation of rotated.

• I'll check out this later today. Thanks for the info, it looks about right. – totokaka Dec 19 '14 at 19:59
• I've posted an answer, based on this one, which includes detailed description and code. I'm unsure what answer I should select as the 'correct' one, though. – totokaka Dec 20 '14 at 10:56

Based on user55565's answer, I did some reading on rotation matrices and took his main idea and did some paper sketching. In the end I came up with the class below, which works.

The basic idea is to reference the position of the square by its center coordinates. When you want to rotate it, you follow these steps:

1. Calculate the current(before the additional rotation) position of the corner you want to rotate around, relative to the center (so the center is the origin). I do this by finding the relative position of the corner without rotation, and then apply a rotation matrix.
2. Find the current position of the center relative to the corner (so the corner is the origin).
3. Rotate the center-relative-to-corner coordinates around its origin (the corner)
4. Calculate the new center coordinates relative to the old (corner-relative-to-old-center + new-center-relative-to-corner) and add this to the old center, so you get the new absolute center coordinates(old-center-absolute + new-center-relative-to-old-center)

Here is my java implementation, using the jama Matrix library:

public class Square
{

private final Image image;

/** The offset from center to anchor point **/
private final float xOffset;
private final float yOffset;

/** The center coordinates **/
private Matrix center;

public Square(Image image, float x, float y)
{
this.image = image;

this.xOffset = image.getWidth()/2.0f;
this.yOffset = image.getHeight()/2.0f;

this.center = new Matrix(new double[][]{{ x },
{ y }});
}

public void draw()
{
image.draw((float)center.get(0, 0)-xOffset, (float)center.get(1,0)-yOffset);
}

public void rotate(float degrees, Corner corner)
{
/** Step 1 **/
// Corner position relative to center (center is origo)
Matrix cornerPos;
switch (corner)
{
case TOP_LEFT:
cornerPos = new Matrix(new double[][]{{ -xOffset },
{ -yOffset }});
break;
case TOP_RIGHT:
cornerPos = new Matrix(new double[][]{{ +xOffset },
{ -yOffset }});
break;
case BOTTOM_LEFT:
cornerPos = new Matrix(new double[][]{{ -xOffset },
{ +yOffset }});
break;
case BOTTOM_RIGHT:
cornerPos = new Matrix(new double[][]{{ +xOffset },
{ +yOffset }});
break;
default:
return;
}
// Compensate for existing rotation
cornerPos = getRotationMatrix(image.getRotation()).times(cornerPos);

/** Step 2 **/
// Center position relative to corner (corner is origo)
Matrix centerPos = new Matrix(new double[][]{{ 0 },
{ 0 }}).minusEquals(cornerPos);

/** Step 3 **/
centerPos = getRotationMatrix(degrees).times(centerPos);

/** Step 4 **/
// Make centerPos be relative to old center
this.center = this.center.plus(cornerPos.plus(centerPos));

// Rotate the actual image
image.setCenterOfRotation(xOffset, yOffset);
image.rotate(degrees);
}

public Matrix getRotationMatrix(float degrees)
{