gameobject array different sequence in built from playmode? - c#

My problem is inside playmode I get expected array sequence: showing all gameobjects, RedCube, Interior, BlueCube, and then GreenCube. But, after I built it and test in my android. I get a different array sequence: showing all gameobjects, GreenCube, BlueCube, RedCube and then Interior. This screenshot shows the sequence of my array.image0.
There are 4 gameobjects under gameobject - Levels Image1. Added a script to Levels.... Image2complete scene screenshot.
public GameObject[] levels;
public Button levelBtn;
int i = 0;
private void Awake()
{
levels = GameObject.FindGameObjectsWithTag("levels");
Button btn = levelBtn.GetComponent<Button>();
}
// Start is called before the first frame update
void Start()
{
levelBtn.onClick.AddListener(onLevelclick);
}
public void onLevelclick()
{
if (i < levels.Length - 1)
{
i++;
}
else if (i >= levels.Length - 1)
{
i = 0;
}
Debug.Log(i);
if (i == 0)
{
levels[0].SetActive(true);
levels[1].SetActive(true);
levels[2].SetActive(true);
levels[3].SetActive(true);
}
else if (i == 1)
{
levels[0].SetActive(true);
levels[1].SetActive(false);
levels[2].SetActive(false);
levels[3].SetActive(false);
}
else if (i == 2)
{
levels[0].SetActive(true);
levels[1].SetActive(true);
levels[2].SetActive(false);
levels[3].SetActive(false);
}
else if (i == 3)
{
levels[0].SetActive(true);
levels[1].SetActive(true);
levels[2].SetActive(true);
levels[3].SetActive(false);
}
}
Inside this script I have a gameobject array. When I click the UIbutton, it will loop within the array.length.... But the array sequence is different from playmode and built. I couldn't figure out why?

If you assign gameobjects to levels in the unity inspector like image0, you don't need to this line.
levels = GameObject.FindGameObjectsWithTag("levels");

Related

Need help fixing code to swap camera positions in Unity3D with C#

I'm revising a code so that a camera will cycle through 3 different locations on a ship. The problem I've come across with this code is that it will only go to a 2nd location & stays there. It needs to cycle through but doesn't.
This is the code I'm working with:
public void CycleCameraView (Vector3 inputValue, int customPlayerInputEventType)
{
// Cycle the current camera view index to the next view.
currentCameraViewIndex = (currentCameraViewIndex + 1) % 3;
SetCurrentView(currentCameraViewIndex);
}
public int GetCurrentCameraViewIndex ()
{
return currentCameraViewIndex;
}
public int GetNextCameraViewIndex ()
{
return (currentCameraViewIndex + 1) % 3;
}
public void SetCurrentView(int viewIndex)
{
if (viewIndex >= 0 && viewIndex < 3 && shipCameraModule != null)
{
currentCameraViewIndex = viewIndex;
if (currentCameraViewIndex == 0)
{
// Camera view 1
// Set the camera parameters to match camera view 1
}
else if (currentCameraViewIndex == 1)
{
// Camera view 2
// Set the camera parameters to match camera view 2
}
else
{
// Camera view 3
// Set the camera parameters to match camera view 3
}
}
}
#endregion
}
First, you are repeating your code here which is obviously not a good practice.
(currentCameraViewIndex + 1) % 3;
Call the GetNextCameraViewIndex and bring the above logic there.
public void CycleCameraView (Vector3 inputValue, int customPlayerInputEventType)
{
// Cycle the current camera view index to the next view.
currentCameraViewIndex = GetNextCameraViewIndex;
SetCurrentView(currentCameraViewIndex);
}
public int GetNextCameraViewIndex ()
{
return (currentCameraViewIndex + 1) % 3; // Please correct if required, I'm not on a dev machine.
}
I think we need more stuff if you want us to be able to help you mate. Also, you shouyld definitly use a switch in your SetCurrentView(int viewIndex)

