Hello.
(be warned: the fomatting is bad in this post)
I’m having a graphics problem with my game. Whenever I move my player sprite, it leaves a black trail behind it. and the sprite also stutters a lot. here’s a video:
Another note: When I shake the window, the black trails also appear on my player, but not on the box (Which also inherits from object). Here’s all of the code that seems to be relevant:
Player.cs:
public class Player : Object
{
public Texture2D Texture;
float speed = 500;
public Player()
{
Collider = new Rectangle(0, 0, 100, 100);
}
public void PlayerUpdate(GameTime gameTime)
{
MoveColliderStart();
if (Input.state.IsKeyDown(Keys.Left))
{
Collider = Move(new Rectangle(Collider.X - (int)(speed * gameTime.ElapsedGameTime.TotalSeconds), Collider.Y, Collider.Width, Collider.Height));
}
if (Input.state.IsKeyDown(Keys.Right))
{
Collider = Move(new Rectangle(Collider.X + (int)(speed * gameTime.ElapsedGameTime.TotalSeconds), Collider.Y, Collider.Width, Collider.Height));
}
if (Input.state.IsKeyDown(Keys.Up))
{
Collider = Move(new Rectangle(Collider.X, Collider.Y - (int)(speed * gameTime.ElapsedGameTime.TotalSeconds), Collider.Width, Collider.Height));
}
if (Input.state.IsKeyDown(Keys.Down))
{
Collider = Move(new Rectangle(Collider.X, Collider.Y + (int)(speed * gameTime.ElapsedGameTime.TotalSeconds), Collider.Width, Collider.Height));
}
MoveColliderEnd();
}
}
}`
Object.cs
namespace City.Objects
{
public class Object
{
/*Adds a Collider, which holds the position and size of the
* object (An object can have only one collider)
*/
public Rectangle Collider;
/*Creates a list of all the colliders in the state. See
* the ChangeState method in state to see how it clears.
*/
public static List<Rectangle> PhysicsColliders = new List<Rectangle>();
public Object()
{
/*If you are creating a moveable object,
* don't add it to PhysicsColliders in the
* constructor. Only do that with Stationary
* objects.
*/
}
/*Move creates a rectangle that takes a position and checks if it
* collides with anything. To use it, assuming you are using the
* collider as the position argument in the draw method of the
* state, you can set the collider position to the move method.
*/
public Rectangle Move(Rectangle position)
{
//Creates a rectangle to hold the return value. Sets it to the current posiiton.
Rectangle newPos = Collider;
bool CanChangeX = true;
bool CanChangeY = true;
//Checks all of the colliders in the PhysicsColliders list.
for (int i = 0; i < PhysicsColliders.Count; i++)
{
/*Checks if the requested position is beyond the edge of another object. If
* It is, it checks to see if the collider intersects with the object. If either
* of these are false, the requested position becomes the new position.
*/
if (CanChangeX)
{
if (!((position.X + position.Width > PhysicsColliders[i].X || position.X < PhysicsColliders[i].X)
&& position.Intersects(PhysicsColliders[i])))
{
CanChangeX = true;
}
else
{
CanChangeX = false;
}
}
if (CanChangeY)
{
if (!((position.Y + position.Height > PhysicsColliders[i].Y || position.Y < PhysicsColliders[i].Y)
&& position.Intersects(PhysicsColliders[i])))
{
CanChangeY = true;
}
else
{
CanChangeY = false;
}
}
}
if (CanChangeX)
{
newPos.X = position.X;
}
if (CanChangeY)
{
newPos.Y = position.Y;
}
//Returns the filtered position
return newPos;
}
//These methods need to be specified before and after moving an object
public void MoveColliderStart()
{
PhysicsColliders.Remove(PhysicsColliders.Find(x => x == Collider));
}
public void MoveColliderEnd()
{
PhysicsColliders.Add(Collider);
}
}
}`
TestState.cs
`using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Content;
using City.Objects;
namespace City.States
{
public class TestState : State
{
Player player = new Player();
PhysicsBox box = new PhysicsBox();
Camera camera;
FrameCounter frameCounter = new FrameCounter();
SpriteFont font;
Tiles.Tilemap map = new Tiles.Tilemap();
public override void Init()
{
player.Texture = content.Load<Texture2D>("WhiteSquare");
box.Texture = player.Texture;
font = content.Load<SpriteFont>("File");
camera = new Camera(device.Viewport);
map.Map.Add(new string[] { "xxxx", "xxxx"});
map.CreateMap();
base.Init();
}
public override void Update(GameTime gameTime)
{
camera.Update(gameTime);
player.PlayerUpdate(gameTime);
}
public override void Draw(GameTime gameTime)
{
spriteBatch.Begin(SpriteSortMode.FrontToBack, null, null, null, null, null, camera.transform);
spriteBatch.Draw(player.Texture, player.Collider, Color.Red);
spriteBatch.Draw(box.Texture, box.Collider, Color.White);
var deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
frameCounter.Update(deltaTime);
var fps = string.Format("FPS: {0}", frameCounter.AverageFramesPerSecond);
spriteBatch.DrawString(font, fps, new Vector2(1, 1), Color.Black);
spriteBatch.End();
}
}
}`
Game1.cs
`using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Content;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using City.States;
using System.Diagnostics;
namespace City
{
///
/// This is the main type for your game.
///
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
public static ContentManager _content;
public static SpriteBatch _spriteBatch;
public static List<State> _states = new List<State>();
public static List<Texture2D> LoadedTextures = new List<Texture2D>();
//Make States
public static State testState;
public static State currentState = null;
public static bool CanCheck;
public Game1()
{
graphics = new GraphicsDeviceManager(this)
{
SynchronizeWithVerticalRetrace = false,
};
graphics.ApplyChanges();
Content.RootDirectory = "Content";
_content = Content;
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
//Create States
testState = new TestState();
testState.isCurrentState = true;
CanCheck = true;
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
State.spriteBatch = spriteBatch;
State.device = this.GraphicsDevice;
// TODO: use this.Content to load your game content here
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// game-specific content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
Input.GetKeyboardInput();
//makes sure the code to set the current state doesn't run unnessesarily
if (CanCheck)
{
//Checks which is the current state
foreach (State i in _states)
{
if (i.isCurrentState)
{
//stores the current state object in a variable
currentState = i;
}
}
CanCheck = false;
}
//runs the init if it hasn't already
if (currentState != null)
{
if (!currentState.isFinishedInit)
currentState.Init();
currentState.Update(gameTime);
}
base.Update(gameTime);
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Green);
// TODO: Add your drawing code here
if(currentState != null)
{
currentState.Draw(gameTime);
}
base.Draw(gameTime);
}
}
}`
If you need any more information, I’d be happy to give it to you.