2
votes

I want to be able to scale my sprite and keep them in the same spot as they were before the scale. I use the center of the sprite for the origin parameter because I want to be able to rotate my sprite too.

I'm sure the solution is going to be trivial but I can't find a proper/general solution to solve this problem.

If it's not really clear I made some pictures to show my code, the result of this code and what I want to achieve.

1 - This my code and the result this is what I get when I scale the sprite, as you can see the sprite is scaled but it "moved":

As suggested in the comment here is the code:

    Vector2 scale = Vector2.One;
    float rotation = 0;

    public void Update(GameTime gameTime)
    {
        if (Input.IsKeyPressed(Keys.P))
            scale += new Vector2(0.05f, 0.0f);
        if (Input.IsKeyPressed(Keys.M))
            scale -= new Vector2(0.05f, 0.0f);

        if (Input.IsKeyPressed(Keys.O))
            scale += new Vector2(0.0f, 0.05f);
        if (Input.IsKeyPressed(Keys.L))
            scale -= new Vector2(0.0f, 0.05f);

        if (Input.IsKeyPressed(Keys.D))
            rotation += MathHelper.ToRadians(5);
        if (Input.IsKeyPressed(Keys.Q))
            rotation -= MathHelper.ToRadians(5);

        Input.Update(gameTime);
    }

    public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
    {
        spriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointClamp, null, null, null, Matrix.CreateScale(4));

        spriteBatch.Draw(Sprites.BACKGROUND, Vector2.Zero, new Rectangle(0, 0, 128, 128), Color.White);

        Vector2 marioPosition = new Vector2(64, 112 - 32);
        Rectangle source = new Rectangle(0,0,16,32);

        Vector2 origin = source.Size.ToVector2() / 2;

        spriteBatch.Draw(Sprites.MARIO, marioPosition + origin, source, Color.White, rotation, origin, scale, SpriteEffects.None, 0f);

        spriteBatch.End();
    }

2 - This is what I want to achieve, I know I can do this by moving my origin point but I want to keep it in the center of the sprite so i can apply rotation around this point: http://pasteboard.co/rzMfc0p.png

2
Welcome to Stackoverflow . Could you paste you code into the body of the question, this makes it easier to read your question without moving between pages and in the event that the page you have linked to is ever removed, we still have the code in your question for future readers.Peter Campbell

2 Answers

1
votes

Someone helped me and found a solution to my problem (Pema99 @pemathedev), as suggested by other people the solution was indeed to move the sprite and here is how much you need to move your sprite :

public void Update(GameTime gameTime)
{
    if (Input.IsKeyPressed(Keys.P))
        scale.X += .05f;
    if (Input.IsKeyPressed(Keys.M))
        scale.X -= .05f;

    //Solution ---------------------------------------------------
    if (Input.IsKeyPressed(Keys.O))
    {
        float previousSize = source.Height * scale.Y;
        float newSize = source.Height * (scale.Y + .05f);
        scale.Y += .05f;
        marioPosition.Y -= (Math.Abs(previousSize - newSize)/2)
    }
    if (Input.IsKeyPressed(Keys.L))
    {
        float previousSize = source.Height * scale.Y;
        float newSize = source.Height * (scale.Y - .05f);
        scale.Y -= .05f;
        marioPosition.Y += (Math.Abs(previousSize - newSize)/2)
    }
    //--------------------------------------------------------------

    if (Input.IsKeyPressed(Keys.D))
        rotation += MathHelper.ToRadians(5);
    if (Input.IsKeyPressed(Keys.Q))
        rotation -= MathHelper.ToRadians(5);

    Input.Update(gameTime);
}

Thanks to everyone !

0
votes

Well, you are definitely keeping your character in place. Literally. What you need is to actually move your character in order for his legs to always stay on the ground.

If this is your whole code, then it means you have no physics (yet). In this case, you must move your character's position up/down by half of its on-screen height (image.height * scale), and do that only when his vertical scale is changing. This will not work well once you put physics in place, but for now, here is the not-tested-but-suggested code.

public void Update(GameTime gameTime)
{
    if (Input.IsKeyPressed(Keys.P))
        scale.X += .05f;
    if (Input.IsKeyPressed(Keys.M))
        scale.X -= .05f;

    if (Input.IsKeyPressed(Keys.O))
    {
        scale.Y += .05f;
        marioPosition.Y -= scale.Y * (Sprites.MARIO.Height / 2f);
    }
    if (Input.IsKeyPressed(Keys.L))
    {
        scale.Y -= .05f;
        marioPosition.Y += scale.Y * (Sprites.MARIO.Height / 2f);
    }

    if (Input.IsKeyPressed(Keys.D))
        rotation += MathHelper.ToRadians(5);
    if (Input.IsKeyPressed(Keys.Q))
        rotation -= MathHelper.ToRadians(5);

    Input.Update(gameTime);
}

The only reason I changed scale += new Vector2(0.0f, 0.05f); to scale.Y += .05f; is for you to see that it can be done faster, and you can make your code more readable.

Also, because of the inverted vertical (Y) axis in XNA, for character to move UP, you have to subtract from his position, and vie versa.

Some extra tips:

  • A class for all sprites is a great idea, also, the class for all input (Input) is great too

  • Instead of writing .05f in 4 places, create a variable, which will be in those places, and set it's value to .05f