Merging the Third Person Controller Course with the RPG Course

hello again Brian. For Tutorial number 37, regarding the timers, is this section purposely left empty, or is something missing?

That aside, there are only two scripts, the ‘CooldownTokenManager.cs’ and the ‘EventPool.cs’, right? Do those go on the player and enemies, or… where do they go?

It’s not that it’s left empty, it’s that both ideas were conquered with the one section. Eventually, I’m going to flesh out the whole thing and break down step by step how I got to the final script, but I ran out of time to work on writing this, so, realizing that where we are right now is sufficient for enemy throttling (the rest is almost all about eliminating Update and allowing UI to easily react to the timers). I’ll eventually go back and finish the rest. For now, the finished classes are in place.

The CooldownTokenManager will go on both the Player and the Enemies and and will need to be added to the [field:SerializeField] like the rest of the components (we’ll cover that in the next section). The EventPool is not a MonoBehaviour, it’s a class that’s used (three times!) in the CooldownTokenManager.

for now, while I can just do that right now, I think I’ll wait for the next tutorial so as not to confuse things up

Hi Brian, thanks for the CD Manager lesson.
Is there any chance to push the lecture’s commit?

Cheers :slight_smile:

Edit:
Thought I’m missing some instructions,
Just read the part that states that this is groundwork for the next lecture,
In that case no rush, I already added the scripts :pray:

The next lecture’s finalized code is written, and tested. Just have to write the actual lesson. That’s usually the hardest part for me. Believe it or not the actual code changes were quick, it’s explaining why they work and writing it so that it’s understandable to newbies and doesn’t get TLDR’d by intermediates and advanced students.

1 Like

I wonder what’s next… :slight_smile: - what’s the next lecture going to be about? (I’m all hyped for the ranged system because I want to add destructive gameObjects in my game. You know… everyone loves a little bit of explosion :slight_smile:, and a little bit of heavy camera vibration to match with it)

By the way, with throttling (the enemy, I plan to try and throttle the player as well and see how it feels) out of the way, this function in ‘Fighter.AttackBehaviour()’ complains whenever I try eliminate ‘timeBetweenAttacks’ in ‘WeaponConfig.cs’. Can I safely eliminate this?:

if (timeSinceLastAttack > currentWeaponConfig.timeBetweenAttacks && CheckForProjectileAndSufficientAmmo()) {

        // Triggering the Attack Event (and resetting the timer to next attack):
        TriggerAttack();
        timeSinceLastAttack = 0; // Resets timer to calculate how long we need to wait before replaying the attack animation

        }

this, and ‘timeBetweenAttacks’ in ‘WeaponConfig.cs’


Also, I tried to throttle the player, but that did NOT go well. Here’s what I tried doing:

  1. in ‘PlayerStateMachine.cs’, I added the following lines of code:
        // TEST (Variable Declaration):
        [field: SerializeField] public CooldownTokenManager CooldownTokenManager {get; private set;}

       // in 'OnValidate()':
       if (CooldownTokenManager == null) CooldownTokenManager = GetComponent<CooldownTokenManager>();

  1. in ‘PlayerAttackingState.cs’, I added the following:
// this line goes as an extra check in the FIRST 'if' condition in 'PlayerAttackingState.Tick()':
&& normalizedTime > currentAttack.Cooldown

// in 'Exit()', after the Root Motion deactivation:
            // TEST
            stateMachine.CooldownTokenManager.SetCooldown("Attack", currentAttack.Cooldown);

The player basically just freezes in time after the first swing is successfully done. Where have I gone wrong…?!

While you should be adding the cooldown in the Exit() of PlayerAttackingState, that’s really all we’re doing. If you review what we add to the EnemyAttackingState, you’ll find it’s only adding the cooldown in Exit(). There’s really no reason to add anything else to PlayerAttackingState.

Where we want to check for a cooldown is whenever we’re going to attack from outside the PlayerAttackingState. That would be within the events responding to the Attack button in PlayerTargetingState and PlayerFreelookState. In your case, I believe you’re only allowing attacks in the TargetingState, so you’ll simply want to check to see if the CooldownTokenManager has the cooldown and not attack if it does.

I’m sorry, I didn’t fully understand this part. Can you please elaborate further?

soo… just add this line in ‘PlayerAttackingState.Exit()’, right?:

    // TEST: Cooldown after an attack happened:
            stateMachine.CooldownTokenManager.SetCooldown("Attack", currentAttack.Cooldown);
        

I’m guessing we don’t need this one:

because by doing just that, he still freezes after the first swipe…

You’re correct, you don’t need it. In fact, if you have it, you’ll likely lock up your player unless the cooldown starts at less than 1. Normalized time is between 0 and 1, it’s the percentage that something is finished. But it has nothing whatsoever to do with cooldowns.

