Merging the Third Person Controller Course with the RPG Course

AND… HERE IS WHERE THE PROBLEM WAS:

            // CapsuleCollider targetCapsule = target.GetComponent<CapsuleCollider>();
            CharacterController targetCapsule = target.GetComponent<CharacterController>();

I was trying in “GetAimLocation()” to get the height of a Capsule Collider (which I no longer have on my enemies) instead of the Character Controller

radius != height. Height should be what’s affecting floating on the ground.

Here’s the stats for the CharacterController I’m using:
image

Ahh, that’s good to know… We fixed it though, by getting the Character Controller instead of the Capsule collider, and now it’s insanely accurate :laughing: (I apologize for troubling you with this one)

I still have 3 problems though:

  1. This one:
  1. The impact forces, although it’s set to a low number on the attack animation, are… a little too excessive, and sometimes push the enemy back a little too much

Any idea why this is happening, or how to fix it? It’s making testing a bit too hard :sweat_smile:

and…

  1. This is my current priority bug:

I Desperately need to fix this before moving on to anything new, otherwise it’ll haunt me down for an insanely long time. Any idea how to start investigating this problem?

Looks like in the if(IsInAttackingRange()) block, the else (as in we still have a cooldown) needs to have an additional line in it

FaceTarget(stateMachine.Player.transform.position, deltaTime);

The projectiles are actually using the damage itself as part of the equation to determine the pushback. You could pass along the Attack when you set it up, pass along the knock back value, or tweak the formula. Right now, I’m using transform.forward * damage… you could multiply this value by .5f, perhaps to adjust the knockback downward.

Any chance this tooltip is with a

[field: SerializeField] public someType MyVariable {get; private set;}

in this case, you also need to add field to the tooltip

