- Home /
(C#)Usage of own type returns NullReferenceException
I have created my own Player Class containing a NetworkPlayer object and some Additional variables (Name, Level, Ping, ...). It looks like this (shortened):
class Player
{
public NetworkPlayer NetPlayer;
public Player()
{
NetPlayer = new NetworkPlayer();
}
}
In the MonoBehaviour class in the same file, I'm creating some Instances of that Player Object:
private void Start()
{
ConnectedPlayers = new Player[32];
MyPlayerInstance = new Player();
MyPlayerInstance.NetPlayer = Network.player;
}
When a player joins the server, I wanted to assign his NetworkPlayer Instance to one of my ConnectedPlayers:
private void OnPlayerConnected(NetworkPlayer player)
{
ConnectedPlayers[PlayerCount].NetPlayer = new NetworkPlayer(); //just in case it didn't work before...
ConnectedPlayers[PlayerCount].NetPlayer = player;
}
Problem: The last line of code returns an NullReferenceException. I have no idea why, when I got this error before, I mostly forgot to create the Instance using "new ...".
Thank you!
Just a little hint: when you put a Debug.Log("Player constructed");
in your constructor you will see that noone is created except the one you've created for yourself in Start.
I actually had that exact line of code in the constructor, just cut it out here. I remember seeing a lot of "Player constructed" messages in the console (?). Perhaps I'm just blind...
Answer by Bunny83 · Jul 23, 2011 at 07:26 PM
You didn't create any of the player objects in your array.
This line:
ConnectedPlayers = new Player[32];
will create an array with 32 Player-references but those are all null because you have to create your Players too.
You have three options:
Create all 32 playerobjects in start and assign them to your array.
Create the playerobject when it's needed (when a player joins).
Turn your Player class into a struct.
Sometimes it's nice to be able to null such instances to indicate that this player isn't used. But if your code needs to be able to access all 32 players you take solution 1 or 3 ;)
Solution1:
ConnectedPlayers = new Player[32];
for(int i = 0;i < ConnectedPlayers.Length; i++)
ConnectedPlayers[i] = new Player();
Solution2:
class Player
{
public NetworkPlayer NetPlayer;
public Player(NetworkPlayer aNetPlayer)
{
NetPlayer = aNetPlayer;
}
}
private void OnPlayerConnected(NetworkPlayer player)
{
ConnectedPlayers[PlayerCount] = new Player(player);
}
Solution3:
struct Player
{
public NetworkPlayer NetPlayer; //NetworkPlayer is also a struct and therefore a value-type
}
private void OnPlayerConnected(NetworkPlayer player)
{
ConnectedPlayers[PlayerCount].NetPlayer = player;
}
ps. an array can get you in trouble when one of the first player leaves and a new one joins. Your playercount (i guess you increment it when someone joins and decrement it when one leaves) can't not be used as index into the array since your array can get "fragmented".
For such a task i would suggest a List<Player>
or maybe a Dictionary<NetworkPlayer,Player>
. You can add and remove players easily.
Thanks for this. I'm still intermediate at this sort of thing and I had no idea that you still had to create and assign objects to an array; I assumed making an array of that type would automatically make empty GameObjects (not null, just empty). Would explain why when I tested out spawning objects from an array a few months ago, I was plagued with null exceptions that stumped me. :)
There's a general big difference between value-types and referece-types. Value types store their actual value in the variable itself. Value types are int, bool, float, Vector3.
Reference types work a bit differently. The object itself (a class instance) will be somewhere in your memory when it is created. The variable you assigned your object to just holds a reference to this object. It's just a pointer so you know where you can find the object when you need it.
// this creates a new object
GameObject GO = new GameObject("$$anonymous$$yObject");
// this will only copy the reference. Both variables points to the same object
GameObject tmp = GO;
// When you change something it changes affects the object behind the reference.
tmp.name = "NewName";
// This will print "NewName"
Debug.Log(GO.name);
Value type don't need to be created. If you declare a variable of an value type the variable exists at this moment within it's scope. However, even value types should be initialized.
// new Vector3() just calls the constructor and assigns the value to our variable
Vector3 V = new Vector3(1,2,3);
// this will copy the "value" of the Vector3 so there are two variables with the same value
Vector3 V2 = V;
// now changes will only affect this value
V2.x = 500;
// this will print "(1,2,3)"
Debug.Log(V);
Thank you! I didn't think about the new[] function only creating an array and not the objects it contains. :)
Just to be sure: A struct (from solution 3) is a value type?
Yes, that's the main difference between a class and a struct ;)
Your answer
Follow this Question
Related Questions
Editor forgets elements of array after saving changes to code 0 Answers
Distribute terrain in zones 3 Answers
Parameter becomes null through UNet Rpc 1 Answer
Multiple Cars not working 1 Answer