I'm making a menu for an Android 2d app, I have a bunch of UI panels in multiple menu's and when I press the next right or previous left button the script should set the next panel active and deactive the previous panel, I've tried doing this with a public class with gameobjects but that didn't work and thought a list should work.
In the Unity editor I've set the size to 4 and dragged 4 panels into the script
and I'm getting this error:
ArgumentOutOfRangeException: Argument is out of range.
Parameter name: index
Here is the relevant part of the script:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class MenuControl : MonoBehaviour
{
//Buttons
public GameObject ShipUpgradeRight;
public GameObject ShipUpgradeLeft;
//Ships
private int shipUpgradeSelected = 0;
List<GameObject> ShipList = new List<GameObject>();
public void Keyword (string keyword)
{
if (keyword == "ShipUpgradeLeft") {
shipUpgradeSelected--;
ShipList[shipUpgradeSelected].SetActive (true);
ShipList[shipUpgradeSelected+1].SetActive (false);
}
if (keyword == "ShipUpgradeRight") {
shipUpgradeSelected--;
CheckShip ();
ShipList[shipUpgradeSelected].SetActive (true);
ShipList[shipUpgradeSelected-1].SetActive (false);
}
}
}
Based on your comments and the actual question I see one possible problem.
The value of shipUpgradeSelected never gets increased. Moreover, shipUpgradeSelected has zero as initial value.
public void Keyword (string keyword)
{
if (keyword == "ShipUpgradeLeft") {
shipUpgradeSelected--;
ShipList[shipUpgradeSelected].SetActive (true);
ShipList[shipUpgradeSelected+1].SetActive (false);
}
if (keyword == "ShipUpgradeRight") {
shipUpgradeSelected--;
CheckShip ();
ShipList[shipUpgradeSelected].SetActive (true);
ShipList[shipUpgradeSelected-1].SetActive (false);
}
}
When keyword equals to ShipUpgradeRight or ShipUpgradeLeft the value of shipUpgradeSelected is decreased (so it's less than zero). And then you try to access the item of list at index that is less than zero.
But this is first problem.
Also you don't clamp (or don't cycle) value of shipUpgradeSelected. So for example you have
if (keyword == "ShipUpgradeRight") {
shipUpgradeSelected++;
CheckShip ();
ShipList[shipUpgradeSelected].SetActive (true);
ShipList[shipUpgradeSelected-1].SetActive (false);
}
If call Keyword("ShipUpgradeRight"); five times (for example), the value of shipUpgradeSelected is 5. And again it's out of range. So you need to decide how to clamp value of this variable.
This code works perfect:
public void Keyword(string keyword) {
if (keyword == "ShipUpgradeLeft") {
shipUpgradeSelected--;
if (shipUpgradeSelected < 0) {
shipUpgradeSelected = 0;
return;
}
ShipList[shipUpgradeSelected].SetActive(true);
if (shipUpgradeSelected + 1 < ShipList.Count) ShipList[shipUpgradeSelected + 1].SetActive(false);
else ShipList[0].SetActive(false);
}
if (keyword == "ShipUpgradeRight") {
shipUpgradeSelected++;
if (shipUpgradeSelected >= ShipList.Count) {
shipUpgradeSelected = ShipList.Count - 1;
return;
}
ShipList[shipUpgradeSelected].SetActive(true);
if (shipUpgradeSelected > 0) ShipList[shipUpgradeSelected - 1].SetActive(false);
else ShipList[ShipList.Count-1].SetActive(false);
}
}
but if i would start over i'd do it like this:
private void Start()
{
ShipUpgradeLeft.GetComponent<Button>().onClick.AddListener(() => { Previous(); });
ShipUpgradeRight.GetComponent<Button>().onClick.AddListener(() => { Next(); });
}
public void Next()
{
ShipList[shipUpgradeSelected].SetActive(false);
shipUpgradeSelected = Mathf.Clamp(shipUpgradeSelected++, 0, ShipList.Count - 1);
ShipList[shipUpgradeSelected].SetActive(true);
}
public void Previous()
{
ShipList[shipUpgradeSelected].SetActive(false);
shipUpgradeSelected = Mathf.Clamp(shipUpgradeSelected--, 0, ShipList.Count - 1);
ShipList[shipUpgradeSelected].SetActive(true);
}
Thanks to walther and d12frosted for helping me solve the issue
Related
I have 4 buttons and each of this button activates an image (Please see the link - Stacking). One script is attached to all the 4 buttons. There are 4 placeholders. I am using an approach of stack to stack images one after another. That is, if the first slot is empty, the image goes there. The button has two functions, to add image and to remove image. If the first slot's image is removed, the second slot's image is placed on 1st slot and third slot's image is placed on 2nd slot.
How do I add push and pop to this scenario?
Edit: I tried with List but I am lost. Could there be a way simpler approach?
public class ActivateStackImages : MonoBehaviour {
public GameObject ImageGameObject_To_Add; //Each instance of this script has unique image
public Vector3[] PositionOfImages; //4 positions
private ActivateStackImages [] activateImages; //Script added to 4 buttons
public bool Slot_1_Filled = false;
public bool Slot_2_Filled = false;
public bool Slot_3_Filled = false;
public bool Slot_4_Filled = false;
public bool isImageAdded = false;
private void Awake () {
activateImages= FindObjectsOfType (typeof (ActivateStackImages )) as ActivateStackImages [];
}
public void ActivateGraph () {
if (this.isImageAdded == false) {
for (int i = 0; i < activateImages.Length; i++) {
if (activateImages[i].Slot_1_Filled == false) {
ImageGameObject_To_Add.SetActive (true);
ImageGameObject_To_Add.GetComponent<RectTransform> ().anchoredPosition = PositionOfImages[0];
activateImages[i].Slot_1_Filled = true;
} else if (activateImages[i].Slot_2_Filled == false) {
ImageGameObject_To_Add.SetActive (true);
ImageGameObject_To_Add.GetComponent<RectTransform> ().anchoredPosition = PositionOfImages[2];
activateImages[i].Slot_2_Filled = true;
} else if (activateImages[i].Slot_3_Filled == false) {
ImageGameObject_To_Add.SetActive (true);
ImageGameObject_To_Add.GetComponent<RectTransform> ().anchoredPosition = PositionOfImages[2];
activateImages[i].Slot_3_Filled = true;
} else if (activateImages[i].Slot_4_Filled == false) {
ImageGameObject_To_Add.SetActive (true);
ImageGameObject_To_Add.GetComponent<RectTransform> ().anchoredPosition = PositionOfImages[3];
activateImages[i].Slot_4_Filled = true;
}
}
this.isImageAdded = true;
} else if (this.isImageAdded == true) {
ImageGameObject_To_Add.SetActive (false);
}
}
}
Stacking
I recently switched out some arrays for Lists in most of my scripts as they are easier to use. The problem though is that brought out some new errors. They are :
InvalidOperationException: Collection was modified; enumeration operation may not execute.
ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
According to the errors, the problem is on line 96 of the Gorean Turret and line 37 of the POW_Camp. A couple other scrips also have that issue, but if I figure out what's wrong with these two I should be able to figure out how to fix the rest.
I searched up what to do about these errors and found a couple solutions. I changed the foreach loops to for (var i=0;) style loops. This was supposed to work, but unfortunately not.
My problem is how do I fix these errors. How do I need to change my scripts so there are no errors. As a side note, if you find something that can be shortened, please tell me. I have a feeling that the code is also longer than it needs to be.
Here is the POW_Camp Script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class POW_Camp : MonoBehaviour
{
public GameObject AmmunitionsDump;
public GameObject Explosion;
public GameObject Fences;
public List<GameObject> Prisoners;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (AmmunitionsDump.GetComponent<Health>().CurrentHealth<=0)
{
AmmunitionsDump.SetActive(false);
Explosion.SetActive(true);
}
//If the ammunitiondump is destroyed then destroy fences
if (AmmunitionsDump.activeSelf == false)
{
Destroy(Fences);
//Activate POWs
for (var i=0;i<Prisoners.Count; i++)
{
if (Prisoners[i] == null)
{
Prisoners.Remove(Prisoners[i]);
}
if (Prisoners[i] != null)
{
Prisoners[i].GetComponent<PlayerData>().Captured = false;
}
}
}
}
}
Here is the GoreanTurret Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GoreanTurret : MonoBehaviour
{
public GameObject Projectile;
public GameObject FiringPoint;
public GameObject GunTower;
public GameObject HealthBar;
public List<GameObject> TargetsWithinRange = new List<GameObject>();
public float FiringRange = 100;
public GameObject CurrentTarget;
public bool TargetLocked;
// Start is called before the first frame update
void Start()
{
InvokeRepeating("Shoot", 1, 0.5f);
HealthBar.GetComponent<Slider>().maxValue = gameObject.GetComponent<Health>().MaxHealth;
HealthBar.GetComponent<Slider>().value = gameObject.GetComponent<Health>().CurrentHealth;
}
// Update is called once per frame
void Update()
{
FindTargetsWithinRange(FiringRange, TargetsWithinRange);
TargetManager(TargetsWithinRange, FiringRange);
HealthBar.GetComponent<Slider>().value = gameObject.GetComponent<Health>().CurrentHealth;
//Look at Target if Target is Locked
if (TargetLocked)
{
GunTower.transform.LookAt(CurrentTarget.transform);
}
// If target is destroyed then set targetLocked to false and target to null;
if (CurrentTarget != null)
{
if (CurrentTarget.GetComponent<Health>().CurrentHealth <= 0)
{
TargetLocked = false;
CurrentTarget = null;
}
}
// If one of the targets in the target list is destroyed then remove that
foreach (GameObject possibleTarget in TargetsWithinRange)
{
if (possibleTarget == null || possibleTarget.GetComponent<Health>().CurrentHealth<=0 || possibleTarget.GetComponent<Health>()==null)
{
TargetsWithinRange.Remove(possibleTarget);
}
}
if (CurrentTarget == null)
{
TargetLocked = false;
CurrentTarget = null;
}
// If target is lost and there are still targets, then switch target
if (TargetLocked == false && (CurrentTarget == null || CurrentTarget.GetComponent<Health>().CurrentHealth<0) && TargetsWithinRange.Count>0)
{
if (TargetsWithinRange[0] != null)
{
CurrentTarget = TargetsWithinRange[0];
TargetLocked = true;
}
}
}
void FindTargetsWithinRange(float range, List<GameObject> TargetList)
{
Collider[] colliders = Physics.OverlapSphere(gameObject.transform.position, range);
foreach (Collider collider in colliders)
{
if (collider.gameObject.GetComponent<PlayerData>())
{
if (collider.gameObject.GetComponent<PlayerData>().Captured == false && TargetList.Contains(collider.gameObject) == false)
{
TargetList.Add(collider.gameObject);
}
}
}
}
void TargetManager(List<GameObject> TargetList, float MaxRange)
{
for (var i = 0; i < TargetList.Count; i++)
{
//If the Target is null or inactive then remove that target or if it has no health
if (TargetList[i] == null || TargetList[i].activeSelf == false || TargetList[i].GetComponent<Health>().CurrentHealth <= 0)
{
TargetList.Remove(TargetList[i]);
if (TargetList[i] == CurrentTarget)
{
TargetLocked = false;
}
}
//If the target is too far
if (Vector3.Distance(gameObject.transform.position, TargetList[i].transform.position) > MaxRange)
{
TargetList.Remove(TargetList[i]);
if (TargetList[i] == CurrentTarget)
{
CurrentTarget = null;
TargetLocked = false;
}
}
}
//If there is no target and the TargetLocked is false then Set a new target
if (CurrentTarget == null && TargetLocked == false && TargetList.Count > 0)
{
CurrentTarget = TargetList[0];
TargetLocked = true;
}
// If target is destroyed then set targetLocked to false and target to null;
if (CurrentTarget != null && CurrentTarget.activeSelf == true && CurrentTarget.GetComponent<Health>().CurrentHealth > 0)
{
if (CurrentTarget.GetComponent<Health>().CurrentHealth <= 0)
{
TargetLocked = false;
CurrentTarget = null;
}
}
}
public void Shoot()
{
if (TargetLocked == true)
{
Instantiate(Projectile, FiringPoint.transform.position, FiringPoint.transform.rotation);
}
}
}
In both your classes you have loops where you are removing elements from your collections while you are iterating over them.
The first one causes the ArgumentOutOfRangeException because after removing certain amount of elements you will iterate until reaching an index that is too high since your list/array is smaller now!
The other exception is pretty self-explanatory: You alter the collection while iterating over it with a foreach.
You can solve both cases using Linq Where in order to filter out the null entries (requires using System.Linq; on top of your file)
// in general use the bool operator of UnityEngine.Object
// never do check for "== null" !
Prisoners = Prisoners.Where(p => p).ToList();
// This basically equals doing something like
//var p = new List<GameObject>();
//foreach(var prisoner in Prisoners)
//{
// if(prisoner) p.Add(prisoner);
//}
//Prisoners = p;
foreach (var prisoner in Prisoners.Count)
{
prisoner.GetComponent<PlayerData>().Captured = false;
}
Exactly the same thing can be done in your second script
// so first again we use the bool operator to check if the element target "existed
// then directly use TryGetComponent instead of GetComponent twice
// your order to check also made little sense ;) you should first Check
// the existence of the component before accessing a value
TargetsWithinRange = TargetsWithinRange.Where(target => target && target.TryGetComponent<Health>(out var health) && health.CurrentHealth > 0).ToList();
Alternatively if it is important that the collection itself stays the same reference you could use RemoveAll instead like
Prisoners.RemoveAll(prisoner => ! prisoner);
and accordingly in your other script
TargetsWithinRange.RemoveAll(target => !target || !target.TryGetComponent<Health>(out var h) || h.CurrentHealth <= 0);
I'm making a board game in Unity with multiple branching paths where the players can decide which one to follow. (Think the Mario Part game board) But the player input on which path to follow isn't working.
So I have a script that has the tokens follow a set path and (Linked List for the path) with a for loop to have the tokens move their allocated amount. Within the loop, I have an If statement that checks how many paths the tile has and if there are more than one if runs a separate script that pauses the game and offers a menu prompt for the players to pick one path or the other.
I've tried tossing in a few contitions for continuing the game within the loop but they either ignore the player input, are an input behind or just break the code.
`for (int i = 0; i < spacesToMove; i++)
{
if (final_Waypoint == null)
{
final_Waypoint = Starting_Waypoint;
}
else
{
if (final_Waypoint.Next_Waypoint == null || final_Waypoint.Next_Waypoint.Length == 0)
{
//we are overshooting the final waypoint, so just return some nulls in the array
//just break and we'll return the array, which is going to have nulls at the end.
Debug.Log(Current_Waypoint);
break;
}
else if (final_Waypoint.Next_Waypoint.Length > 1) // && if playerID == 0 so it only appears for players.
{
menu.Pause_for_Choice();
//if (menu.ButtonPress == true)
final_Waypoint = final_Waypoint.Next_Waypoint[menu.choice_int];
//***There's a bug here. It calls menu as per normal, and the game pauses.
//But when I click 'no', choice_int isn't updated first: this function finishes first,
//so this function gets old choice_int. THEN the button function executes.
Debug.Log("test 3 " + menu.choice_int);
}
else
{
final_Waypoint = final_Waypoint.Next_Waypoint[0];
}
}
listOfWaypoints[i] = final_Waypoint;
Debug.Log("i:" + i);
}
return listOfWaypoints;
}`
`{
public GameObject choice_Menu;
public bool isPaused = true;
public int choice_int=0;
public int choice_placeholder = 0;
public void Pause_for_Choice()
{
isPaused = true;
choice_Menu.SetActive(true);
Time.timeScale = 0;
}
public void Yes()
{
choice_placeholder = 0;
UnPause_Game();
}
public void No()
{
choice_placeholder = 1;
UnPause_Game();
}
public void UnPause_Game()
{
isPaused = false;
choice_Menu.SetActive(false);
Time.timeScale = 1;
}
}`
I am trying to check if the value in string word from one class matches any element in the array stringAnswers in another and if it does i want the score to increment by 1. For some reason the code im using below increments the score by 1,2 and 3 depending on the word that is displayed any help would be awesome cheers.
public class Player : MonoBehaviour
{
public int Score = 0;
private string[] StringAns = {"steve", "grace", "lilly"};
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
if (Input.GetKeyDown(KeyCode.Space))
{
RaycastHit hit;
if (Physics.Raycast(transform.position, transform.forward, out hit))
{
if (hit.transform.GetComponent<ButtonNo>() != null)
{
foreach (string stringAnsers in StringAns)
{
if (stringAnsers.Equals(FindObjectOfType<GameController>().word))
{
Debug.Log(" Button has been looked at");
FindObjectOfType<GameController>().RandText();
}
else
{
Debug.Log(" Button has been looked at");
FindObjectOfType<GameController>().RandText();
Score++;
}
}
}
}
if (Physics.Raycast(transform.position, transform.forward, out hit))
{
if (hit.transform.GetComponent<ButtonYes>() != null)
{
foreach (string stringAnsers in StringAns)
{
if (stringAnsers.Equals( FindObjectOfType<GameController>().word) )
{
Debug.Log(" Button has been looked at");
FindObjectOfType<GameController>().RandText();
Score++;
}
else
{
FindObjectOfType<GameController>().RandText();
}
}
}
}
}
}
}
GameController
public class GameController : MonoBehaviour
{
public TextMesh InfoText;
public TextMesh WallText;
public string word;
public Player player;
public string[] Strings = { "stev", "lilly", "grace" };
// Use this for initialization
void Start()
{
RandText();
}
// Update is called once per frame
void Update()
{
InfoText.text = "Is this Spelling Correct ?\n Score: " + player.Score;
}
public void RandText()
{
word = Strings[Random.Range(0, Strings.Length)];
WallText = GameObject.Find("WallText").GetComponent<TextMesh>();
WallText.text = word;
}
}
In general you should call FindObjectOfType<GameController>() only once e.g in Start
private GameController _gameController;
private void Start()
{
_gameController= FindObjectOfType<GameController>();
}
and than reuse that _gameController reference everywhere instead of FindObjectOfType<GameController>().
The same for WallText in GameController:
public TextMesh WallText;
private void Start()
{
WallText = GameObject.Find("WallText").GetComponent<TextMesh>();
RandText();
}
public void RandText()
{
word = Strings[Random.Range(0, Strings.Length)];
WallText.text = word;
}
better would even be you already reference those in the Inspector in Unity via drag&drop than you don't have to use Find at all
Than to your problem: You are setting a new value for word in every iteration for the loop
foreach (string stringAnsers in StringAns)
{
if (stringAnsers.Equals(FindObjectOfType<GameController>().word))
{
Debug.Log("Button has been looked at");
FindObjectOfType<GameController>().RandText();
}
else
{
Debug.Log("Button has been looked at");
FindObjectOfType<GameController>().RandText();
Score++;
}
}
So it might happen that the word doesn't match so you call Score++; but at the same time you do FindObjectOfType<GameController>().RandText(); everytime so a new random word is generated/selected for each iteration.
So in the next iteration of the foreach loop you check against a new random word which might or might not match the next answer string in the list.
Instead you should only generate a new random word after the loop is done e.g. like
foreach (string stringAnsers in StringAns)
{
if (stringAnsers.Equals(FindObjectOfType<GameController>().word))
{
Debug.Log("Button has been looked at-> matched");
Score++;
}
else
{
Debug.Log("Button has been looked at -> didn't match");
}
}
FindObjectOfType<GameController>().RandText();
Note this would still add 1-3 points depending how many of the given stringAnswer match the word. So you should add a break; after increasing Score once if you want only 1 added.
Using Linq you could also do this in only one line instead a loop:
if(StringAns.Any(answer => string.Equals(answer, _gameController.word)))) Score++;
_gameController.RandText();
or for the No button
if(!StringAns.Any(answer => string.Equals(answer, _gameController.word)))) Score++;
I guess the problem is that you are generating a new random word inside the foreach loop that check the word itself. Also, i suggest you not to use a foreach loop, because items inside the array could be more that 3 items, so it could slow the method. I suggest you to use contains instead, like so:
if (StringAns.Contains(FindObjectOfType<GameController>().word))
{
Debug.Log(" Button has been looked at");
Score++;
}
else
Debug.Log(" Button has *not* been looked at");
FindObjectOfType<GameController>().RandText();
Hey everyone i am trying to make an inventory list in C# for unity but i run into an array error when i pickup my item, I cant figure out why i wondered if someone could help. I have searched everywhere for some tips but not come across any the error is :-
ArgumentException: Destination array was not long enough. Check destIndex and length, and the array's lower bounds
As an edit iv attached the full code
code attached below :-
using UnityEngine;
using System.Collections;
[AddComponentMenu ("Inventory/Inventory")]
public class Inventory : MonoBehaviour {
//This is the central piece of the Inventory System.
public Transform[] Contents; //The content of the Inventory
public int MaxContent = 12; //The maximum number of items the Player can carry.
bool DebugMode = true; //If this is turned on the Inventory script will output the base of what it's doing to the Console window.
private InventoryDisplay playersInvDisplay; //Keep track of the InventoryDisplay script.
public Transform itemHolderObject; //The object the unactive items are going to be parented to. In most cases this is going to be the Inventory object itself.
//Handle components and assign the itemHolderObject.
void Awake (){
itemHolderObject = gameObject.transform;
playersInvDisplay = GetComponent<InventoryDisplay>();
if (playersInvDisplay == null)
{
Debug.LogError("No Inventory Display script was found on " + transform.name + " but an Inventory script was.");
Debug.LogError("Unless a Inventory Display script is added the Inventory won't show. Add it to the same gameobject as the Inventory for maximum performance");
}
}
//Add an item to the inventory.
public void AddItem ( Transform Item ){
ArrayList newContents = new ArrayList();
//FIXME_VAR_TYPE newContents= new Array(Contents);
newContents.Add(Item);
//Contents=newContents.ToBuiltin(Transform); //Array to unity builtin array
newContents.CopyTo(Contents); //Array to unity builtin array
System.Array.Resize(ref Contents, 1);
if (DebugMode)
{
Debug.Log(Item.name+" has been added to inventroy");
}
//Tell the InventoryDisplay to update the list.
if (playersInvDisplay != null)
{
playersInvDisplay.UpdateInventoryList();
}
}
//Removed an item from the inventory (IT DOESN'T DROP IT).
public void RemoveItem ( Transform Item ){
ArrayList newContents = new ArrayList();
//FIXME_VAR_TYPE newContents=new Array(Contents); //!!!!//
int index = 0;
bool shouldend = false;
foreach(Transform i in newContents) //Loop through the Items in the Inventory:
{
if(i == Item) //When a match is found, remove the Item.
{
newContents.RemoveAt(index);
shouldend=true;
//No need to continue running through the loop since we found our item.
}
index++;
if(shouldend) //Exit the loop
{
//Contents=newContents.ToBuiltin(Transform); //!!!!//
Contents=newContents.ToArray(typeof (Transform)) as Transform[];
if (DebugMode)
{
Debug.Log(Item.name+" has been removed from inventroy");
}
if (playersInvDisplay != null)
{
playersInvDisplay.UpdateInventoryList();
}
return;
}
}
}
//Dropping an Item from the Inventory
public void DropItem (Item item){
gameObject.SendMessage ("PlayDropItemSound", SendMessageOptions.DontRequireReceiver); //Play sound
bool makeDuplicate = false;
if (item.stack == 1) //Drop item
{
RemoveItem(item.transform);
}
else //Drop from stack
{
item.stack -= 1;
makeDuplicate = true;
}
item.DropMeFromThePlayer(makeDuplicate); //Calling the drop function + telling it if the object is stacked or not.
if (DebugMode)
{
Debug.Log(item.name + " has been dropped");
}
}
//This will tell you everything that is in the inventory.
void DebugInfo (){
Debug.Log("Inventory Debug - Contents");
int items=0;
foreach(Transform i in Contents){
items++;
Debug.Log(i.name);
}
Debug.Log("Inventory contains "+items+" Item(s)");
}
//Drawing an 'S' in the scene view on top of the object the Inventory is attached to stay organized.
void OnDrawGizmos (){
Gizmos.DrawIcon (new Vector3(transform.position.x, transform.position.y + 2.3f, transform.position.z), "InventoryGizmo.png", true);
}
}
Hope someone could help thank you in advance :)
Arrays have a fixed size when they are allocated only complex types that mimic array interaction have auto grow functionality.
Check the capacity of the target array you are copying your original array contents too.
I am not sure what ToBuiltIn method does but it must be creating a new array as a copy of the origin (your data might already be in the array by the way, check it by debugging it) with the capacity set to the total number of items in the array which could be 1 or 0.
Check your variables and debug the code to see the lengths and capacities of you arrays.
UPDATE (From the updated code)
Your Contents array is not initialized when calling the Add Item method.
To make it clear I have rewritten the code you pasted I dont have all the classes you are using so I have not tested or checks it it builds however it will give you an idea of what you can do. Your array management can be simplified if you use generic list.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[AddComponentMenu ("Inventory/Inventory")]
public class Inventory : MonoBehaviour {
//This is the central piece of the Inventory System.
public List<Transform> Contents; //The content of the Inventory
public int MaxContent = 12; //The maximum number of items the Player can carry.
bool DebugMode = true; //If this is turned on the Inventory script will output the base of what it's doing to the Console window.
private InventoryDisplay playersInvDisplay; //Keep track of the InventoryDisplay script.
public Transform itemHolderObject; //The object the unactive items are going to be parented to. In most cases this is going to be the Inventory object itself.
public Inventory()
{
this.Contents = new List<Transform> (MaxContent);
}
//Handle components and assign the itemHolderObject.
void Awake (){
itemHolderObject = gameObject.transform;
playersInvDisplay = GetComponent<InventoryDisplay>();
if (playersInvDisplay == null)
{
Debug.LogError("No Inventory Display script was found on " + transform.name + " but an Inventory script was.");
Debug.LogError("Unless a Inventory Display script is added the Inventory won't show. Add it to the same gameobject as the Inventory for maximum performance");
}
}
//Add an item to the inventory.
public void AddItem ( Transform Item ){
if (this.Contents.Count < this.MaxContent) {
Contents.Add (Item);
if (DebugMode) {
Debug.Log (Item.name + " has been added to inventroy");
}
//Tell the InventoryDisplay to update the list.
if (playersInvDisplay != null) {
playersInvDisplay.UpdateInventoryList ();
}
} else {
// show message that inventory is full
}
}
//Removed an item from the inventory (IT DOESN'T DROP IT).
public void RemoveItem ( Transform Item ){
if (this.Contents.Remove (Item)) {
if (DebugMode) {
Debug.Log (Item.name + " has been removed from inventroy");
}
if (playersInvDisplay != null) {
playersInvDisplay.UpdateInventoryList ();
}
return;
} else {
// Item is not in inventory
}
}
//Dropping an Item from the Inventory
public void DropItem (Item item){
gameObject.SendMessage ("PlayDropItemSound", SendMessageOptions.DontRequireReceiver); //Play sound
bool makeDuplicate = false;
if (item.stack == 1) //Drop item
{
RemoveItem(item.transform);
}
else //Drop from stack
{
item.stack -= 1;
makeDuplicate = true;
}
item.DropMeFromThePlayer(makeDuplicate); //Calling the drop function + telling it if the object is stacked or not.
if (DebugMode)
{
Debug.Log(item.name + " has been dropped");
}
}
//This will tell you everything that is in the inventory.
void DebugInfo (){
Debug.Log("Inventory Debug - Contents");
int items=0;
foreach(Transform i in Contents){
items++;
Debug.Log(i.name);
}
Debug.Log("Inventory contains "+items+" Item(s)");
}
//Drawing an 'S' in the scene view on top of the object the Inventory is attached to stay organized.
void OnDrawGizmos (){
Gizmos.DrawIcon (new Vector3(transform.position.x, transform.position.y + 2.3f, transform.position.z), "InventoryGizmo.png", true);
}
}