Enemy health display not full

I have an issue that when I set up my enemy to start as a high-level, for example here it is set to level 3.
The enemy health only displays the health for a level 1 enemy.
Where do I update so that the health is full when the game starts?

base stat archer


You need the slider’s maximum value to equal the enemy’s starting health. This would be done in your UI display script.

1 Like

Paste in your Health.cs, so we can see how currentHealth is getting it’s starting value. Don’t forget to format the code using the </> button.

using UnityEngine;
using GameDevTV.Saving;
using RPG.Core;
using RPG.Stats;
using GameDevTV.Utils;
using UnityEngine.Events;

namespace RPG.Attributes
{
	public class Health : MonoBehaviour, ISaveable
	{
		[SerializeField] UnityEvent<float> _takeDamage;
		[SerializeField] UnityEvent _onDie;
		LazyValue<float> _healthPoints;

		private bool isDead = false;

		private void Awake()
		{
			_healthPoints = new LazyValue<float>(GetInitialHealth);
		}

		private float GetInitialHealth()
		{
			return GetComponent<BaseStats>().GetStat(Stat.Health);
		}

		private void Start()
		{
			_healthPoints.ForceInit();
		}

		private void OnEnable()
		{
			GetComponent<BaseStats>().OnLevelUp += RegenerateHealth;
		}

		private void OnDisable()
		{
			GetComponent<BaseStats>().OnLevelUp -= RegenerateHealth;
		}

		public bool IsDead()
		{
			return isDead;
		}

		public void Heal(float healthToRestore)
		{
			_healthPoints.value = Mathf.Min(_healthPoints.value + healthToRestore, GetMaxHealthPoints());
			print("HEALTH PICKED UP");
		}

		public void TakeDamage(GameObject instigator, float damage)
		{
			_healthPoints.value = Mathf.Max(_healthPoints.value - damage, 0);

			if (_healthPoints.value == 0f)
			{
				_onDie.Invoke();
				Die();
				AwardExperience(instigator);
			}
			else
			{
				_takeDamage.Invoke(damage);
			}
		}

		public float GetHealthPoints()
		{
			return _healthPoints.value;
		}

		public float GetMaxHealthPoints()
		{
			return GetComponent<BaseStats>().GetStat(Stat.Health);
		}

		private void AwardExperience(GameObject instigator)
		{
			Experience experience = instigator.GetComponent<Experience>();
			if (experience == null) return;

			experience.GainExperience(GetComponent<BaseStats>().GetStat(Stat.ExperienceReward));
		}

		public float GetPercentage()
		{
			return 100 * GetHealthBarValue();
		}

		public float GetHealthBarValue()
		{
			return (_healthPoints.value / GetComponent<BaseStats>().GetStat(Stat.Health));
		}

		private void Die()
		{
			if (isDead) return;

			isDead = true;
			GetComponent<Collider>().enabled = false; // added this code to disable colliders of dead npc's/player
			GetComponent<Animator>().SetTrigger("die");
			GetComponent<ActionScheduler>().CancelCurrentAction();
		}

		private void RegenerateHealth()
		{
			_healthPoints.value = GetComponent<BaseStats>().GetStat(Stat.Health);
		}

		public object CaptureState()
		{
			return _healthPoints.value;
		}

		public void RestoreState(object state)
		{
			_healthPoints.value = (float)state;

			if (_healthPoints.value == 0f)
			{
				Die();
			}
		}
	}
}

Pasted my current health script.

Ok, that looks right, which leads us to BaseStats… since it appears that BaseStats is returning the level 1 value when starting Level is 3… Is level a LazyValue as well? Paste in your BaseStats and we’ll take a look.

This is my current BaseStats

using GameDevTV.Utils;
using System;
using UnityEngine;

namespace RPG.Stats
{
	public class BaseStats : MonoBehaviour
	{
		[Range(1,99)]
		[SerializeField] private int _startingLevel = 1;
		[SerializeField] private CharacterClass _characterClass;
		[SerializeField] private Progression _progression = null;
		[SerializeField] private GameObject _LevelUpParticleEffect = null;
		[SerializeField] private bool _shouldUseModifier = false;

