Death Bug, when building the game

OK so a week or two ago, me and Brian fixed the infinity loot glitch by eliminating ‘onDie()’ from ‘UpdateState()’ in ‘Health.cs’. I’m guessing the drawbacks of this are slowly crawling back up, because when I was playing my game in build mode now, well… in one of the fights I was having with a guard, wielding my player sword, I actually died in the battle. The guard registered it as me being dead, and he actually stopped fighting me, but my player did not register himself as dead for some reason. In a ‘once in a bluemoon’ chance, my player actually kept on fighting the guard (although he is supposedly dead), killed the guard (again, my player is dead, but the guard still accepted damage from my player, as if he was alive, but he sees me as dead, so he didn’t fight back), and then my player levelled up and restored his health, as if he was never even killed to begin with, and all of a sudden now, I’m back to life (when my player was “dead”, his controller was disabled, and now it’s enabled again, because… well… I was alive, and “levelled up”).

What went wrong here?

Most likely, your death occurred close enough to the Hit() in the attack animation that while the animator was in transition from Attack to Death, the event fired.

This is like a parting shot, or a last gasp attack. I actually employ this mechanic with some enemies death animations in the first place (I use InfinityPBR’s Giant Worm, with the damage being collider based, when the worm dies, it does a bit of a spin in it’s death animation. I leave the damage collider on, so if you’re fighting one in my game and it starts to die, run like hell because a ton of worm is about to sweep you.

The real problem isn’t the damage. The real problem is the experience gain.

When the enemy dies, he grants experience to the instigator.

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

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

Let’s refactor this method a bit to test that the instigator is actually alive before awarding experience. While we’re at it, we’ll take advantage of TryGetComponent .

        private void AwardExperience(GameObject instigator)
        {
            if (instigator.TryGetComponent(out Experience experience))
            {
                if (instigator.TryGetComponent(out Health otherHealth) && !otherHealth.IsDead())
                {
                    experience.GainExperience(GetComponent<BaseStats>().GetStat(Stat.ExperienceReward));
                }
            }
        }

Oh I really am curious on how you implemented this (That would be one amazing final boss animation I’d love to have added to my game… Speaking of bosses, what boss cycles would you recommend me to have in my game? I can really use some help here)

As for the code, I’ll give it a test run when I get home :slight_smile: (for now, I still want to enhance my AggroGroup a bit more)

the Giant Worm has a SphereCollider along it’s skeleton that’s used for it’s Sweep attack. (To avoid the Sweep attack, you must jump at EXACTLY the right time). If the collider hits anything, it checks for a Health, Damages that health, and applies force to that Health (The player controller is based on the Third Person Character course, and I’m not getting into the weeds on that one). This one required hours (more like weeks) of playtesting to get exactly right, making the Giant Worm a difficult challenge to beat, but still making it beatable.

I just leave that collider on when the worm dies. The collision does the rest.

In terms of boss battles in general, that depends a lot on what models you have, and what kind of time you’re willing to put into them. That’s far enough out of the course context (because each boss is usually a bit unique), that I don’t offer a lot of aid. It can be as simple as making a bigger model and heavier stats, or as complex as you could ever imagine. In general, you can expect to spend quite a bit of time crafting a good boss battle.

At this point in time, considering I already fixed two major bugs and added an entire system on my own, I have faith that I can take this on, hopefully :slight_smile:

Debugging will take most of it, significantly more than just planning it all out. Hopefully it goes well though, I want a few bosses out there to make this game exciting

Uhh Brian… this issue did return to me in Unity itself. I don’t know if it’s just the Engine or the game as well, but this time it’s a bit more… weird, because the player Controller is indeed deactivated on my death, and the guard registers me as dead, but the player continues attacking him as if he’s still alive for god knows what reason. In the once in a bluemoon chance this issue gets caught, he doesn’t respawn or do anything, he just stays there after the fight. He doesn’t die, and the cursor is locked, so he’s stuck there forever unless we quit the game

You have the most interesting bugs…

When the character dies, there should be a call to

GetComponent<ActionScheduler>().CancelCurrentAction();

Let me take a very wild guess and say this goes in ‘Health.IsDead()’, right before the return statement, right?

No, as that would cancel all actions every time IsDead() is called, (which is fairly often).

You might take a look at TakeDamage()… At a certain point, we check to see if the wound was fatal…

public void TakeDamage(GameObject instigator, float damage) {
            
            print(gameObject.name + " took damage: " + damage);

        // This function clamps the health of the player, based on taken damage
        // and if the target is dead, we want them to die and give our player some XP
        // (using the 'AwardExperience(GameObject instigator)' function)

        healthPoints.value = Mathf.Max(healthPoints.value - damage, 0); // Clamps our health value to never go negative, neither above what our player currently has

        takeDamage.Invoke(damage);        // invoking a 'TakeDamage' event (if our player is not dead), 
                                          // so when our player gets hit by an enemy, we want to display 
                                          // the text of the damage taken

        onTakenHit?.Invoke(instigator);     // if you get hit, you automatically fight back!

        if (healthPoints.value == 0) {
        // THIS IS THE NEW LINE:        
        GetComponent<ActionSchedular>().CancelCurrentAction();

        onDie.Invoke(); // Invokes external UnityEvent Audio 'Die', combined with other events, when our Enemy/Player has taken enough damage to die
        AwardExperience(instigator);    // Award experience to whoever won the battle

        }

        UpdateState();  // Update the Players' health state

    }

is it like this…? (under comment 'This is the new line:"). If so, then I’m back to the Quiver xD

That should do it.

Fair enough, thanks again Brian :slight_smile: (I’ll go through the Quiver now)

Hello again Brian. Sorry if I’m asking a lot of questions today, but this death bug is now more frequent than ever, where the player frequently now, although he’s dead, still tries to attack the enemy even if he’s dead, and there’s no way for him to stop (the only way for him to stop is if he’s using melee, and the enemies walk away), and Respawn (Respawning pretty much never happens now…). Any other solutions to this problem? The more the enemies attacking him, the less likely he is to respawn, and this is now becoming a serious problem for my player in-game. This is my current ‘AwardExperience()’ function:

private void AwardExperience(GameObject instigator, Skill skill) {

            if (instigator.TryGetComponent(out SkillExperience skillExperience)) {

                if (instigator.TryGetComponent(out Health otherHealth) && !otherHealth.IsDead()) {

                    skillExperience.GainExperience(skill, Mathf.RoundToInt(GetComponent<AIController>().GetXPReward()));

                    // If you don't want to assign individual XP to your enemies, use the below formula instead (and change them up in 'Progression' attached to each individual enemy):
                    // skillExperience.GainExperience(skill, Mathf.RoundToInt(GetComponent<BaseStats>().GetStat(Stat.ExperienceReward)));

                }

            }

        }

And this is my ‘TakeDamage()’ function:

public void TakeDamage(GameObject instigator, float damage, Skill skill) {

    // Check what type of weapon the player is holding, so the game knows what type of skill to train him up for:
    // skill = weaponConfig.CheckForSkill();

    print(gameObject.name + " took damage: " + damage);

        // This function clamps the health of the player, based on taken damage
        // and if the target is dead, we want them to die and give our player some XP
        // (using the 'AwardExperience(GameObject instigator)' function)

        healthPoints.value = Mathf.Max(healthPoints.value - damage, 0); // Clamps our health value to never go negative, neither above what our player currently has

        takeDamage.Invoke(damage);        // invoking a 'TakeDamage' event (if our player is not dead),
                                          // so when our player gets hit by an enemy, we want to display
                                          // the text of the damage taken

        onTakenHit?.Invoke(instigator);     // if you get hit, you automatically fight back!

        // when the player dies:
        if (healthPoints.value == 0) {  

        onDie.Invoke(); // Invokes external UnityEvent Audio 'Die', combined with other events, when our Enemy/Player has taken enough damage to die
        // AwardExperience(instigator); // (SECOND 'AwardExperience()' FUNCTION) Award experience to whoever won the battle
        AwardExperience(instigator, skill);    // Award experience to whoever won the battle, for the chosen skill (for the player obviously) that won the battle with (Attack, Defence, Mage or Range)
        GetComponent<ActionSchedular>().CancelCurrentAction();

            }

            // ADDON LINE RIGHT BELOW THIS COMMENT:
            // else takeDamage.Invoke(damage);

            UpdateState();  // Update the Players' health state

    }

Both are in ‘Health.cs’. Any other ways to entirely eliminate the issue?

Are you saying that despite being dead, and that death cancelling the current Action, that Fighter somehow aquires a target and keeps attacking anyways? Perhaps a check in PlayerController at the beginning of the Update() method?

if(GetComponent<Health>().IsDead()) return;

There is one more thing to check… In another thread, a student had an issue with the character dying and coming back to life to get hit again over and over and over… It turned out in his case, it was because currentHealth was regenerating before the Respawn could occur. Are you doing any form of health regeneration in an Update() in Health? (It’s a common thing for students to add, but it does require ensuring that the character is not dead to begin with).

Not the fighter… The player. Yes, although he’s dead, he still comes back to life

Do you have some sort of periodic regeneration in your Health component?

None that I am aware of, no… Just that with my old combat system (I’m the same guy trying to implement the XP Based system :stuck_out_tongue_winking_eye:), we used to regenerate health when the combat level rises (which doesn’t work for now anymore since we’re replacing the system)

This line is already in my ‘Player Controller.cs’ script. Health is declared in awake, and checked for in the update() function

We really need to change what you’re calling that. The course project uses an XP based system, what you’re changing to is a Skills based system.

Sure, why not :laughing:

Privacy & Terms