This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 5 years ago.
I've been trying to make a test game in XNA (visual studio 2015), but i get a NullReferenceException every time i load this, even though i actually do initialize it. Here is a very short version of it...
namespace Overbox
{
public class Player
{
private Player[] characterList = new Player[14];
virtual public void Initialize()
{
//characterList = new Player[14];
characterList[0] = new Hero();
//for (int i = 0; i <= characterList.Length; i++)
// characterList[i].Initialize();
characterList[0].Initialize();
}
}
virtual public void Draw(SpriteBatch spriteBatch, Texture2D texture)
{
//for (int i = 0; i <= characterList.Length; i++)
//{
// if (characterList[i].Active)
// characterList[i].Draw(spriteBatch, texture);
//}
characterList[0].Draw(spriteBatch, texture); //Here the error occurs
}
}
}
If someone wants the whole class for any reason i could edit this, but this is all the related code i could find.
Edit: stack trace
Overbox.exe!Overbox.Player.Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch, Microsoft.Xna.Framework.Graphics.Texture2D texture) Line 53 C#
Overbox.exe!Overbox.MediaHandler.Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch spriteBatch) Line 54 C#
Overbox.exe!Overbox.Program.Main(string[] args) Line 15 C#
It's all supposed to be there.
Hero class:
namespace Overbox.Characters
{
class Jacketed : Player
{
override public void Initialize()
{
//Unrelated setting of variables
}
public override void Draw(SpriteBatch spriteBatch, Texture2D texture)
{
spriteBatch.Draw(texture, PlayerPosition, Color.White);
}
}
}
Very short version of game loop class:
public class Game1 : Microsoft.XNA.Framework.Game
{
public static Player player;
//I do load the content which playerTexture requires before anyone asks about it
private Texture2D playerTexture;
protected override void Initialize()
{
player = new Player();
player.Initialize();
}
protected override void Draw(GameTime gameTime)
{
spriteBatch.Begin();
player.Draw(spriteBatch, playerTexture);
spriteBatch.End();
}
}
private Player[] characterList = new Player[14];
Makes an array of Player, but does not actually construct the objects. So what you end up with is basically an array full of null values.
You are missing something like this:
public Player()
{
foreach (var character in characterList)
{
character = new Player();
}
}
This is a wild guess, but I'm assuming Hero overrides one or both or Initialize and Draw. Let's say Hero looks like this:
class Hero : Player
{
public override void Initialize()
{
// Do some stuff. Don't call base.Initialize()
}
}
So we've overridden Initialize(), but haven't called base.Initialize(). We've also not overriden Draw(), so the Draw() from Player will be used when called on a Hero instance.
So let's consider when a Player player is constructed. Then player.characterList is also created, but its elements are null. Next, player.Initialize() is called, setting characterList[0] = new Hero(). Note that characterList[0] has its own characterList array as well.
The next thing to happen is characterList[0].Initialize(). This called the Initialize() override in Hero. This does not call Initialize() inside Player, so the characterList inside the Hero instance still has null elements.
Some time in the future, the Draw method is called in the Player. This, in turn, calls characterList[0].Draw(spriteBatch, texture). Since we didn't override the Draw method in Hero, this calls the same method, but on our Hero instance. But remember that the Hero's characterList still has null values? Well, the only thing to happen here is calling characterList[0].Draw(spriteBatch, texture), which as we now know, is calling Draw on a null value.
This is my guess as to what is happening. The details may vary, but I would imagine this sort of thing is the root cause. To be sure, check the stack trace of the exception. You'll notice two frames for the Draw method, letting you know that the exception occurred in a recursive call to Draw.
I've had this solution in mind for a while, but I didn't want to do it because of organizing reasons. All I had to do was to move characterList to the main game loop class and making it public, guaranteeing that it would be initialized before the draw method would be called. This did work.
Related
I'm currently programming a 2D Game Engine in C# using GDI+ and at the moment I'm trying to implement a component based structure.
The idea is that my GameObject class has a list of components. Each component can be completely different to the next.
I represented components by creating a Component class, which looks like this:
public class Component : BaseObject
{
/// <summary>
/// The game object this component is attached too.
/// </summary>
private GameObject gameObject = null;
/*
* Below I called the protected virtual methods from the "BaseObject" class.
* The base object class only contains these 4 protected virtual methods. Nothing else.
*/
public void Load()
{
OnLoad(this, EventArgs.Empty);
}
public void Unload()
{
OnUnload(this, EventArgs.Empty);
}
public void Update(GameTime gameTime)
{
OnUpdate(this, new UpdateEventArgs(gameTime));
}
public void Render(GraphicsEngine graphicsEngine)
{
OnRender(this, new RenderEventArgs(graphicsEngine));
}
public GameObject GameObject
{
get { return gameObject; }
set { gameObject = value; }
}
}
In my game object class, every component that is within the components list gets updated and rendered like so:
internal void Update(GameTime gameTime)
{
OnUpdate(this, new UpdateEventArgs(gameTime));
// All components being updated
components.ForEach(c => c.Update(gameTime));
}
With all of that being said, I've created a SpriteComponent class, which is meant to render a simple 2D sprite, based on the game objects position, it's overrided render method looks like this:
protected override void OnRender(object sender, RenderEventArgs e)
{
e.GraphicsEngine.DrawBitmap(bitmap, GameObject.Transform.Position);
base.OnRender(sender, e);
}
However for some reason this happens (This is the render method of the GameObject class):
internal void Render(GraphicsEngine graphicsEngine)
{
if (Enabled)
{
// Rendering a sprite component like this works fine
// Here I've created created a SpriteComponent inside the game object class to test it
if(sprite != null)
graphicsEngine.DrawBitmap(sprite.Bitmap, transform.Position);
OnRender(this, new RenderEventArgs(graphicsEngine));
// But rendering it using it's own method doesn't work
//sprite.Render(graphicsEngine);
// and this doesn't work properly either
// components.ForEach(c => c.Render(graphicsEngine));
}
}
And here is a picture of the result when I either iterate through the components list and render it, or render the sprite component by it's self:
I would look into you calling the OnRender. It is not best practice to call these event handlers. The has to be some other method you need to call which will invoke the OnRender.
Similar to OnDraw (Event handler) and Update (Invoke method)
I think you did override wrong method, As I see you have override the OnRender
While probably you calling Render method.
Try to make the Render method virtual and override it in child classes
I am building an XNA game and I have used this method to create new levels.
First I make an abstract class called Level:
public abstract class Level {
public abstract void Update(GameTime gameTime);
public abstract void Draw(SpriteBatch spriteBatch);
}
In the Game1 object, I declare a public static Level currentLevel;
and after initialising it (Like : currentLevel = new GameLevel()), call it's update and draw methods in the Game1.Update and Game1.Draw. When I want to change the level, I do Game1.currentLevel = new RandomLevel()
I load my textures for all my levels in Game1.LoadContent by calling the static Load method in my levels.
My actual levels look like this:
class GameLevel : Level {
Background sky = new Background(new Vector2(0, 0), -0.2f);
Background land = new Background(new Vector2(0, 0), -0.2f);
public static void Load()
{
...
}
public override void Update(GameTime gameTime)
{
...
}
public override void Draw(SpriteBatch spriteBatch)
{
...
}
}
My problem:
If my textures are static in the levels, I can load them in my static Load method which I call in the Game1.LoadContent. It works fine only if there are static textures(In fact, It works like that in my other levels). But in this level, I have a normal background objects. So I can't call sky.Load and land.Load in a static method. I want to create a lot of backgrounds with different textures. So how do I load the texture for my each of my background objects at the start of the GameLevel?
I was thinking of using a DrawableGameComponent and inherit it in GameLevel but I can't. Because I already inherited Level. I also got to know that GameComponents are deprecated.
I made a static ContentManager reference in Game1and assigned Game1's Content to it. Then I used that content to load the texture for the Background object in the constructor of the GameLevel object. I didn't think it will work before because I thought the contents are only loaded once per game. (As it was written in the comments of the LoadContent method. It worked anyway.
If there is a better way to do it, please do tell me.
I'm trying to implement screen management into my XNA game.
So far I've successfully implemented Example 3 from this link: http://www.xnadevelopment.com/tutorials/thestateofthings/thestateofthings.shtml
My current screen switch event is as follows:
public void GoToScreenOverview(object obj, EventArgs e)
{
screenStart = null;
screenOverview = new ScreenOverview(this, new EventHandler(GoToScreenOverview), globalVariables);
mCurrentScreen = screenOverview;
}
This moves from the (initial) screen "Start", and moves the game to the next screen "Overview". The equivalent reciprocal method GoToScreenStart does the opposite.
My question is this: How do I manage all the events?
Let's say I have 20 screens. Each screen Class will need 19 EventHandlers passed to it, which seems massively inefficient, and makes it a pain to add a new screen. Currently GoToScreenX type are events are in the Game1 class, but it seems to me that it would make more sense for all the events to be in the "BaseScreen" class, which each Screen inherits from.
If I were you, I would create a ScreenManager class. You could start with something like this:
public class ScreenManager
{
List<GameScreen> screens;
bool isinitialized = false;
public override void Initialize()
{
base.Initialize();
isinitialized = true;
}
protected override void LoadContent()
{
foreach (GameScreen screen in screens)
screen.LoadContent();
}
public void AddScreen(GameScreen screen)
{
screens.Add(screen);
if (isinitialized) screen.LoadContent();
}
// also create a removescreen
public void Draw(Gametime gametime)
{
foreach (GameScreen screen in screens)
{
screen.Draw(gametime);
}
}
// also create a similar method for Updating
}
You could make ScreenManager a DrawableGameComponent (recommended), or you could have the maingame call ScreenManager.Update() and ScreenManager.Draw() in it's respective methods. Finally, you'd have to create an abstract GameScreen class that has update and draw methods, and then have all your other Game Screens inherit from the GameScreen class. hopefully this will give you some ideas.
I'm trying to store a series of GameObjects on a List. For some reason any time I put an object on the list, it loses it sprite reference (becomes null). All other object data (position, Color, etc) seems to stay in the object just fine. Here's what I've been trying:
static class Global
{
public static List<GameObject> objects = new List<GameObject>();
}
This is the list I'm using. Now for the object in question - the player:
class Player : GameObject
{
public Vector2 position = Vector2.Zero;
public Texture2D sprite;
public Color image_blend = Color.White;
public Player() : base()
{
//nothing here, nothing in base class either
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(sprite, position, image_blend);
}
}
And finally in my main XNA class (important snippets):
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
sprPlayer = Content.Load<Texture2D>("player");
player = new Player();
player.sprite = sprPlayer;
Global.objects.Add(player);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
for (int i = 0; i < Global.objects.Count; i++)
{
Global.objects[i].Draw(spriteBatch);
}
spriteBatch.End();
base.Draw(gameTime);
}
I have a feeling I may be going about this the wrong way. Any help is appreciated.
Player has a the Texture2D member called "sprite" not your GameObject class (which you didn't post the code for).
So when you create the Player class, you assign it's member the Texture2D, then you store the Player as it's parent GameObject making all of it's specific object type memebers inaccessible.
To fix, you'll want to make your base GameObject have the member "sprite" and not have on in your Player class that's inheriting from GameObject.
Your list objects is a GameObject list. I am guessing that any data in your player object that is not part of the GameObject class is being thrown out. I'm not sure though..
Also, you really should take a different approach for your sprite's textures. When you decide to add a bunch of entities of players and enemies and what not, each of those entities will have their own separate texture. If you decide to add 100 of these guys or so, you will have 100 duplicates of the same texture.
First I would recommend loading the texture into an array of textures.
//Please excuse my bugs, I haven't used c# in a while
//Place this in your global class:
public static Texture2D[] myTextures = new Texture2D[1]; //or more if you decide to load more.
//And place this in your LoadContent() Method:
Global.myTextures[0] = Content.Load<Texture2D>("player");
//Also, modify your player class:
public int textureIndex = 0;
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(Global.myTextures[textureIndex], position, image_blend);
}
Now instead of each player object having it's own separate texture, It uses a texture from the array. Now you can have a lot of entities without unnecessary duplicate textures for each entity
public Block[,] Layer2ID;
Layer2ID[X, Y].Draw(spriteBatch, new Vector2(X * 32, Y * 32)); //Child of Block, let's call it Wall
Layer2ID is populated with an array of Block's children, but is of the Block type, thus, when I call the draw function, it uses Block's draw function instead of the child's. Why is this, and how do I fix it?
Thank you.
From your description, it sounds like you have something like this
class Block
{
public void Draw(SomeObj spriteBatch, Vector2 vector) { }
}
class Wall : Block
{
public void Draw(SomeObj spriteBatch, Vector2 vector) { }
}
The method inside Wall is hiding the method in Block, it is not virtual. You may even have a new modifier on the method inside Wall, as the compiler will generally warn you of the hiding method and recommend the new keyword to mark your intent. This hiding method is only called via the Wall reference, not via a reference of Block.
Unlike Java, for example, methods in C# are not virtual by default, you have to mark them as such. To use your methods polymorphically, apply the virtual and override modifiers to the methods in the base and derived classes, respectively.
class Block
{
public virtual void Draw(SomeObj spriteBatch, Vector2 vector) { }
}
class Wall : Block
{
public override void Draw(SomeObj spriteBatch, Vector2 vector) { }
}
With this in place, the overriding method will be invoked.
Block block = new Wall();
block.Draw(spriteBatch, vector); // should observe derived behavior
Layer2ID[x, y].Draw(spriteBatch, vector); // same, if this element is a Wall