		LazyValue<int> _currentLevel;
		public event Action OnLevelUp;

		private Experience _experience;

		private void Awake()
		{
			_experience = GetComponent<Experience>();
			_currentLevel = new LazyValue<int>(CalculateLevel);
		}

		private void Start()
		{
			_currentLevel.ForceInit();
		}

		private void OnEnable()
		{
			if (_experience != null)
			{
				_experience.onExperienceGained += UpdateLevel;
			}
		}

		private void OnDisable()
		{
			if (_experience != null)
			{
				_experience.onExperienceGained -= UpdateLevel;
			}
		}

		private void UpdateLevel()
		{
			if (_currentLevel.value >= _progression.MaxLevel(_characterClass)) return;

			int newLevel = CalculateLevel();

			if (newLevel > _currentLevel.value)
			{
				_currentLevel.value = newLevel;
				LevelUpEffect();
				OnLevelUp();
			}
		}

		private void LevelUpEffect()
		{
			Instantiate(_LevelUpParticleEffect, transform);
		}

		public float GetStat(Stat stat)
		{
			return (GetBaseStat(stat) + GetAdditiveModifier(stat)) * (1 + GetPercentageModifier(stat)/100);
		}

		private float GetBaseStat(Stat stat)
		{
			return _progression.GetStat(stat, _characterClass, GetLevel());
		}

		private float GetAdditiveModifier(Stat stat)
		{
			if (!_shouldUseModifier) return 0f;

			float total = 0f;

			foreach (IModifierProvider provider in GetComponents<IModifierProvider>())
			{
				foreach (float modifier in provider.GetAdditiveModifiers(stat))
				{
					total += modifier;
				}
			}
			return total;
		}

		private float GetPercentageModifier(Stat stat)
		{
			if (!_shouldUseModifier) return 0f;

			float total = 0f;

			foreach (IModifierProvider provider in GetComponents<IModifierProvider>())
			{
				foreach (float percentModifier in provider.GetPercentageModifiers(stat))
				{
					total += percentModifier;
				}
			}
			return total;
		}

		public int GetLevel()
		{
			return _currentLevel.value;
		}

		private int CalculateLevel()
		{
			Experience experience = GetComponent<Experience>();
			if (experience == null) return _startingLevel;

			float currentXP = experience.GetExperiencePoints();
			int penultimateLevel = _progression.GetLevels(Stat.ExperienceToLevelUp, _characterClass);

			for (int level = 1; level <= penultimateLevel; level++)
			{
				float XPToLevelUp = _progression.GetStat(Stat.ExperienceToLevelUp, _characterClass, level);
				if (XPToLevelUp > currentXP)
				{
					return level;
				}
			}
			return penultimateLevel + 1;
		}
	}
}

That looks exactly right… does your archer have an Experience component attached?

My archer has no experience component.

I think it’s a bug. I can’t explain why, but it’s fixed now.

I added some log messages, and try some code on the Health.cs Start().

		private void Start()
		{
			_healthPoints.ForceInit();

			print($"{this.gameObject.name} HEALTH POINTS = {_healthPoints.value}");
			print($"{this.gameObject.name} HEALTH BASE = {GetComponent<BaseStats>().GetStat(Stat.Health)}");
			
			_healthPoints.value = GetComponent<BaseStats>().GetStat(Stat.Health);
			GetHealthBarValue();
			print($"HEALTH BAR VALUE {GetHealthBarValue()}");
		}

It fixed my issue of the healthbar now full on start.
so I commented my additional codes to see if it will return. but amazingly It didn’t.

The code is the same as the original one and now the issue is gone, how did that happen?
I restarted unity and yeah. the issue is really gone with just the same code from the original. :thinking:

Sometimes, Unity just fails to pick up a change in a script. It’s a caching bug where it will use a cached version of the CLR in a script instead of the new version.

1 Like

you’re right. thanks for trying to help. The game is okay at this moment. :ok_hand:

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms