0
\$\begingroup\$

I'm writing a Transform script for a Monogame project and I'm trying for a few days now to fix the Rotate method of this script, but without success.

Currently, the Parent transform only rotates around itself and also its Children does not translate around the specified Point (the Parent), only around themselves and with a lot of imprecision. When tested in other scenarios, the RotatePoint method is working correctly, but not when used in the Rotate method written below.

public class Tranform
{
    public Vector2 Position
    {
        get { return new Vector2 (x, y); }
        set { return x = value.X; y = value.Y; }
    }

    public float Rotation
    {
        get { return rotation;  }
        set { rotation = value; }
    }

    public void Rotate(float degrees)
    {
        this.rotation += degrees;
        
        if (rotation >= 360) rotation = 0;
        if (rotation <= -360) rotation = 0;
        
        foreach (var child in this.Children)
        {
            child.Position = RotatePoint(child.Position, this.Position, degrees);
            child.Rotate(degrees);
        }
    }

    public override void Update(GameTime time)
    {
        if (Keyboard.GetState().IsKeyDown(Keys.A))
        {
            Translate(-1, 0);
            Rotate(-1 * (float)time.ElapsedGameTime.TotalMilliseconds);
        }
        
        if (Keyboard.GetState().IsKeyDown(Keys.D))
        {
            Translate(1, 0);
            Rotate(1 * (float)time.ElapsedGameTime.TotalMilliseconds);
        }
    }

    public override void Render(SpriteBatch sprite_batch)
    {
        sprite_batch.Draw(pixel, this.Position, this.Boundaries, Color.White, MathHelper.ToRadians (this.Rotation), this.Origin, 1, SpriteEffects.None, 0);
    }

    public Vector2 RotatePoint(Vector2 point, Vector2 origin, float degrees)
    {
        float radians = MathHelper.ToRadians(degrees);
        
        Vector2 rotation_origin = new Vector2(point.X - origin.X, point.Y - origin.Y);
        
        double radius = Math.Sqrt(rotation_origin.X * rotation_origin.X + rotation_origin.Y * rotation_origin.Y);
        
        float x = (float)((radius * Math.Cos(radians)) + origin.X);
        float y = (float)((radius * Math.Sin(radians)) + origin.Y);
        
        return new Vector2(x, y);
    }
}

I'm creating the objects like this:

var parent = new Tranform();

parent.Position = new Vector2(0, 0);
parent.Scale = new Vector2(100, 100);
parent.Origin = new Vector2(50, 50);

child.SetParent(parent);
\$\endgroup\$
8
  • 1
    \$\begingroup\$ Can you describe in more detail or show what you mean by "completely messed up"? \$\endgroup\$
    – DMGregory
    Jan 16, 2023 at 16:05
  • \$\begingroup\$ @DMGregory I don't know how to describe it but the rotation of the parent and also the child becomes offset by some amount every time i set a new different value to the Rotation property. \$\endgroup\$
    – NOrlYNcE
    Jan 16, 2023 at 17:07
  • 1
    \$\begingroup\$ just so I understand where you are at, can you tell me if you are getting syntax errors as I am getting them or are you able to play the game but not getting the desired outcome? \$\endgroup\$ Jan 16, 2023 at 22:08
  • \$\begingroup\$ What is your purpose ? \$\endgroup\$
    – TimChang
    Jan 17, 2023 at 8:28
  • \$\begingroup\$ @TimChang I'm trying to make a transform system for a future game project. \$\endgroup\$
    – NOrlYNcE
    Jan 17, 2023 at 9:44

1 Answer 1

0
\$\begingroup\$

In this version of the question, you are doubling the positional rotation when drawing. The origin of rotation in the Draw() call needs to be the origin of the local rotation of the sprite, normally the center of the sprite texture (pixel).

I would move the Translate(); calls to their own keyboard keys. Rotations and translations should be kept separate on inputs, unless you want nautilus shell like movements. If the child and parent objects are of the same type, all objects will move uniformly.

The position of the rotation is already adjusted for the parent rotation offset.

Imagine a Ferris Wheel. The origin of the wheel is in the center. Each of the cabins is translated by the radius and angle from the rotation of the origin, but each cabin has its own local rotation, loosely fixed to world up by gravity.

Boundaries is the source rectangle within the pixel texture in texture space, not the boundaries of the object in world space. This parameter allows for the use of texture atlases(sprite sheets).

You still cannot rotate rectangles, directly. The Draw handles rotations, but it is not usually helpful for collisions.


// int >> 1 is a much faster version of int / 2 ,it only works with integers.

// DrawOrigin = new Vector2(pixel.Width >> 1, pixel.Heigth >> 1);
DrawOrigin = new Vector2(Boundaries.Width >> 1, Boundaries.Heigth >> 1);

// Remove the Boundaries, if not needed.
sprite_batch.Draw(pixel, Position - DrawOrigin, Boundaries, Color.White, MathHelper.ToRadians(Rotation), DrawOrigin, 1, SpriteEffects.None, 0);

Also, due the inverted nature of the Y axis the Sin needs to be negated for proper positive counter clockwise rotation angles:

// Added a minus before the Sin call, to correct the "Y up is negative"
 float y = (float)((radius * -Math.Sin(radians)) + origin.Y);
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .