Am I Doing Something Wrong here Unity 3D - c#

I've been stuck on this script for about some weeks. I have this script where as to the items that are on a list shuffle every time a new game starts. I don't know why but I can't seem to shuffle an item list at all. Please help, and tested it for yourself if you can. Also please explain to me what might be the problem or what I can do to fix it, I'm still pretty new to this.
`using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class RayCasting : MonoBehaviour
{
public float pickupDistance;
public List<Item> items;
public List<Item> finalItems;
#region Unity
void Start ()
{
Screen.lockCursor = true;
// Do a while loop until finalItems contains 5 Items
while (finalItems.Count < 5) {
Item newItem = items[Random.Range(0, items.Count)];
if (!finalItems.Contains(newItem)) {
finalItems.Add(newItem);
}
items.Clear();
}
}
void Update ()
{
RaycastHit hit;
Ray ray = new Ray(transform.position, transform.forward);
if (Physics.Raycast(ray, out hit, pickupDistance))
{
foreach(Item item in finalItems)
{
if(Input.GetMouseButtonDown(0)) {
if (item.gameObject.Equals(hit.collider.gameObject))
{
numItemsCollected++;
item.Collect();
break;
}
}
}
}
}
void OnGUI()
{
GUILayout.BeginArea(new Rect(130,400,100,130));
{
GUILayout.BeginVertical();
{
if (numItemsCollected < items.Count)
{
foreach (Item item in finalItems)
GUILayout.Label(string.Format("[{0}] {1}", items.Collected ? "" + items.password: " ", items.name ));
}
else
{
GUILayout.Label("You Win!");
}
}
GUILayout.EndVertical();
}
GUILayout.EndArea();
}
#endregion
#region Private
private int numItemsCollected;
#endregion
}
[System.Serializable]
public class Item
{
public string name;
public GameObject gameObject;
public int password;
public bool Collected { get; private set; }
public void Collect()
{
Collected = true;
gameObject.SetActive(false);
}
public void passwordNumber()
{
password = 0;
Collected = true;
gameObject.SetActive(false);
}
}
`

This example is too complicated, and has a lot of unrelated code to the question you seem to be asking. As a basic strategy, you should try to isolate the code you think has a problem, fix that problem, then apply it to the larger case.
For example, your basic logic has at least one error: Random.Range is inclusive, so you could possibly have an out-of-bounds index unless you use "index.Count-1".
Here's an example that creates a list of 5 random items from a larger "original" list. You should be able to apply this to your code:
using UnityEngine;
using System.Collections.Generic;
public class RandomList : MonoBehaviour {
public List <int> originals = new List<int>();
public List <int> randomized = new List<int>();
public int desiredNumberOfRandomInts = 5;
// Use this for initialization
void Awake () {
for(int i = 1; i <= 20; ++i) {
originals.Add(i);
}
while(randomized.Count < desiredNumberOfRandomInts) {
int randomSelection = originals[Random.Range(0, originals.Count-1)];
if (!randomized.Contains(randomSelection)) {
randomized.Add(randomSelection);
}
}
}
}

I think removing the items.Clear() might work, with the reason I explained in my comment.
while (finalItems.Count < 5) {
Item newItem = items[Random.Range(0, items.Count)];
if (!finalItems.Contains(newItem)) {
finalItems.Add(newItem);
}
}
But still, I'm assuming you already have list of items somewhere already (and the list must be >5 since you will loop minimum 5 times). If you don't items.Count will still stay 0, and making your random become Random.Range(0,0).

Related

Problems with C # Lists - RemoveAt

I am practicing with C # Lists in Unity and I have encountered a problem.
My test script, instantiates 5 prefabs which are added in a gameobject list. I then wrote a code that generates a random int and from that number moves the prefab instantiated with that index (indexof). Everything works correctly, but the method that moves and deletes the prefab is repeated for all the gameobjects in the scene with an index higher than the one chosen. I enclose the two scripts to better explain the problem. (I would need the unlist method to be done only once.
how can i solve this problem and remove one item from the list at a time? (one each time the button is pressed, not all as it is now. Thanks)
script:
NpcController: Added in each instantiated prefab
ListCOntroller: added in the scene.
public class ListCOntroller : MonoBehaviour
{
public GameObject cubePrefab;
private GameObject cubeInstance;
public static List<GameObject> cubeList = new List<GameObject> ();
public TextMeshProUGUI checkText;
public static event Action chooseNpc;
public static int randNpcValue;
int rand;
private void Start()
{
for(int i =0; i < 5; i++)
{
cubeInstance = Instantiate(cubePrefab, new Vector3(i, -2, 0), Quaternion.identity);
cubeList.Add(cubeInstance);
}
}
public void CheckListText()
{
checkText.text = "Npc in list: " + cubeList.Count.ToString();
}
public static void SelectRandomCube()
{
randNpcValue = Random.Range(0, cubeList.Count);
chooseNpc?.Invoke();
}
}
public class NpcController : MonoBehaviour
{
void Start()
{
ListCOntroller.chooseNpc += NpcEvent;
}
private void NpcEvent()
{
if (ListCOntroller.cubeList.IndexOf(gameObject) == ListCOntroller.randNpcValue)
{
transform.localPosition = new Vector3(transform.position.x, 2, 0);
DeleteFromList();
}
}
private void DeleteFromList()
{
ListCOntroller.cubeList.RemoveAt(ListCOntroller.randNpcValue);
Debug.Log($"Delete from list: {ListCOntroller.randNpcValue}");
}
}
the int random number generated in the attached images is: 2
Because events are executed one after another.
Let's say you have 3 NPCs: NPC0, NPC1, NPC2
Now the random number you choosen is 1, when NPC1's NpcEvent runs, ListCOntroller.cubeList.IndexOf(gameObject) is 1 which equals to the randNpcValue, and then NPC1 will be removed from the list.
Note that now the list has 2 items left: NPC0, NPC2. Next NPC2's NpcEvent runs in turn, at this time, ListCOntroller.cubeList.IndexOf(gameObject) is still 1 because the list has only 2 items, so NPC2 is also removed from the list.
A solution is you can change the randNpcValue to an invalid value when a NPC is removed.
if (ListCOntroller.cubeList.IndexOf(gameObject) == ListCOntroller.randNpcValue)
{
transform.localPosition = new Vector3(transform.position.x, 2, 0);
DeleteFromList();
ListCOntroller.randNpcValue = -2;
}
In addition to this answer in general I don't really see the purpose mixing the the logic into two different scripts.
You have one for storing a list and raising an event and the other one listens to the event and manipulates the stored list -> This doesn't sounds right.
You could as well simply do `why don't you pass a long the the according object into the event in the first place and rather do something like
public class ListCOntroller : MonoBehaviour
{
// Singleton instance
private static ListCOntroller _instance;
// Read-only getter
public static ListCOntroller Instance => _instance;
// pass in the target object reference instead of doing things index based
public event Action<GameObject> chooseNpc;
public GameObject cubePrefab;
// THIS is the list controller -> nobody else should be able to manipulate this list
private readonly List<GameObject> cubeList = new ();
public TextMeshProUGUI checkText;
private void Awake()
{
if(_instance && _instance != this)
{
Destroy(this);
return;
}
_instance = this;
}
private void Start()
{
for(int i =0; i < 5; i++)
{
cubeInstance = Instantiate(cubePrefab, new Vector3(i, -2, 0), Quaternion.identity);
cubeList.Add(cubeInstance);
}
}
public static void SelectRandomCube()
{
if(cubeList.Count == 0)
{
Debug.LogWarning("Trying to pick item from empty list");
return;
}
var randomIndex = Random.Range(0, cubeList.Count);
var randomItem = cubeList[randomIndex];
// remove from the list yourself instead of relying on others to work correctly
cubeList.RemoveAt(randomIndex);
// pass along the target object
chooseNpc?.Invoke(randomItem);
}
}
and then
public class NpcController : MonoBehaviour
{
void Start()
{
ListCOntroller.Instance.chooseNpc += NpcEvent;
}
private void NpcEvent(GameObject target)
{
// check if you are the target object
if (target == gameObject))
{
// adjust your position - you don't care about other NPCs or the existence of a list
transform.localPosition = new Vector3(transform.position.x, 2, 0);
}
}
}

Unity android. Loading Function after killing an app doesn't work properly (Object Reference not set to an instance of an object)

I am at begginner level with unity.
I have Load() function that goes off in OnApplicationPause(false). It works fine if I block the screen or minimalise app, and come back to it. However, when I kill it, I get error and the data doesnt get loaded.
Below is the script attached to the GameObject "SaveManager"
using System.Collections.Generic;
using UnityEngine;
using System;
public class SaveManager : MonoBehaviour
{
public GameObject ZwierzetaGroup;
public GameObject JedzeniaGroup;
public GameObject PrzedmiotyGroup;
public List<GameObject> zwierzeta_sprites;
public List<GameObject> jedzenia_sprites;
public List<GameObject> przedmioty_sprites;
public static DateTime oldDate;
Camera mainCamera;
public SaveState saveState;
void Start()
{
mainCamera = Camera.main;
FillArrays();
}
public void Save()
{
Debug.Log("Saving.");
SaveSpriteArray("zwierze", zwierzeta_sprites);
SaveSpriteArray("przedmiot", przedmioty_sprites);
SaveSpriteArray("jedzenie", jedzenia_sprites);
PlayerPrefs.SetInt("pieniazki", saveState.GetPieniazki());
PlayerPrefs.SetInt("HayAmount", saveState.GetHayAmount());
PlayerPrefs.SetInt("HayMax", saveState.GetHayMax());
PlayerPrefs.SetInt("FruitAmount", saveState.GetFruitAmount());
PlayerPrefs.SetInt("FruitMax", saveState.GetFruitMax());
//time:
PlayerPrefs.SetString("sysString", System.DateTime.Now.ToBinary().ToString());
PlayerPrefs.SetInt("First", 1);
}
public void SaveSpriteArray(string saveName, List<GameObject> sprites)
{
for (int i = 0; i < sprites.Count; i++)
{
if (sprites[i].activeSelf)
{
PlayerPrefs.SetInt(saveName + i, 1);
}
else
{
PlayerPrefs.SetInt(saveName + i, 0);
}
}
}
public void Load()
{
Debug.Log("Loading.");
//wczytanie czasu:
long temp = Convert.ToInt64(PlayerPrefs.GetString("sysString"));
oldDate = DateTime.FromBinary(temp);
Debug.Log("oldDate: " + oldDate);
//wczytywanie aktywnych sprite'ow
LoadSpriteArray("zwierze", zwierzeta_sprites);
LoadSpriteArray("przedmiot", przedmioty_sprites);
LoadSpriteArray("jedzenie", jedzenia_sprites);
saveState.SetPieniazki(PlayerPrefs.GetInt("pieniazki"));
saveState.SetHayAmount(PlayerPrefs.GetInt("HayAmount"));
saveState.SetHayMax(PlayerPrefs.GetInt("HayMax"));
saveState.SetFruitAmount(PlayerPrefs.GetInt("FruitAmount"));
saveState.SetFruitMax(PlayerPrefs.GetInt("FruitMax"));
mainCamera.GetComponent<UpdateMoney>().MoneyUpdate();
}
public void LoadSpriteArray(string saveName, List<GameObject> sprites)
{
for (int i = 0; i < sprites.Count; i++)
{
if (PlayerPrefs.GetInt(saveName + i) == 1)
{
sprites[i].SetActive(true);
}
else
{
sprites[i].SetActive(false);
}
}
}
private void FillArrays()
{
//find children
foreach (Transform child in ZwierzetaGroup.transform)
{
zwierzeta_sprites.Add(child.gameObject);
}
foreach (Transform child in PrzedmiotyGroup.transform)
{
przedmioty_sprites.Add(child.gameObject);
}
foreach (Transform child in JedzeniaGroup.transform)
{
jedzenia_sprites.Add(child.gameObject);
}
}
}
Below is a chunk of script attached to the main camera (probably a mistake). SaveManager GameObject with Script is attached to this one in inspector. This script is pretty big, so I'll skip the parts that I don't find relevant.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class ManageEncouters: MonoBehaviour
{
DateTime currentDate;
public int First;
public SaveState saveState;
public SaveManager saveManager;
public HayBar hayBar;
public FruitBar fruitBar;
public GameObject[] jedzenia_sprites;
void Start()
{
}
void OnApplicationPause(bool pauseStatus)
{
if (!pauseStatus)
{
currentDate = System.DateTime.Now;
//Sprawdzanie czy jest to piersze uruchomienie gry (brak zapisu)
First = PlayerPrefs.GetInt("First");
if (First == 0)
{
Debug.Log("First time in app.");
RandomiseAnimals();
SaveManager.oldDate = currentDate;
hayBar.SetHayMax(1);
hayBar.SetHay(0);
fruitBar.SetFruitMax(1);
fruitBar.SetFruit(0);
saveState.SetPieniazki(100);
this.GetComponent<UpdateMoney>().MoneyUpdate();
}
else
{
Debug.Log("Not the first time in app.");
saveManager.Load();
}
if (TimeInSeconds(currentDate, SaveManager.oldDate) > 12)
{
Debug.Log("It's been more than 12 seconds sience last time.");
EatFood(currentDate, SaveManager.oldDate);
RandomiseAnimals();
}
else
{
Debug.Log("It's been less than 12 seconds sience last time.");
}
}
if (pauseStatus)
{
saveManager.Save();
}
}
private int TimeInSeconds(DateTime newD, DateTime oldD)
{
TimeSpan difference = newD.Subtract(oldD);
int seconds = (int)difference.TotalSeconds;
return seconds;
}
}
Below is the error I get, I don't know how to copy the text, so it's an Image.
I'm pretty sure that what you have here is a timing issue.
OnApplicationPause
Note: MonoBehaviour.OnApplicationPause is called as a GameObject starts. The call is made after Awake. Each GameObject will cause this call to be made.
So to me this sounds like it might be called when your SaveManager is not yet initialized, in particular the mainCamera.
I think you could already solve the issue by moving the initialization into Awake instead
private void Awake()
{
mainCamera = Camera.main;
FillArrays();
}
In general my little thumb rule is
use Awake wherever possible. In particular initialize everything where you don't depend on other scripts (initialize fields, use GetComponent, etc)
use Start when you need other scripts to be initialized already (call methods on other components, collect and pass on instances of some prefabs spawned in Awake, etc)
This covers most of cases. Where this isn't enough you would need to bother with the execution order or use events.

Implement stacking to my inventory system in Unity

I'm currently working on a game, and now I've just finished the inventory system, which is highly inspired by the one Brackeys made a while back. Right now the player can pick up items, which will go into the inventory's list and be displayed on some UI. After having finished this, I tried to make items stack together, however I was never able to find a working solution. I don't want anything fancy, I just want every item to be able to stack infinitely. If anyone could help me out I'd greatly appreciate it!
Sorry for putting so much code in here, I'm not sure what I should and shouldn't add.
My "Items" script:
using UnityEngine;
[CreateAssetMenu(fileName = "New item", menuName = "Inventory/Items")]
public class Item : ScriptableObject
{
new public string name = "New item";
public Sprite icon = null;
public bool itemDefaut = false;
public virtual void Use()
{
Debug.Log("Using " + name);
}
}
My "Inventory" script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
#region Singleton
public static Inventory instance;
void Awake()
{
if (instance != null)
{
Debug.LogWarning("More than one inventory instance found!");
return;
}
instance = this;
}
#endregion
public delegate void OnItemChanged();
public OnItemChanged onItemChangedCallback;
public List<Item> items = new List<Item>();
public void Add(Item item)
{
items.Add(item);
if (onItemChangedCallback != null)
{
onItemChangedCallback.Invoke();
}
}
public void Remove(Item item)
{
items.Remove(item);
if (onItemChangedCallback != null)
{
onItemChangedCallback.Invoke();
}
}
}
My "InventorySlot" script:
using UnityEngine;
using UnityEngine.UI;
public class InventorySlot : MonoBehaviour
{
Item item;
public Image icon;
public void AddItem(Item newItem)
{
item = newItem;
icon.sprite = item.icon;
icon.enabled = true;
}
public void RemoveItem()
{
item = null;
icon.sprite = null;
icon.enabled = false;
}
public void UseItem()
{
if (item != null)
{
item.Use();
}
}
}
My "InventoryUI" script:
using UnityEngine;
public class InventoryUI : MonoBehaviour
{
public Transform itemsParent;
public GameObject inventoryUI;
Inventory inventory;
InventorySlot[] slots;
// Start is called before the first frame update
void Start()
{
inventory = Inventory.instance;
inventory.onItemChangedCallback += UpdateUI;
slots = itemsParent.GetComponentsInChildren<InventorySlot>();
}
// Update is called once per frame
void Update()
{
if (Input.GetButtonDown("Inventory"))
{
inventoryUI.SetActive(!inventoryUI.activeSelf);
}
if (inventoryUI.activeSelf)
{
Time.timeScale = 0;
}
else
{
Time.timeScale = 1;
}
}
void UpdateUI()
{
for (int i = 0; i < slots.Length; i++)
{
if (i < inventory.items.Count)
{
slots[i].AddItem(inventory.items[i]);
}
else
{
slots[i].RemoveItem();
}
}
}
}
My "ItemPickup" script:
using UnityEngine;
public class ItemPickup : Interactable
{
public Item item;
public override void Interact()
{
base.Interact();
PickUp();
}
void PickUp()
{
Debug.Log("Picking up " + item.name);
Inventory.instance.Add(item);
Destroy(gameObject);
}
}
And my "Interactable" script:
using UnityEngine;
public class Interactable : MonoBehaviour
{
public float radius = 3f;
[SerializeField] Player player;
bool interacted = false;
void Start()
{
interacted = false;
}
public virtual void Interact()
{
//This method is meant to be overwritten
Debug.Log("Interacting with " + transform.name);
}
void Update()
{
if (!interacted)
{
float distance = Vector3.Distance(player.transform.position, transform.position);
if (distance <= radius)
{
Interact();
interacted = true;
}
}
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(transform.position, radius);
}
}
Finally, here's what my hierarchy looks like for my inventory (just replace "inventaire" by "inventory" and don't mind the item names):
If I understand you correctly it sounds like you basically want a counter for the slot so you can add multiple of the Item instance.
You could probably do something like
public class InventorySlot : MonoBehaviour
{
// Have a counter for the amount of items added
int _amount;
Item item;
public Image icon;
public Text amountText;
// optionally add an amount parameter
// if not passed 1 is used but allows to add multiple at once
public void AddItem(Item newItem, int amount = 1)
{
// If there is no item yet
// then simply add the first one
if(!item)
{
item = newItem;
icon.sprite = item.icon;
icon.enabled = true;
_amount = amount;
}
else
{
// Otherwise check first if it is the same item
if(item != newItem)
{
Debug.LogWarning($"Type mismatch between current item {item} and added item {newItem}!", this);
// TODO handle this?
return;
}
// simply increase the amount
_amount += amount;
}
// update text
amountText.text = _amount.ToString();
}
// Again maybe add optional parameter
// if nothing is passed 1 is used
// but allows to remove multiple at once
public void RemoveItem(int amount = 1)
{
// check if enough
if(!item)
{
Debug.LogWarning("This slot is empty! Can't remove", this);
// TODO handle this?
return;
}
if(_amount - amount < 0)
{
Debug.LogWarning($"Not enough items in this slot to remove {amount}!", this);
}
// simply reduce the amount
_amount -= amount;
// update the text
_amountText.text = amount.ToString();
// Only if you reached 0 -> removed the last item
// reset this slot
if(amount == 0)
{
item = null;
icon.sprite = null;
icon.enabled = false;
}
}
public void UseItem()
{
if (item)
{
item.Use();
// TODO also remove one?
}
}
}

How to add all MonoBehaviours of Scene into the List?

I've read an article 10000 UPDATE() CALLS.
Author uses UpdateManager. It has Update method which calls Update method in all of other MonoBehaviours of objects. It works faster than calling Update method from each MonoBehaviour separately.
This Manager looks like:
private ManagedUpdateBehavior[] list;
private void Start() {
list = GetComponents<ManagedUpdateBehavior>();
}
private void Update() {
var count = list.Length;
for (var i = 0; i < count; i++) {
// UpdateMe
list[i].UpdateMe();
}
}
And every objects now contains component with the code:
public class ManagedUpdateBehavior : MonoBehaviour {
// some variables
public void UpdateMe() {
// some logic
}
}
It's okay if 5-6-7-8- objects will be have that component.
But what if I have 100 objects? 1000? 10000?
How to find and add all ManagedUpdateBehaviors from all objects of scene? Should I use some recursive method on On Start? Cause every object may contain other objects with the script, they may contain the other objects etc...unlimited nesting
Also some objects can be instantiating dynamically...How to add their mono to manager? What is the right way?
Also some objects can be instantiating dynamically
Let each ManagedUpdateBehavior subscribe to the ManagedUpdateBehavior list by adding its instance to the ManagedUpdateBehavior instance. They should also unsubscribe from the ManagedUpdateBehavior when destroyed by removing itself from the ManagedUpdateBehavior instance.
Your new ManagedUpdateBehavior script:
public class ManagedUpdateBehavior : MonoBehaviour
{
UpdateSubscriber updateSUBSCR;
//Add it self to the List
void Start()
{
updateSUBSCR = GameObject.Find("UpdateSUBSCR").GetComponent<UpdateSubscriber>();
updateSUBSCR.addManagedUpdateBehavior(this);
}
//Remove it self from the List
void OnDestroy()
{
updateSUBSCR.removeManagedUpdateBehavior(this);
}
public void UpdateMe()
{
// some logic
Debug.Log("Update from: " + gameObject.name);
}
}
Create a GameObject called UpdateSUBSCR and attach the Script below to it:
public class UpdateSubscriber : MonoBehaviour
{
private List<ManagedUpdateBehavior> managedUpdateBehavior = new List<ManagedUpdateBehavior>();
public void addManagedUpdateBehavior(ManagedUpdateBehavior managedUB)
{
managedUpdateBehavior.Add(managedUB);
}
public void removeManagedUpdateBehavior(ManagedUpdateBehavior managedUB)
{
for (int i = 0; i < managedUpdateBehavior.Count; i++)
{
if (managedUpdateBehavior[i] == managedUB)
{
managedUpdateBehavior.RemoveAt(i);
break;
}
}
}
/*
public List<ManagedUpdateBehavior> getManagedUpdateBehaviorinstance
{
get
{
return managedUpdateBehavior;
}
}*/
public void updateAll()
{
for (int i = 0; i < managedUpdateBehavior.Count; i++)
{
managedUpdateBehavior[i].UpdateMe();
}
}
}
Then you can call it with:
public class Test : MonoBehaviour
{
UpdateSubscriber updateSUBSCR;
void Start()
{
updateSUBSCR = GameObject.Find("UpdateSUBSCR").GetComponent<UpdateSubscriber>();
}
void Update()
{
updateSUBSCR.callUpdateFuncs();
}
}
Be aware that array is faster than List but this is better than the having the Update() function in every script.
You can find and add all ManagedUpdateBehaviours using Object.FindObjectsOfType method.
You can add your dynamically instantiate objects using a static method that can be called from created game object to add it to list.
My suggestion is created a SceneUpdateManager, something like this:
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
public class SceneUpdateManager : MonoBehaviour {
private static List<ManagedUpdateBehavior> list;
private void Start ()
{
list = Object.FindObjectsOfType<ManagedUpdateBehavior> ().ToList ();
}
public static void AddBehavior(ManagedUpdateBehavior behaviour)
{
list.Add (behaviour);
}
private void Update () {
var count = list.Count;
for (var i = 0; i < count; i++)
{
list [i].UpdateMe();
}
}
}
Object.FindObjectsOfType does not return inactive objects.

Shuffling Items in Unity 3D

I have this script of an array that shows a listing of items.
Now the thing is I only want this list to have five items shown out of ten and also shuffled, so you can't have the same list every time you start a new game
I was thinking if there should be a Random.Range implemented but I don't know where.
Please Help, and explain what should be done. I'm still a bit new to this and Thanks.
Here's the script:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class RayCasting : MonoBehaviour
{
public float pickupDistance;
public List<Item> items;
#region Unity
void Start ()
{
Screen.lockCursor = true;
}
void Update ()
{
RaycastHit hit;
Ray ray = new Ray(transform.position, transform.forward);
if (Physics.Raycast(ray, out hit, pickupDistance))
{
foreach(Item item in items)
{
if(Input.GetMouseButtonDown(0))
{
if (item.gameObject.Equals(hit.collider.gameObject))
{
numItemsCollected++;
item.Collect();
break;
}
}
}
}
}
void OnGUI()
{
GUILayout.BeginArea(new Rect(130,400,100,100));
{
GUILayout.BeginVertical();
{
if (numItemsCollected < items.Count)
{
foreach (Item item in items)
{
GUILayout.Label(string.Format("[{0}] {1}", item.Collected ? "" + item.password: " ", item.name ));
}
}
else
{
GUILayout.Label("You Win!");
}
}
GUILayout.EndVertical();
}
GUILayout.EndArea();
}
#endregion
#region Private
private int numItemsCollected;
#endregion
}
[System.Serializable]
public class Item
{
public string name;
public GameObject gameObject;
public int password;
public bool Collected { get; private set; }
public void Collect()
{
Collected = true;
gameObject.SetActive(false);
}
public void passwordNumber()
{
password = 0;
Collected = true;
gameObject.SetActive(false);
}
}
I assume you'll want to leave items intact without removing any Items, so I'd suggest creating a second List called finalItems, which will contain your 5 random Items.
public List<Item> items;
public List<Item> finalItems;
#region Unity
void Start ()
{
Screen.lockCursor = true;
// Do a while loop until finalItems contains 5 Items
while (finalItems.Count < 5) {
Item newItem = items[Random.Range(0, items.Count)];
if (!finalItems.Contains(newItem)) {
finalItems.Add(newItem);
}
}
}
And then in your foreach statements, loop through finalItems instead of items.
This will give you 5 random Items every game!

Categories