[field: Tooltip("This is a tooltip for a field:SerializeField variable");

This applies to any attributes you wish to add to a [field: SerializeField]. Not sure why Unity went that way.

Make sure that the value isn’t being overridden in the Scene…
For example, if you set a value in the scene implementation of a prefab, no amount of changes to the prefab will change this value because an overriding value is serialized.

Check the animations for extra events. Log out the TakeDamage method with something like

Debug.Log($"{gameObject.name} has taken {damage} from {instigator.name}");

and then look at the stack trace to see what methods are calling TakeDamage…

I’m assuming this is done in the ‘EnemyAttackingState.cs’, in this block of code:

if (IsInAttackingRange())
            {
                if (!stateMachine.CooldownTokenManager.HasCooldown("Attack"))
                {
                FaceTarget(stateMachine.Player.transform.position, deltaTime); // <- new line here
                stateMachine.SwitchState(new EnemyAttackingState(stateMachine));
                return;
                }

                else 
                {
                    Move(deltaTime);
                    // stateMachine.Animator.SetFloat(FreeLookSpeedHash, 0);
                    stateMachine.Animator.SetFloat(TargetingForwardSpeedHash, 0);
                    return;
                }
            }

            else MoveToPlayer(deltaTime);

that’s the only “IsInAttackingRange()” I can find in my code, and I can see where this is going. Any chance we can get the facing done right for the projectile itself, rather than the enemy? I think this would be a better solution, as it will give the player a chance to evade a fight, if necessary. What do you think? (I’m debating the idea in my head)

Ahh, a whole lot better now :slight_smile:

yup, that’s what happened… :sweat_smile:

OK I’m a little confused… how do we fix this? I think that’s exactly where I went wrong

I’ll start debugging this right as soon as I get the enemy scene thingy fixed :smiley:

This should be happening in the else section of this, just before the return statement.

Not even sure what you’re meaning there.

Right click on the component in the scene, select Modified Component(or properties, or a few other ways it’s expressed over several versions) and then select Revert.

does the same procedure work for an enemy that only exists as a prefab, but is only instantiated in the scene by the Respawn Manager? Because the variables that never change only occur there… I don’t even know how this happened tbh

ahh nevermind that… my character though does not rotate consistently as he tries to attack, and for non-homing missiles, this makes evading the missile insanely easy. I’ll go through my code again to see if I can spot where I made the change for that

Then I’m not sure what’s going on. The RespawnManager should be instantiating the Prefab, in which case the values in the prefab should be what’s in play, unless you’re intentionally changing those values via the RespawnManager.

lol I just found out EXACTLY what’s causing the problem. Here you go:

// in 'EnemyStateMachine.cs:'

    private void Awake() 
    {
        if (Fighter) Fighter.OnWeaponChanged += HandleWeaponChanged;
    }

    private void HandleWeaponChanged(WeaponConfig weaponConfig) 
    {
        if (weaponConfig) 
        {
            PlayerChasingRange = weaponConfig.GetTargetRange() * 0.8f; // the player has a slight advantage now, because the enemy can't fully reach him whilst he's in targeting mode
            PlayerChasingRange = Mathf.Max(PlayerChasingRange, weaponConfig.GetWeaponRange()); // keep the range of pursuit of the enemy below the players' targeting range
            PlayerChasingRangedSquared = PlayerChasingRange * PlayerChasingRange;
        }
    }

I think this was from the new projectile tutorial… Any idea how we can fix this?

So… you don’t want the equipped weapon to drive the values for the enemy? Then delete this code. Problem solved.

ah well, time to investigate the big old ‘double-damage dealt’ bug :slight_smile: - after that, I’ll investigate why in the world do I still instantiate a hit effect on the player, even if the projectile missed him

I wanted to plug an Egyptian meme here tbh… :stuck_out_tongue:

Edit: I went and thought about this a bit more, and as it turns out, this is one fancy way of changing the chasing range, and it allows me to make it a private variable, so I ended up deciding to keep it :slight_smile:

TakeDamage, at the beginning and at the end, logs out the expected value, and animations only have one event on them… Nothing wrong with the text spawner, but the damage being dealt itself to the player is twice for some reason (as if something external is applying more damage that I am uncertain of)… Any other ideas?

and this only occurs for the Enemies’ Melee attacks (the Enemy ranged attacks are perfectly fine, sometimes it does double the hit though… and the players’ Melee and Ranged attacks are perfectly fine as well… so it’s narrowed down to just the enemies’ melee attacks)

LOL… I think I see where the problem is coming from. Remember when I used to complain that only incredibly nearby damage will cause the projectile system to work? Yup, that’s probably the reason why. I noticed that because even the projectiles from the enemy deal double the damage if the player is like incredibly close, and when he takes a couple of steps back, the values return to normal…

But I still have absolutely no idea what’s the reason behind this, and naturally, no idea how in the world to fix that

Edit: When I got off the computer, a hot fix got into my mind. Here’s how I did it. I went to ‘Health.TakeDamage()’, and replaced the ‘healthPoints.value’ algorithm from this:

healthPoints.value = Mathf.Max(healthPoints.value - damage, 0);

to this:

            // if you're a player, and your enemy has an attack weapon, half the damage you lose because of him (since some weird glitch doubles it, I don't know where from though)
            if (GetComponent<SkillStore>() && (instigator.GetComponent<Fighter>().GetCurrentWeaponConfig().GetSkill() == Skill.Attack || instigator.GetComponent<Fighter>().GetCurrentWeaponConfig().GetSkill() == Skill.Ranged) && instigator.CompareTag("Enemy"))
            {
                healthPoints.value = Mathf.Max(healthPoints.value - damage / 2, 0);
            }

            else healthPoints.value = Mathf.Max(healthPoints.value - damage, 0);

I still desperately want to know where I went wrong, but for the time being this is a hot-fix, until I can think of something else (it still doesn’t solve the problem of ‘the Ranger hits double when we’re too close to him’ though (I tried, but failed)… and I’m guessing the reason for this one is that he fires two arrows when we’re too close or something. I say this because before the long distance arrows worked, only short distance ones did, so I’m guessing that one is still there)

and a side note, change the ‘hitEffect’ instantiation line from this:

if (hitEffect != null) Instantiate(hitEffect, GetAimLocation(), transform.rotation);

to this:

            if (hitEffect != null) Instantiate(hitEffect, transform.position, transform.rotation);

otherwise the particles will play everytime on the target (enemy or player), even if it hit some sort of terrain, and just confuse everyone

Is it fixed? I’d say for the moment, but I’d still appreciate Brian’s input on this, because this seems like a cheap ticket out of a problem :sweat_smile:

This reads like the TakeDamage method is applying the damage twice. Once at the beginning and once at the end. Post the whole method so we can look.

sure thing, here you go (it’s a little messy though, but these comments help me understand what I’m doing). I wrote “// this is the troublesome line” beside where the changes make a difference:

    // OUT OF COURSE PARAMETER: Skill skill, as the player now inputs 'skills' to gain XP according to the damage he did
    // (the beauty here is that 'TakeDamage' now gives the player XP based on the weapon he used to win the war):
    public void TakeDamage(GameObject instigator, float damage, Skill skill = Skill.None) {

            // 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, Skill skill)' function)

            healthPoints.value = Mathf.Max(healthPoints.value - damage, 0); // this is the troublesome line

            takeDamage.Invoke(damage);        // initiate the damage text spawner and other mechanics

        OnTakenHit?.Invoke(instigator);     // I was testing with this one... it does nothing right now though, just a debug

        OnDamageTaken?.Invoke(); // for now, just aggregate and set the cooldown timer for the enemies

        // Adding damage count to the skill currently doing the damage, so we can, by the end of the fight, award
        // the fight experience to the skill that did the most damage:
        AddDamage(skill, damage);

        // when the player dies:
        if (IsDead()) {

        onDie.Invoke(); // Invokes external UnityEvent Audio 'Die', combined with other events, when our Enemy/Player has taken enough damage to die

        // Based off the damage accumulated by 'AddDamage(skill, damage)' above, we now award experience
        // after the fight to the skill that has done the most damage within the fight:
        AwardExperience(instigator, GetMostDamagingSkill());
        
        GetComponent<ActionSchedular>().CancelCurrentAction();

            // This UpdateState() is an addon here, to ensure the player truly dies on his death:
            UpdateState();

            }

            // This else makes sure that the Update happens anyway
            else {
                UpdateState();
            }

        }

The line you tagged looks good. There are four lines of code that follow it. Take a look at takeDamage, OnTakenHit, OnDamageTaken, and AddDamage. Probably one of them mistakenly is also adding damage. If you can’t find it, post them and I will look when I get a few minutes (I am at work now).

the small t of ‘TakeDamage’ (they make a difference) is called only in ‘AIController.Start()’ (obsolete script, although it’s still on the player because it contains the XP Reward System. Overall though, it’s deactivated), and then in ‘HealthBar.cs’, so we can display the changes to the health bar of the player

‘OnTakenHit’ is called in my custom ‘AggroGroup.cs’ script to add and delete fighters:

        public void AddFighterToGroup(EnemyStateMachine enemy)
        {
            // If you got the fighter you want to add on your list, return:
            if (enemies.Contains(enemy)) return;
            // For other fighters on the list, add them:
            enemies.Add(enemy);
            enemy.GetComponent<Health>().OnTakenHit += OnTakenHit; // NEW LINE
        }

        public void RemoveFighterFromGroup(EnemyStateMachine enemy)
        {
            // if the enemy is gone, don't try removing him again:
            if (enemy == null) return;
            // else Remove fighters from the list
            enemies.Remove(enemy);
            enemy.GetComponent<Health>().OnTakenHit -= OnTakenHit;
        }

and in ‘Fighter.cs’ but only as a debugger. I had plans to try something that already exists back then

and then there’s all of this in ‘EnemyStateMachine.cs’:

    private void OnEnable()
    {
        Health.OnTakenHit += OnTakenHit;
    }

    private void OnDisable()
    {
        Health.OnTakenHit -= OnTakenHit;
    }

    private void OnTakenHit(GameObject instigator)
    {
        CooldownTokenManager.SetCooldown("Aggro", CooldownTimer, true); // 'true' in the end basically allows the enemy to add up to his total anger time
    }

this one was another custom function Brian created for me, so I can aggrevate nearby enemies if an enemy can ‘AggrevateOthers’:

        Health.OnDamageTaken += () => 
        {
            // TEST (if statement and its contents only - the else statement has nothing to do with this):
            if (AggrevateOthers) 
            {
            foreach (Collider collider in Physics.OverlapSphere(transform.position, PlayerChasingRange).Where(collider => collider.TryGetComponent(out EnemyStateMachine enemyStateMachine))) 
            {
                collider.GetComponent<EnemyStateMachine>().CooldownTokenManager.SetCooldown("Aggro", CooldownTimer, true);
            }
            }
            // else CooldownTokenManager.SetCooldown("Aggro", CooldownTimer, true);
        };

AddDamage is one that Brian also helped me create so I can classify which skill did the most damage, and split the XP accordingly:

    private void AddDamage(Skill skill, float damage) {

            // 1. Order the skills from the first used to the last:
            if (damageOrder.IndexOf(skill) < 0) damageOrder.Add(skill);
            // if the skill doesn't exist, add it to the dictionary, and assign a value to it:
            if (!damagePerSkill.ContainsKey(skill)) damagePerSkill[skill] = damage;
            // otherwise add damage to the currently existing skill damage:
            else damagePerSkill[skill] += damage;

    }

it’s used with another method. It has nothing to do with the damage dealt to the player as far as I understood, and the error is recent enough to eliminate this one as a possibility

I’m not seeing anything that would add damage second time. (You have unique issues :slightly_smiling_face:) Maybe one of our more seasoned veterans can spot something.

That’s what I’ve been saying all day, and it’s been frustrating me for at least 8 straight hours now to say the least :confused:

that’s my entire life with this project in a nutshell, but frankly speaking, I want to complete this one, at any cost possible :slight_smile:

// if you're a player, and your enemy has an attack weapon, half the damage you lose because of him (since some weird glitch doubles it, I don't know where from though)
            if (GetComponent<SkillStore>() && (instigator.GetComponent<Fighter>().GetCurrentWeaponConfig().GetSkill() == Skill.Attack || instigator.GetComponent<Fighter>().GetCurrentWeaponConfig().GetSkill() == Skill.Ranged) && instigator.CompareTag("Enemy"))
            {
                healthPoints.value = Mathf.Max(healthPoints.value - damage / 2, 0);
            }

            else healthPoints.value = Mathf.Max(healthPoints.value - damage, 0);

until Brian or @bixarrio (hello :stuck_out_tongue:, just tagging you in case you have any ideas, xD. The problem starts at response 445) come along, the hot fix above will be my solution to this weird problem

Making an RPG as a solo developer is a huge undertaking. You will get there eventually. Have patience.

Privacy & Terms