How to crop an image

I have a bar/slider created, and I want to crop it based on the percentage given. Here is the code that I am using.

In the Constructor

private Texture2D barTexture;
private Rectangle spriteRect;
private Rectangle newBounds;
private int oldPercent;

oldPercent = percent;
newBounds = spriteRect;

Then in the update method

newBounds.Width += percent - oldPercent;

Im adding to the width of newbounds based on the change in percent between the last change and this one.

And then finally in the draw method

public void Render(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(barTexture, spriteRect, newBounds, Color.White);
    }

Here is where I expected the image to be cropped based on the newBounds rectangle. However when I run the program, the bar displays as fully black. The bar image shows up if I just comment the newBounds variable in the draw method, it only doesn’t work when I try and crop the image.

Can anyone help me here?

I think you just have your parameters mixed up. The overload of SpriteBatch.Draw calls for the destination rect before the source rect.

So, assuming your other code is all fine, the solution would be: spriteBatch.Draw(barTexture, newBounds, spriteRect, Color.White); Though I think you’ll need to debug what your newBounds.Width value is, since it seems like that would just forever make it wider and wider (adding to it every frame).

1 Like

I changed that around and now the bar changes in length if I manually tweak the values, so thanks for that :smiley:

However the image itself just renders as black instead of actually rendering in the texture. I know the texture itself is fine because if I just remove the segment of code that is cropping the image, it renders. Do you know why this is?

Debug your values for the destinationRectangle and sourceRectangle parameters. Almost certainly one or both of them is malformed.

I tried doing the same thing but replacing the newBounds rectangle with the original spriterect rectangle, meaning the destination rectangle and the crop rectangle should be the exact same, which means the full image should render. However it still just renders as fully black. Either there’s something really obvious I’m missing here or there’s some issue with the command itself.

3 Likes

Ahahah I was close to share your tuto too :stuck_out_tongue:

2 Likes

I actually just implemented something like this yesterday, and while it’s not nearly as fancy as Lubii’s solution I figured I’d still drop it to see who else it helps… I did this for my very primitive health bar and should be easily usable in whatever you want (health, mana, xp, etc). I just import a 1px white square that I made in paint and use that texture for all my random shapes that need to be sized and painted in any color I want. I then slap it in with custom rects and draw.

I had mine split between two functions (one that gets called when health changes, and the other that gets called by draw) and a few class variables. You’ll just need to reference your Game1 into game1 (or maybe g?):

        /// <summary>
        /// Whenever health is changed (either by damage or healing) send player's health info here.
        /// This assumes you have Game1 referenced to game
        /// </summary>
        /// <param name="currentHp">The value used for the 'fill' bar</param>
        /// <param name="totalHp">Value used for a full bar</param>
        private void UpdateHealthBar(int currentHp, int totalHp)
        {
            int healthWidth = 120;
            int healthFraction = healthWidth / totalHp;

            Rectangle outterRect = new Rectangle(10, 20, healthWidth, 30);
            Rectangle fillRect = new Rectangle(10, 20, healthFraction * currentHp, 30);

        }

        /// <summary>
        /// Call this from your draw function 
        /// </summary>
        private void DrawHealthBar()
        {

            Texture2D rectTex = g.Content.Load<Texture2D>("images/1pxWhite");

            spriteBatch.Draw(rectTex, outterRect, Color.Red);
            spriteBatch.Draw(rectTex, fillRect, Color.Green);

        }

Good luck :wink:

I found the solution myself, I had the newBounds rectangle set to the same position as the SpriteRect, which means while drawing, the game was trying to find the rectangle that was, like for example, 100, 100 away from 100, 100, instead of drawing at 0, 0. (Which would be 100, 100). Simply initializing the newBounds rectangle at 0, 0 fixed that for me. I found that out by following that video, so thanks a ton!
: D