Merging the Third Person Controller Course with the RPG Course

Gotten by the Auto Property I setup, I see…

        private void Awake() 
            Health.onDie.AddListener(() =>  //never use the underlying health field, only the Health with this style of auto property construction...

hmm… nope, that didn’t seem to solve the issue. Anything else I should know of?

You’re still getting a null reference with Health?

Just change the whole construction, get rid of the autoproperty stuff

Health health;
public Health Health => health;

void Awake()
    health = GetComponent<Health>();

It was mainly for demonstrating how I have null proof properties, and this construction has never failed for me before, so not sure what’s going on there…

no not that xD, the NRE is gone… sorry I fell asleep
but the targeter that switches cameras still isn’t working (i.e: I can’t focus on the guard when I get into combat and see the effects for some reason, that’s what I’m currently trying to figure out. Is it yet to come in a tutorial down the line, or did I mess something up?)

Seriously though, I don’t think we worked around Cinemachine target groups, and this is probably what’s causing me the major confusion

If you’re really seeking errors though, there’s a leaking stack trace from your projects’ fighter and mover script (from your master copy of the project), as shown below (it’s not hurting anyone though, so we can safely ignore that):

"Stop" can only be called on an active agent that has been placed on a NavMesh.
UnityEngine.StackTraceUtility:ExtractStackTrace ()
RPG.Movement.Mover:Cancel () (at Assets/Scripts/Movement/Mover.cs:66)
RPG.Combat.Fighter:Update () (at Assets/Scripts/Combat/Fighter.cs:65)

It only occurs when the player is fighting an NPC

Something else I accidentally noticed, is that when you go through portals, these controllers don’t work (just a heads up)

Edit: AND… Through debugging, I just realized the targeter doesn’t even get called to begin with. I threw a debugger in this function in ‘PlayerFreeLookState.cs’:

private void InputReader_HandleTargetEvent() 
            if (stateMachine.Targeter.SelectTarget()) 
                stateMachine.SwitchState(new PlayerTargetingState(stateMachine));
                Debug.Log("Targeter is at work");


and it never read out

Edit: I created all the hierarchy components for the targeting camera, but it still won’t focus on the enemy (and yes, he has a ‘Target.cs’ component on him)

We’ll start with this… if you don’t update the Core and Player prefabs with the updated components, GameObjects, etc, they won’t work in other scenes.
Best practice (and this isn’t just for the tutorial) is whenever you need to edit the Player, you should edit the Prefab, not the Player in the scene. Whenever you need to edit the Core, you should edit the Core Prefab, not the one in the scene.

You have to assign the states in the State Driven Camera. The StateDriven Camera switches based on entering a state in the Animator.
This isn’t explicitly covered in the tutorial, as it’s part of Nathan’s lessons, which should be referenced along the way.

This doesn’t mean the Targeter isn’t getting called, it means that the Targeter didn’t find a target. A Debug at the beginning of Targeter.SelectTarget() would be more meaningful.

This was purely a mistake on my behalf, my bad :sweat_smile:

Done that, still not working :sweat_smile:

That targeter works through Debug, but… the player still doesn’t transition for some reason (I probably need to go setup the hash names, not sure at this point of what went wrong)

I used your new Targeting code by the way (at the start of the function, the Debugger works, but the “Target Found” debugger I placed at the end of the function didn’t work unfortunately):

public bool SelectTarget()
            Debug.Log("Selecting Target...");
            if (targets.Count == 0) return false;   // no target to select
            Rect bounds = new Rect(0,0,1,1);
            Target closestTarget = null;
            float ClosestDistanceToCenter = Mathf.Infinity;
            foreach (Target target in targets.OrderByDescending(t => Vector3.SqrMagnitude(t.transform.position - transform.position)))
                Target candidate = null;
                // float candidateToCenter = Mathf.Infinity;
                Vector2 viewPos = mainCamera.WorldToViewportPoint(target.transform.position);
                if (!bounds.Contains(viewPos)) continue;
                Vector2 toCenter = viewPos - new Vector2(0.5f, 0.5f);
                float distanceToTarget = toCenter.sqrMagnitude;
                if (distanceToTarget < ClosestDistanceToCenter) candidate = target;
                else if (closestTarget != null)
                    float distanceOfCandidateToCamera = Vector3.SqrMagnitude(target.transform.position - transform.position);
                    float distanceOfClosestToCamera = Vector3.SqrMagnitude(closestTarget.transform.position - transform.position);
                    if (distanceOfCandidateToCamera > distanceOfClosestToCamera * distanceWeight) continue;
                    candidate = target;

                closestTarget = candidate;
                ClosestDistanceToCenter = distanceToTarget;

            if (closestTarget == null) return false;
            CurrentTarget = targets[0]; // select the target closest to the screen (you can only get this far in-code if you actually have someone on your targeting list, i.e: not null)
            cinemachineTargetGroup.AddMember(CurrentTarget.transform, 1, 2);    // the camera has another target to consider
Debug.Log("Target Found!");
            return true;

When you target, is it switching to the PlayerTargetingState()?
Are you Crossfading to the correct state in the Animator? These things are basically compltely unchanged from the Third Person Course, so best to review those lectures.

Apparently not. I placed a debugger in the “InputReader_HandleTargetEvent()” function in ‘PlayerFreeLookState.cs’ script, but that doesn’t get called… pretty much ever, neither does the Targeter add anything to its list, even when there’s a nearby enemy with a ‘Target.cs’ script attached to him

Well, I did add a “TargetingBlendTree” blend tree into my animator, but that’s all that I changed (and the second blend tree was my Locomotion, which I left as is… I just changed its name to “FreeLookBlendTree”, added the required parameters, and referenced it in my State Driven Camera)

So the Targeter is getting called for a SelectTarget, but isn’t getting a result from the targeting…
For now, let’s bypass the code for selecting the closest target to center vs target code…
Just put this at the beginning of SelectTarget()

Debug.Log("Selecting Target, targets.Count = {targets.Count}");
if(targets.Count==0) return false;
return targets[0];

[FIXED, Under edc’s comment]

You forgot the $ sign at the start of the debugger :stuck_out_tongue_winking_eye: (just saying that for other viewers later down the line)

and the count remains as zero, which probably means that it doesn’t detect a target to begin with (although the enemy has a Target.cs script on him)

Edit: I noticed my enemy’s capsule collider trigger was turned off. Turned it on, no result. Tried deleting it and replacing it with a Character Controller, no result either… Did a little bit of research about how ‘OnTriggerEnter()’ and ‘OnTriggerExit()’ work (because OnTriggerEnter is the only one adding the target to the list), and that failed as well… A little bit of further debugging, and my enemy actually gets detected by ‘OnTriggerEnter()’ (but that’s before the if statement…)

and the movement animations don’t work either :sweat_smile: - but we can get to that later

Thanks for creating this. I was stuck on how I wanted to handle how the hits were determined. Then I got distracted by the turn based strategy course. I had started my attempt to merge the systems by using the TPC state machine project and adding the RPG systems one by one. I did not get far. I am going to go through this tutorial on a new project. You already have some simple solutions for things I did not think of yet. Incase anyone is interested, I upgraded a copy of the RPG project from the repo to version 2022.3.12f1 and have had no issues playtesting it before starting the merge. Thanks again for all of the hard work, your efforts are appreciated.


My dummy brain, for god knows what reason, set this value up without the ‘!’ sign:

        // Checking if the target is valid, based on whether he has health or not:
        public bool IsValid() => !Health.IsDead();

This one comes from lecture 16, under ‘Target.cs’.

Now it’s time for me to go and understand why he’s extremely slow (during the targeting state), and why my movement animations are currently not working (neither in the freelook nor the targeting state… he’s moving, but no movement animation is being played in either states, and for the targeting state, he’s extremely slow, and I’m taking a wild guess that the issue is relevant to world and local coordinates or something, I don’t know tbh… probably taking the normalized vector, not the full speed number, and that’s why he’s so slow)

Oh, and if he’s in a fight in targeting state, he tends to back off instead of fight for some reason… I’m still in Lecture 18

Edit: After a bit of analysis of the blend tree, I realize the movement blend tree relies on ‘forwardSpeed’ over ‘FreeLookSpeed’, hence the animation doesn’t even play to begin with, because the blend tree variable isn’t even adjusted. I then change the variable it seeks to ‘forwardSpeed’ in code, and the issue of the value maxing out at 1.0f is still there, so now it’s a bit of a nightmare…

Edit 2: After a bit more analysis, I learned that the blendTree factor name can change, so I changed the ‘forwardSpeed’ reliance for the blend tree to ‘ForwardSpeed’, the new variable we created, and that got my freelook animations to work as well. HOWEVER, the problem that these values max out at 1.0f is still driving me nuts, I think it’s all I need to know for now

Edit 3: I fixed the ForwardSpeed issue by being a bit too smart… I took the old maximum values and converted them to a fraction that does not exceed 1.0f, which is what the normalizer gives out. Works beautifully now :slight_smile: (not for the targeting state yet though, time to investigate that)


I highly recommend you start on a copy of the repo he provided though, that’s what I’m personally doing. Do all the testing, figure out the common issues, then integrate it again into your main project :slight_smile: (although right now I’m lowkey wishing I would’ve just started with my own project, but on the long run this is good practice)

Good to see you again btw

I am working with a copy of the RPG repo. I always listen to Brian.

Are you multiplying the calculated movement by the TargetingMovementSpeed in the PlayerStateMachine? Is that value set in the Player’s PlayerStateMachine inspector?

 Move(CalculateMovement() * stateMachine.TargetingMovementSpeed, deltaTime);

Ahh… I had that accidentally set to “0.6f” instead of “6.0f”, he’s back on speed

But his animation still plays for like one frame, and never again…

If only there was a setting in the animation itself to indicate if it should stop at the end or go back to the beginning…

ahh, the good old Loop Time… Turned that on, fixed the issue :slight_smile:

but since I have changed the reliance of the freelook blend tree from ‘forwardSpeed’ to ‘FreeLookSpeed’, the enemy now approaches the player with the idle animation (i.e: he’s not programmed to search for that trigger instead).

Where in the code can we quickly fix this though…? (rusty memory… xD)

You were supposed to create a new Animator, and not touch the shared animator that the enemies and player used in the original RPG.

When we start doing state machines and change the animation logic for the enemies, they’ll switch to the new animator.

ooh dear god… OK, I’ll try doing that (might be a bit of a catastrophe though, but sure why not)

So how many new animators am I creating in total, apart from the currently existing one? Just two, right?

Privacy & Terms