Using Health Potion to Increase Health (3D RPG Game)

Good day everyone! I’m still relatively new to Unity and I’m working on a 3D RPG game by following Brackey’s tutorial on Youtube.

I’d like to implement a health potion that will increase the player’s health, however I’ve ran into a bit of a problem. When I use the potion from my inventory it doesn’t do anything.

Here’s my HealthPotion script that derives from my Item script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "HealthPotion", menuName = "Inventory/Potion")]
public class HealthPotion : Item
{
     public int health; // 10
     public GameObject player; // reference to the player object
     public override void Use()
     {
         base.Use();
         // doesnt run line 13 at all
         player.GetComponent<CharacterStats>().currentHealth += health;
         Debug.Log("Increasing health by " + health);
     }
}

Item script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "New Item", menuName = "Inventory/Item")]
public class Item : ScriptableObject
{
     new public string name = "New Item"; // name of the item
     public Sprite icon = null; // item icon
     public bool isDefaultItem = false; // is the item default wear
   
     public virtual void Use()
     {
         // Use the item
         // Something might happen
         Debug.Log("Using " + name);
     }
     // removes the item from inventory when it's equipped
     public void RemoveFromInventory()
     {
         Inventory.instance.Remove(this);
     }
}

CharacterStats script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CharacterStats : MonoBehaviour
{
     public int maxHealth = 100; // default max health;
     public int currentHealth; // current health
     public Stat damage; // damage value
     public Stat armor; // armor value
     void Awake()
     {
         currentHealth = maxHealth;
     }

     public void TakeDamage(int damage)
     {
         damage -= armor.GetValue();
         damage = Mathf.Clamp(damage, 0, int.MaxValue); // so that the damage never goes below 0
         currentHealth -= damage; // decreasing health of character whenever they take damage
         Debug.Log(transform.name + " takes " + damage + " damage");
         // if health is below 0, the player or the enemy will die
         if (currentHealth <= 0)
         {
             Die();
         }
     }
     public virtual void Die()
     {
         // Die in some way
         // This method is meant to be overwritten
         Debug.Log(transform.name + " died");
     }
}

When I use the potion, it outputs the Debug.Log statement in the HealthPotion script, however it doesn’t actually apply the change to my current health. :frowning: Where am I going wrong?

And I’m also not quite sure if referencing the Player game object in the HealthPotion script is the right way to go.

  • Do you get any error output?
  • What is player set to in the scriptable object?
  • are you sure you get a component with GetComponent?

I recommend not stringing together statements like you do in line 13, as you don’t know if, when or where it fails. Take the compound statement apart, and check each time if what you have is what you expect.

Hello! I made a couple of adjustments to my script and got rid of the game object in my HealthPotion script entirely:

  1. I set up a singleton in my CharacterStats script so I can access values easily from my HealthPotion script.
  2. I created an IncreaseHealth() method in my CharacterStats script that increases the health:
    public void IncreaseHealth(int amount)
    {
        currentHealth += amount;
        Debug.Log(amount);
    }
  1. I modified my HealthPotion script so that it accesses the IncreaseHealth() function from my CharacterStats script:
[CreateAssetMenu(fileName = "HealthPotion", menuName = "Inventory/Potion")]
public class HealthPotion : Item
{
    public int health;
    public override void Use()
    {
        base.Use();
        CharacterStats.instance.IncreaseHealth(health);

        Debug.Log("Increasing health by " + health);

        RemoveFromInventory(); // Remove it from the inventory

    }
}

I don’t get any errors, however it doesn’t seem to increase my current health in the inspector when I consume the potion.

At first, I was wondering if my IncreaseHealth() function had a problem, so I tested it out by calling it in the Update() method in my CharacterStats script, and it works properly (it increases the health by 10 each time I press a key). The problem lies in the HealthPotion() script and I’m not quite sure what I’m doing wrong.:frowning:

Check the value of health. Log it when entering IncreaseHealth upon invocation. You probably are sending 0 health

But Debug.Log("Increasing health by " + health); successfully outputs “Increasing health by 10” on the console, so I don’t think that’s the issue.

Try it. It may well be that you are not invoking what you intend to invoke, i.e. the wrong GO

Don’t stop there, keep putting in logging, or else attach the debugger. Only you are going to be able to figure out where the code is executing, nobody else here can do that.

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run?
  • what are the values of the variables involved? Are they initialized?

Knowing this information will help you reason about the behavior you are seeing.

I’ve put multiple logs throughout my HealthPotion script and my CharacterStats script in order to check if the health system is working properly. The debugs all output 10 which is the health value that I assigned.

I also tried calling the IncreaseHealth() method in Update() directly within the CharacterStats script by pressing a key (e.g. P), and it works perfectly, it increases my current health by 10 each time I press the key.

The problem starts when I try to call the IncreaseHealth() method in the HealthPotion script (The potion is a scriptable object). it prints all the Debug.Log() statements in the console correctly, however it doesn’t update the actual current health. I think I’m having issues with invoking the Player game object, and I’m not quite sure how to fix it. It’s my first time working with scriptable objects so I’m struggling quite a bit. :slight_smile:

Print out the currentHealth before you add health to it, then print it again afterwards. You gotta just get suspicious of EVERYTHING, nobody here can do it. You’ll find it. There is also nothing magical about ScriptableObjects, they’re just classes.

I managed to find the problem. There are two scripts that inherit from my CharacterStats script: PlayerStats and EnemyStats. PlayerStats is attached to the player game object, and EnemyStats is attached to the enemy game object.

What my code does is that it accesses the EnemyStats script instead of PlayerStats. I’m guessing this happens because the program doesn’t know which child script to use. I realized that the enemy’s health is increasing instead of the player’s. :slight_smile: So I just have to figure out how to use the PlayerStats script instead.

Look into some tutorials on C# interfaces… they play really well with Unity for this sort of thing.

You would make something like:

public interface IHealable
{
  void Heal( float amountToHeal);
}

Any class anywhere can implement this interface, then your heal script can just see if it has an IHealable, and if it does, call the .Heal() method!

You can even say .GetComponent<IHealable(); and if something is healable on that GameObject, well, you’ll get it!

You’re right, I think I’ll go watch some C# interface tutorials and then come back to this problem. :slight_smile: I’m still fairly new to unity and c# (it’s been 3-4 months since I started learning), so I still don’t really know what would be the most optimal thing to use in certain situations. :smile: Thank you for your suggestion!

1 Like