How to fix inventory error in unity 2021.3.13f1 - c#

EDITED MORE SCRIPTS SHOWN!
I'm making an inventory system from This YouTube Video and I can't seem to get it to work.
the error1:
Assets\Scripts\InventoryScripts\InventorySystem.cs(31,33): error CS1579: foreach statement cannot operate on variables of type 'InventorySlot' because 'InventorySlot' does not contain a public instance or extension definition for 'GetEnumerator'
The error2:
Assets\Scripts\InventoryScripts\InventorySystem.cs(55,19): error CS0029: Cannot implicitly convert type 'System.Collections.Generic.List' to 'InventorySlot'
And my code:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Events;
[System.Serializable]
public class InventorySystem
{
[SerializeField] private List<InventorySlot> inventorySlots;
public int InventorySize => InventorySlots.Count;
public List<InventorySlot> InventorySlots => inventorySlots;
public UnityAction<InventorySlot> OnInventorySlotChanged;
public InventorySystem(int size)
{
inventorySlots = new List<InventorySlot>(size);
for(int i = 0; i < size; i++)
{
inventorySlots.Add(new InventorySlot());
}
}
public bool AddToInventory(InventoryItemData itemToAdd, int amountToAdd)
{
if(ContainsItem(itemToAdd, out InventorySlot invSlot))
{
foreach(var slot in invSlot)
{
if(slot.RoomLeftInStack(amountToAdd))
{
slot.AddToStack(amountToAdd);
OnInventorySlotChanged?.Invoke(invSlot);
return true;
}
}
}
if(HasFreeSlot(out InventorySlot freeSlot))
{
freeSlot.UpdateInvSlot(itemToAdd, amountToAdd);
OnInventorySlotChanged?.Invoke(freeSlot);
return true;
}
return false;
}
public bool ContainsItem(InventoryItemData itemToAdd, out InventorySlot invSlot)
{
invSlot = InventorySlots.Where(i => i.ItemData == itemToAdd).ToList();
return invSlot == null ? false : true;
}
public bool HasFreeSlot(out InventorySlot freeSlot)
{
freeSlot = InventorySlots.FirstOrDefault(i => i.ItemData == null);
return freeSlot == null ? false : true;
}
}
Holder script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
[System.Serializable]
public class InventoryHolder : MonoBehaviour
{
[SerializeField] private int inventorySize;
[SerializeField] protected InventorySystem inventorySystem;
public InventorySystem InventorySystem => inventorySystem;
public static UnityAction<InventorySystem> OnDynamicInventoryDisplayRequested;
private void Awake()
{
inventorySystem = new InventorySystem(inventorySize);
}
}
Slot Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class InventorySlot
{
[SerializeField] private InventoryItemData itemData;
[SerializeField] private int stackSize;
public InventoryItemData ItemData => itemData;
public int StackSize => stackSize;
public InventorySlot(InventoryItemData source, int amount)
{
itemData = source;
stackSize = amount;
}
public InventorySlot()
{
ClearSlot();
}
public bool RoomLeftInStack(int amountToAdd, out int amountRemaining)
{
amountRemaining = ItemData.maxStackSize - stackSize;
return RoomLeftInStack(amountToAdd);
}
public bool RoomLeftInStack(int amountToAdd)
{
if(stackSize + amountToAdd <= itemData.maxStackSize) return true;
else return false;
}
public void ClearSlot()
{
itemData = null;
stackSize = -1;
}
public void UpdateInvSlot(InventoryItemData data, int amount)
{
itemData = data;
stackSize = amount;
}
public void AddToStack(int amount)
{
stackSize += amount;
}
public void RemoveFromStack(int amount)
{
stackSize -= amount;
}
}
I'm just trying to remove these errors so I can test it.

The Where method of the List class returns a List rather than a single InventorySlot object.
You can rewrite the function 'ContainsItem' like this:
public bool ContainsItem(InventoryItemData itemToAdd, out InventorySlot invSlot)
{
invSlot = InventorySlots.FirstOrDefault(i => i.ItemData == itemToAdd);
return invSlot == null ? false : true;
}

Related

Unity 2d İ had some error ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection

Hello guys I'm newbie in unity and c# i was trying make little game but i have a an error i cant fix that can you help me? and whats wrong? you explain so I can learn? I'm making a mistake somewhere but I don't understand where...
I also looked at the friends who got the same error in the forums, but I could not find the relevance of what was said with my code.I also made these codes with the things I learned on youtube, so if there are mistakes, please excuse me
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine.UI;
public class LobbyNetworkManager : MonoBehaviourPunCallbacks
{
int number;
public Text su;
private List<RoomItemUI> _roomList = new List<RoomItemUI>();
[SerializeField] private RoomItemUI _roomItemUIPrefab;
[SerializeField] private Transform _roomListParent;
[SerializeField] private Text _statusField;
[SerializeField] private Button _leaveRoomButton;
private void Start()
{
Initialize();
Connect();
}
#region PhotonCallbacks
public override void OnConnectedToMaster()
{
Debug.Log("Connected to master server");
PhotonNetwork.JoinLobby();
}
public override void OnRoomListUpdate(List<RoomInfo> roomList)
{
UpdateRoomList(roomList);
}
public override void OnDisconnected(DisconnectCause cause)
{
Debug.Log("Disconnect");
}
public override void OnJoinedLobby()
{
Debug.Log("Joined Lobby!");
}
public override void OnJoinedRoom()
{
_statusField.text = "Joined" + PhotonNetwork.CurrentRoom.Name;
Debug.Log("Joined Room " + PhotonNetwork.CurrentRoom.Name);
_leaveRoomButton.interactable = true;
}
public override void OnLeftRoom()
{
_statusField.text = "Lobby";
Debug.Log("Left Room");
_leaveRoomButton.interactable = false;
}
#endregion
private void Initialize()
{
_leaveRoomButton.interactable = false;
}
private void Connect()
{
PhotonNetwork.NickName = "Player" + Random.Range(0, 5000);
PhotonNetwork.ConnectUsingSettings();
PhotonNetwork.AutomaticallySyncScene = true;
}
private void UpdateRoomList(List<RoomInfo> roomList)
{
//clear current list of room
for (int i = 0; i < roomList.Count; i++)
{
Destroy(_roomList[i].gameObject);
}
_roomList.Clear();
//Generate a new list with the updated info
for(int i = 0; i < roomList.Count; i++)
{
//skip empty rooms
if(roomList[i].PlayerCount == 0) { continue; }
RoomItemUI newRoomItem = Instantiate(_roomItemUIPrefab);
newRoomItem.LobbyNetworkParent = this;
newRoomItem.SetName(roomList[i].Name);
newRoomItem.transform.SetParent(_roomListParent);
_roomList.Add(newRoomItem);
}
}
public void JoinRoom(string roomName)
{
PhotonNetwork.JoinRoom(roomName);
}
public void CreateRoom()
{
number = Random.Range(1000000, 9999999);
PhotonNetwork.CreateRoom(su.text + number, new RoomOptions() { MaxPlayers = 4 }, null);
}
public void LeaveRoom()
{
PhotonNetwork.LeaveRoom();
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
public class RoomItemUI : MonoBehaviour
{
public LobbyNetworkManager LobbyNetworkParent;
[SerializeField] private Text _roomName;
public void SetName(string roomName)
{
_roomName.text = roomName;
}
public void OnJoinPressed()
{
LobbyNetworkParent.JoinRoom(_roomName.text);
}
}

Unity3D [SerializeField] Menu Array not showing

So I'm following Rugbug Redfern's tutorial on how to make Photon multiplayer but the Menu SerializeField array isn't showing. Please help.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MenuManager : MonoBehaviour
{
public static MenuManager Instance;
[SerializeField] Menu[] menus;
void Awake()
{
Instance = this;
}
public void OpenMenu(string menuName)
{
for(int i = 0; i < menus.Length; i++)
{
if(menus[i].menuName == menuName)
{
menus[i].Open();
}
else if(menus[i].open)
{
CloseMenu(menus[i]);
}
}
}
public void OpenMenu(Menu menu)
{
for(int i = 0; i < menus.Length; i++)
{
if(menus[i].open)
{
CloseMenu(menus[i]);
}
}
menu.Open();
}
public void CloseMenu(Menu menu)
{
menu.Close();
}
}

Value correctly initializes, but breaks when updating

I'm a beginner learning C# and Unity and I'm following this tutorial, https://www.youtube.com/watch?v=5U5TiW21Inw because I did some scripting beforehand and it had already been getting a bit messy I decided to start over and found this which doesn't declare valuables in a long page like I was doing prior, instead it creates a valuable tool. I'm finished with episode 2 (https://www.youtube.com/watch?v=gj5LfqwGvgA) and everything but my recalculator seems to be working. When I play the scene the HP Formula makes the HP UI correctly displays 75 so I know it's sending and storing values correctly but when I press X which in Episode 1 we set up to increase testValueReference (Which later is switched to Strength) by 1, which it does. The problem is that as soon as I press X the HP value zeroes (nulls?).
The program so far consists of nine scripts in total and as the value initializes correctly I know it it's not in Formula.cs, HPFormula.cs, Value.cs, TextCharacterValue.cs, ValueFloat.cs, ValueInt.cs, or ValueStructure.cs. Mostly because these are short scripts that are easily copied when they appear in full and none of them use the recalculator function. The only two scripts that use the recalculator are Character.cs and ValueReference.cs.
Formula.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class Formula : ScriptableObject
{
public abstract List<Value> GetReferences();
}
public abstract class FormulaInt : Formula
{
public abstract int Calculate(StatsContainer stats);
}
public abstract class FormulaFloat: Formula
{
public abstract float Calculate(StatsContainer stats);
}
HPFormula.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(menuName = "Formula/HP")]
public class HPFormula : FormulaInt
{
// Health Formula below
public Value vitality;
int vit;
public Value strength;
int str;
public override int Calculate(StatsContainer stats)
{
stats.Get(vitality, out vit);
stats.Get(strength, out str);
return vit * 6 + str * 2 + 30; // Placeholder Formula
}
public override List<Value> GetReferences()
{
List<Value> values = new List<Value>();
values.Add(vitality);
values.Add(strength);
return values;
}
}
TextCharacterValue.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TextCharacterValue : MonoBehaviour
{
public Value trackValue;
public Character character;
void UpdateText()
{
string str = character.statsContainer.GetText(trackValue);
GetComponent<Text>().text = str;
}
// Start is called before the first frame update
void Start()
{
character.statsContainer.Subscribe(UpdateText, trackValue);
UpdateText();
}
}
Value.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Value : ScriptableObject
{
public string Name;
public Formula formula;
}
ValueInt.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
[CreateAssetMenu(menuName = "Value/Int")]
public class ValueInt : Value
{
}
ValueFloat.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
[CreateAssetMenu(menuName = "Value/Float")]
public class ValueFloat : Value
{
}
ValueStructure.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
[CreateAssetMenu(menuName = "Value/Structure")]
public class ValueStructure : ScriptableObject
{
public List<Value> values;
}
ValueReference.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public abstract class ValueReference
{
public Value valueBase;
public Action onChange;
public Action<Value> recalculate;
public List<Value> dependent;
public void RecalculateDependencies()
{
if (dependent != null)
{
foreach(Value v in dependent)
{
recalculate?.Invoke(v);
}
}
}
public virtual string TEXT { get; internal set; }
public abstract void Null();
public class ValueFloatReference : ValueReference
{
public float value;
public ValueFloatReference(Value _valueBase, float _value = 0)
{
valueBase = _valueBase;
value = _value;
}
internal void Sum(float sum)
{
value += sum;
onChange?.Invoke();
base.RecalculateDependencies();
}
public override void Null()
{
value = 0f;
onChange?.Invoke();
base.RecalculateDependencies();
}
public override string TEXT
{
get
{
return valueBase.Name + " " + value.ToString();
}
}
}
public class ValueIntReference : ValueReference
{
public int value;
public ValueIntReference(Value _valueBase, int _value = 0)
{
valueBase = _valueBase;
value = _value;
}
internal void Sum(int sum)
{
value += sum;
onChange?.Invoke();
base.RecalculateDependencies();
}
public override void Null()
{
value = 0;
onChange?.Invoke();
base.RecalculateDependencies();
}
public override string TEXT
{
get
{
return valueBase.Name + " " + value.ToString();
}
}
}
}
All seems fine on this end, so I assume the problem lies in Character.cs.
Character.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using static ValueReference;
public class StatsContainer
{
public List<ValueReference> valueList;
public StatsContainer()
{
valueList = new List<ValueReference>();
}
internal string GetText(Value value)
{
ValueReference valueReference = valueList.Find(x => x.valueBase == value);
return valueReference.TEXT;
}
public void Sum(Value value, int sum)
{
ValueReference valueReference = valueList.Find(x => x.valueBase == value);
if (valueReference != null)
{
ValueIntReference reference = (ValueIntReference)valueReference;
reference.Sum(sum);
}
else
{
Add(value, sum);
}
}
private void Add(Value value, float sum)
{
valueList.Add(new ValueFloatReference(value, sum));
}
private void Add(Value value, int sum)
{
valueList.Add(new ValueIntReference(value, sum));
}
public void Get(Value value, out int state)
{
ValueReference valueReference = valueList.Find(x => x.valueBase == value);
ValueIntReference valueInt = (ValueIntReference)valueReference;
if (valueInt == null)
{
state = 0;
}
else
{
state = valueInt.value;
}
}
public void Get(Value value, out float state)
{
ValueReference valueReference = valueList.Find(x => x.valueBase == value);
ValueFloatReference valueFloat = (ValueFloatReference)valueReference;
if (valueFloat == null)
{
state = 0;
}
else
{
state = valueFloat.value;
}
}
public ValueReference GetValueReference(Value value)
{
return valueList.Find(x => x.valueBase == value);
}
public void Subscribe(Action action, Value value)
{
ValueReference valueReference = valueList.Find(x => x.valueBase == value);
valueReference.onChange += action;
}
public void Subscribe(Action<Value> action, Value dependency, Value subscribeTo)
{
ValueReference valueReference = valueList.Find(x => x.valueBase == subscribeTo);
if (valueReference.recalculate == null)
{
valueReference.recalculate = action;
}
if (valueReference.dependent == null)
{
valueReference.dependent = new List<Value>();
}
valueReference.dependent.Add(dependency);
}
public void Sum(Value value, float sum)
{
ValueReference valueReference = valueList.Find(x => x.valueBase == value);
if (valueReference != null)
{
ValueFloatReference reference = (ValueFloatReference)valueReference;
reference.Sum(sum);
}
else
{
Add(value, sum);
}
}
}
public class Character : MonoBehaviour
{
public ValueStructure statsStructure;
public StatsContainer statsContainer;
// Start is called before the first frame update
void Start()
{
Init();
}
void Init()
{
InitValues();
InitFormulas();
}
private void InitValues()
{
statsContainer = new StatsContainer();
for (int i = 0; i < statsStructure.values.Count; i++)
{
Value value = statsStructure.values[i];
if (value is ValueFloat)
{
statsContainer.valueList.Add(new ValueFloatReference(value, 5f));
}
if (value is ValueInt)
{
statsContainer.valueList.Add(new ValueIntReference(value, 5)); // (value, x) x = Initialized Value
}
}
}
private void InitFormulas()
{
foreach (ValueReference valueReference in statsContainer.valueList)
if (valueReference.valueBase.formula)
{
valueReference.Null();
if (valueReference.valueBase.formula is FormulaInt)
{
FormulaInt formula = (FormulaInt)valueReference.valueBase.formula;
statsContainer.Sum(valueReference.valueBase, formula.Calculate(statsContainer));
}
else
{
FormulaFloat formula = (FormulaFloat)valueReference.valueBase.formula;
statsContainer.Sum(valueReference.valueBase, formula.Calculate(statsContainer));
}
List<Value> references = valueReference.valueBase.formula.GetReferences();
for (int i = 0; i < references.Count; i++)
{
statsContainer.Subscribe(ValueRecalculate, valueReference.valueBase, references[i]);
}
}
}
public void ValueRecalculate(Value value)
{
ValueReference valueReference = statsContainer.GetValueReference(value);
valueReference.Null();
// Adds all relevant stat sources.
}
public Value testReferenceValue;
public Value baseSkillPoints;
public Value baseStrength;
public Value baseVitality;
public Value baseHP;
public Value baseDexterity;
public Value baseIntelligence;
public Value baseLuck;
private void Update()
{
{
if (Input.GetKeyDown(KeyCode.X))
{
statsContainer.Sum(testReferenceValue, 1);
}
}
}
}
To be clear, the expected result is as follows. When I run the program my HP UI displays 75 and my attributes are all initialized to 5. Then upon pressing X my Strength UI goes up and that should also increase my HP UI because of the HP Formula.
Instead, When I run the program my HP UI displays 75 and my attributes are all initialized to 5. Then upon pressing X my Strength UI goes up, but my HP UI goes to 0.
This leads me to believe the problem lies specifically in the Recalculating.
Any and all help is appreciated.
I would refactor the Formula recalculation code into its own method then call that in InitFormulas and ValueRecalculate. I would also do some renaming for the sake of clarity and also use a switch statement instead of a long if/else if/else for type checking:
// for fast error detection
using UnityEngine.Assertions;
private void InitFormulas()
{
foreach (ValueReference valueReference in statsContainer.valueList)
{
if (valueReference.valueBase.formula)
{
RecalculateFormulaReference(valueReference);
List<Value> references = valueReference.valueBase.formula.GetReferences();
for (int i = 0; i < references.Count; i++)
{
statsContainer.Subscribe(RecalculateFormulaByValue,
valueReference.valueBase, references[i]);
}
}
}
}
private void RecalculateFormulaReference(ValueReference valueReference)
{
valueReference.Null();
// better to use a switch with pattern matching like this
switch (valueReference.valueBase.formula)
{
case FormulaInt formula:
statsContainer.Sum(valueReference.valueBase,
formula.Calculate(statsContainer));
break;
case FormulaFloat formula:
statsContainer.Sum(valueReference.valueBase,
formula.Calculate(statsContainer));
break;
default:
Assert.IsTrue(false, "Unsupported Formula Type");
}
}
// more descriptive name
public void RecalculateFormulaByValue(Value value)
{
ValueReference valueReference = statsContainer.GetValueReference(value);
RecalculateFormulaReference(valueReference);
}

The member XXX cannot be used as a method or delegate

I have done copied this of a tutorial online, but when I compile it shows 2 errors as below:
Non-invocable member 'Feature.choices' cannot be used like a method
and
The member `Feature.choices' cannot be used as method or delegate
The last "choices" in the script has a red squiggly line. Any idea that might be wrong?
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[ExecuteInEditMode]
public class FeatureManager : MonoBehaviour {
public List<Feature> features;
public int currFeature;
void OnEnable()
{
LoadFeatures();
}
void OnDisable()
{
SaveFeatures();
}
void LoadFeatures()
{
features = new List<Feature>();
features.Add(new Feature(("hair"), transform.FindChild("hair").GetComponent<SpriteRenderer>()));
}
void SaveFeatures()
{
}
}
[System.Serializable]
public class Feature
{
public string ID;
public int currIndex;
public Sprite[] choices;
public SpriteRenderer renderer;
public Feature(string id, SpriteRenderer rend)
{
ID = id;
renderer = rend;
UpdateFeature();
}
public void UpdateFeature()
{
choices = Resources.LoadAll<Sprite>("Character/" + ID);
if (choices == null || renderer == null)
return;
if (currIndex < 0)
currIndex = choices.Length - 1;
if (currIndex >= choices.Length)
currIndex = 0;
renderer.sprite = choices(currIndex);
}
}
Change this
renderer.sprite = choices(currIndex);
to this:
renderer.sprite = choices[currIndex]; // use square brackets not parenthesis

why can't call a function in A class but can call it in B class

I need to call updateGold() in ShowMoney class but failed.
If success,it should show money.gold in console, but don't show anything.
And golText.text don't update.
Even I change to Debug.Log("OK") in updateGold(),don't show anything in console.
But when I call updateGold() in Money class, it success. What the difference?
=========================================================
//Prop.cs
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class Prop : MonoBehaviour,IPointerClickHandler
{
public int goldPrice;
public int diamondPrice;
public int propID;
public GameObject goldError;
public GameObject diamondError;
public GameObject purchasePanel;
//check if purchased when back to this Level
void Awake()
{
if(Bag.propIsPurchased[propID]==true)
{
alreadySold();
}
}
//show purchase panel and add delegate
public void OnPointerClick (PointerEventData eventData)
{
purchasePanel.SetActive(true);
ConfirmPurchase.ensureOperation += this.purchase;
CancelPurchase.cancelOperation += this.cancel;
}
public void purchase()
{
if (goldPrice>0)
{
if(goldPrice > Money.gold)
{
goldError.SetActive(true);
}
else
{
Money.payGold(goldPrice);
ShowMoney.updateGold();//problem here
Bag.addProp(propID);
alreadySold();
}
}
//...
}
//...
//ShowMoney.cs
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class ShowMoney : MonoBehaviour
{
public GameObject goldText;
public GameObject diamondText;
public static Text golText;
public static Text diaText;
void Awake()
{
golText = goldText.GetComponent<Text>();
diaText = diamondText.GetComponent<Text>();
updateGold();
updateDiamond();
}
public static void updateGold()
{
Debug.Log(Money.gold);
golText.text = Money.gold.ToString();
}
public static void updateDiamond()
{
diaText.text = Money.diamond.ToString();
}
}
//Money.cs
using UnityEngine;
using System.Collections;
public class Money: MonoBehaviour
{
public static int gold = 100;
public static int diamond = 20;
public static Money instance;
void Awake()
{
instance = this;
}
public static void earnGold(int gol)
{
gold += gol;
}
public static void earnDiamond(int dia)
{
diamond += dia;
}
public static void payGold(int gol)
{
gold -= gol;
//ShowMoney.updateGold();//can work here
}
public static void payDiamond(int dia)
{
diamond -= dia;
}
}
Define your method Before Void and still Problem not solved then Make Protected Method that only accessible by its next method .
public static void updateGold()
{
Debug.Log(Money.gold);
golText.text = Money.gold.ToString();
}
public static void updateDiamond()
{
diaText.text = Money.diamond.ToString();
}
public void Awake()
{
golText = goldText.GetComponent<Text>();
diaText = diamondText.GetComponent<Text>();
updateGold();
updateDiamond();
}

Categories