Within PlayerTargetingState(), we have an if state to see if we’re attacking:

            if (stateMachine.InputReader.IsAttacking)
            {
                stateMachine.SwitchState(new PlayerAttackingState(stateMachine, 0));
                return;
            }

You should also check (with an && in the if statement) to make sure there is no “Attack” cooldown in progress… something like !stateMachine.CooldownManager.HasCooldown("Attack)… you know, the same check we make in EnemyChasingState(). We don’t need to worry about the Move() stuff, in this case because we’re already calculating movement with the controller… you’re just adding not having a cooldown to the condition for entering Attack state.

ironically, even without it, my player still locks up. I keep some of my cooldown times below 1 second for the intense wars… Do I need it longer than 1 second to avoid locking up? How can we avoid locking up overall?

AND… Placing this code:

in the if statement mentioned in ‘PlayerTargetingState.Tick()’, results in this NRE:

NullReferenceException: Object reference not set to an instance of an object
RPG.States.Player.PlayerTargetingState.Tick (System.Single deltaTime) (at Assets/Project Backup/Scripts/State Machines/Player/PlayerTargetingState.cs:23)
RPG.States.StateMachine.Update () (at Assets/Project Backup/Scripts/State Machines/StateMachine.cs:18)

which is basically the line where we added the Cooldown checking condition

Edit: I forgot to add the ‘CooldownTokenManager’ back to the player and check for the cooldown token manager in ‘OnValidate()’. My bad… :sweat_smile:

albeit the cooldown only occurs when the attack combo is done, right? And the randomizer we had in one of the previous lessons ensures we don’t always reach the end?

Sometimes it’s just easier to wait until you figure out what weird thing you did and it’s all solved before I can get to it…

I have to assume it’s locking up because of the quote above… a shorter cooldown should just mean you can attack quicker.

Correct, the combos should bypass the cooldown or they will never actually happen.

I only had the randomizer in the Enemies, but yeah, that’s the idea.

yup, that was the problem… If one day I decide to unlock my attack out of combat mode though, will this system have any issues I need to be aware of? (when it comes to ranged attacks, this will be something to think of)

I’ll find where it was and try replicate it in my player and keep it commented out, JUST IN CASE :slight_smile:

You’ll just add the same check in PlayerFreelookState before entering PlayerAttackingState, just like you did in PlayerTargetingState. It really is that easy.

OK so let me get this straight, because this one was a whacko job. The condition must be met in the Attack State introduced in ‘tick()’, right? I introduced it in the attack switch in ‘HandleAttackButtonPressed()’ as well (I really need to change that to ‘HandleInteractButtonPressed()’ instead, and set that to “E”…), and it was as good as pointless, but it worked when I added the condition to the state switch in’Tick()’

I can delete the condition check from the switch that happens in ‘HandleAttackButtonPress’, right? Apart from that, what’s the next step on this roadmap? :stuck_out_tongue:

        void HandleAttackButtonPressed()
        {
            if (stateMachine.Targeter.HasTargets)
            {
                if (!stateMachine.CooldownTokenManager.HasCooldown("Attack"))
                {
                    stateMachine.SwitchState(new PlayerAttackingState(stateMachine, 0));
                }
                return;
            }

            if (stateMachine.PickupFinder.HasTargets)
            {
                InputReader_HandlePickupEvent();
                if (stateMachine.PickupFinder.CurrentTarget) return;
            }

            if (stateMachine.ConversantFinder.HasTargets)
            {
                InputReader_HandleDialogueEvent();
                if (stateMachine.ConversantFinder.CurrentTarget) return;
            }
            stateMachine.SwitchState(new PlayerAttackingState(stateMachine, 0));
        }

that didn’t work either… It’s all good though, as long as the one in ‘Tick()’ works. I don’t think they make a big difference :slight_smile:

and it still baffles me why we have two switches to the attack in ‘HandleAttackButtonPressed()’, and I’m guessing that’s why it’s not working (the switch ignores the check)…

Anyway, day 1 of asking Brian what the next topic will be :stuck_out_tongue:

https://community.gamedev.tv/t/more-states/242327/17?u=edc237

Brian already told us what the roadmap looks like. I believe that jumping is next.

My impatience got me to work on these solo… I’m probably trying ranged next, mainly because mine is a little more complex than the tutorials… :skull:

I just need help with my construction system above anything else first

Hey, just a heads up for lesson 38
anyone trying to get the TargetingBlendTree switch, your enemy will slide instead of walk forward if you move your player away from the enemy.

In EnemyChaseState.cs
I added

public readonly int TargetingForwardSpeedHash = Animator.StringToHash("TargetingForwardSpeed");

and switched from FreeLookSpeedHash to TargetingForwardSpeedHash in the tick method.
Now the enemies will move in targeting mode right from the beginning (and not run / target based on distance, which is the next step perhaps), but it does look better than the slide.

Privacy & Terms