I have one class that is going to contain multiple lists that hold a variety of game objects. These lists will get populated by JSON scripts further in development.
Right now, I'm trying to access 1 element in 1 list. I have filled my class out as so:
public class ShopManager : MonoBehaviour
{
public List<GameObject> primaryWeapons = new List<GameObject>();
public List<GameObject> PrimaryWeapons
{
get { return primaryWeapons; }
}
public GameObject gameObj1, gameObj2;
// Use this for initialization
void Start ()
{
FillList();
}
public void FillList()
{
primaryWeapons.Add(gameObj1);
primaryWeapons.Add(gameObj2);
}
}
In my second class I'm trying to access one of the game objects I have placed in the list. This what I have so far:
ShopManager primary;
public GameObject temp;
public List<GameObject> tmpList;
void Awake()
{
primary = new ShopManager();
primary.FillList();
tmpList= new List<GameObject>();
}
// Use this for initialization
void Start()
{
for (int i = 0; i < primary.PrimaryWeapons.Count; i++)
{
tmpList.Add(primary.PrimaryWeapons[i]);
}
Debug.Log(primary.PrimaryWeapons.Count);
}
public void SelectWeapon1()
{
temp = primary.PrimaryWeapons.Where(obj => obj.gameObject.name == "DoorParts_1").SingleOrDefault();
}
}
In my list in the shop manager class I am manually setting the objects myself, so I know the names of them. However, whilst I can get a count returning correctly, I am unable to access this named object.
When I run the code I get a null reference pointing to the following line:
temp = primary.PrimaryWeapons.Where(obj => obj.gameObject.name == "DoorParts_1").SingleOrDefault();
Additonally I even created another list with the idea of passing the contents from my List property in the ShopManager class to this temp one. However, this lists populates with 2 empty positions.
I'm still not 100% on using properties like this. Espcially with lists. Could someone please tell me what it is I'm doing wrong?
You didn't initialize your objects in ShopManager.
Replace this:
public GameObject gameObj1, gameObj2;
With this:
public GameObject gameObj1 = new GameObject(), gameObj2 = new GameObject();
Check GameObject initialization. Especially gameObject field.
primary.PrimaryWeapons.Where(obj => obj.gameObject.name == "DoorParts_1").SingleOrDefault(); can fail with null reference in just few conditions:
primary is null
primary.PrimaryWeapons is null
obj.gameObject is null
The first two look covered in your code. So, check how GameObject.gameObject field is initialized.
Related
I have this problem in Unity (or maybe C#) that's very weird to me. Here is a virtual class:
public abstract class ActionTaken : MonoBehaviour {
protected char type;
protected Transform minionTakingAction;
public abstract void activate();
}
And this virtual class is a parent to the one that interests me:
public class AbilityTaken : ActionTaken
{
public int index;
List<Transform> selectedFriendlyMinions;
List<Transform> selectedEnemyMinions;
List<Transform> selectedTiles;
public override void activate()
{
//The value here is 0 !!! And it should be 1...
Debug.Log(selectedEnemyMinions.Count);
if (selectedFriendlyMinions.Count == 0 && selectedEnemyMinions.Count == 0 && selectedTiles.Count == 0 )
{
minionTakingAction.GetComponentInParent<AbilitiesActivation>().activateAbility(index);
}
else
{
minionTakingAction.GetComponentInParent<AbilitiesActivation>().activateAbility(index, selectedFriendlyMinions, selectedEnemyMinions, selectedTiles);
}
}
public AbilityTaken(Transform _minionTakingAction, int abilityIndex, List<Transform> _selectedFriendlyMinions, List<Transform> _selectedEnemyMinions, List<Transform> _selectedTiles)
{
type = 'S';
minionTakingAction = _minionTakingAction;
index = abilityIndex;
selectedEnemyMinions = _selectedEnemyMinions;
selectedFriendlyMinions = _selectedFriendlyMinions;
selectedTiles = _selectedTiles;
//The value here is 1 !!!
Debug.Log(selectedEnemyMinions.Count);
}
public AbilityTaken(Transform _minionTakingAction, int abilityIndex)
{
type = 'S';
minionTakingAction = _minionTakingAction;
index = abilityIndex;
selectedFriendlyMinions = new List<Transform>();
selectedEnemyMinions = new List<Transform>();
selectedTiles = new List<Transform>();
}
}
As you can see in the comments, the value of selectedEnemyMinions list of Transforms changes from the constructor (count value: 1) to the "activate()" function (count value: 0), without me making any changes to it. All I do is:
1. I create a new instance of AbilityTaken giving to the constructor an enemyMinionSelection list with 1 element
2. I add abilityTaken to a list
3. I call activate() from LateUpdate()
AbilityTaken abilityTaken = new AbilityTaken(minionTakingAction, gameMaster.abilitySelected,
// value of enemyMinionSelected.Count here is 1
new List<Transform>(), gameMaster.enemyMinionsSelected, new List<Transform>());
List<ActionsTaken> actionsTaken = new List<ActionTaken>();
actionsTaken.Add(abilityTaken);
private void LateUpdate()
{
if (!actionInProgress &&
actionsTaken.Count>0)
{
ActionTaken currentAction = actionsTaken[0];
currentAction.activate();
}
}
If you can tell me why adding the class instance to List and accessing this instance would cause a member List of Transforms to change their value, that would be great. On the other hand the value of member variable "index" doesn't change (it's always 1). I tried changing Lists to public but that doesn't help as expected.
If you can tell me why adding the class instance to List and accessing this instance would cause a member List of Transforms to change their value, that would be great.
It's not. There's nothing wrong with doing that, it won't change the current values of AbilityTaken.
There is something else going on, that is, the problem is somewhere else. For example, Debug.Log(selectedEnemyMinions); is not printing the Count.
I thoroughly debugged my code and found that the problem here is that I am giving the
constructor of ActionTaken parameters (Namely List) that get changed after assignment in ActionTaken constructor. Then I execute some code that changes the first list of transforms, but due to C# not copying the value, but referencing the assigned value the List of Transforms changes when the firstly assigned value changes.
void function()
{
//Some code here
AbilityTaken abilityTaken = new AbilityTaken(minionTakingAction, gameMaster.abilitySelected, new List<Transform>(), gameMaster.enemyMinionsSelected, new List<Transform>())
//Here we go in the constructor and everything seems fine
// ! Some code here that changes gameMaster.enemyMinionsSelected. The class object doesn't copy the List of Transforms, but references it's address and when it changes, the reference in ActionTaken also changes.
}
Unity makes me confused when it comes to referencing players to another object's script. I have used several ways to reference a localPlayer object:
Comparing Tags(not so good in some situations)
gameObject.Name(never used it but it is also not reliable)
Assigning public GameObject Player; in the inspector Drag and Drop (face problems when the player is a prefab)
Making public static [PlayerControllerClass] instance; and setting instance = thisin void Start() function.In order to access playerSpeed from another script I do PlayerControllerClass.instance.playerSpeed = 10;
Is there other solutions for referencing players in a proper way.
Note: I know my question might not be relating to a specific problem but I can explain more if somebody will help.
Edit1: for example I want to find localPlayer in a NetworkGame where all players have same name, same tag but only one player is a localPlayer. Can I access the localPlayer from another script?
Edit2 : The answer I accepted is what I felt the best.I will use the answer provided in previewing score text of the localPlayerby accessing it from a set of players [localPlayer]
Your question wasn't clear until your edit then I realized that this is a networking question.
I need to find localPlayer in a NetworkGame where all players have
same name, same tag but only one player is a localPlayer can I access
the localPlayer from another script?
You can find players with NetworkConnection.playerControllers which retruens List of PlayerController then loop over it and check if it is valid. After that, get NetworkBehaviour from it check the isLocalPlayer property. That's really it.
Something like this:
GameObject FindLocalNetworkPlayer()
{
NetworkManager networkManager = NetworkManager.singleton;
List<PlayerController> pc = networkManager.client.connection.playerControllers;
for (int i = 0; i < pc.Count; i++)
{
GameObject obj = pc[i].gameObject;
NetworkBehaviour netBev = obj.GetComponent<NetworkBehaviour>();
if (pc[i].IsValid && netBev != null && netBev.isLocalPlayer)
{
return pc[i].gameObject;
}
}
return null;
}
If you have NetworkIdentity attached to the player instead of NetworkBehaviour, just get the NetworkIdentity and check the isLocalPlayer property. You can also find the GameObject then check the NetworkIdentity and the isLocalPlayer property.
if (obj.GetComponent<NetworkIdentity>().isLocalPlayer){}
Other useful player operation you may need:
Find all players:
List<GameObject> ListPlayers()
{
NetworkManager networkManager = NetworkManager.singleton;
List<PlayerController> pc = networkManager.client.connection.playerControllers;
List<GameObject> players = new List<GameObject>();
for (int i = 0; i < pc.Count; i++)
{
if (pc[i].IsValid)
players.Add(pc[i].gameObject);
}
return players;
}
Find player by name(Can also be changed to by tag or layer):
GameObject FindNetworkPlayer(string name)
{
NetworkManager networkManager = NetworkManager.singleton;
List<PlayerController> pc = networkManager.client.connection.playerControllers;
for (int i = 0; i < pc.Count; i++)
{
if ((pc[i].IsValid) && (name == pc[i].gameObject.name))
return pc[i].gameObject;
}
return null;
}
OLD answer before your edit:
Is there other solutions for referencing players in a proper way.
Yes, you Find the GameObject with GameObject.Find, after this, you can use the GetComponent function to get the script that is attached to it.
I notice you mentioned you want to reference prefabs in the scene too. There is a difference between prefabs and objects already the scene and they both have different ways to reference them.
Here is an example of Objects in the Scene already. You can see them in the Hierarchy tab:
Let's reference the "Canvas" GameObject by name:
GameObject canvasObj = GameObject.Find("Canvas");
Let's reference the Canvas script attache to the "Canvas" GameObject:
GameObject canvasObj = GameObject.Find("Canvas");
Canvas canvas = canvasObj.GetComponent<Canvas>();
Prefabs:
Here is an example of prefabs in the Project tab:
Put the prefabs in a folder named "Resources". You must so that you can reference them with the Resources API.
Let's reference the "Capsule" prefab GameObject:
GameObject prefab = Resources.Load<GameObject>("Capsule");
To use it, you have to instantiate it:
GameObject instance = Instantiate(prefab);
You can only get components on prefabs after when they are instantiated:
CapsuleCollider cc = instance.GetComponent<CapsuleCollider>();
I recommend the Singleton Pattern. I implement it in almost all my Unity Projects for objects that only have 1 class, yet is a monobehaviour.
using UnityEngine;
public abstract class SingletonBehaviour<T> : MonoBehaviour where T : MonoBehaviour
{
public bool dontDestroyOnLoad = true;
private bool isInitialized = false;
private static T instance;
public static T Instance
{
get
{
if (instance == null)
{
instance = FindObjectOfType<T>();
if (instance == null)
{
var obj = new GameObject
{
name = typeof(T).Name
};
instance = obj.AddComponent<T>();
}
}
return instance;
}
}
protected virtual void Awake()
{
if (instance == null)
{
instance = this as T;
if (dontDestroyOnLoad)
{
DontDestroyOnLoad(this.transform.root.gameObject);
}
}
else if (instance != this)
{
Destroy(gameObject);
}
}
private void OnEnable()
{
if (!isInitialized)
{
OnInitialize();
isInitialized = true;
}
}
public abstract void OnInitialize();
}
You can then create a class like so:
public class MyClass : SingletonBehaviour<MyClass>
{
public void OnInitialize()
{
// You can use this instead of awake or start
}
public void DoStuff();
}
And call it like so:
MyClass.Instance.DoStuff()
I have always sought usage of GameObject.FindGameObjectsWithTag when I need multiple references or else GameObject.FindWithTag when I need just the one reference to a specific GameObject available in the system.
To reference a script on said GameObject (found using the API reference above), you simply use `` as described in GameObject.GetComponent API reference.
A complete example would be:
Assign a tag to your Player GameObject e.g. PlayerA.
GameObject player = GameObject.FindWithTag("PlayerA");
PlayerScript playerScript = player.GetComponent<PlayerScript>();
I hope this helps and should you require further clarification, I'll be more than happy to help.
EDIT: Another solution:
Concern: 50 or x amount of players would be too mundane to assign tags.
Solution: If you have a set of 50 players:
I would group them under a parent GameObject.
Assign the parent GameObject a tag e.g. ParentPlayer
Use the GetComponentsInChildren reference.
I am a bit confused with how i set up my scene to do this. I want to create an array of my class System. Of which contains a Vector3 position a reference to a sprite renderer and the game object. I also instantiate the game object in that position in my array creation.
I setup my array like this in an empty game object in my game world:
public System[] systemArray;
void Start () {
systemArray = new System[totalSystems];
for (int i = 0; i < totalSystems; i++)
{
systemArray[i].worldPos = new Vector3(Random.Range(min,max),Random.Range(min,max), Random.Range(minZ,maxZ));
Instantiate(systemObject,systemArray[i].worldPos,Quaternion.identity);
}
}
Now my System script is not attached to a game object it is just a script that will store the data of the instantiated game objects i just made. And the code looks like this:
public class System : MonoBehaviour {
public SpriteRenderer spriteRenderer;
public GameObject gameObject;
public Vector3 worldPos;
}
My confusion here is how do i link this all up.
The goal here is i will want to be able to destroy the game objects from the scene but i will still be able to access their Vector3, the GO and sprite renderer from System so i can re-instantiate again.
I got myself really confused so am hoping for some help on how i am suppose to set this up efficiently.
Create a seperate class that is responsible for maintaining the systems.
For best practice: The class would not expose the collection of systems directly but rather through methods to make it possible to decorate manipulation with logic.
It would look something like this:
public class SystemRepository
{
private static List<System> _systems;
public List<System> GetAll() {
if (_systems == null) {
_systems = new List<System>()
}
// Further logic
return _systems
}
public System GetBy(GameObject v) { ... }
public void Add(List<System> s) { ... }
public void DestroyBy(Vector3 v) { ... }
...
}
So when you need to access the Systems for adding/removing/getting them you'd do the following:
using Namespace/Of/SystemRepository
// ...
var systemRepo = new SystemRepository();
systemRepo.Add(totalSystems);
And somewhere else..
var systemRepo = new SystemRepository();
var allSystems = systemRepo.GetAll();
for (int i = 0; i < allSystems.Count(); i++)
{
allSystems[i].worldPos = new Vector3(Random.Range(min, max), Random.Range(min, max), Random.Range(minZ, maxZ));
Instantiate(systemObject, allSystems[i].worldPos, Quaternion.identity);
}
Note: Inside the SystemRepository I declared the list of systems to be static and only instantiate it if it is null. That means it can be only instantiated once in the lifetime of your game so that you always get the same data back no matter what instance of the repo you access. Such a thing usually would be done using a Database.
I'm currently trying to set up multiple Input Field in Unity and having issue do so. I can only get one input to work (intPressure) but don't know how to add a second one (drillpipe). It seem to me that unity only allow one Input Field at a time. I would think that just changing it to InputField2, ect will do the trick, but that doesn't seem to work. Other have mentioned creating an empty gameobject and inserting the inputfield to each gameobject.
To be honest, I still quite confuse about how to setup the second input field.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class UserInput : MonoBehaviour {
InputField input;
int intPressure = 0;
int drillpipe = 0;
public DataManager data;
void Start ()
{
var input = gameObject.GetComponent<InputField>();
var se= new InputField.SubmitEvent();
se.AddListener(SubmitName);
input.onEndEdit = se;
}
private void SubmitName(string pressure)
{
var pressureScript =
GameObject.FindObjectOfType(typeof(DataManager)) as DataManager;
if (int.TryParse(pressure, out intPressure))
{
pressureScript.pressure = intPressure;
}
else
{
// Parse fail, show an error or something
}
}
}
I am not sure about the way you want to implement this (using single GameObject), however you most certainly would be able to do this if you had a couple of GameObjects (One object per control) nested within another GameObject (let's call it UserInputRoot) like this:
UserInputRoot (has UserInputController script)
|
+--- InputPressure (has InputField component)
|
+--- InputDrillpipe (has InputField component)
The controlling script would then have either a couple of public InputField's or a couple of private ones, initialized within the Start() or Awake() method:
class UserInputController : MonoBehaviour {
//These can be set from the inspector and controlled from within the script
public InputField PressureInput;
public InputField DrillpipeInput;
// It would be better to pass this reference through
// the inspector instead of searching for it every time
// an input changes
public DataManager dataManager;
private void Start() {
// There is no actual need in creating those SubmitEvent objects.
// You can attach event handlers to existing events without a problem.
PressureInput.onEndEdit.AddListener(SubmitPressureInput);
DrillpipeInput.onEndEdit.AddListener(SubmitDrillpipeInput);
}
private void SubmitDrillpipeInput(string input) {
int result;
if (int.TryParse(input, out result)) {
dataManager.drillpipe = result;
}
}
private void SubmitPressureInput(string input) {
int result;
if (int.TryParse(input, out result)) {
dataManager.pressure = result;
}
}
}
And by the way, the formatting of your code is absolutely atrocious. You MUST fix it.
It looks like the script you are showing is attached to an input field gameobject is that correct? You have a member variable in your object named input but then you create a new variable input in your Start method. Rather than have a script attached to your first InputField, create an empty gameobject in the editor and attach a script to that. In the script add two public members:
public class UserInput : MonoBehaviour {
public InputField PressureInput;
public InputField DrillPipeInput;
Now pop back to the editor, you should see the two input fields showing up when you select your empty gameobject. Drag and drop your two input fields into the slots for each inputfield. Now when the scene starts your UserInput script will be set with the input fields and you can use them both.
I am currently working with C# using the Unity3D engine and have come upon the following problem:
I created a class that has two private references to instances of another class which it has to access. Once I create multiple instances of the class and set the references I found out that all instances were using the same variable. I realized this as I was destroying an instance and just before that set the two variables holding the references to null. Immediately after doing that all other instances were throwing NullReferenceExceptions because they were still trying to access the references. The referenced objects are fine, other scripts can still access them.
Here is some pseudo code illustrating the structure:
public class Character
{
// Character data
}
public class StatusEffect
{
private Character target;
private Character originator;
public void Init(Character _Target, Character _Originator)
{
target = _Target;
originator = _Originator;
}
public void Destroy()
{
target = null;
originator = null;
}
}
In the program it would be called like this:
StatusEffect effect = new StatusEffect();
effect.Init(player1, player2);
// Time goes by
effect.Destroy();
After calling Destroy() every StatusEffect's two references will be null.
This is not only an issue when destroying StatusEffects, but also when creating new ones. As soon as I touch the references from within a new instance all StatusEffects will reference the two Characters specified by the new StatusEffect.
I do not understand why or how I can fix this issue. Can someone enlighten me on this matter?
Cheers,
Valtaroth
EDIT:
Here is the real code as requested:
I have a container class holding several StatusEffects. As soon as it starts, it initializes all of them.
public class CElementTag
{
// ..Other data..
public float f_Duration; // Set in the editor
private CGladiator gl_target;
private CGladiator gl_originator;
private float f_currentDuration;
public CStatusEffect[] ar_statusEffects;
// Starts the effect of the element tag
public void StartEffect(CGladiator _Originator, CGladiator _Target)
{
gl_originator = _Originator;
gl_target = _Target;
f_currentDuration = f_Duration;
for(int i = 0; i < ar_statusEffects.Length; i++)
ar_statusEffects[i].Initialize(gl_originator, gl_target);
}
// Ends the effect of the element tag
public void EndEffect()
{
for(int i = 0; i < ar_statusEffects.Length; i++)
{
if(ar_statusEffects[i] != null)
ar_statusEffects[i].Destroy();
}
}
// Called every update, returns true if the tag can be destroyed
public bool ActivateEffect()
{
f_currentDuration -= Time.deltaTime;
if(f_currentDuration <= 0.0f)
{
EndEffect();
return true;
}
for(int i = 0; i < ar_statusEffects.Length; i++)
{
if(ar_statusEffects[i] != null && ar_statusEffects[i].Update())
RemoveStatusEffect(i);
}
return false;
}
// Removes expired status effects
private void RemoveStatusEffect(int _Index)
{
// Call destroy method
ar_statusEffects[_Index].Destroy();
// Remove effect from array
for(int i = _Index; i < ar_statusEffects.Length - 1; i++)
ar_statusEffects[i] = ar_statusEffects[i+1];
ar_statusEffects[ar_statusEffects.Length - 1] = null;
}
}
The actual StatusEffect class is holding the two references as well as some other data it needs to work. It has virtual methods because there are some classes inheriting from it.
public class CStatusEffect
{
// ..Necessary data..
// References
protected CGladiator gl_target;
protected CGladiator gl_originator;
virtual public void Initialize(CGladiator _Target, CGladiator _Originator)
{
gl_target = _Target;
gl_originator = _Originator;
// ..Initialize other necessary stuff..
}
virtual public void Destroy()
{
gl_target = null;
gl_originator = null;
// ..Tidy up other data..
}
virtual public bool Update()
{
// ..Modifying data of gl_target and gl_originator..
// Returns true as soon as the effect is supposed to end.
}
}
That should be all the relevant code concerning this problem.
EDIT2
#KeithPayne I have a static array of ElementTags defined in the editor and saved to xml. At the beginning of the program the static array is loading the xml and stores all element tags. When creating a new element tag to use I utilize this constructor:
// Receives a static tag as parameter
public CElementTag(CElementTag _Tag)
{
i_ID = _Tag.i_ID;
str_Name = _Tag.str_Name;
enum_Type = _Tag.enum_Type;
f_Duration = _Tag.f_Duration;
ar_statusEffects = new CStatusEffect[_Tag.ar_statusEffects.Length];
Array.Copy(_Tag.ar_statusEffects, ar_statusEffects, _Tag.ar_statusEffects.Length);
}
Do I have to use a different method to copy the array to the new tag? I thought Array.Copy would make a deep copy of the source array and stored it in the destination array. If it is in fact making a shallow copy, I understand where the problem is coming from now.
From Array.Copy Method (Array, Array, Int32):
If sourceArray and destinationArray are both reference-type arrays or
are both arrays of type Object, a shallow copy is performed. A shallow
copy of an Array is a new Array containing references to the same
elements as the original Array. The elements themselves or anything
referenced by the elements are not copied. In contrast, a deep copy of
an Array copies the elements and everything directly or indirectly
referenced by the elements.
Consider this fluent version of the StatusEffect class and its usage below:
public class StatusEffect
{
public Character Target { get; private set; }
public Character Originator { get; private set; }
public StatusEffect Init(Character target, Character originator)
{
Target = target.Clone()
Originator = originator.Clone();
return this;
}
//...
}
public CElementTag(CElementTag _Tag)
{
i_ID = _Tag.i_ID;
str_Name = _Tag.str_Name;
enum_Type = _Tag.enum_Type;
f_Duration = _Tag.f_Duration;
ar_statusEffects = _Tag.ar_statusEffects.Select(eff =>
new StatusEffect().Init(eff.Target, eff.Originator)).ToArray();
// ar_statusEffects = new CStatusEffect[_Tag.ar_statusEffects.Length];
// Array.Copy(_Tag.ar_statusEffects, ar_statusEffects, _Tag.ar_statusEffects.Length);
}
Because you're passing in references to the objects via your Init() method, you're not actually "copying" the objects, just maintaining a reference to the same underlying objects in memory.
If you have multiple players with the same references to the same underlying objects, then changes made by player 1 will effect the objects being used by player 2.
Having said all that, you're not actually disposing the objects in your Destory method. Just setting the local instance references to Null which shouldn't affect any other instances of StatusEffects. Are you sure something else isn't disposing the objects, or that you haven't properly init'd your other instances.
If you do want to take a full copy of the passed in objects, take a look at the ICloneable interface. It looks like you want to pass in a copy of the objects into each Player.
public class Character : ICloneable
{
// Character data
//Implement Clone Method
}
public class StatusEffect
{
private Character target;
private Character originator;
public void Init(Character _Target, Character _Originator)
{
target = _Target.Clone()
originator = _Originator.Clone();
}
The fields aren't shared(static) among other instances. So calling target = null; in Destroy() won't affect other instances.
StatusEffect effect1 = new StatusEffect();
effect1.Init(player1, player2);
StatusEffect effect2 = new StatusEffect();
effect2.Init(player1, player2);
// Time goes by
effect2.Destroy();
// Some more time goes by
// accessing effect1.target won't give a `NullReferenceException` here unless player1 was null before passed to the init.
effect1.Destroy();
I think you did forget the Init(..) on the other instances. Every time you create an instance of StatusEffect, you need to call Init(...).
Update:
This line will clear the reference to the effect, but you never recreate it:
ar_statusEffects[ar_statusEffects.Length - 1] = null;
so the next time you call ar_statusEffects[x].Update() or Initialize() etc it will throw a NullReferenceException
If you want to clear out effects within you array, you could create an Enable bool in the effect, this way you only have to set/reset it.
for(int i = 0; i < ar_statusEffects.Length; i++)
if(ar_statusEffects[i].IsEnabled)
ar_statusEffects[i].Update();
Why don't you use a List instead? Arrays will be faster as long you don't have to shuffle in it. (like circulair buffers etc)
Thanks to Keith Payne I figured out where the problem was. I was creating a deep copy of CElementTag, but not of my ar_statusEffects array. I wrongly assumed Array.Copy was creating a deep copy of an array when it actually was not.
I implemented the IClonable interface for my CStatusEffect and use the Clone() method to create a true deep copy for each member of the static array and add it to the new tags ar_statusEffects array. This way I have seperate instances of the effects instead of references to the same static effect.
Thanks to everyone, especially Keith Payne, for their help and support!