I am currently unable to print all elements of my array. I am trying to use a nested for loop to print and number all elements but I can only print one element over and over again which is the last element that I click in the game.
The first 7 elements printed are all the same and the last element is left completely blank.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PickUpItem : MonoBehaviour, IInteractable
{
public string DisplaySprite;
public string DisplayImage;
public int counter;
public int j;
public string[] ChoosenItems = new string[7];
private GameObject InventorySlots;
public void Interact(DisplayImage currentDisplay)
{
ItemPickUp();
}
void Start()
{
}
void Update()
{
}
void ItemPickUp()
{
InventorySlots = GameObject.Find("Slots");
counter = 0;
foreach (Transform slot in InventorySlots.transform)
{
if (slot.transform.GetChild(0).GetComponent<Image>().sprite.name == "empty_item")
{
slot.transform.GetChild(0).GetComponent<Image>().sprite =
Resources.Load<Sprite>("Inventory Items/" + DisplaySprite);
Destroy(gameObject);
break;
}
if (counter <= 7)
{
ChoosenItems[counter] = (gameObject.name);
counter++;
if (counter >= 7)
{
Debug.Log("You have choosen 8 itmes, would you like to continue or retry?");
for (j = 0; j <= 7; j++)
{
Debug.LogFormat("Element[{0}] = {1}", j, ChoosenItems[j]);
}
}
}
}
}
}
//http://csharp.net-informations.com/collection/list.html
You are declaring your ChoosenItems = new string[7] with 7 element, ChoosenItems[0], through ChoosenItems[6]. As you can see, this is only 7 items. Thus, you will never have 8 items. Try declaring it as ChoosenItems = new string[8] to have it contain 8 items. See Mozilla Developer Docs for more information.
Hope this helps!
Related
I want to create a minigame which select random buttons from an array of game objects and store the value in an array. After the first step is completed the user need to tap on the same buttons or he will lose. The problem is when I want to compare the values from this two arrays, every value from index 0-2 is set to 0 in both arrays. I tried to debug the adding part and that works fine, even in my editor I can see the stored values. Here is a photo:
storedobjectsEditor. I even put two for loops to check the values from array in the game, instead of getting 3 prints I get 6 of them, first 3 represent the values right and the other 3 have value = 0 (this apply to both arrays). In my CheckWin() the result will be always true because the values which are compared there are 0 for every position from both arrays. I can't figure it out what force the arrays to have all components set to zero in that method. Here is the script:
public class Script : MonoBehaviour
{
[SerializeField] private GameObject[] buttons;
[SerializeField] private int[] culoriINT;
[SerializeField] private int[] culoriComparareINT;
int index = 0;
int index2 = 0;
private bool win = false;
private void Start()
{
StartCoroutine(ChangeColors2());
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.P))
{
for (int i = 0; i < culoriINT.Length; i++)
{
Debug.Log("INT vector[" + i + "]: " + culoriINT[i]);
}
}
if (Input.GetKeyDown(KeyCode.W))
{
for (int i = 0; i < culoriComparareINT.Length; i++)
{
Debug.Log("Al doilea vector[" + i + "]: " + culoriComparareINT[i]);
}
}
}
IEnumerator ChangeColors2()
{
yield return new WaitForSeconds(1f);
for (int j = 0; j < buttons.Length; j++)
{
var randomBtn = UnityEngine.Random.Range(0, buttons.Length);
buttons[randomBtn].GetComponent<Image>().color = Color.green;
var introducereIndex = buttons[randomBtn].GetComponent<IndexButtons>().index;
culoriINT[index] = introducereIndex;
Debug.Log($"Index adaugat {introducereIndex} total {culoriINT.Length}");
index++;
yield return new WaitForSeconds(0.5f); //seteaza coloare alb pe acelas buton in cazu in care nimereste acelas sa se vada
buttons[randomBtn].GetComponent<Image>().color = Color.white;
Debug.Log("verde");
yield return new WaitForSeconds(1f);
}
}
public void OnButtonClick()
{
index2++;
}
public void numePeClick()
{
if (index2 < buttons.Length)
{
string a = EventSystem.current.currentSelectedGameObject.name;
culoriComparareINT[index2] = Convert.ToInt32(a);
Debug.Log($"Index adaugat {Convert.ToInt32(a)} total {culoriComparareINT.Length}");
}
else
{
Debug.Log("Array plin");
}
}
public void CheckWin()
{
win = true;
for (var i = 0; i < culoriINT.Length; i++)
{
if (culoriINT[i] != culoriComparareINT[i])
{
win = false;
break;
}
else
{
win = true;
}
}
if (win)
{
Debug.Log("Ai castigat!");
}
else
{
Debug.Log("Ai pierdut!");
}
}
}
It sounds like you have two instances of the same Script component in your scene. One of them has the correct values 3,2,3, the other one has the wrong values 0,0,0. This is why six values get printed to the console instead of three with a single input.
I don't want the player to spam the continueButtonSE hence, I only want it to appear after the dialogue has finished.
It works in the first index but for the next element, the continueButton does not appear. Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class DialogueSE : MonoBehaviour
{
public TextMeshProUGUI textDisplaySE;
public string[] sentencesSE;
private int index;
public float typingSpeedSE;
public GameObject continueButtonSE;
void Start()
{
StartCoroutine(Type());
}
void Update()
{
if(textDisplaySE.text == sentencesSE[index])
{
continueButtonSE.SetActive(true);
}
}
IEnumerator Type()
{
foreach (char letter in sentencesSE[index].ToCharArray())
{
textDisplaySE.text += letter;
yield return new WaitForSeconds(typingSpeedSE);
}
}
public void NextSentenceSE()
{
continueButtonSE.SetActive(false);
if (index < sentencesSE.Length - 1)
{
index++;
textDisplaySE.text = " ";
StartCoroutine(Type());
}
else
{
textDisplaySE.text = " ";
continueButtonSE.SetActive(false);
}
}
}
I've disabled the continueButtonSE from the start so that it can only appear once sentencesSE[index] is done appearing.
You are prepending a space when you say textDisplaySE.text = " "; and then you add things in the coroutine therefore if(textDisplaySE.text == sentencesSE[index]) is never true because your in the second case textDisplaySE.text is actually [space]test2 instead of just test2 which is what sentencesSE[index].
On line 31 instead you can initialize to textDisplaySE.text = string.Empty; to not have any whitespace.
In addition to the explanation of your issue from this answer
Why do you need the check at all?
You could simply let your Coroutine handle the end of the typing and enabling the continue button like e.g.
IEnumerator Type()
{
foreach (char letter in sentencesSE[index].ToCharArray())
{
textDisplaySE.text += letter;
yield return new WaitForSeconds(typingSpeedSE);
}
if (index < sentencesSE.Length - 1)
{
continueButtonSE.SetActive(true);
}
}
public void NextSentenceSE()
{
continueButtonSE.SetActive(false);
if (index < sentencesSE.Length - 1)
{
index++;
textDisplaySE.text = "";
StartCoroutine(Type());
}
else
{
textDisplaySE.text = "";
Debug.Log("Reached end of dialog");
}
}
This way you don't need the Update method and string compare at all and wouldn't even get into the issue with the prepend space character ;)
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(PickupObjects))]
public class PickupObjectsEditor : Editor
{
private static List<GameObject> pickeditems = new List<GameObject>();
private static bool picked = false;
private SerializedProperty _serializedpickeditems;
[MenuItem("GameObject/Generate as Pickup Item", false, 30)]
public static void GeneratePickupItems()
{
if (Selection.gameObjects.Length > 0)
{
for (int i = 0; i < Selection.gameObjects.Length; i++)
{
if (Selection.gameObjects[i].GetComponent<TestScript>() == null)
{
Selection.gameObjects[i].AddComponent<BoxCollider>();
Selection.gameObjects[i].AddComponent<TestScript>();
}
Selection.gameObjects[i].layer = 9;
Selection.gameObjects[i].tag = "Pickup Item";
pickeditems.Add(Selection.gameObjects[i]);
}
picked = true;
}
}
public override void OnInspectorGUI()
{
serializedObject.Update();
PickupObjects myTarget = (PickupObjects)target;
DrawDefaultInspector();
if (picked == true)
{
for (int i = 0; i < pickeditems.Count; i++)
{
myTarget.pickUpObjects.Add(pickeditems[i]);
var item = _serializedpickeditems.GetArrayElementAtIndex(i);
var serializedItem = new SerializedObject(item.objectReferenceValue);
serializedItem.Update();
EditorGUILayout.PropertyField(item, new GUIContent("Picked Item " + i + " " + item.name));
serializedItem.ApplyModifiedProperties();
}
pickeditems.Clear();
picked = false;
serializedObject.ApplyModifiedProperties();
}
}
private void OnEnable()
{
_serializedpickeditems = serializedObject.FindProperty("pickUpObjects");
}
}
And the mono script
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
public class PickupObjects : MonoBehaviour
{
public List<GameObject> pickUpObjects = new List<GameObject>();
}
I tried to use serialize and PropertyField but still it's showing the List with Element0,Element1,Element2.... And I want it to be :
Picked Item Box
Picked Item Can
Picked Item Cube
Picked Item Dock_Pod
Your
EditorGUILayout.PropertyField(item, new GUIContent("Picked Item " + i + " " + item.name));
sits within a code block that is only executed once.
What you see currently is actually only the list drawn by
DrawDefaultInspector();
since the rest is disappeared after 1 frame/draw call.
You would rather want to separate the pick "method" from the drawing like e.g.
public override void OnInspectorGUI()
{
serializedObject.Update();
if (picked)
{
for (var i = 0; i < pickeditems.Count; i++)
{
// NOTE: Never mix serializedProperties and direct access/modifications on the target!
// This messes up the marking dirty and saving these changes!
// Rather always go through the SerializedProperties so the editor handles everything automatically
_serializedpickeditems.arraySize++;
_serializedpickeditems.GetArrayElementAtIndex(i).objectReferenceValue = pickeditems[i];
}
picked = false;
pickeditems.Clear();
}
for (var i = 0; i < _serializedpickeditems.arraySize; i++)
{
var item = _serializedpickeditems.GetArrayElementAtIndex(i);
// little bonus from me: Color the field if the value is null ;)
var color = GUI.color;
if(!item.objectReferenceValue) GUI.color = Color.red;
{
EditorGUILayout.PropertyField(item, new GUIContent("Picked Item " + i + " " + (item.objectReferenceValue ? item.objectReferenceValue.name : "null")));
}
GUI.color = color;
// The only case you would need to go deeper here and use
// your new SerializedObject would be if you actually make changes
// to these objects/components like e.g. directly allow to edit their name
}
serializedObject.ApplyModifiedProperties();
}
Note you should also clear the pickeditems list before adding new items:
[MenuItem("GameObject/Generate as Pickup Item", false, 30)]
public static void GeneratePickupItems()
{
if (Selection.gameObjects.Length > 0)
{
pickeditems.Clear();
for (int i = 0; i < Selection.gameObjects.Length; i++)
{
if (Selection.gameObjects[i].GetComponent<Whilefun.FPEKit.FPEInteractablePickupScript>() == null)
{
Selection.gameObjects[i].AddComponent<BoxCollider>();
Selection.gameObjects[i].AddComponent<Whilefun.FPEKit.FPEInteractablePickupScript>();
}
Selection.gameObjects[i].layer = 9;
Selection.gameObjects[i].tag = "Pickup Item";
pickeditems.Add(Selection.gameObjects[i]);
}
picked = true;
}
}
In general I always recommend to use a ReorderableList!
It's a bit tricky at first to get into it but as soon as you have set it up it is an amazing tool. even if you don't make it actually reorderable it is still a huge advantage to be e.g. able to dynamically remove an item from the middle ;)
This question already has an answer here:
Unity Crashing on Play, most likely infinite While loop, but cannot locate issue
(1 answer)
Closed 5 years ago.
So I am very nooby with C#. I am currently following a tutorial to make a memory game (https://www.youtube.com/watch?v=prfzIpNhQMM).
I have followed it all and managed to fix all problems I ran into until now; every time I click play, Unity freezes. There a few comments on the videos of people having the same issues with the creator saying that its probably due to an infinite loop in the code. I do not have enough knowledge to enable me to recognise what one of those would be.
I know that the issue is with my GameManager script. If someone could take a look over it and see if they can find my issue, I would be most grateful:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.Collections;
using System.Collections.Generic;
public class GameManager : MonoBehaviour {
public Sprite[] cardFace;
public Sprite cardBack;
public GameObject[] cards;
public Text matchText;
private bool _init = false;
private int _matches = 6;
// Update is called once per frame
void Update () {
if (!_init)
initializeCards ();
if (Input.GetMouseButtonUp(0))
checkCards();
}
void initializeCards()
{
for(int id = 0; id < 2; id++)
{
for(int i = 1; i < 6; i++)
{
bool test = false;
int choice = 0;
while (!test) {
choice = Random.Range(0, cards.Length);
test = !(cards[choice].GetComponent<Card>().initialized);
}
cards[choice].GetComponent<Card>().cardValue = i;
cards[choice].GetComponent<Card>().initialized = true;
}
}
foreach (GameObject c in cards)
c.GetComponent<Card>().setupGraphics();
if (!_init)
_init = true;
}
public Sprite getCardBack()
{
return cardBack;
}
public Sprite getCardFace(int i)
{
return cardFace[i - 1];
}
void checkCards()
{
List<int> c = new List<int>();
for(int i = 0; i < cards.Length; i++)
{
if (cards[i].GetComponent<Card>().state == 1)
c.Add(i);
}
if (c.Count == 2)
cardComparison(c);
}
void cardComparison(List<int> c)
{
Card.DO_NOT = true;
int x = 0;
if(cards[c[0]].GetComponent<Card>().cardValue == cards[c[1]].GetComponent<Card> ().cardValue)
{
x = 2;
_matches--;
matchText.text = "Number of Matches: " + _matches;
if (_matches == 0)
SceneManager.LoadScene("VirusInfo3");
}
for(int i = 0; i < c.Count; i++)
{
cards[c[i]].GetComponent<Card>().state = x;
cards[c[i]].GetComponent<Card>().falseCheck();
}
}
}
Thanks!
The only code part where I think something could lead to an infinite loop in your code is the following:
while (!test) {
choice = Random.Range(0, cards.Length);
test = !(cards[choice].GetComponent<Card>().initialized);
}
The problem of this section is that, if all your cards are initialized (so initialized being equal to true), your test variable will always be equal to false. So you will end up with while(!test) being while(true) everytime, leading to the infinite loop.
Add a way to not enter this while section or to exit it if such a case happens, and you should be done.
This code is creating an inventory for an RPG game. I'm calling the item information from Items database that is a json file. For some reasons it is skipping this line. I marked it in the code to make it stand out a little more.
data.transform.GetChild(0).GetComponent<Text>().text = data.amount.ToString();
here is the entire code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Inventory : MonoBehaviour {
ItemDataBase database;
GameObject inventoryPanel;
GameObject slotPanel;
public GameObject inventorySlot;
public GameObject inventoryItem;
int slotAmount;
public List<Item> items = new List<Item>();
public List<GameObject> slots = new List<GameObject>();
private void Start()
{
database = GetComponent<ItemDataBase>();
slotAmount = 20;
inventoryPanel = GameObject.Find("Inventory Panel");
slotPanel = inventoryPanel.transform.FindChild("Slot Panel").gameObject;
for (int i = 0; i < slotAmount; i++)
{
items.Add(new Item());
// and empty slot
slots.Add(Instantiate(inventorySlot));
//set parent to slot panel
slots[i].transform.SetParent(slotPanel.transform);
}
for (int i = 0; i < items.Count; i++)
{
items[i].ID = -1;
}
AddItem(0);
AddItem(1);
AddItem(1);
Debug.Log(items[1].Title);
}
public void AddItem(int id)
{
Item itemToAdd = database.FetchItemByID(id);
if (itemToAdd.Stackable && checkIfItemIsInInventory(itemToAdd))
{
for (int i = 0; i < items.Count; i++)
{
if (items[i].ID == id)
{
ItemData data = slots[i].transform.GetChild(0).GetComponent<ItemData>();
data.amount++;
**data.transform.GetChild(0).GetComponent<Text>().text = data.amount.ToString();**
break;
}
}
}
else
{
for (int i = 0; i < items.Count; i++)
{
// in video had this set to -1
if (items[i].ID == -1)
{
items[i] = itemToAdd;
GameObject itemObj = Instantiate(inventoryItem);
itemObj.transform.SetParent(slots[i].transform);
itemObj.transform.position = Vector2.zero;
itemObj.GetComponent<Image>().sprite = itemToAdd.Sprite;
itemObj.name = itemToAdd.Title;
itemObj.name = itemToAdd.Title;
break;
}
}
}
}
bool checkIfItemIsInInventory(Item item)
{
for (int i = 0; i<items.Count; i++)
{
if (items[i].ID == item.ID)
{
return true;
}
}
return false;
}
}
Here is some debugging information. First here is the whole function it is messing up on
public void AddItem(int id)
{
Item itemToAdd = database.FetchItemByID(id);
if (itemToAdd.Stackable && checkIfItemIsInInventory(itemToAdd))
{
for (int i = 0; i < items.Count; i++)
{
if (items[i].ID == id)
{
ItemData data = slots[i].transform.GetChild(0).GetComponent<ItemData>();
data.amount++;
data.transform.GetChild(0).GetComponent<Text>().text = data.amount.ToString();
break;
}
}
}
so when I get to this line while debugging
data.amount++;
the watch says
data ---- null
data.amount ---- Could not find the member 'amount' for 'object'
amount---- the identifier 'amount'is not in the scope
so to break all of this down data is initialized here
ItemData data = slots[i].transform.GetChild(0).GetComponent();
amount is here (this is a different file called ItemData
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ItemData : MonoBehaviour {
public Item item;
public int amount;
}
thanks everyone for being helpful I really just want to learn how to code better.
Try placing a break point at the block above:
if (items[i].ID == id){
or even higher at:
if (itemToAdd.Stackable && checkIfItemIsInInventory(itemToAdd)){
Step through (using F10) and see if it's hitting the line. It's probably jumping out when one of the conditions aren't met. That, or if you need to execute this line through the entirety of the for loop, it's jumping out of the loop when it hits the line the first time because of the break; following.
Either way, step through the lines after the break point, and check the values of everything. Make sure you're not getting null references or values.