Trying to Implement Elemental Damage But Introduced Bug

OH, yeah, this didn’t cover projectile weapons at all.

The projectile weapons will still be sending just the damage.

Give the player a melee weapon with elemental and test this to make sure it works. I’ll have to work up changes to projectile later tonight.

This weapon:

Is melee and should be dealing 5 Myth type damage. It doesn’t produce any text on a hit.

Paste in your entire Health script

using System.Reflection;
using System;
using System.Collections;
using System.Collections.Generic;
using RPG.Saving;
using UnityEngine;
using RPG.Core;
using RPG.Saving.Utils;
using UnityEngine.Events;

namespace RPG.Attributes
{
    public class Health : MonoBehaviour, ISaveable
    {
        [SerializeField] UnityEvent<float> takeDamage;
        public LazyValue<float> maxHealth;
        public LazyValue<float> health;
        public UnityEvent<string> takeDamageText;
        bool isDead = false;
        bool isHurt = false;
        bool hasAwardedExperience = false;

        private void Awake()
        {
            health = new LazyValue<float>(GetInitialHealth);
            maxHealth = new LazyValue<float>(GetCurrentMaxHealth);
            GetComponent<BaseStats>().onLevelUp += RegenerateHealth;
        }
        private void Start()
        {
            health.ForceInit();
            maxHealth.ForceInit();
        }
        private void Update()
        {
            maxHealth.value = GetComponent<BaseStats>().GetStat(Stats.Health);
        }
        public bool IsDead()
        {
            return isDead;
        }
        public bool IsHurt()
        {
            return isHurt;
        }

        public void Heal(float heal)
        {
            if(health.value >= 0)
            {
            health.value = Mathf.Min(health.value + heal, maxHealth.value);
            }
        }
        public void TakeDamage(GameObject instigator, float damage, string damageInfo = "")
        {
            health.value = Mathf.Max(health.value - damage, 0);           
            {
                takeDamage.Invoke(damage);//Can place in an else statement after if statement to make text not appear on death
                if(health.value <= 0)
                {
                    Die();
                    AwardExperience(instigator);
                }
                else
                {
                    takeDamage?.Invoke(damage);
                    takeDamageText?.Invoke($"{damage} {damageInfo}");
                }
                //UpdateState();
            }
            isHurt = true;
        }
        private float GetInitialHealth()
        {
            return GetComponent<BaseStats>().GetStat(Stats.Health);
        }
        public float GetCurrentMaxHealth()
        {
            return GetComponent<BaseStats>().GetStat(Stats.Health);
        }
        public float GetCurrentHealth()
        {
            return health.value;
        }
        public float GetMaxHealth()
        {
            return maxHealth.value;
        }
        private void RegenerateHealth()
        {
            maxHealth.value = GetComponent<BaseStats>().GetStat(Stats.Health);
            health.value = Mathf.Max(maxHealth.value * .8f, health.value);
        }
        private void Die()
        {
            if(isDead) return;

            isDead = true;
            GetComponent<Animator>().SetTrigger("Die");
            GetComponent<ActionScheduler>().CancelCurrentAction();
        }
        private void AwardExperience(GameObject instigator)
        {
            Experience experience = instigator.GetComponent<Experience>();
            if(experience == null) return;
            
            if(hasAwardedExperience == false)
            {
            hasAwardedExperience = true;
            experience.GainExperience(GetComponent<BaseStats>().GetStat(Stats.ExperienceReward));
            }
        }

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

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

            if(health.value <= 0)
            {
                Die();
            }
        }
    }
}

Are you getting any errors in the inspector during a hit?

I do not. I will be sleeping soon so I doubt we will solve this tonight but thanks for all your help. This isn’t a huge rush or anything. But let me try adding fire damage to the sword and seeing if that changes anything.

Not that (which I tested because Fire is the first damage type I think) and it also doesn’t seem to be the animator override controller, which I also got rid of to test if it was a different set of animations or something triggering stuff wrong.

When you’re back on, paste in your completed DamageTextSpawner.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace RPG.UI
{
    public class DamageTextSpawner : MonoBehaviour
    {
        [SerializeField] DamageText damageTextPrefab = null;
        [SerializeField] private float timeBetweenMessages = 0.25f;//delay is for elemental damage so numbers don't overlap
        private float last = 0;
        public void Spawn(float damageAmount)
        {
            actions.Enqueue(() =>
            {
            DamageText instance = Instantiate<DamageText>(damageTextPrefab, transform);
            instance.SetValue(damageAmount);
            });
        }
        private Queue<Action> actions = new Queue<Action>();

        private void Update()
        {
            last += Time.deltaTime;
            if (actions.Count > 0 && (last > timeBetweenMessages))
            {
                var action = actions.Dequeue();
                action.Invoke();
                last = 0;            
            }
        }

        /// <summary>
        /// Spawns a new text message at the spawner's location.
        /// </summary>
        /// <param name="text">The message to spawn.</param>
        public void SpawnText(string text)
        {
            actions.Enqueue(() =>
            {
                DamageText instance = Instantiate<DamageText>(damageTextPrefab, transform);
                instance.SetText(text);
            });
        }
    }
}

Swapped the enemy’s weapons for one I know isn’t producing damage numbers for the player, and it worked fine. So something is odd with the player specifically.

The enemies and the player use the same code for Fighter, Health, and WeaponConfig. I don’t think the problem is with the player, I think it is still with the enemies, in their Health setups.

Here’s something to check: Go through EACH enemy, and make sure it has the correct hookups in the Health as above with the DamageText.SpawnText. It’s possible that the changes to the prefab didn’t propagate to the scene.

Here is the enemy I have been testing on:

And who isn’t producing damage text as far as I can tell

Specifically when using a weapon that isn’t the Unarmed against them, anyway.

I now longer have the slightest idea why. If you’ve linked the DamageTextSpawner.SpawnText to both the enemy and the player, they should both behave the same.

Zip up your project and upload it to https://gdev.tv/projectupload Be sure to remove the Library folder to conserve space.

What I don’t understand is what about Unarmed is unique in that it works for the player

Neither do I. A WeaponConfig is a WeaponConfig, and the same code is being used. It has to be a setup issue.

I am getting the files ready. Sorry, I haven’t done this before so it may take a minute.

I believe it should have been submitted

Unfortunately, the program was incomplete… While I didn’t need the entire project, there are no WeaponConfigs, no Resource Directory to store them, and most of the scene is Prefab Missing, including the characters not being setup with animator controllers, character animations, or even the correct Avatars… As such, I was unable to test the game in any meaninful way…

Let me try again, something did seem a little funky when I first did it. Sorry about that, I appreciate all your help immensely.

Privacy & Terms