I would like to ask you a question, if you dont mind.
I dot a script with a function, in the Start Method I create a new dictionary and then add some keys and values to it.
Also in the same script there is a function that changes value of a certain key, that is being passed to it by the onCLick button event set up in the inspector.
Later in the game I got a button that passes a string of a key to that function and according to which key I get, the value is being change by a certain amount.
If I access this function from within the other script, it works fine and changes the value with no problems.
When I access this function from a button from the inspector, setting onClick to this button to send string, it sends the string across, but when Im trying to change a value for a received string Key it does not detect any Dictionary, so I need to reinitialize a Dictionary again for it to work.
Maybe there is a solution that would let me operate the dictionary of the script through a Button from the inspector as I do not really want to create another Dictionary as it really messes and twists things up.
There is no difference except that one is being called from another script, so before calling this function the actual script, where the function is, is being initialized and a Dictionary as well. Another method is being called tom the UI button click and I assume that it does not go beyond and above that function and as a result Dictionary is missing. I would think UI button onClick would take variables and all the rest from the script, but as I can see it does not. Well at least it is what i can understand from digging into for quite a some time.
So in this script in function AddAmmo im passing a String from a button click:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CharacterStatsChanger : MonoBehaviour
{
CharacterLinkage linkToCharStats;
CollectablesLinkage linkToItems;
public int curretCharArmor;
public int currentCharHealth;
public Dictionary<string, int> weaponsList;
public int globalAmmoLeft;
void Awake()
{
}
// Start is called before the first frame update
void Start()
{
weaponsList = new Dictionary<string, int>();
InitalizingStats();
InitalizingWeapons();
}
// Update is called once per frame
void Update()
{
}
public void Heal(int amount)
{
if (currentCharHealth == 100)
{
Debug.Log("HEALTH IS FULL");
}
if (currentCharHealth < 100)
{
currentCharHealth = Mathf.Clamp(currentCharHealth + amount, 0, 100);
Debug.Log("HEALED " + currentCharHealth);
}
}
public void AddAmmo(string weaponName)
{
Debug.Log(weaponName);
Debug.Log(weaponsList[weaponName]);
//weaponsList[weapon] += linkToItems.ReturnItemValue(weapon);
//Debug.Log(linkToItems.ReturnItemalue(weapon));
}
public void UseAmmo(string weapon)
{
weaponsList[weapon] -- ;
globalAmmoLeft = weaponsList[weapon];
Debug.Log(weaponsList[weapon]);
}
public void InitalizingWeapons ()
{
weaponsList.Add("Pistol", 100);
weaponsList.Add("AK47", 200);
}
void InitalizingStats()
{
currentCharHealth = linkToCharStats.characterLife;
curretCharArmor = linkToCharStats.characterArmor;
}
}
And from this code im doing the same from the function ShotTheWeapon ( line 69), and passing a string into the Function UseAmmo, which if you check works absolutely the same
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WeaponShoot : MonoBehaviour
{
WeaponLinkage linkToWeaponStats;
public CharacterStatsChanger changingCharStats;
[Header("Weapon Parts")]
public GameObject bullet;
public GameObject firingPoint;
public GameObject muzzle;
public GameObject shell;
public GameObject shellOutSlot;
public Light muzzleLighting;
float shelOutSpeed;
float shotTimer;
float shotSpeedDelay;
bool reloading;
int bulletsLeft;
//int reloadingTImer;
// Start is called before the first frame update
void Start()
{
muzzleLighting.enabled = false;
linkToWeaponStats = GetComponent<WeaponLinkage>();
shotTimer = 0;
reloading = false;
bulletsLeft = linkToWeaponStats.weaponAmmoCount;
shelOutSpeed = 20;
}
// Update is called once per frame
void Update()
{
if(Input.GetKey(KeyCode.R))
{
StartCoroutine(ReloadTheWeapon());
}
if (Input.GetMouseButton(0) && linkToWeaponStats.weaponShotSpeedDelay < shotTimer && !reloading)
{
bulletsLeft--;
if (bulletsLeft == 0)
{
StartCoroutine(ReloadTheWeapon());
}
ShootTheWeapon();
// muzzleLighting.enabled = false;
}
shotTimer += Time.deltaTime;
}
void ShootTheWeapon()
{
muzzleLighting.enabled = true;
GameObject muzzleInstance = (GameObject)Instantiate(muzzle, firingPoint.transform.position, Quaternion.identity);
StartCoroutine(MuzzleFlash());
GameObject bulletInstance = (GameObject)Instantiate(bullet, firingPoint.transform.position, Quaternion.identity);
changingCharStats.UseAmmo(linkToWeaponStats.weaponName);
Vector3 shootDirection = firingPoint.transform.forward;
WeaponBulletShot passToBullet = bulletInstance.GetComponent<WeaponBulletShot>();
passToBullet.GetDirection(shootDirection);
passToBullet.GetRange(linkToWeaponStats.weaponRange);
GameObject shellInstance = (GameObject)Instantiate(shell, shellOutSlot.transform.position, Quaternion.identity);
Rigidbody shellRB = shellInstance.GetComponent<Rigidbody>();
shellRB.AddForce(transform.forward * shelOutSpeed);
DestroyInstances(muzzleInstance, shellInstance);
shotTimer = 0;
}
IEnumerator ReloadTheWeapon()
{
reloading = true;
yield return new WaitForSeconds(linkToWeaponStats.weaponReloadSpeed);
reloading = false;
bulletsLeft = linkToWeaponStats.weaponAmmoCount;
}
IEnumerator MuzzleFlash()
{
yield return new WaitForSeconds(0.05f);
muzzleLighting.enabled = false;
}
public void UpdateWeaponStats ()
{
bulletsLeft = linkToWeaponStats.weaponAmmoCount;
reloading = false;
}
void DestroyInstances (GameObject vfxInstance01, GameObject vfxInstance02)
{
Destroy(vfxInstance01, 2);
Destroy(vfxInstance02, 10);
}
}
So First option does no see the dictionary unless i do relaunch Start function before changing the Dictionary value.
Not really, the error is on the line (51) in AddAmmo function after i click a button (image on the very top), the one you mentioned, works fine, that is why I’m confused.
Debug.Log(weaponsList[weaponName]);
And the error is ( Object reference not set to an instance of an Object C#)
If I use start method in a function it finds a Dictionary and works fine.
Is the gameobject that contains the WeaponShoot component active or inactive?
If the gameobject is inactive it won’t call Start and then it won’t initialize the weaponsList dictionary.
Add a debug log with gameObject as context (second parameter of Debug.Log, when you click on the debug log it will highlight the gameObject in the hierarchy) in the Start method, does it get executed before you clicking the button?
Well, this button gets instantiated in the inactive GameObject (inventory, inactive by default), when I pick up item. Though when i open the inventory it becomes active, and only then Im able to press the button.
About the Start, it is a good question, I was thinking is UseAmmo function functions properly, then the Dictionary is being Initialized and means that Start is being launched, though, when I click the button, it appears that it is not or there is another reason.
Will try to perform suggested thing when ill come back home from work, as always, wish I could stay and do this only thing
Oh well ill rework my inventory with JSon database, i think it will be more practical in this case rather than scriptable objects. Thanks anyway, when I’ll reach the stage when i will need to use an Item from the Inventory I will see how will it work in that case.