so the code above should go in the “ActiveWeapon” code?
No, it goes in the Pickup code. This allows the pickup to find the ActiveInventory.
in the Pickup class I have
private void Awake() { rb = GetComponent<Rigidbody2D>(); activeInventory = PlayerController.Instance.GetComponentInChildren<ActiveInventory>(); }
and I still get the error as before.
In My ActiveInventory script I have
`
public InventorySlot GetEmptyInventorySlot() // NEW for active weapon.
{
Debug.Log("TEST1");
foreach (Transform child in transform)
{
//Debug.Log("inventorySlot");
if (child.TryGetComponent(out InventorySlot inventorySlot)) return inventorySlot;
Debug.Log(inventorySlot);
}
return null;
}
`
The Log (“TEST1”) doesnt come up. so I think it never gets into this script for some reason.
Paste in the complete Pickup script, and your complete ActiveInventory script again.
Quick note on formatting, it’s three ``` on it’s own line, not one ` to format a code block.
Pick Up Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PickUp : MonoBehaviour
{
private enum PickUpType
{
GoldCoin,
StaminaGlobe,
HealthGlobe,
Sword,
}
[SerializeField] private PickUpType pickUpType;
[SerializeField] AudioClip pickupClip;
[SerializeField] private float pickUpDistance = 5f;
[SerializeField] private float moveSpeed = 3f;
[SerializeField] private float accelarationRate = .4f;
[SerializeField] private AnimationCurve animCurve;
[SerializeField] private float heightY = 1.5f;
[SerializeField] private float popDuration = 1f;
ActiveInventory activeInventory; // NEW
WeaponInfo weaponInfo;
private Vector3 moveDir;
private Rigidbody2D rb;
private void Awake()
{
rb = GetComponent<Rigidbody2D>();
activeInventory = PlayerController.Instance.GetComponentInChildren<ActiveInventory>();
}
private void Start()
{
StartCoroutine(AnimCurveSpawnRoutine());
}
private void Update()
{
Vector3 palyerPosition = PlayerController.Instance.transform.position;
if(Vector3.Distance(transform.position, palyerPosition) < pickUpDistance)
{
moveDir = (palyerPosition - transform.position).normalized;
moveSpeed += accelarationRate;
}
else
{
moveDir = Vector3.zero;
moveSpeed = 0f;
}
}
private void OnTriggerEnter2D(Collider2D other)
{
if(other.gameObject.GetComponent<PlayerController>())
{
DetectPickupType();
Destroy(gameObject);
}
}
private void FixedUpdate()
{
rb.velocity = moveDir * moveSpeed * Time.deltaTime;
}
private IEnumerator AnimCurveSpawnRoutine()
{
Vector2 startPoint = transform.position;
float randomX = transform.position.x + Random.Range(-2f,2f);
float randomY = transform.position.y + Random.Range(-1f,1f);
Vector2 endPoint = new Vector2(randomX,randomY);
float timePassed = 0f;
while (timePassed < popDuration)
{
timePassed += Time.deltaTime;
float linearT = timePassed / popDuration;
float heightT = animCurve.Evaluate(linearT);
float height = Mathf.Lerp(0f,heightY,heightT);
transform.position = Vector2.Lerp(startPoint,endPoint,linearT) + new Vector2(0f,height);
yield return null;
}
}
private void DetectPickupType()
{
switch (pickUpType)
{
case PickUpType.GoldCoin:
//Do GoldCoin Stuff
AudioSource.PlayClipAtPoint(pickupClip,Camera.main.transform.position);
EconomyManager.Instance.UpdateCurrentGold();
//Debug.Log("Gold Coin");
break;
case PickUpType.HealthGlobe:
//Do Health Stuff
AudioSource.PlayClipAtPoint(pickupClip,Camera.main.transform.position);
PlayerHealth.Instance.HealPlayer();
//Debug.Log("Health Gloab");
break;
case PickUpType.StaminaGlobe:
//Do Stamina Globe stuff
AudioSource.PlayClipAtPoint(pickupClip,Camera.main.transform.position);
Stamina.Instance.RefreshStamina();
//Debug.Log("Stmina Golbe");
break;
case PickUpType.Sword: //NEW For inventory
AudioSource.PlayClipAtPoint(pickupClip,Camera.main.transform.position);
Debug.Log(activeInventory);
InventorySlot slot = activeInventory.GetEmptyInventorySlot();
if (slot != null)
{
Debug.Log("TEST2");
slot.AssingWeaponInfor(weaponInfo);
Debug.Log("TEST3");
}
break;
default:
break;
}
}
}
ActiveInventory Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ActiveInventory : Singleton<ActiveInventory>
{
private int activeSlotIndexNum = 0;
private PlayerActions playerActions;
protected override void Awake()
{
base.Awake();
playerActions = new PlayerActions();
}
private void Start()
{
playerActions.Inventory.Keyboard.performed += ctx => ToggleActiveSlot((int)ctx.ReadValue<float>());
}
private void OnEnable()
{
playerActions.Enable();
}
public void EquipStartingWeapon()
{
//Give the player the sword in the inventory
ToggleActiveHighlight(0);
}
private void ToggleActiveSlot(int numPressed)
{
//Need to match up number pressed to the actual inventory index {0-4} [1-5]that is why we -->(- 1)
ToggleActiveHighlight(numPressed -1);
}
private void ToggleActiveHighlight(int indexNum)
{
activeSlotIndexNum = indexNum;
//First set all agme objects for the inventory slots off
foreach (Transform inventorySlot in this.transform)
{
inventorySlot.GetChild(0).gameObject.SetActive(false);
}
//Now set the one that we want to be active
this.transform.GetChild(indexNum).GetChild(0).gameObject.SetActive(true);
ChangeActiveWeapon();
}
private void ChangeActiveWeapon()
{
if(PlayerHealth.Instance.IsDead){return;}
if(ActiveWeapon.Instance.CurrentActiveWeapon != null)
{
Destroy(ActiveWeapon.Instance.CurrentActiveWeapon.gameObject);
}
Transform childTransform = transform.GetChild(activeSlotIndexNum);
InventorySlot inventorySlot = childTransform.GetComponentInChildren<InventorySlot>();
WeaponInfo weaponInfo = inventorySlot.GetWeaponInfo();
// if nothing is in an inventory slot
if (weaponInfo == null)
{
//return null
ActiveWeapon.Instance.WeaponNull();
return;
}
GameObject weaponToSpawn = weaponInfo.weaponPrefab;
//Now Instantiate the new weapon
GameObject newWeapon = Instantiate(weaponToSpawn, ActiveWeapon.Instance.transform.position, Quaternion.identity);
// we are cleaning out first the rotation of a prior wepon so any weapon does not spin on a certain point.
ActiveWeapon.Instance.transform.rotation = Quaternion.Euler(0,0,0);
//now make the weapon a child of our active weapon.
newWeapon.transform.parent = ActiveWeapon.Instance.transform;
ActiveWeapon.Instance.NewWeapon(newWeapon.GetComponent<MonoBehaviour>());
}
public InventorySlot GetEmptyInventorySlot() // NEW for active weapon.
{
Debug.Log("TEST1");
foreach (Transform child in transform)
{
//Debug.Log("inventorySlot");
if (child.TryGetComponent(out InventorySlot inventorySlot)) return inventorySlot;
Debug.Log(inventorySlot);
}
return null;
}
}
Thank you.
This actually looks right, but I forgot one of my own rules in avoiding Race Conditions.
It’s possible for the Pickup’s Awake() to be executed before ActiveInventory’s Awake.
I also forgot that we made ActiveInventory a Singleton, which actually makes this much easier to work with.
All of our changes at this point should be in Pickup.cs:
- Remove the line in Awake to get the ActiveInventory. We don’t need it.
Also remove this line
ActiveInventory activeInventory; //NEW
we don’t need it. We can get a reference to the ActiveInventory through ActiveInventory.Instance.
Lastly, we just need to change our case statement in DetectPickupType()
will become
case PickUpType.Sword: //NEW For inventory
AudioSource.PlayClipAtPoint(pickupClip,Camera.main.transform.position);
Debug.Log(ActiveInventory.Instance);
InventorySlot slot = ActiveInventory.Instance.GetEmptyInventorySlot();
if (slot != null)
{
Debug.Log("TEST2");
slot.AssingWeaponInfor(weaponInfo);
Debug.Log("TEST3");
}
break;
we are really close now. I get logs 1,2 and not 3 yet. it seems like it does not like line 19 in InventorySlot script
public void AssingWeaponInfor(WeaponInfo weaponInfo) // NEW for active weapon.
{
this.weaponInfo = weaponInfo;
transform.GetChild(1).GetComponent<Image>().sprite = weaponInfo.sprite;
Debug.Log(weaponInfo.weaponRange);
}
}
So test 3 in the Pickup script doesn’t hit.
It’s not easy to tell which one of these things is line 19. There are two lines where a null reference could occur, and one of them has multiple lines… So let’s add some debugs to find the culprit.
This is in InventorySlot.cs:
public void AssignWeaponInfo(WeaponInfo weaponInfo)
{
if (weaponInfo == null)
{
Debug.Log($"WeaponInfo is null!");
return;
}
this.weaponInfo = weaponInfo;
if (transform.childCount < 2)
{
Debug.Log($"Not enough slots!");
return;
}
Image image = transform.GetChild(1).GetComponent<Image>();
if (image == null)
{
Debug.Log($"Image is null");
return;
}
transform.GetChild(1).GetComponent<Image>().sprite = weaponInfo.sprite;
}
Ah, that makes sense.
WeaponInfo needs to be a [SerializedField] in Pickup
It did not Bomb, However it did not add the item in the inventory slot and I still have my Sword as a weapon when I start the game.
just a sec. I forgot something.
The sword you started with should still be in slot 1, we’re adding the weapon to a new slot, which you can switch to by selecting the icon.
Yeah, it didn’t add.
And it got through all of the Debugs?
Have you set the sprite in the WeaponConfig attached to the Pickup?
i want to add the sword. and I added the Scriptable object Sword info to the Weapon Infor SerializeField.
Look at the WeaponInfo itself, does it have the sword sprite assigned?