Hello stackoverflow!
I'm working on a 2D sidescroller adventure game in C# using MonoGame, and I've come upon a peculiar problem.
In short: Player instance has assigned a Texture2D containing the player's texture (in this example a blue box with a 2px green border) When player moves, texture "stays in place" and player gradually becomes green as he leaves the space where the texture is. This is of course not supposed to happen, as the texture is supposed to be redrawn at Player's exact location everytime Draw() is called.
In other words - the player should still be a blue box with a 2px green border no matter where he moves.
Images for better illustration:
Original state
Player moves downward, leaving texture behind.
Until he is completely green.
And when he comes back to his original position, the correct texture starts to show again
I've cut down the code to it's bare bones, but the issue is still persisting.
Game.cs contains nothing interesting, Player initialization and Draw method here:
//inside of Initialize()
player = new Player(GraphicsDevice, Vector2.Zero);
protected override void Draw(GameTime gameTime) {
GraphicsDevice.Clear(Color.CornflowerBlue);
levelSpriteBatch.Begin();
player.Draw(gameTime, levelSpriteBatch);
levelSpriteBatch.End();
base.Draw(gameTime);
}
Player.cs (whole file) here:
class Player {
public Vector2 Position
{
get { return position; }
}
Vector2 position;
public Texture2D Texture { get; private set; }
public const int Width = 32;
public const int Height = 32;
// Input configuration
private const Keys leftButton = Keys.A;
private const Keys rightButton = Keys.D;
private const Keys upButton = Keys.W;
private const Keys downButton = Keys.S;
//Current state
private float LRmovement;
private float UDmovement;
public Player(GraphicsDevice graphicsDevice, Vector2 position) {
this.position = position;
CreateTexture(graphicsDevice, Width, Height);
}
public void Update(GameTime gameTime, KeyboardState keyboardState) {
GetInput(keyboardState);
position.X += LRmovement;
position.Y += UDmovement;
LRmovement = 0.0f;
UDmovement = 0.0f;
}
private void CreateTexture(GraphicsDevice graphicsDevice, int width, int height) {
Texture = new Texture2D(graphicsDevice, width, height);
GraphicsHelper.FillRectangle(Texture, Color.Red);
GraphicsHelper.OutlineRectangle(Texture, Color.Green, 2);
}
private void GetInput(KeyboardState keyboardState) {
LRmovement = 0;
UDmovement = 0;
if (Math.Abs(LRmovement) < 0.5f)
LRmovement = 0.0f;
if (Math.Abs(UDmovement) < 0.5f)
UDmovement = 0.0f;
if (keyboardState.IsKeyDown(leftButton))
LRmovement = -1.0f;
else if (keyboardState.IsKeyDown(rightButton))
LRmovement = 1.0f;
if (keyboardState.IsKeyDown(upButton))
UDmovement = -1.0f;
else if (keyboardState.IsKeyDown(downButton))
UDmovement = 1.0f;
}
public void Draw(GameTime gameTime, SpriteBatch spriteBatch) {
spriteBatch.Draw(Texture, position, new Rectangle((int)Position.X, (int)Position.Y, Width, Height), Color.White);
}
}
And GraphicsHelper.cs:
class GraphicsHelper {
public static void FillRectangle(Texture2D texture, Color fill) {
Color[] color = new Color[texture.Width * texture.Height];
texture.GetData(color);
for (int i = 0; i < texture.Width * texture.Height; ++i)
color[i] = fill;
texture.SetData(color);
}
public static void OutlineRectangle(Texture2D texture, Color outline, int outlineWidth) {
Color[] color = new Color[texture.Width * texture.Height];
texture.GetData(color);
int index = 0;
for (int y = 0; y < texture.Height; ++y) {
for (int x = 0; x < texture.Width; ++x) {
if (y < outlineWidth || x < outlineWidth || y > texture.Height - outlineWidth || x > texture.Width - outlineWidth)
color[index] = outline;
++index;
}
}
texture.SetData(color);
}
}
This is ALL THE CODE THERE IS. I'm honestly out of ideas.
This is the problematic line:
spriteBatch.Draw(Texture, position, new Rectangle((int)Position.X, (int)Position.Y, Width, Height), Color.White);
The third parameter (the rectangle) defines which part of the texture to draw. And you always want to draw the same part of the texture, hence you should pass a constant rectangle.
Actually, if you just want to draw the entire texture, pass null
:
spriteBatch.Draw(Texture, position, null, Color.White);