3
\$\begingroup\$

This is probably a very easy question, but I can't seem to understand why it's not working.

I want the basketball to bounce horizontally when it touches the borders on the right and left, but when it bounces on the right, it seems to go just a little bit further than it should.

Any suggestions?

protected override void Update(GameTime gameTime)
{
    // Allows the game to exit
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
        this.Exit();

    basketballPosition.X += ballSpeed;
    if (basketballPosition.X > Window.ClientBounds.Width - basketball.Width || basketballPosition.X < 0)
    {
        ballSpeed *= -1;
    }

    base.Update(gameTime);
}

And my Draw method:

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);

        spriteBatch.Begin();

        spriteBatch.Draw(basketball, 
                         basketballPosition, 
                         null,
                         Color.White, 
                         0, 
                         Vector2.Zero, 
                         1.5f,
                         SpriteEffects.None, 
                         0);

        spriteBatch.End();

        base.Draw(gameTime);
    }

enter image description here


Edit The problem was I was using a scale of 1.5f for drawing the image. Can someone explain how I would get the true border of the image if I were using scale? It seems the border stay as the original size, but the texture is drawn to whatever scale I choose.

\$\endgroup\$

1 Answer 1

12
\$\begingroup\$

Since your ball is scaled, it means that using the texture's width (basketball.Width) is not correct, since the real width is the texture's width times the scale.

Your code would change like this:

if (basketballPosition.X > Window.ClientBounds.Width - (basketball.Width * 1.5f) ||
    basketballPosition.X < 0)

This is because supplying a scale parameter different than 1.0f to spriteBatch.Draw has the effect of modifying how the image is drawn, it does not change its stored width and height however.

So, you have to keep in mind when using the width of a texture that you're using the width of the original image, not the scaled one.

You simply need to scale the width and height whenever appropriate. In this case you want to know when the drawn right border of the image goes too far on the right, so you need the scaled width.


A suggestion to clean the code a little bit...

Keeping magic values isn't always nice, so you might want to make a class out of that basketball:

Note: I have not tested the code below, but you get the general idea.

public class BasketBall
{
    Texture2D texture;
    public Vector2 Position { get; set; }
    public float Scale { get; set; }
    float ballSpeed;

    Rectangle screenRectangle;

    /// <summary>
    /// Returns the scaled bounding rectangle of the basketball.
    /// </summary>
    public Rectangle BoundingRectangle
    {
        get
        {
            return new Rectangle((int)Position.X, (int)Position.Y,
                (int)(texture.Width * Scale), (int)(texture.Height * Scale));
        }
    }

    public BasketBall(string assetPath, Vector2 startPos, float scale, float startSpeed,
        Rectangle screenRectangle)
    {
        texture = Content.Load<Texture2D>(assetPath);
        Position = startPos;
        Scale = scale;
        ballSpeed = startSpeed;
        this.screenRectangle = screenRectangle;
    }

    public void Update(GameTime gameTime)
    {
        Position.X += ballSpeed * gameTime.ElapsedGameTime.TotalSeconds; // multiply by delta seconds for consistent behavior on different machines

        // Much more straightforward now. The scaling happens when calling BoundingRectangle
        if (BoundingRectangle.Left < 0f || BoundingRectangle.Right > screenRectangle.Right)
        {
            ballSpeed *= -1;
        }
    }

    public void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Begin();

        spriteBatch.Draw(texture,
                         Position,
                         null,
                         Color.White,
                         0,
                         Vector2.Zero,
                         Scale,
                         SpriteEffects.None,
                         0);

        spriteBatch.End();
    }
}

So much cleaner to use imho:

BasketBall basketBall;

When you load its content:

basketBall = new BasketBall("basketBall", Vector2.Zero, 1.5f, 50f, 
                            new Rectangle(Window.ClientBounds.X, 
                                          Window.ClientBounds.Y, 
                                          Window.ClientBounds.Width, 
                                          Window.ClientBounds.Height));

When you update it:

basketBall.update(gameTime);

When you draw it:

basketBall.draw(spriteBatch);

If you do prefer the no-class version, then I'd recommend at least keeping a Vector2 showing the scaled measures of the sprite, for cleaner calculations. Also, a constant for the scale would be nice. Like so:

const float BALL_SCALE = 1.5f;
Vector2 basketBallMeasures = new Vector2(basketball.Width, basketball.Height) * BALL_SCALE;
\$\endgroup\$
0

You must log in to answer this question.

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