Search code examples
c#colorspngspritemonogame

MonoGame / VS - PNG as Texture2D displaying as wrong color?


I'm using MonoGame in Visual Studio 2019 for Mac. I was following this Microsoft tutorial to make a little iOS program where a character walks toward wherever you touch.

I completed the tutorial and everything worked perfectly, however the character from the spritesheet they provided was tiny on the high-res display of the iPhone 11 simulator, so I wanted to make it bigger. I opened VSCode and used the "Image Resizer" extension to double the width and height. Here are the two spritesheets for comparison—I'm only using the top row of each.

I then went back to full Visual Studio and added it to the project, so both versions of the image are in the "Content" folder.

The only adjustments I made to the actual code were to: 1) change the filename from charactersheet.png to charactersheetbigger.png; 2) adjust the coordinates of the Rectangle being used for each frame of animation, either doubling them or leaving them as-is.

When I ran the updated program, the shape and animation of the sprite displayed correctly, but to my surprise, everything had a blue tint. When I revert to using the original file and original coordinates, everything works fine. When I use the doubled coordinates but with the smaller spritesheet, the color is correct. Here are screenshots of all three variations.

In light of this, it seems like the issue must be with how it's loading the larger spritesheet, but all I did was resize it, so I don't understand why that would be.

Here are images of the placement of the files in the solution explorer as well as a side-by-side comparison of the "Get info" pages for both images in Finder.

Below is the code from the CharacterEntity constructor with the altered code plus the method that actually draws it. I know it's inelegant to sequence the animation in the character constructor but that's how the tutorial did it.

    public class CharacterEntity
    {
        static Texture2D characterSheetTexture;

        public CharacterEntity(GraphicsDevice graphicsDevice)
        {
            if (characterSheetTexture == null)
            {
                // using (var stream = TitleContainer.OpenStream("Content/charactersheet.png"))
                using (var stream = TitleContainer.OpenStream("Content/charactersheetbigger.png"))
                {
                    characterSheetTexture = Texture2D.FromStream(graphicsDevice, stream);
                }
            }

            walkDown = new Animation();
            walkDown.AddFrame(new Rectangle(0, 0, 32, 32), TimeSpan.FromSeconds(.25));
            walkDown.AddFrame(new Rectangle(32, 0, 32, 32), TimeSpan.FromSeconds(.25));
            walkDown.AddFrame(new Rectangle(0, 0, 32, 32), TimeSpan.FromSeconds(.25));
            walkDown.AddFrame(new Rectangle(64, 0, 32, 32), TimeSpan.FromSeconds(.25));

            walkUp = new Animation();
            walkUp.AddFrame(new Rectangle(288, 0, 32, 32), TimeSpan.FromSeconds(.25));
            walkUp.AddFrame(new Rectangle(320, 0, 32, 32), TimeSpan.FromSeconds(.25));
            walkUp.AddFrame(new Rectangle(288, 0, 32, 32), TimeSpan.FromSeconds(.25));
            walkUp.AddFrame(new Rectangle(352, 0, 32, 32), TimeSpan.FromSeconds(.25));

            walkLeft = new Animation();
            walkLeft.AddFrame(new Rectangle(96, 0, 32, 32), TimeSpan.FromSeconds(.25));
            walkLeft.AddFrame(new Rectangle(128, 0, 32, 32), TimeSpan.FromSeconds(.25));
            walkLeft.AddFrame(new Rectangle(96, 0, 32, 32), TimeSpan.FromSeconds(.25));
            walkLeft.AddFrame(new Rectangle(160, 0, 32, 32), TimeSpan.FromSeconds(.25));

            walkRight = new Animation();
            walkRight.AddFrame(new Rectangle(192, 0, 32, 32), TimeSpan.FromSeconds(.25));
            walkRight.AddFrame(new Rectangle(224, 0, 32, 32), TimeSpan.FromSeconds(.25));
            walkRight.AddFrame(new Rectangle(192, 0, 32, 32), TimeSpan.FromSeconds(.25));
            walkRight.AddFrame(new Rectangle(256, 0, 32, 32), TimeSpan.FromSeconds(.25));

            standDown = new Animation();
            standDown.AddFrame(new Rectangle(0, 0, 32, 32), TimeSpan.FromSeconds(.25));

            standUp = new Animation();
            standUp.AddFrame(new Rectangle(288, 0, 32, 32), TimeSpan.FromSeconds(.25));

            standLeft = new Animation();
            standLeft.AddFrame(new Rectangle(96, 0, 32, 32), TimeSpan.FromSeconds(.25));

            standRight = new Animation();
            standRight.AddFrame(new Rectangle(192, 0, 32, 32), TimeSpan.FromSeconds(.25));
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            Vector2 topLeftOfSprite = new Vector2(this.X, this.Y);
            Color tintColor = Color.White;
            var sourceRectangle = currentAnimation.CurrentRectangle;
            spriteBatch.Draw(characterSheetTexture, topLeftOfSprite, sourceRectangle, tintColor);
        }

I've combed the internet and have yet to find anyone else with this exact problem. I've seen where some people have trouble loading pngs at all, and in response I've seen some people suggest converting the png to an xnb with MonoGame's content pipeline, but I don't know how to do that and, when my code does work with the original png, it seems there must be a simpler solution, or at least an explanation for why this is happening.

Any thoughts? Happy to share more details as needed.


Solution

  • I fixed the problem!

    It must've been something to do with how I resized the image. I fixed it by opening the original, smaller spritesheet in Photoshop, resizing it there, and using that version. If anyone has any suggestion as to why this worked I would love to understand.