Tiles not following input in a branching board game path

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;
}
}`

Unity3d Associate an action with a different parameter (incremented index) to a button prefab

I'm having a button prefab so i tried to associate a scene object script to it , which i guess is not possible , but now i'm trying to associate a button click action to a dynamically created button in some script , here is the code snippet.
int index = 0
public IEnumerator GenerateItems()
{
foreach (ArrayList eat in eatArray))
{
Debug.Log (index);
GameObject localItem = (GameObject)Instantiate(item, Vector3.zero, Quaternion.identity);
UnityEngine.Events.UnityAction action = () => { Debug.Log(index); };
++index;
localItem.GetComponent<Button>().onClick.AddListener(action);
localItem.transform.SetParent(grid.transform);
localItem.transform.localScale = autoLocalScale;
localItem.transform.localPosition = Vector3.zero;
}
yield return new WaitForSeconds(.1f);
///1. Two ways to move the scroll to first item
scrollRect.horizontalNormalizedPosition = 0;
// //2. Moving the scroll bar to left
// //scrollBar.value = 0;
}
What i get the value of index is 2 and i want that when i click on the indexed button (like 2 buttons are there so i should get 0 on the first buttons click and 1 on second buttons click ) .
The item is a prefab , contains a button component that I get by get component function and add action to the button .eatArray is also an arrayList. And I instantitate the item to localItem giving it a position and so localItem is a gameobject with component button on it .eatarray is basically used to get the count number of times the loop runs
Edit :
public void OnClick()
{
Debug.Log(index);
}
I can get the correct index value when i attach the script on button prefab with the index variable in it and I increment the index in the for loop as
localItem.GetComponent<GridButton> ().index = index++;
and now this OnClick() function does return correct index but i can't do it this way because there are lot of functions written on other script and i don't want to duplicate code and can't use reference cause many functions are private.
All you have to do is create a callback function that takes an int as a parameter. You can then pass in the loop index to AddListener function so that when the Button is clicked, it will call the callback function and pass in the index Button clicked. Below is code to to this.
public IEnumerator GenerateItems()
{
for (int i = 0; i < eatArray.Count; i++)
{
Debug.Log(i);
GameObject localItem = (GameObject)Instantiate(item, Vector3.zero, Quaternion.identity);
localItem.GetComponent<Button>().onClick.AddListener(() => buttonCallBack(i));
localItem.transform.SetParent(grid.transform);
localItem.transform.localScale = autoLocalScale;
localItem.transform.localPosition = Vector3.zero;
}
yield return new WaitForSeconds(.1f);
///1. Two ways to move the scroll to first item
scrollRect.horizontalNormalizedPosition = 0;
// //2. Moving the scroll bar to left
// //scrollBar.value = 0;
}
void buttonCallBack(int buttonIndex)
{
//Button Index 0
if (buttonIndex == 0)
{
}
//Button Index 1
if (buttonIndex == 1)
{
}
}
EDIT:
You want this with foreach loop. Do NOT use foreach loop with List or ArrayList in Unity, but since you want it like that, there you go.
public IEnumerator GenerateItems()
{
int i = 0;
foreach (ArrayList eat in eatArray)
{
Debug.Log(i);
GameObject localItem = (GameObject)Instantiate(item, Vector3.zero, Quaternion.identity);
localItem.GetComponent<Button>().onClick.AddListener(() => buttonCallBack(i));
localItem.transform.SetParent(grid.transform);
localItem.transform.localScale = autoLocalScale;
localItem.transform.localPosition = Vector3.zero;
i++;
}
yield return new WaitForSeconds(.1f);
///1. Two ways to move the scroll to first item
scrollRect.horizontalNormalizedPosition = 0;
// //2. Moving the scroll bar to left
// //scrollBar.value = 0;
}
void buttonCallBack(int buttonIndex)
{
//Button Index 0
if (buttonIndex == 0)
{
Debug.Log("Button: " + buttonIndex + "PRESSED");
}
//Button Index 1
if (buttonIndex == 1)
{
Debug.Log("Button: " + buttonIndex + "PRESSED");
}
}

Set active gameobjects in a list

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

Array error in C# for Unity

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);
}
}

Categories