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(@"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
{
///
/// This is the main type for your game
///
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";
}
///
/// 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.
///
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();
}
///
/// LoadContent will be called once per game and is the place to load
/// all of your content.
///
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(@"Images\Lancer");
Lancer = new UserControlledSprite(lancerTexture, position, frameSize, collisionOffset,
currentFrame, sheetSize, spriteToUse, speed, millisecondsPerFrame);
}
///
/// UnloadContent will be called once per game and is the place to unload
/// all content.
///
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
///
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
///
/// Provides a snapshot of timing values.
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);
}
///
/// This is called when the game should draw itself.
///
/// Provides a snapshot of timing values.
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(@"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(@"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);
}
}
}
Answer
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.
No comments:
Post a Comment