program crashes (white screen) when using gamestates - c#
I'm pretty new to programming. I'm developing a 2D game using monogame where you have to run around killing enemies and jumping from one moving tile to another trying not to fall on the spikes and die.
I almost have everything of the mechanics, collision. I want to start making multiple levels, a beginscreen where you have to press s to start and when you die a gameover screen.
I have implemented gamestates. the program starts on the first state(menu) where you get a picture that says press S to start but when i press S to start the program crashes and I get a null reference exeption... but if I don't use the menu state as the first state and instead I use the level1 gamestate the game works so there is no null reference exeption (but you don't get the menuscreen of course).
I'm doing something wrong but i cant find it. I will paste my game1.cs below. I think that's where the problem is. if you need something else please ask.
please help, thanks in advance. ps: sorry for the large amount of code but the problem could be everywhere
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.Collections.Generic;
namespace ninjaprincess
{
/// <summary>
/// This is the main type for your game.
/// </summary>
public class Game1 : Game
{
//Game states http://community.monogame.net/t/switch-scenes-in-monogame/2605
enum GameState
{
Menu,
GamePlayLevel1,
EndGame
}
GameState _state;
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Hero ninja;
private Texture2D ninjasprite;
private Texture2D background;
private LevelDesign level;
private Texture2D StartScreen;
Camera camera;
bool start;
List<Knife> knives = new List<Knife>();
KeyboardState pastkey;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
/// dit toevoegen voor fullscreen////
graphics.PreferredBackBufferHeight = 1080;
graphics.PreferredBackBufferWidth = 1920;
graphics.IsFullScreen = true;
}
protected override void Initialize()
{
camera = new Camera(GraphicsDevice.Viewport);
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
level = new LevelDesign();
background = Content.Load<Texture2D>("background");
ninja = new Hero(ninjasprite, new Vector2(10, 20));
ninja.Content(Content);
level.content = Content;
StartScreen = Content.Load<Texture2D>("Startscherm");
Block.Content = Content;
level.tileArray = new byte[,]
{
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{ 0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{ 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0},
{ 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,4,4,0,4,4,4,0,0,0,0},
{ 0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0},
{ 0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0},
{ 0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{ 0,0,1,1,1,0,0,0,0,0,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0}
};
level.CreateWorld(105);
ninja.controllers = new KeyboardArrows();
}
/// <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
}
/// <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();
if (_state == GameState.GamePlayLevel1)
{
camera.Update(ninja.Position, level.Width + 400, 1080);
ninja.Update(gameTime);
if (ninja.controllers.shooting && pastkey.IsKeyUp(Keys.Space))
{
ShootKnife();
}
pastkey = Keyboard.GetState();
UpdateKnife();
foreach (Block block in level.blockArray)
{
if (block is Grass)
{
ninja.CollideOnGrass(block.Rectangle);
}
if (block is Spikes)
{
ninja.CollideOnSpikes(block.Rectangle);
}
if (block is MovingGrassLeft)
{
ninja.CollideOnGrass(block.Rectangle);
block.Update(gameTime);
}
}
foreach (Enemy enemy in level.enemyArray)
{
if (enemy is Enemy)
{
ninja.CollideOnEnemy(enemy.EnemyRectangle, 2840, 1080, level.enemyArray, (enemy.EnemyRectangle.X - (enemy.EnemyRectangle.Width / 3)), enemy.EnemyRectangle.Y + (enemy.EnemyRectangle.Height / 2));
enemy.Update(gameTime);
}
}
if (ninja.isAlive == false)
{
_state = GameState.EndGame;
}
}
base.Update(gameTime);
switch (_state)
{
case GameState.Menu:
UpdateMenu(gameTime);
break;
case GameState.GamePlayLevel1:
UpdateGameplay(gameTime);
break;
case GameState.EndGame:
UpdateEndGame(gameTime);
break;
}
}
void UpdateMenu(GameTime gametime)
{
KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.S))
_state = GameState.GamePlayLevel1;
else if (keyState.IsKeyDown(Keys.Q))
Exit();
}
void UpdateGameplay(GameTime gametime)
{
KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.Escape))
_state = GameState.Menu;
}
void UpdateEndGame(GameTime gametime)
{
KeyboardState keyState = Keyboard.GetState();
if (keyState.IsKeyDown(Keys.Q))
Exit();
if (keyState.IsKeyDown(Keys.S))
_state = GameState.GamePlayLevel1;
}
public void UpdateKnife()
{
foreach (Knife knife in knives)
{
knife.position.X += 25f;
for (int i = 1; i < knives.Count; i++)
{
if (knives[i].isVisible == false)
{
knives.RemoveAt(i);
i--;
}
}
}
}
public void ShootKnife()
{
Knife newKnife = new Knife(Content.Load<Texture2D>("KunaiRight"));
newKnife.isVisible = true;
newKnife.velocity.X = 3f;
newKnife.position = new Vector2(ninja.Position.X, ninja.Position.Y + (ninja.PlayerRectangle.Height / 2));
if (knives.Count < 50)
{
knives.Add(newKnife);
}
}
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.White);
switch (_state)
{
case GameState.Menu:
DrawMenu(gameTime);
break;
case GameState.GamePlayLevel1:
DrawGamePlayLevel1(gameTime);
break;
case GameState.EndGame:
DrawEndGame(gameTime);
break;
}
base.Draw(gameTime);
}
void DrawMenu(GameTime GameTime)
{
spriteBatch.Begin();
spriteBatch.Draw(StartScreen, new Rectangle(0, 0, 1920, 1080), Color.AliceBlue);
spriteBatch.End();
}
void DrawGamePlayLevel1(GameTime GameTime)
{
GraphicsDevice.Clear(Color.White);
spriteBatch.Begin();
spriteBatch.Draw(background, new Rectangle(0, 0, 1920, 1080), Color.White);
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, null, camera.Transform);
level.DrawLevel(spriteBatch);
ninja.Draw(spriteBatch);
foreach (Knife knife in knives)
{
knife.Draw(spriteBatch);
}
spriteBatch.End();
}
void DrawEndGame(GameTime GameTime)
{
spriteBatch.Begin();
spriteBatch.Draw(StartScreen, new Rectangle(0, 0, 1920, 1080), Color.White);
spriteBatch.End();
}
}
}
If the problem is only a nullreference Exception, then try debugging your code by looking where the exception happens. I also recommend reading this: What is a NullReferenceException, and how do I fix it?
In a nutshell: Nullreference exceptions happens because the game's expecting a value in a variable, but that variable is not set. (and the standard value of 'not set' is null).
I think it's because your _state isn't set, and your Switch statements doesn't have a default case. So if It reads something that's not defined in the cases, it'll crash.
That's just my assumption though. To know the exact problem, you have to try debugging it and find where and when the exception occurs.
Related
Low framerate in MonoGame
I'm writing a 2D puzzle game in MonoGame. I just added my first moving sprite to the program, and discovered that I'm getting about 10fps on it, and I haven't got the faintest idea why. I don't know if I can provide enough information to get help here, but I thought it was worth a shot. For reference, the moving object is a Ball. Main update routine: protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) Exit(); MouseState newState = Mouse.GetState(); if (newState.LeftButton == ButtonState.Pressed && oldState.LeftButton == ButtonState.Released) { MouseLeftClicked(newState.X, newState.Y); } oldState = newState; if (gameState == GameState.Playing) { try { foreach (Ball ball in ballList) { ball.Update(gameTime); } } catch(NullReferenceException) { } } // TODO: Add your update logic here base.Update(gameTime); } Ball update routine: public void Update(GameTime gameTime) { this.pos += this.motion * (float)gameTime.ElapsedGameTime.TotalSeconds; } Main Draw routine: protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here spriteBatch.Begin(); for (int x = 0; x < 8; x++) { for (int y = 0; y < 6; y++) { if (gameGrid[x, y] != null) { spriteBatch.Draw(backgroundTile, gameGrid[x, y].rect, Color.White); } } } //Draw menu if (gameState == GameState.StartMenu) { spriteBatch.Draw(startButton, orbPosition, Color.White); } //Draw game while playing if (gameState == GameState.Playing) { for (int x = 0; x < 8; x++) { for (int y = 0; y < 6; y++) { try { gameGrid[x, y].pipe.Draw(spriteBatch); } catch (NullReferenceException) { continue; } } } foreach (Wheel wheel in wheelList) { wheel.Draw(spriteBatch); } foreach (Ball ball in ballList) { ball.Draw(spriteBatch); } } spriteBatch.End(); base.Draw(gameTime); } Ball Draw routine: public void Draw(SpriteBatch spriteBatch) { int sprite = (int)color; Rectangle sourceRect = new Rectangle(sprite * spriteSize, 0, spriteSize, spriteSize); Rectangle ballRect = new Rectangle((int)this.pos.X, (int)this.pos.Y, spriteSize * scale, spriteSize * scale); //spriteBatch.Begin(); spriteBatch.Draw(this.texture, ballRect, sourceRect, Color.White); //spriteBatch.End(); }
I tested your code and it does not lag when providing a texture. I had to make slight modification to your code in order to make it work since you omitted parts from it. I suppose the omitted parts may be responsible but it is unlikely. I don't know on what kind of machine you are testing this but, I will provide some recommendations in order to resolve the problem you have locally. When writing performant code, forget everything you know about 'object oriented behaviour' and think data. Data oriented design is all about sticking data that belongs together into big chunks and processing it all at once. This is much faster. In many cases as for game design, when there is one, there are many. Use that to your advantage and pass the whole array and act upon it directly on the spot. Avoid nesting exceptions and iterative loops if possible. Exceptions are expensive when they occur, they should only be used when it is very exceptional, or if it is extremely unusual that the case actually does occur, and you wish to handle this 'edge' case by throwing an exception to force consumers of the code to handle it. for (int x = 0; x < 8; x++) { for (int y = 0; y < 6; y++) { try { gameGrid[x, y].pipe.Draw(spriteBatch); } catch (NullReferenceException) { continue; } } } Catching the Null Reference Exception that you nested in the two for loops might be a bad idea. If you need to throw from one of these, and that allows you to draw the next consider why the throw is necessary if you wish to keep the code as it is. If it's there to catch empties in gameGrid or pipe, consider that a constructor should always put the item in a valid state and that the list should always be 'complete'. If an element stops existing it should not be in the list anymore. Otherwise, if one failure means all fail move the try block outside. This is more common. Profiling your application is a mechanism that helps you find where things are slower than you expected and sometimes even why. Here's a reference on how to do this in visual studio. Beginners Guide to Performance Profiling as well as Walkthrough: Profiling Applications. That said, none of these would slow your application down to the sort of degree you are describing. Therefore I advice you to edit your question and include other relevant sections of the code that may be the cause. I have attached below a sample constructed from your small example with some small modifications in order to simulate your environment in a much more extreme manner. This example draws 100 rectangles of which each one is 50x50 and they all rescale and move like your application does as well. These are 100 tiles, if this is slow for you on its own you should definitely look into the profiler topic above if you are using visual studio or try getting the latest binaries from Mono Game's official website or your latest graphics card drivers. /// <summary> /// This is the main type for your game /// </summary> public class Game1 : Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } public IList<Ball> Balls { get; private set; } /// <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); var rand = new Random(); Balls = new List<Ball>(5); for(var iii = 0; iii < 100; ++iii) Balls.Add(new Ball(GraphicsDevice, new Vector2(rand.Next(50, 500), rand.Next(50, 500)))); } /// <summary> /// UnloadContent will be called once per game and is the place to unload /// all content. /// </summary> protected override void UnloadContent() { } /// <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(); foreach (var ball in Balls) ball.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.CornflowerBlue); spriteBatch.Begin(); foreach (var ball in Balls) ball.Draw(spriteBatch); spriteBatch.End(); base.Draw(gameTime); } } public class Ball { public Texture2D Texture { get; } public Vector2 Position { get; private set; } public double Scale { get; private set; } public Ball(GraphicsDevice gd, Vector2 initialPosition) { Texture = new Texture2D(gd, 50, 50); Position = initialPosition; var data = new Color[100*100]; for (var iii = 0; iii < data.Length; ++iii) data[iii] = Color.YellowGreen; Texture.SetData(data); } private bool _increaseScale, _increaseX, _increaseY; public void Update(GameTime gameTime) { if (Scale < 1) _increaseScale = true; else if (Scale > 4) _increaseScale = false; if (Position.X < 50) _increaseX = true; else if (Position.X > 500) _increaseX = false; if (Position.Y < 50) _increaseY = true; else if (Position.Y > 500) _increaseY = false; Scale += (_increaseScale ? 1.5 : -1.5) * gameTime.ElapsedGameTime.TotalSeconds; Position += new Vector2((float)((_increaseX ? 100 : -100)*gameTime.ElapsedGameTime.TotalSeconds), (float)((_increaseY ? 100 : -100)*gameTime.ElapsedGameTime.TotalSeconds)); } public void Draw(SpriteBatch spriteBatch) { var source = new Rectangle(0, 0, Texture.Height, Texture.Width); var dest = new Rectangle((int)Position.X, (int)Position.Y, Texture.Width * (int)Scale, Texture.Height* (int)Scale); spriteBatch.Draw(Texture, dest, source, Color.White); } }
XNA Switch Statement Error
I'm new to Xna and I'm trying to make an rpg. I built my game and received an error in my main game class. I'm getting errors from the Draw method of my code. I'm not used to using switch statements and I'm not sure what the proper way to make one is. What steps can I take to solve my error? Thanks. error: On the line: "switch (activeScreen)" A switch expression or case label must be a bool, char, string, integral, enum, or corresponding nullable type Game Class: public class Game1 : Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; SpriteFont font; KeyboardState keyboardState; KeyboardState oldKeyboardState; GameScreen activeScreen; StartScreen startScreen; ActionScreen actionScreen; CharScreen charScreen; ClassScreen classScreen; GenderScreen genderScreen; Vector2 charPosition = new Vector2(0, 0); Texture2D charSprite; int charHorizSpeed = 1; int charVertSpeed = 1; Texture2D logoTexture; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; graphics.IsFullScreen = false; oldKeyboardState = Keyboard.GetState(); } protected override void Initialize() { base.Initialize(); } protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); charSprite = this.Content.Load<Texture2D>("charSprite"); //create new instance of the startScreen startScreen = new StartScreen( this, spriteBatch, //loads the font to the screen font = Content.Load<SpriteFont>("menufont"), //loads the image to the screen Content.Load<Texture2D>("RPGLogo")); //adds the screen to components Components.Add(startScreen); //startScreen.Hide(); //creates new instance the actionScreen actionScreen = new ActionScreen( this, spriteBatch, Content.Load<Texture2D>("tileMap"), Content.Load<Texture2D>("character"), charSprite = Content.Load<Texture2D>("charSprite")); //adds the screen to components Components.Add(actionScreen); //actionScreen.Hide(); activeScreen.Hide(); activeScreen = startScreen; activeScreen.Show(); charScreen = new CharScreen( this, spriteBatch, charSprite = Content.Load<Texture2D>("charSprite"), font = Content.Load<SpriteFont>("menufont")); Components.Add(charScreen); //charScreen.Hide (); activeScreen.Hide(); activeScreen = charScreen; activeScreen.Show(); classScreen = new ClassScreen( this, spriteBatch, charSprite = Content.Load<Texture2D>("charSprite"), font = Content.Load<SpriteFont>("menufont")); Components.Add(classScreen); activeScreen.Hide(); activeScreen = classScreen; activeScreen.Show(); } protected override void Update(GameTime gameTime) { //get hte current state of the keyboard keyboardState = Keyboard.GetState(); UpdateSprite(gameTime); if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); //checks if instances are the same if (activeScreen == startScreen) { //checks if enter key was pressed if (CheckKey(Keys.Enter)) { //if the selected index is on the first item (start game), the current active screen will hide adn it will be switched to the action screen if (startScreen.SelectedIndex == 0) { activeScreen.Hide(); activeScreen = actionScreen; activeScreen.Show(); } //if the selected index is on the second item (exit) the game will exit if (startScreen.SelectedIndex == 1) { this.Exit(); } } } if (activeScreen == charScreen) { if (CheckKey(Keys.Enter)) { if (charScreen.SelectedIndex == 0) { activeScreen.Hide(); activeScreen = classScreen; activeScreen.Show(); //create a drop down menu for character class options/pop up? } } if (CheckKey(Keys.Enter)) { if (charScreen.SelectedIndex == 1) { activeScreen.Hide(); activeScreen = genderScreen; activeScreen.Show(); } } } if (activeScreen == classScreen) { if (CheckKey(Keys.Enter)) { if (classScreen.SelectedIndex == 0) { //call warior class } if (classScreen.SelectedIndex == 1) { //call mage class } if (classScreen.SelectedIndex == 2) { //call ranger class } } } if (activeScreen == genderScreen) { if (CheckKey(Keys.Enter)) { if (genderScreen.SelectedIndex == 0) { //call gender class (male) } if (genderScreen.SelectedIndex == 1) { //call gender class (female) } } } base.Update(gameTime); oldKeyboardState = keyboardState; } private bool CheckKey(Keys theKey) { //returns if the key was pressed in the last frame return keyboardState.IsKeyUp(theKey) && oldKeyboardState.IsKeyDown(theKey); } private void DrawStartScreen() { spriteBatch.DrawString(font, "Vengence In Albion", new Vector2(20, 45), Color.White); } private void DrawCharScreen() { spriteBatch.DrawString(font, "Character Selection", new Vector2(20, 45), Color.White); spriteBatch.Draw(charSprite, charPosition, Color.White); } private void DrawClassScreen() { spriteBatch.DrawString(font, "Choose your Class", new Vector2(20, 45), Color.White); } private void DrawGenderScreen() { spriteBatch.DrawString(font, "Choose a gender", new Vector2(20, 45), Color.White); } private void UpdateSprite(GameTime gameTime) { //move the sprite by speed KeyboardState newState = Keyboard.GetState(); int MaxX = Window.ClientBounds.Width - charSprite.Width; int MaxY = Window.ClientBounds.Height - charSprite.Height; int MinX = 0; int MinY = 0; if (newState.IsKeyDown(Keys.Left)) { // Move left charHorizSpeed = -1; } if (newState.IsKeyDown(Keys.Right)) { // Move left charHorizSpeed = 1; } if (newState.IsKeyDown(Keys.Up)) { // Move left charVertSpeed = -1; } if (newState.IsKeyDown(Keys.Down)) { // Move left charVertSpeed = 1; } if (charPosition.X > MaxX) { charHorizSpeed *= -1; charPosition.X = MaxX; } else if (charPosition.X < MinX) { charHorizSpeed *= -1; charPosition.X = MinX; } if (charPosition.Y > MaxY) { charVertSpeed *= -1; charPosition.Y = MaxY; } else if (charPosition.Y < MinY) { charVertSpeed *= -1; charPosition.Y = MinY; } oldKeyboardState = keyboardState; } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.DarkSlateBlue); spriteBatch.Begin(); switch (activeScreen) { case activeScreen.startScreen: DrawStartScreen(); StartScreen(); break; case activeScreen.charScreen: DrawCharScreen(); CharScreen(); break; case activeScreen.actionScreen: //draw map break; case activeScreen.classScreen: DrawClassScreen(); ClassScreen(); break; case activeScreen.genderScreen: DrawGenderScreen(); GenderScreen(); break; } base.Draw(gameTime); spriteBatch.End(); } }
Without seeing types it is hard to tell, but activeScreen is definitely not a type you can use as a switch. Also, it looks like you are repeating the same methods in every case. According to the code above you don't need a switch statement at all. Use a different method of determining the current screen like activeScreen is activeScreen.startScreen or something within if blocks..
Pause Menu Buttons not drawing
currently working on a pause menu for an space invader game, problem I've got however is that when pressing the enter key the game displays the pause menu but it doesn't display the buttons: btnResume & btnMainMenu within the pause menu & my sprite in the game can still operate e.g. Rotate either via the left & arrows keys & shoot bullets via the space bar. Preferably I would like to get the buttons to display but also I would like to see it that my sprite is frozen in place including bullets instead of them flying across the screen when game is paused. Code is below: namespace Rotationgame { /// <summary> /// This is the main type for your game /// </summary> public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; // Different Windows enum GameState { MainMenu, Playing, } GameState CurrentGameState = GameState.MainMenu; // Screeb Adjustments int screenWidth = 1250, screenHeight = 930; // Main Menu Buttons button btnPlay; button btnQuit; // Pause Menu & buttons bool paused = false; button btnResume; button btnMainMenu; Vector2 spriteVelocity; const float tangentialVelocity = 0f; float friction = 1f; Texture2D spriteTexture; Rectangle spriteRectangle; // The centre of the image Vector2 spriteOrigin; Vector2 spritePosition; float rotation; // Background Texture2D backgroundTexture; Rectangle backgroundRectangle; // Shield Texture2D shieldTexture; Rectangle shieldRectangle; // Bullets List<Bullets> bullets = new List<Bullets>(); KeyboardState pastKey; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "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() { // TODO: Add your initialization logic here 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); shieldTexture = Content.Load<Texture2D>("Shield"); shieldRectangle = new Rectangle(517, 345, 250, 220); spriteTexture = Content.Load<Texture2D>("PlayerShipright"); spritePosition = new Vector2(640, 450); backgroundTexture = Content.Load<Texture2D>("Background"); backgroundRectangle = new Rectangle(0, 0, 1250, 930); // Screen Adjustments graphics.PreferredBackBufferWidth = screenWidth; graphics.PreferredBackBufferHeight = screenHeight; graphics.ApplyChanges(); IsMouseVisible = true; // Main menu Buttons & locations btnPlay = new button(Content.Load<Texture2D>("Playbutton"), graphics.GraphicsDevice); btnPlay.setPosition(new Vector2(550, 310)); btnQuit = new button(Content.Load<Texture2D>("Quitbutton"), graphics.GraphicsDevice); btnQuit.setPosition(new Vector2(550, 580)); // Pause menu buttons & locations btnResume = new button(Content.Load<Texture2D>("Playbutton"), graphics.GraphicsDevice); btnResume.setPosition(new Vector2(550, 310)); btnMainMenu = new button(Content.Load<Texture2D>("Quitbutton"), graphics.GraphicsDevice); btnMainMenu.setPosition(new Vector2(550, 580)); // TODO: use this.Content to load your game content here } /// <summary> /// UnloadContent will be called once per game and is the place to unload /// all 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) { MouseState mouse = Mouse.GetState(); // Allows the game to exit if (Keyboard.GetState().IsKeyDown(Keys.Escape)) this.Exit(); switch (CurrentGameState) { case GameState.MainMenu: if(btnPlay.isClicked == true) CurrentGameState = GameState.Playing; btnPlay.Update(mouse); if (btnQuit.isClicked == true) this.Exit(); btnQuit.Update(mouse); break; case GameState.Playing: if (!paused) { if (Keyboard.GetState().IsKeyDown(Keys.Enter)) { paused = true; btnResume.isClicked = false; } } else if (paused) { if (Keyboard.GetState().IsKeyDown(Keys.Enter)) if (btnResume.isClicked) paused = false; if (btnMainMenu.isClicked) CurrentGameState = GameState.MainMenu; } break; } // TODO: Add your update logic here if (Keyboard.GetState().IsKeyDown(Keys.Space) && pastKey.IsKeyUp(Keys.Space)) Shoot(); pastKey = Keyboard.GetState(); spritePosition = spriteVelocity + spritePosition; spriteRectangle = new Rectangle((int)spritePosition.X, (int)spritePosition.Y, spriteTexture.Width, spriteTexture.Height); spriteOrigin = new Vector2(spriteRectangle.Width / 2, spriteRectangle.Height / 2); if (Keyboard.GetState().IsKeyDown(Keys.Right)) rotation += 0.025f; if (Keyboard.GetState().IsKeyDown(Keys.Left)) rotation -= 0.025f; if (Keyboard.GetState().IsKeyDown(Keys.Up)) { spriteVelocity.X = (float)Math.Cos(rotation) * tangentialVelocity; spriteVelocity.Y = (float)Math.Sin(rotation) * tangentialVelocity; } else if (Vector2.Zero != spriteVelocity) { float i = spriteVelocity.X; float j = spriteVelocity.Y; spriteVelocity.X = i -= friction * i; spriteVelocity.Y = j -= friction * j; base.Update(gameTime); } UpdateBullets(); } public void UpdateBullets() { foreach (Bullets bullet in bullets) { bullet.position += bullet.velocity; if (Vector2.Distance(bullet.position, spritePosition) > 760) bullet.isVisible = false; } for (int i = 0; i < bullets.Count; i++) { if(!bullets[i].isVisible) { bullets.RemoveAt(i); i--; } } } public void Shoot() { Bullets newBullet = new Bullets(Content.Load<Texture2D>("bullet")); newBullet.velocity = new Vector2((float)Math.Cos(rotation),(float)Math.Sin(rotation)) * 3f + spriteVelocity; newBullet.position = spritePosition + newBullet.velocity * 5; newBullet.isVisible = true; if(bullets.Count() < 25) bullets.Add(newBullet); } /// <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.CornflowerBlue); spriteBatch.Begin(); switch (CurrentGameState) { case GameState.MainMenu: spriteBatch.Draw(Content.Load<Texture2D>("MainMenu"), new Rectangle(0, 0, screenWidth, screenHeight), Color.White); btnPlay.Draw(spriteBatch); btnQuit.Draw(spriteBatch); break; case GameState.Playing: // Drawing Background spriteBatch.Draw(backgroundTexture, backgroundRectangle, Color.White); // Drawing Shield spriteBatch.Draw(shieldTexture, shieldRectangle, Color.White); // Drawing Bullets foreach (Bullets bullet in bullets) bullet.Draw(spriteBatch); // Drawing Player's Character spriteBatch.Draw(spriteTexture, spritePosition, null, Color.White, rotation, spriteOrigin, 1f, SpriteEffects.None, 0); if (paused) { spriteBatch.Draw(Content.Load<Texture2D>("PauseMenu"), new Rectangle(0, 0, screenWidth, screenHeight), Color.White); btnResume.Draw(spriteBatch); btnMainMenu.Draw(spriteBatch); } break; } spriteBatch.End(); Any ideas where I've gone wrong?
You need to modify your Update method to move your bullet and player movement code into the Playing section of your Update method. protected override void Update(GameTime gameTime) { MouseState mouse = Mouse.GetState(); // Allows the game to exit if (Keyboard.GetState().IsKeyDown(Keys.Escape)) this.Exit(); switch (CurrentGameState) { case GameState.MainMenu: if(btnPlay.isClicked == true) CurrentGameState = GameState.Playing; btnPlay.Update(mouse); if (btnQuit.isClicked == true) this.Exit(); btnQuit.Update(mouse); break; case GameState.Playing: if (paused) { if (Keyboard.GetState().IsKeyDown(Keys.Enter)) if (btnResume.isClicked) paused = false; if (btnMainMenu.isClicked) CurrentGameState = GameState.MainMenu; } else if (!paused) { if (Keyboard.GetState().IsKeyDown(Keys.Enter)) { paused = true; btnResume.isClicked = false; } if (Keyboard.GetState().IsKeyDown(Keys.Space) && pastKey.IsKeyUp(Keys.Space)) Shoot(); pastKey = Keyboard.GetState(); spritePosition = spriteVelocity + spritePosition; spriteRectangle = new Rectangle((int)spritePosition.X, (int)spritePosition.Y, spriteTexture.Width, spriteTexture.Height); spriteOrigin = new Vector2(spriteRectangle.Width / 2, spriteRectangle.Height / 2); if (Keyboard.GetState().IsKeyDown(Keys.Right)) rotation += 0.025f; if (Keyboard.GetState().IsKeyDown(Keys.Left)) rotation -= 0.025f; if (Keyboard.GetState().IsKeyDown(Keys.Up)) { spriteVelocity.X = (float)Math.Cos(rotation) * tangentialVelocity; spriteVelocity.Y = (float)Math.Sin(rotation) * tangentialVelocity; } else if (Vector2.Zero != spriteVelocity) { float i = spriteVelocity.X; float j = spriteVelocity.Y; spriteVelocity.X = i -= friction * i; spriteVelocity.Y = j -= friction * j; base.Update(gameTime); } UpdateBullets(); break; } } } I think you should have Paused as an additional GameState, instead of checking for its paused value in the GameState.Playing scenario.
XNA 4.0 Collision Detection causes sprite to bounce
My collision detection seems to be working, all be it some of the collisions it is detecting are odd as in it'll say that the collision was on the bottom of the platform when it isn't. However that isn't the main problem. When the player collides with the platform, instead of moving to the surface of the platform he moves above it and with my gravity in place it looks like he is constantly bouncing. I can't figure out why. If you guys could help it would be much appreciated. It could be something very simple I'm missing since I'm new to XNA and C#. I will list my Game1, Player and Platoform classes below. (My collision detection is in the player class) Thanks Game1 Class public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Texture2D background; Movement character; Platform[] platforms; //private Vector2 SnapePosition = Vector2.Zero; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; graphics.PreferredBackBufferHeight = 440; graphics.PreferredBackBufferWidth = 782; } /// <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() { // TODO: Add your initialization logic here platforms = new Platform[15]; 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); for (int i = 0; i < platforms.Length; i++) { platforms[i] = new Platform( Content.Load<Texture2D>("Platforms/lvl2_platform"), new Rectangle(i*100, 410, 100, 30)); } character = new Movement(Content.Load<Texture2D>("snape"), new Rectangle(0, 360, 50, 50), platforms); // TODO: use this.Content to load your game content here background = Content.Load<Texture2D>("Backgrounds/lvl2_background"); } /// <summary> /// UnloadContent will be called once per game and is the place to unload /// all 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) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); //Allows the player to move character.Update(); // TODO: Add your update logic here 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.CornflowerBlue); // TODO: Add your drawing code here spriteBatch.Begin(); spriteBatch.Draw(background, Vector2.Zero, Color.White); character.Draw(spriteBatch); foreach (Platform platform in platforms) { platform.Draw(spriteBatch); } spriteBatch.End(); base.Draw(gameTime); } } Player Class class Player { public Texture2D Snape; public Rectangle SnapePosition; public enum CollisionPosition { None, Top, Bottom, Left, Right }; public CollisionPosition collisionType; public bool inCollision; public int collisionDepth; public Platform[] plat; public int num; public virtual void Update() { } public void Draw(SpriteBatch spriteBatch) { spriteBatch.Draw(Snape, SnapePosition, Color.White); } } class Movement : Player { public Movement(Texture2D newSnape, Rectangle newSnapePosition, Platform[] a) { Snape = newSnape; SnapePosition = newSnapePosition; plat = a; } public override void Update() { // Check for collision Collisions(); // Determine collision type //DetermineCollisionType(); // Separate snape //SeparateSnape(); KeyboardState keyBoard = Keyboard.GetState(); if (keyBoard.IsKeyDown(Keys.A)) { SnapePosition.X -= 5; } if (keyBoard.IsKeyDown(Keys.D)) { SnapePosition.X += 5; } if (keyBoard.IsKeyDown(Keys.W)) { SnapePosition.Y -= 5; } //if (keyBoard.IsKeyDown(Keys.S)) //{ SnapePosition.Y += 5; // } // if (SnapePosition.X < 0) // SnapePosition.X = 0; // if (SnapePosition.Y < 0) // SnapePosition.Y = 0; // if (SnapePosition.X > GraphicsDevice.Viewport.Width - Snape.Width) // SnapePosition.X = GraphicsDevice.Viewport.Width - Snape.Width; // if (SnapePosition.Y > GraphicsDevice.Viewport.Height - Snape.Height) // SnapePosition.Y = GraphicsDevice.Viewport.Height - Snape.Height; } public void Collisions() { for (int i = 0; i < plat.Length; i++) { if (plat[i].rectangle.Intersects(SnapePosition)) { inCollision = true; num = i; DetermineCollisionType(); } } } public void DetermineCollisionType() { if (inCollision == false) { collisionType = CollisionPosition.None; collisionDepth = 0; } else { // Determine the side of *least intersection* for snape int minColDepth = int.MaxValue; // Check the top side int tColDepth = (plat[num].rectangle.Y + plat[num].texture.Height / 2) - (SnapePosition.Y - Snape.Height / 2); if (tColDepth > 0 && tColDepth < minColDepth) { collisionType = CollisionPosition.Top; minColDepth = tColDepth; } // Check the bottom side int bColDepth = (SnapePosition.Y + Snape.Height / 2) - (plat[num].rectangle.Y - plat[num].texture.Height / 2); if (bColDepth > 0 && bColDepth < minColDepth) { collisionType = CollisionPosition.Bottom; minColDepth = bColDepth; } // Check the right overlap int rColDepth = (SnapePosition.X + Snape.Width / 2) - (plat[num].rectangle.X - plat[num].texture.Width / 2); if (rColDepth > 0 && rColDepth < minColDepth) { collisionType = CollisionPosition.Right; minColDepth = rColDepth; } // Check the left overlap int lColDepth = (plat[num].rectangle.X + plat[num].texture.Width / 2) - (SnapePosition.X - Snape.Width / 2); if (lColDepth > 0 && lColDepth < minColDepth) { collisionType = CollisionPosition.Left; minColDepth = lColDepth; } // Update the collision depth collisionDepth = minColDepth; SeparateSnape(); } } public void SeparateSnape() { switch (collisionType) { case CollisionPosition.None: break; case CollisionPosition.Top: SnapePosition.Y += (collisionDepth); break; case CollisionPosition.Bottom: SnapePosition.Y -= collisionDepth; break; case CollisionPosition.Right: SnapePosition.X -= collisionDepth; break; case CollisionPosition.Left: SnapePosition.X += collisionDepth; break; } } } Platform Class class Platform { public Texture2D texture; public Rectangle rectangle; public Platform(Texture2D newTexture, Rectangle newRectangle) { texture = newTexture; rectangle = newRectangle; } public void Update() { } public void Draw(SpriteBatch spriteBatch) { spriteBatch.Draw(texture, rectangle, Color.White); } }
I fixed up your collision. All of your depth calculations were incorrect. You were doing them based upon the center of the entity (player/platform) and using their texture sizes instead of their rectangle sizes. You may have been thinking that everything draws from the middle, but by default it draws from the top left in XNA. Here are the new depth calculations located in your "Movement" class under the "DetermineCollisionType()" function. The top depth needs to work on the top of the platform (Y), and on the bottom of snape (Y + Height). int tColDepth = (SnapePosition.Y + SnapePosition.Height) - (plat[num].rectangle.Y); The bottom depth needs to work on the bottom of the playform (Y + Height) and on the top of snape (Y). int bColDepth = (plat[num].rectangle.Y + plat[num].rectangle.Height) - (SnapePosition.Y); The right depth needs to work on the left of the platform (X) and the right of snape (X + Width). int rColDepth = (SnapePosition.X + SnapePosition.Width) - (plat[num].rectangle.X); The left depth needs to work on the right of the platform (X + Width) and on the left of Snape (X). int lColDepth = (plat[num].rectangle.X + plat[num].rectangle.Width) - (SnapePosition.X); This will work from now on in. However you may want to use lists for your platform. Lists are easier for when/if you do a level editor as you don't have to say "I want 15 platforms".
XNA 4.0 Collision Detection not working
I've managed to get the values where I think they need to be getting so that the collision detection between snape and the platform bounding boxes takes place in the platform class. However it isn't working. There are no errors and I can't see where I'm going wrong. Your help would be much appreciated. My 3 classes are below. Game1 Class public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Texture2D background; Movement character; Platform[] platforms; //private Vector2 SnapePosition = Vector2.Zero; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; graphics.PreferredBackBufferHeight = 440; graphics.PreferredBackBufferWidth = 782; } protected override void Initialize() { // TODO: Add your initialization logic here platforms = new Platform[15]; base.Initialize(); } protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); character = new Movement(Content.Load<Texture2D>("snape"), new Rectangle(0, 350, 50, 50)); for (int i = 0; i < platforms.Length; i++) { platforms[i] = new Platform( Content.Load<Texture2D>("Platforms/lvl2_platform"), new Rectangle(i*100, 410, 100, 30), character.Snape, character.SnapePosition); } // TODO: use this.Content to load your game content here background = Content.Load<Texture2D>("Backgrounds/lvl2_background"); } /// <summary> /// UnloadContent will be called once per game and is the place to unload /// all 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) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); //Allows the player to move character.Update(); // TODO: Add your update logic here 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.CornflowerBlue); // TODO: Add your drawing code here spriteBatch.Begin(); spriteBatch.Draw(background, Vector2.Zero, Color.White); character.Draw(spriteBatch); foreach (Platform platform in platforms) { platform.Draw(spriteBatch); } spriteBatch.End(); base.Draw(gameTime); } } } Player Class class Player { public Texture2D Snape; public Rectangle SnapePosition; public virtual void Update() { } public void Draw(SpriteBatch spriteBatch) { spriteBatch.Draw(Snape,SnapePosition,Color.White); } } class Movement : Player { public Movement(Texture2D newSnape, Rectangle newSnapePosition) { Snape = newSnape; SnapePosition = newSnapePosition; } public override void Update() { KeyboardState keyBoard = Keyboard.GetState(); if (keyBoard.IsKeyDown(Keys.A)) { SnapePosition.X -= 5; } if (keyBoard.IsKeyDown(Keys.D)) { SnapePosition.X += 5; } if (keyBoard.IsKeyDown(Keys.W)) { SnapePosition.Y -= 5; } if (keyBoard.IsKeyDown(Keys.S)) { SnapePosition.Y += 5; } } } } Platform Class class Platform { Texture2D texture; Rectangle rectangle; Texture2D snape; Rectangle snapePosition; public Rectangle test; public enum CollisionPosition { None, Top, Bottom, Left, Right }; public CollisionPosition collisionType; public bool inCollision; public int collisionDepth; public Platform(Texture2D newTexture, Rectangle newRectangle, Texture2D newSnape, Rectangle newSnapePos) { texture = newTexture; rectangle = newRectangle; snapePosition = newSnapePos; snape = newSnape; } public void Draw(SpriteBatch spriteBatch) { spriteBatch.Draw(texture, rectangle, Color.White); } public void Collisions() { if (rectangle.Intersects(snapePosition)) inCollision = true; } public void DetermineCollisionType() { if (inCollision == false) { collisionType = CollisionPosition.None; collisionDepth = 0; } else { // Determine the side of *least intersection* for snape int minOverlap = int.MaxValue; // Check the top side int tOverlap = (rectangle.Y + texture.Height / 2) - (snapePosition.Y - snape.Height / 2); if (tOverlap > 0 && tOverlap < minOverlap) { collisionType = CollisionPosition.Top; minOverlap = tOverlap; } // Check the bottom side int bOverlap = (snapePosition.Y + snape.Height / 2) - (rectangle.Y - texture.Height / 2); if (bOverlap > 0 && bOverlap < minOverlap) { collisionType = CollisionPosition.Bottom; minOverlap = bOverlap; } // Check the right overlap int rOverlap = (snapePosition.X + snape.Width / 2) - (rectangle.X - texture.Width / 2); if (rOverlap > 0 && rOverlap < minOverlap) { collisionType = CollisionPosition.Right; minOverlap = rOverlap; } // Check the left overlap int lOverlap = (rectangle.X + texture.Width / 2) - (snapePosition.X - snape.Width / 2); if (lOverlap > 0 && lOverlap < minOverlap) { collisionType = CollisionPosition.Left; minOverlap = lOverlap; } // Update the collision depth collisionDepth = minOverlap; } } public void SeparateSnape() { switch (collisionType) { case CollisionPosition.None: break; case CollisionPosition.Top: snapePosition.Y += collisionDepth; break; case CollisionPosition.Bottom: snapePosition.Y -= collisionDepth; break; case CollisionPosition.Right: snapePosition.X -= collisionDepth; break; case CollisionPosition.Left: snapePosition.X += collisionDepth; break; } } public void Update() { // Check for collision Collisions(); // Determine collision type DetermineCollisionType(); // Separate snape SeparateSnape(); } public Rectangle getSnapePos { get { return snapePosition; } } } }
protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); //Allows the player to move character.Update(); // TODO: Add your update logic here base.Update(gameTime); } I do not see any updates regarding your platforms. try adding foreach (Platform platform in platforms) { platform.Update(); }
Part of your problem appears to be that you don't know what the difference between a class and a struct is. A rectangle is a struct, meaning that when you pass it as an argument into any method it gets passed 'by value' meaning a copy of the value is made and it lives for as long as the method is running, after which it no longer exists. Classes on the other hand are reference types, so if you passed a class as an argument, you'd be passing it 'by reference' meaning the method would get a value telling it where to access the class. The difference here is that although the reference gets destroyed when the method ends, it is just a reference, not the value itself, unlike the struct. On top of this, even if you were giving the platforms a reference to snape's position instead of just a value, when you move snape, you change the entire value of his position, not just parts of it, so it would be overwriting snape's reference, making the platform's references outdated anyway. To be honest I think you would be better rethinking your design a bit. Firstly, try moving the keyboard management outside of the character, so the game essentially hooks onto one character and controls the movement of that one character. This is important because it means that the game itself knows who the main character is, what platforms the character can collide with and thus can perform collision checking with the platforms and the character. If the platforms can't change the character's position and the player doesn't know what all the platforms on the map are, then it seems more sensible to have the game itself monitoring that. Here's an example: protected override void Update() { KeyboardState keyboardState = Keyboard.GetState(); Rectangle oldBounds = player.Bounds; if (keyboardState.IsKeyDown(Keys.W)) { player.Y--; } if (keyboardState.IsKeyDown(Keys.A)) { player.X--; } if (keyboardState.IsKeyDown(Keys.X)) { player.Y++; } if (keyboardState.IsKeyDown(Keys.D)) { player.X++; } foreach (Platform platform in platforms) { if (player.Bounds.Intersects(platform.Bounds)) { player.Bounds = oldBounds; break; } } } You'll want to make it a bit more sophisticated, but that's probably the most basic collision system available. Obviously if you're doing a platformer, you're probably going to want to be a bit more clever. I suggest you do as much research and experimentation as you can, also be sure to look up how to add breakpoints into your code and run your code line by line, as well as using the local and watch boxes to figure out exactly what's going on when your code runs. If you can identify what is happening and what should be happening, it will make things much easier to fix and understand.