I am writing a simple game based on grid movements, something like Sokoban game. I need to use several different text files to store levels. I wrote some code, and now I get error:
System.ArgumentNullException "This method does not accept null for
this parameter. Nazwa parametru: texture"
Whole code is in several files. What is wrong with my code?
Game1.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace Sokoban
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
public Texture2D tOtoczenie;
public Rectangle kOtoczenie;
Sceny scena;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferHeight = 660; // 11
graphics.PreferredBackBufferWidth = 900; // 15
Content.RootDirectory = "Content";
}
// Sterowanie po gridzie (en - grid movement with stops)
KeyboardState stanKlawiatury, poprzedniStanKlawiatury;
public bool WcisnietyKlawisz(Keys klawisz)
{
return stanKlawiatury.IsKeyDown(klawisz) && poprzedniStanKlawiatury.IsKeyUp(klawisz);
}
/// <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
scena = new Sceny();
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);
// TODO: use this.Content to load your game content here
tOtoczenie = Content.Load<Texture2D>("Otoczenie");
kOtoczenie = new Rectangle(0, 0, 900, 660);
}
/// <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();
// TODO: Add your update logic here
poprzedniStanKlawiatury = stanKlawiatury;
stanKlawiatury = Keyboard.GetState();
if (WcisnietyKlawisz(Keys.Right))
scena.wspX += 60;
else if (WcisnietyKlawisz(Keys.Left))
scena.wspX -= 60;
else if (WcisnietyKlawisz(Keys.Up))
scena.wspY -= 60;
else if (WcisnietyKlawisz(Keys.Down))
scena.wspY += 60;
if (Keyboard.GetState().IsKeyDown(Keys.NumPad1))
scena.LoadScene("level1");
scena.Update();
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(tOtoczenie, kOtoczenie, Color.White);
spriteBatch.End();
scena.Draw(spriteBatch);
base.Draw(gameTime);
}
}
}
Sceny.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.IO;
using Microsoft.Xna.Framework.Content;
namespace Sokoban
{
public class Sceny
{
public List<ObiektyGry> sciany;
public List<ObiektyGry> sloty;
public List<ObiektyGry> diamenty;
public List<ObiektyGry> graczL;
public Texture2D tDiament;
public Texture2D tSlot;
public Texture2D tSciana;
public Rectangle kDiament;
public Rectangle kSlot;
public Rectangle kSciana;
public Texture2D tGracz;
public Rectangle kGracz;
public int wspX;
public int wspY;
public Sceny()
{
sciany = new List<ObiektyGry>();
sloty = new List<ObiektyGry>();
diamenty = new List<ObiektyGry>();
graczL = new List<ObiektyGry>();
}
public void LoadContent(ContentManager theContentManager, string theAssetName)
{
tGracz = theContentManager.Load<Texture2D>("Gracz");
tDiament = theContentManager.Load<Texture2D>("Diament");
tSlot = theContentManager.Load<Texture2D>("Slot");
tSciana = theContentManager.Load<Texture2D>("Ściana");
}
public void Update()
{
foreach (ObiektyGry obiekt in sciany)
obiekt.Update();
foreach (ObiektyGry obiekt in sloty)
obiekt.Update();
foreach (ObiektyGry obiekt in diamenty)
obiekt.Update();
foreach (ObiektyGry obiekt in graczL)
obiekt.Update();
}
public void Draw(SpriteBatch spriteBatch)
{
foreach (ObiektyGry obiekt in sciany)
obiekt.Draw(spriteBatch, obiekt.Tekstura, obiekt.Kształt);
foreach (ObiektyGry obiekt in sloty)
obiekt.Draw(spriteBatch, obiekt.Tekstura, obiekt.Kształt);
foreach (ObiektyGry obiekt in diamenty)
obiekt.Draw(spriteBatch, obiekt.Tekstura, obiekt.Kształt);
foreach (ObiektyGry obiekt in graczL)
obiekt.Draw(spriteBatch, obiekt.Tekstura, obiekt.Kształt);
}
public void LoadScene(string name)
{
sciany.Clear();
graczL.Clear();
diamenty.Clear();
sloty.Clear();
StreamReader reader = new StreamReader(name+".txt");
int x = 0;
int y = 0;
string file = reader.ReadToEnd();
for (int i = 0; i<file.Length; i++)
{
if (file[i] == 13)
{
y++;
x = 0;
}
else if (file[i] != 10)
x++;
if (file[i] == '1' ) // sciana
{
ObiektyGry sciana = new ObiektyGry();
sciana.Kształt = new Rectangle(x * 60, y * 60,60,60);
sciana.Tekstura = tSciana;
sciany.Add(sciana);
}
else if (file[i] == '2') // slot
{
ObiektyGry slot = new ObiektyGry();
slot.Kształt = new Rectangle(x * 60, y * 60, 60, 60);
slot.Tekstura = tSlot;
sloty.Add(slot);
}
else if (file[i] == '3') // diament
{
ObiektyGry diament = new ObiektyGry();
diament.Kształt = new Rectangle(x * 60, y * 60, 60, 60);
diament.Tekstura = tDiament;
diamenty.Add(diament);
}
else if (file[i] == '4') //gracz
{
ObiektyGry gracz = new ObiektyGry();
wspX = x * 60;
wspY = y * 60;
gracz.Kształt = new Rectangle(wspX, wspY, 60, 60);
gracz.Tekstura = tGracz;
graczL.Add(gracz);
}
}
}
}
}
ObiektyGry.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
namespace Sokoban
{
public class ObiektyGry
{
public Rectangle Kształt { get; internal set; }
public Texture2D Tekstura { get; internal set; }
public static ContentManager contentManager;
public ObiektyGry()
{
}
public void Update()
{
}
public void Draw(SpriteBatch spriteBatch, Texture2D Tekstura, Rectangle Ksztalt)
{
//Tekstura = obiekt.Tekstura;
//Kształt = obiekt.Kształt;
//spriteBatch.Begin();
spriteBatch.Draw(Tekstura, Ksztalt, Color.White);
//spriteBatch.End();
}
}
}
level1.txt (for example)
111111111111111
100000000000001
100000000000001
100000000000001
100020000000001
100000034000001
100000000000001
100000000000001
100000000000001
100000000000001
111111111111111
Yea, as already mentioned in the comments, you haven't loaded your textures for your sceny. I see that you have loaded your level, but not your textures...
So, I deleted all Sceny class and I implemented level changing in Game1 class. After that I hadn't any problem with textures at all!
Related
I am trying to create a simple menu, the string that is selected changes colur as it is instructed to do, I just can't seem to space out each item in the string list on the Y axis, currently they are all positioned in the middle but at the top of the screen overlapping each other. I know this is probably a very simple fix but I am a novice at XNA. Any help would be very appreciated. Thanks in advance.
MenuManagement Class
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Game2
{
class MenuManagement
{
KeyboardState keyboard;
KeyboardState prevKey;
MouseState mouse;
Vector2 position;
List<String> buttonList = new List<string>();
SpriteFont spriteFont;
int selected = 0;
public MenuManagement ()
{
buttonList.Add("Play");
buttonList.Add("Options");
buttonList.Add("instructions");
buttonList.Add("Exit");
}
private void MeasureMenu()
{
height = 0;
width = 0;
foreach (string item in buttonList)
{
Vector2 size = spriteFont.MeasureString(item);
height += spriteFont.LineSpacing + 5;
}
}
public void LoadContent (ContentManager Content )
{
spriteFont = Content.Load<SpriteFont>("spriteFont");
}
public void Update (GameTime theGameTime)
{
keyboard = Keyboard.GetState();
if (checkKeyBoard(Keys.Up))
{
if (selected > 0)
{
selected--;
}
}
if (checkKeyBoard(Keys.Down))
{
if (selected < buttonList.Count - 1)
{
selected++;
}
}
prevKey = keyboard;
}
public bool checkKeyBoard (Keys key)
{
return (keyboard.IsKeyDown(key) && prevKey.IsKeyDown(key));
}
public void Draw (SpriteBatch theSpriteBatch)
{
theSpriteBatch.Begin();
Color color;
for (int i = 0; i < buttonList.Count; i++)
{
Vector2 location = position;
if (i == selected)
{
color = Color.Yellow;
}
else
{
color = Color.Blue;
}
location.Y += spriteFont.LineSpacing + 5;
}
theSpriteBatch.DrawString(spriteFont, buttonList[0], new Vector2 (300, 100), color);
theSpriteBatch.DrawString(spriteFont, buttonList[1], new Vector2(300, 150), color);
theSpriteBatch.DrawString(spriteFont, buttonList[2], new Vector2(300, 200), color);
theSpriteBatch.DrawString(spriteFont, buttonList[3], new Vector2(300, 250), color);
theSpriteBatch.End();
}
}
}
Game1
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace Game2
{
/// <summary>
/// This is the main type for your game.
/// </summary>
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch theSpriteBatch;
public static Rectangle screen;
public static string GameState = "Menu";
MenuManagement menuManagement;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
menuManagement = new MenuManagement();
screen = new Rectangle(0, 0, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight);
base.Initialize();
}
protected override void LoadContent()
{
theSpriteBatch = new SpriteBatch(GraphicsDevice);
menuManagement.LoadContent(Content);
// TODO: use this.Content to load your game content here
}
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();
switch (GameState)
{
case "Menu":
menuManagement.Update(gameTime);
break;
}
base.Update(gameTime);
}
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
switch (GameState)
{
case "Menu":
menuManagement.Draw(theSpriteBatch);
break;
}
base.Draw(gameTime);
}
}
}
You can calculate the length of the strings and place the next item where you want. You should look to SpriteFont.MeasureString().
https://msdn.microsoft.com/en-us/library/bb464128(v=xnagamestudio.30).aspx
To be clear, the reason they are overlapping is because you are putting them all in the same position:
Vector2 location = position;
and then:
new Vector2 (300, location.Y)
is where you are drawing the entire batch. You need to change the position of each of the menu items. The simplest fix is to increment the Y value of the location for each item. That will move the next menu item toward the bottom. Increment X to move right.
So I have a problem that I cant figure out, and that is drawing objects into my main Game1 class from a class of drawablegamecomponent.
I'v been playing around with it for a bit and looking at other examples, but can't figure out the issue. There isn't much code as it is, so I'll just post the two classes I have, the main class Game1 and the class I want to draw, Balloon.
The error is in the draw method I get this...
An unhandled exception of type 'System.NullReferenceException' occurred in Burst.exe
Additional information: Object reference not set to an instance of an object.
Main Class.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace Burst
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Rectangle bounds;
Balloon ball;
Diamond dia;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferWidth = 1152;
graphics.PreferredBackBufferHeight = 648;
Content.RootDirectory = "Content";
bounds = new Rectangle(0, 0, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight);
ball = new Balloon(bounds, 1, this, spriteBatch);
dia = new Diamond(bounds, new Vector2(200, 200), this, spriteBatch);
}
/// <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);
// 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)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
ball.Update();
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();
// TODO: Add your drawing code here
ball.Draw(gameTime);
dia.Draw(gameTime);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Balloon Class:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Burst
{
public class Balloon : Microsoft.Xna.Framework.DrawableGameComponent
{
Vector2 position;
Vector2 motion;
Texture2D texture;
Rectangle bounds;
Rectangle screenBounds;
Game game;
SpriteBatch spriteBatch;
float balloonSpeed = 4;
int colour = 0;
public Balloon(Rectangle screenBounds, int colour, Game game, SpriteBatch spriteBatch) : base (game)
{
this.colour = colour;
this.game = game;
this.spriteBatch = spriteBatch;
this.screenBounds = screenBounds;
this.position = new Vector2(200,200);
}
protected override void LoadContent()
{
switch (colour)
{
case 1: texture = Game.Content.Load<Texture2D>("Images/BlueBalloon");
break;
case 2: texture = Game.Content.Load<Texture2D>("Images/GreenBalloon");
break;
case 3: texture = Game.Content.Load<Texture2D>("Images/RedBalloon");
break;
case 4: texture = Game.Content.Load<Texture2D>("Images/YellowBalloon");
break;
case 5: texture = Game.Content.Load<Texture2D>("Images/PurpleBalloon");
break;
}
}
public Rectangle Bounds
{
get
{
bounds.X = (int)position.X;
bounds.Y = (int)position.Y;
return bounds;
}
}
public void Update()
{
position += motion * balloonSpeed;
}
private void CheckWallColision()
{
if (position.X < 0)
{
position.X = 0;
motion.X *= -1;
}
if (position.X + texture.Width > screenBounds.Width)
{
position.X = screenBounds.Width - texture.Width;
motion.X *= -1;
}
if (position.Y < 0)
{
position.Y = 0;
motion.Y *= -1;
}
if (position.Y + texture.Height > screenBounds.Height)
{
position.Y = screenBounds.Height - texture.Height;
motion.Y *= -1;
}
}
public void SetStartPosition()
{
Random rand = new Random();
motion = new Vector2(rand.Next(2, 6), -rand.Next(2, 6));
motion.Normalize();
position = new Vector2(200, 300);
}
public void Draw()
{
spriteBatch.Draw(texture, position, Color.White);
}
}
}
"spriteBatch" == null when you create objects "ball" and "dia".
You need move this code:
bounds = new Rectangle(0, 0, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight);
ball = new Balloon(bounds, 1, this, spriteBatch);
dia = new Diamond(bounds, new Vector2(200, 200), this, spriteBatch);
to method "LoadContent". After creating "spriteBatch".
So currently, I am a newb starting coding in c#. I started making a space game akin to space invaders and ran into an issue, in the draw method, I set it to draw my bullet and head upward on the string as soon as i hit space. But the problem was as soon as I let go of space, my bullet disappeared. I made a work around where as soon as the bullet left the screen it would teleport to the ship. Is there anyway to make the game check if the button has been pressed in the past and make the bullet keep moving until i want it to disappear.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace Spaceteroids
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
Texture2D spriteSheet;
Texture2D laser;
Texture2D Enemyship;
spriteAnimation loading;
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
KeyboardState currentKeyboard;
KeyboardState oldKeyboard;
PlayerShip character;
Rectangle characterRectangle;
Bullet bullet;
Bullet bullet2;
bool heightCheck;
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
currentKeyboard = new KeyboardState();
oldKeyboard = new KeyboardState();
//characterRectangle = new Rectangle((int)character.Position.X,(int)character.Position.Y, spriteSheet.Width / 4, spriteSheet.Height);
character = new PlayerShip(new Vector2(GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height - 40));
bullet = new Bullet(new Vector2(character.Position.X, character.Position.Y - 20));
base.Initialize();
}
void Movement()
{
if (IsHeld(Keys.A))
{
character.xSpeed = -6;
}
else if (IsHeld(Keys.D))
{
character.xSpeed = 6;
}
else
{
character.xSpeed = 0;
}
}
void Collision()
{
if (character.Position.X < 0)
{
character.Position.X = 0;
}
else if (character.Position.X + (spriteSheet.Width/4) > graphics.GraphicsDevice.Viewport.Width)
{
character.Position.X = graphics.GraphicsDevice.Viewport.Width - (spriteSheet.Width/4) ;
}
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
laser = Content.Load<Texture2D>("Laser");
Enemyship = Content.Load<Texture2D>("EnemyShip");
spriteSheet = Content.Load<Texture2D>("shipSpriteSheet");
spriteBatch = new SpriteBatch(GraphicsDevice);
loading = new spriteAnimation(Content.Load<Texture2D>("shipSpriteSheet"), 4);
loading.Position = new Vector2(character.Position.X);
loading.IsLooping = true;
loading.FramesPerSecond = 30;
// 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)
{
bullet.Position.X = character.Position.X;
currentKeyboard = Keyboard.GetState();
oldKeyboard = currentKeyboard;
loading.Update(gameTime, character);
bullet.ySpeed = -10;
bullet.UpdateBullet();
Collision();
Movement();
if (NotPressed(Keys.Space))
{
bullet.Position.Y = character.Position.Y - 15;
}
if (bullet.Position.Y < 0)
{
bullet.Position.Y = character.Position.Y - 15;
}
character.UpdateShip();
// 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.Black);
spriteBatch.Begin();
spriteBatch.Draw(laser, new Vector2(bullet.Position.X, bullet.Position.Y), Color.White);
loading.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
public bool IsHeld(Keys key)
{
if (currentKeyboard.IsKeyDown(key))
{
return true;
}
else
{
return false;
}
}
public bool IsReleased(Keys key)
{
if (currentKeyboard.IsKeyUp(key) && oldKeyboard.IsKeyDown(key))
{
return true;
}
else
{
return false;
}
}
public bool JustPressed(Keys key)
{
if (currentKeyboard.IsKeyDown(key) && oldKeyboard.IsKeyUp(key))
{
return true;
}
else
{
return false;
}
}
public bool NotPressed(Keys key)
{
if (IsHeld(key) != true)
{
return true;
}
else
{
return false;
}
}
public bool HasBeenPressed(Keys key)
{
if (oldKeyboard.IsKeyDown(key))
{
return true;
}
else return false;
}
}
}
If you need any other information, feel free to ask.
No, there is nothing in XNA to track keystroke history (or anywhere else either). You have to do it yourself.
The usual solution to your problem is to maintain state on an object that represents the bullet. The keystroke may go away, but the object remains and keeps the bullet visible and moving until it is destroyed. You appear to have that state in your bullet object, so the likelihood is you just have logic errors in when to update it.
The problem is not instantly obvious from a quick read but your handling of keyboard state seems overly complex. All you need is key down and key up. All the rest you should track for yourself.
I have been trying to create a collision for a "top down view" like game. I have made a player class and a block class, in my Game1 class I have checked for the collision, don't know if this is a right way, but it's only a test right now. So if I intersect them I don't know what to do next.
This is my Game1.cs
using System; using System.Collections.Generic; using System.Linq;
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace Collision_Testing {
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Player player = new Player(100, 100);
Block block = new Block(500, 500);
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferWidth = 800;
graphics.PreferredBackBufferHeight = 600;
}
/// <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);
block.LoadContent(Content);
player.LoadContent(Content);
}
/// <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();
block.Update(gameTime);
player.Update(gameTime);
base.Update(gameTime);
if (player.boundingBox.Intersects(block.boundingBox))
{
player.playerPos.X -= player.speed;
player.playerPos.Y -= player.speed;
}
}
/// <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();
player.Draw(spriteBatch);
block.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
} }
This is my Player.cs
using System; using System.Collections.Generic; using System.Linq;
using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input;
namespace Collision_Testing {
class Player
{
public Vector2 playerPos;
public Texture2D playerTex;
public int speed;
KeyboardState oldState;
public Rectangle boundingBox;
public Player(int positionX, int positionY)
{
playerPos.X = positionX;
playerPos.Y = positionY;
speed = 14;
}
public void LoadContent(ContentManager Content)
{
playerTex = Content.Load<Texture2D>("player");
boundingBox = new Rectangle((int)playerPos.X, (int)playerPos.Y, playerTex.Width, playerTex.Height);
}
public void Update(GameTime gameTime)
{
KeyboardState newState = Keyboard.GetState();
if(newState.IsKeyDown(Keys.Right))
{
playerPos.X += speed;
}
if (newState.IsKeyDown(Keys.Left))
{
playerPos.X -= speed;
}
if (newState.IsKeyDown(Keys.Up))
{
playerPos.Y -= speed;
}
if (newState.IsKeyDown(Keys.Down))
{
playerPos.Y += speed;
}
oldState = newState;
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(playerTex, playerPos, Color.White);
}
} }
This is my Block.cs
using System; using System.Collections.Generic; using System.Linq;
using System.Text; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input;
namespace Collision_Testing {
class Block
{
public Vector2 blockPos;
public Texture2D blockTex;
public Rectangle boundingBox;
public Block(int blockX, int blockY)
{
blockPos.X = blockX;
blockPos.Y = blockY;
}
public void LoadContent(ContentManager Content)
{
blockTex = Content.Load<Texture2D>("wall");
boundingBox = new Rectangle((int)blockPos.X, (int)blockPos.Y, blockTex.Width, blockTex.Height);
}
public void Update(GameTime gameTime)
{
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(blockTex, blockPos, Color.White);
}
} }
I think I've done quite a good job for a beginner but don't know what to do next.
It looks to me like speed is a scalar. so when you intersect with the box,
if (player.boundingBox.Intersects(block.boundingBox))
{
player.playerPos.X -= player.speed;
player.playerPos.Y -= player.speed;
}
you're merely moving the player 14 units to the left, and 14 units up, regardless of where the player was.
It looks like you're intending to subtract the velocity. In order to do that, you first have to declare a velocity
public Vector2 playerVelocity;
make sure you initialize playerVelocity in your constructor.
and then you should modify the velocity instead of the position when measuring input
if(newState.IsKeyDown(Keys.Right))
{
playerVelocity.X = speed;
}
else if (newState.IsKeyDown(Keys.Left))
{
playerVelocity.X = -speed;
}
else
{
playerVelocity.X = 0;
}
...
playerPos += playerVelocity;
// i believe you can just add Vectors in XNA like this
// but if it makes you feel better you can do playerPos.X += playerVelocity.X
and then you can reverse your player's position when you collide
if (player.boundingBox.Intersects(block.boundingBox))
{
player.playerPos -= player.playerVelocity;
}
If your character doesn't stop moving I think you miss something like this:
if (newState.IsKeyUp(Keys.Up) && newState.IsKeyUp(Keys.Down) &&
newState.IsKeyUp(Keys.Left) && newState.IsKeyUp(Keys.Right))
{
playerVelocity = Vector2.Zero;
}
I'm trying to code a very basic top down 2D game with XNA, and I've gotten to the part where I'm trying to add grass textures to the game and then draw those textures to the bottom portion of the screen.
However, I'm getting a "NullReferenceException was Unhandled" error on Line 32 of my Level.cs class. As I'm just new to XNA and fairly new (in comparison) to C#, I can't figure this out for the life of me.
UPDATE 1: Thanks mcmonkey4eva, that error is resolved. However, my code now stops during the Draw() method of my TestLevel class (Level.cs). The error is still a "NullReferenceException was Unhandled" error, and the methods are a bit different from what they were.
Anyone know this what I'm doing wrong here?
Here's my updated Level.cs class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using First.Tiles;
using First;
namespace First.Level
{
class TestLevel
{
//An array of groundtiles that will be set to grass, lava, etc
public GroundTile[,] groundlevel;
//Width/Height of the Level
int width, height;
Grass grass;
public TestLevel(int width, int height, ContentManager myContent)
{
content = myContent;
//I input my screen dimensions as my level size
this.width = width;
this.height = height;
groundlevel = new GroundTile[width, height];
grass = new Grass(content.Load<Texture2D>(#"Images\GroundTiles"));
}
//Drawing the grass near the bottom of the screen
public void generateGround()
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x += 32)
{
if (y == (height - 100))
{
if (groundlevel[x, y] == null)
{
groundlevel[x, y] = grass;
}
}
}
}
}
public void draw(GameTime gameTime, SpriteBatch spriteBatch)
{
foreach(GroundTile ground in groundlevel)
{
ground.Draw(gameTime, spriteBatch); //Here's where the error is
}
}
public static ContentManager Content
{
get { return content; }
}
static ContentManager content;
}
}
Here's my updated Game1.cs class:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using First.Entity;
using First.Tiles;
using First.Level;
namespace First
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
const int SCREEN_WIDTH = 600;
const int SCREEN_HEIGHT = 400;
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
TestLevel level;
UserControlledSprite Lancer;
Texture2D lancerTexture;
Vector2 position = new Vector2(200, 200);
Point frameSize = new Point(32, 48);
int collisionOffset = 0;
Point currentFrame = new Point(0, 0);
Point sheetSize = new Point(4, 4);
Point spriteToUse = new Point(0, 0);
Vector2 speed = new Vector2(2, 2);
int millisecondsPerFrame = 500;
Rectangle clientBounds;
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
clientBounds = graphics.GraphicsDevice.Viewport.Bounds;
clientBounds.Width = SCREEN_WIDTH;
clientBounds.Height = SCREEN_HEIGHT;
this.IsMouseVisible = 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);
Content.RootDirectory = "Content";
level = new TestLevel(SCREEN_WIDTH, SCREEN_HEIGHT, Content);
level.generateGround();
lancerTexture = Content.Load<Texture2D>(#"Images\Lancer");
Lancer = new UserControlledSprite(lancerTexture, position, frameSize, collisionOffset,
currentFrame, sheetSize, spriteToUse, speed, millisecondsPerFrame);
}
/// <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();
Lancer.Update(gameTime, clientBounds);
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();
Lancer.Draw(gameTime, spriteBatch);
level.draw(gameTime, spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
Here's my Grass.cs class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using First.Tiles;
using First;
namespace First.Level
{
class TestLevel
{
//An array of groundtiles that will be set to grass, lava, etc
public GroundTile[,] groundlevel;
//Width/Height of the Level
int width, height;
Grass grass;
public TestLevel(int width, int height, ContentManager myContent)
{
content = myContent;
//I input my screen dimensions as my level size
this.width = width;
this.height = height;
groundlevel = new GroundTile[width, height];
grass = new Grass(content.Load<Texture2D>(#"Images\GroundTiles"));
}
//Drawing the grass near the bottom of the screen
public void generateGround()
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x += 32)
{
if (y == (height - 100))
{
if (groundlevel[x, y] == null)
{
groundlevel[x, y] = grass;
}
}
}
}
}
public void draw(GameTime gameTime, SpriteBatch spriteBatch)
{
foreach(GroundTile ground in groundlevel)
{
ground.Draw(gameTime, spriteBatch);
}
}
public static ContentManager Content
{
get { return content; }
}
static ContentManager content;
}
}
Just in case, here's my GroundTile class too:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using First.Entity;
namespace First.Tiles
{
class GroundTile
{
//public GroundTile grass = new Grass(content.Load<Texture2D>(#"Images\GroundTiles"));
// frameSize needs to be modular, for the objects above walking-ground level
public Texture2D texture;
protected Point frameSize;
public Point frame;
public Vector2 position;
int collisionOffset;
protected Point sheetSize = new Point(9, 19);
public GroundTile(Texture2D tiles, Point frame, Point frameSize, int collisionOffset)
{
this.frame = frame;
this.frameSize = frameSize;
this.collisionOffset = collisionOffset;
this.texture = tiles;
}
//Collision Detection, incase of water or something
public Rectangle collisionRect
{
get
{
return new Rectangle(
(int)position.X + collisionOffset,
(int)position.Y + collisionOffset,
frameSize.X - (collisionOffset * 2),
frameSize.Y - (collisionOffset * 2));
}
}
//Not really used, but just in case
public bool collidesWith(GroundTile tile, Sprite sprite)
{
if (sprite.collisionRect.Intersects(collisionRect))
{
sprite.position -= sprite.direction;
}
return false;
}
public static ContentManager Content
{
get { return content; }
}
static ContentManager content;
public GraphicsDevice Graphicsdevice
{
get { return graphicsDevice; }
}
GraphicsDevice graphicsDevice;
public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture,
position,
new Rectangle(frame.X * frameSize.X,
frame.Y * frameSize.Y,
frameSize.X, frameSize.Y),
Color.White, 0, Vector2.Zero,
1f, SpriteEffects.None, 0);
}
}
}
You're accessing Content before it's set - or, rather, you're never setting it at all.
Change
public TestLevel(int width, int height)
{
//I input my screen dimensions as my level size
to
public TestLevel(int width, int height, ContentManager myContent)
{
content = myContent;
//I input my screen dimensions as my level size
and then add the Content argument when you create your TestLevel object (I assume from Game1.cs) (Note: Be sure to create TestLevel after you create the Content object [in the LoadContent method]!)
EDIT:
For the new problem:
You're not defining the contents of the array, except a single layer of grass...
The line
ground.Draw(gameTime, spriteBatch);
Change to
if (ground != null)
{
ground.Draw(gameTime, spriteBatch);
}
But you should also make sure that ground is actually getting filled with content... specifically, new tile objects for each and every point in the array, not just a single line, and not just the same 'grass' instance for every location.
I don't mean to offend, but you're dealing with pretty basic errors here. It might be beneficial for you to look up and follow some basic C# tutorials.
I don't know about XNA, but clearly you Content. returns null.
Is this a class name or a property of your level class? If it's a property, then make sure it is initialized. Otherwize, I don't understand how you would received a nullreferenceexception if you call a static property of a class