Merging the Third Person Controller Course with the RPG Course

This is actually from the InputReader… well… sort of…
The cause is most likely not unsubscribing from the input event in PlayerFreeLookState.
Check PlayerFreeLookState.Enter() and Exit() and make sure that everything that is subscribed in Enter() is unsubscribed in Exit()

For curiousity’s sake, also post both of those methods, because there should have been a different message (similar, but not exactly this one, and I think I know why…

yup, the subscription and unsubscription were both happening, as shown in both the ‘Enter()’ and ‘Exit()’ methods:

Enter():

public override void Enter()
        {
            stateMachine.InputReader.JumpEvent += InputReader_HandleJumpEvent;
            stateMachine.InputReader.TargetEvent += InputReader_HandleTargetEvent;
            stateMachine.InputReader.PickupEvent += InputReader_HandlePickupEvent; // here is the subscription
            stateMachine.InputReader.DialogueEvent += InputReader_HandleDialogueEvent;
            stateMachine.InputReader.ShopEvent += InputReader_HandleShopEvent;
            stateMachine.InputReader.CraftingEvent += InputReader_HandleCraftingEvent;
            stateMachine.InputReader.InteractWithResourceEvent += InputReader_HandleResourceGatheringEvent;
            stateMachine.Animator.CrossFadeInFixedTime(FreeLookBlendTreeHash, stateMachine.CrossFadeDuration);
        }

Exit():

        public override void Exit()
        {
            stateMachine.InputReader.JumpEvent -= InputReader_HandleJumpEvent;
            stateMachine.InputReader.TargetEvent -= InputReader_HandleTargetEvent;
            stateMachine.InputReader.PickupEvent -= InputReader_HandlePickupEvent; // unsubscription
            stateMachine.InputReader.DialogueEvent -= InputReader_HandleDialogueEvent;
            stateMachine.InputReader.ShopEvent -= InputReader_HandleShopEvent;
            stateMachine.InputReader.CraftingEvent -= InputReader_HandleCraftingEvent;
            stateMachine.InputReader.InteractWithResourceEvent -= InputReader_HandleResourceGatheringEvent;
        }

and if it helps in anyway, this is what my ‘HandlePickupEvent’ function looks like:

        private void InputReader_HandlePickupEvent() 
        {
            // if (stateMachine.PickupFinder.GetNearestPickup() != null) 
            if (stateMachine.PickupFinder.FindNearestTarget())
            {
                stateMachine.SwitchState(new PlayerPickupState(stateMachine, stateMachine.PickupFinder.CurrentTarget));
            }
        }

Ok, the PlayerFreeLookState looks correct.
Here’s what’s confounding me… it’s that error message in particular.

I did some more research, and it should only be popping up when you subscribe to the InputAction.performed callback (and forget to unsubscribe while the object is being destroyed). But I’m not mreaning InputReader.InputAction, I’m meaning getting the Action from the Action Map and adding Player.Pickup.Performed += HandleSomething; and forgetting to unsubscribe.

And we’re not doing that anywhere in any of our code…

lol I don’t know if this helps or not, but… here’s the Pickup Handling event data from my ‘InputReader.cs’:


    public event Action PickupEvent;

    public void OnPickup(InputAction.CallbackContext context) 
    {
        if (context.performed) PickupEvent?.Invoke();
    }

Not sure what’s going on, then. Is this a breaking error? (Is it a blip or causing a messup in the game?) Could be a Unity Glitch (which is becoming more and more common lately)

usually returning to the main menu and then coming back solves the issue, but I was hoping we can eliminate that entirely

probably not, the first time this was an issue was in the game build itself… it just took me a while to be able to get it to show up in the Engine itself

Check each script and see if it references the InputReader or UnityEngine.InputSystem; and scour the code for any subscriptions to the InputSystem or to the Controls.Player.OnPickup

I went and started scouring the Player State Machine scripts the moment you posted that message… nothing seemed to be out of the ordinary… the only interesting thing I can find was a subscription and unsubscription to the PickupItem event in the Animation Event Relay, in ‘PlayerPickupState.cs’:

// in 'Enter()':
            stateMachine.AnimationEventRelay.PickupItemEvent += AnimationEventRelay_HandlePickup;

// in 'Exit()':
            stateMachine.AnimationEventRelay.PickupItemEvent -= AnimationEventRelay_HandlePickup;

That’s not the issue. AnimationEventRelay doesn’t have anything to do with the Input System.

Are you using Input.GetKeyDown(KeyCode.P) anywhere in your code (legacy code from your project before conversion)?

skimming through the old scripts, and nope… can’t find any

Edit: here is the second error by the way:

MissingReferenceException: The object of type 'PickupTarget' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
RPG.Core.RangeFinder`1[T].FindNearestTarget () (at Assets/Project Backup/Scripts/Core/RangeFinder.cs:56)
RPG.States.Player.PlayerFreeLookState.InputReader_HandlePickupEvent () (at Assets/Project Backup/Scripts/State Machines/Player/PlayerFreeLookState.cs:100)
RPG.InputReading.InputReader.OnPickup (UnityEngine.InputSystem.InputAction+CallbackContext context) (at Assets/Project Backup/Scripts/Input Controls/InputReader.cs:145)
UnityEngine.InputSystem.Utilities.DelegateHelpers.InvokeCallbacksSafe[TValue] (UnityEngine.InputSystem.Utilities.CallbackArray`1[System.Action`1[TValue]]& callbacks, TValue argument, System.String callbackName, System.Object context) (at Library/PackageCache/com.unity.inputsystem@1.7.0/InputSystem/Utilities/DelegateHelpers.cs:46)
UnityEngine.InputSystem.LowLevel.<>c__DisplayClass7_0:<set_onUpdate>b__0(NativeInputUpdateType, NativeInputEventBuffer*)
UnityEngineInternal.Input.NativeInputSystem:NotifyUpdate(NativeInputUpdateType, IntPtr)

Then I"m out of ideas… you may need to take this to the Unity Forums

have you checked the edit as well?

This is where line 56 of ‘RangeFinder.cs’ goes to…:

using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

namespace RPG.Core 
{

    public abstract class RangeFinder<T> : MonoBehaviour where T : MonoBehaviour, ITarget
    {

        protected List<T> Targets = new List<T>();
        public T CurrentTarget {get; protected set;}

        public event System.Action<T> OnTargetAdded;
        public event System.Action<T> OnTargetRemoved;

        public bool HasTargets => Targets.Count > 0;

        private void OnTriggerEnter(Collider other)
        {
            if (other.TryGetComponent(out T target))
            {
                if (target.IsValid()) {
                AddTarget(target);
                }
            }
        }

        private void OnTriggerExit(Collider other)
        {
            if (other.TryGetComponent(out T target)) RemoveTarget(target);
        }

        protected virtual void AddTarget(T target) 
        {
            Targets.Add(target);
            // because you're invoking an event with a datatype ('T', generic in this case), we need to give 'Invoke()'
            // a datatype similar to the one set by the event up (again, 'T', a generic for now):
            OnTargetAdded?.Invoke(target);
        }

        protected virtual void RemoveTarget(T target) 
        {
            Targets.Remove(target);
            // because you're invoking an event with a datatype ('T', generic in this case), we need to give 'Invoke()'
            // a datatype similar to the one set by the event up (again, 'T', a generic for now):
            OnTargetRemoved?.Invoke(target);
        }

        public bool FindNearestTarget() 
        {
            CurrentTarget = null;
            float closestDistance = Mathf.Infinity;
            foreach (T target in Targets) 
            {
// line 56 below this one:
                float distance = Vector3.Distance(transform.position, target.transform.position); // line 56
                if (distance < closestDistance) 
                {
                    closestDistance = distance;
                    CurrentTarget = target;
                }
            }

            return CurrentTarget;

        }

    }

}

NO, because I don’t get a notification about an edit… Editing your posts to correct a typo is one thing, editing a post and adding a ton of info IS CONFUSING!.

Is this condition happening with the ill advised “L)oad” key in SavingWrapper? Or is it happening also in scene changes/load from menu?

apologies, I’ll notify you moving on from now when major changes occur :slight_smile:

I eliminated the ‘L) oad’ key update in savingWrapper. To keep this as simple as possible, this is a very occasionaly bug, and surprisingly, it always happens at the exact same time

In other words, the first time you quit to the main menu and return to your game, the bug is there. After that, the bug is no longer there regardless of how many times you switch between the main game and the main menu (and right now it’s back to not happening…)

Since the PickupFinder should only be on the Player, who should not be Singleton, I’m a bit confused as to how this could happen. When you switch scenes, everything in that scene is tossed away, disposed of, forgotten.
Then when you go into a new scene, a new PickupFinder is created.

Actually, there is one (and only one) possibility I can think of… if the RangeFinder picks up the item, but the item has already been picked up via the Save File, and gets deleted by the PickupSpawner… I’ll have to have a think about that one. It won’t be tonight, however, as I’m still on question 1 of 18 on the Udemy site…

no worries, take your time :slight_smile: - all the best with the Udemy questions as well

I had a quick look, and I do see a situation where the bug could happen when entering a scene, if the player was in range of the Pickup before it was destroyed by the saving system’s Load feature…

Go to PickupTarget.cs, and add this code


        private bool handled; //Add this
        public void PickupItem()
        {
            OnPickedUp?.Invoke(this);
            handled = true;//Add this 
            pickup.PickupItem();
        }

        //Add this entire method
        void OnDestroy()
        {
            if(!handled) OnPickedUp?.Invoke(this);
        }
1 Like

that’s brilliant, thank you Brian

I’ll keep you updated if this bug ever happens again in the future :slight_smile:

Hi Brian, thanks for the recent update.

Now this may be adressed in the next part, or in Nathan’s course, if that is the case please let me know

Getting errors for pathing on switch state exit after hitting an enemy
Since the state is switched with the agent disabled

SetDestination
"SetDestination" can only be called on an active agent that has been placed on a NavMesh.
UnityEngine.AI.NavMeshAgent:SetDestination (UnityEngine.Vector3)
RPG.States.Enemies.EnemyPatrollingState:Enter () (at Assets/Scripts/States/Enemies/EnemyPatrollingState.cs:63)
RPG.States.StateMachine:SwitchState (RPG.States.State) (at Assets/Scripts/States/StateMachine.cs:13)
EnemyIdleState:Enter () (at Assets/Scripts/States/Enemies/EnemyIdleState.cs:18)
RPG.States.StateMachine:SwitchState (RPG.States.State) (at Assets/Scripts/States/StateMachine.cs:13)
RPG.States.Enemies.EnemyAttackingState:Tick (single) (at Assets/Scripts/States/Enemies/EnemyAttackingState.cs:56)
RPG.States.StateMachine:Update () (at Assets/Scripts/States/StateMachine.cs:18)
ResetPath
"ResetPath" can only be called on an active agent that has been placed on a NavMesh.
UnityEngine.StackTraceUtility:ExtractStackTrace ()
RPG.States.Enemies.EnemyPatrollingState:Exit () (at Assets/Scripts/States/Enemies/EnemyPatrollingState.cs:108)
RPG.States.StateMachine:SwitchState (RPG.States.State) (at Assets/Scripts/States/StateMachine.cs:11)
RPG.States.Enemies.EnemyPatrollingState:Tick (single) (at Assets/Scripts/States/Enemies/EnemyPatrollingState.cs:75)
RPG.States.StateMachine:Update () (at Assets/Scripts/States/StateMachine.cs:18)
SetDestination - Chasing State
"SetDestination" can only be called on an active agent that has been placed on a NavMesh.
UnityEngine.AI.NavMeshAgent:set_destination (UnityEngine.Vector3)
RPG.States.Enemies.EnemyChasingState:MoveToPlayer (single) (at Assets/Scripts/States/Enemies/EnemyChasingState.cs:84)
RPG.States.Enemies.EnemyChasingState:Tick (single) (at Assets/Scripts/States/Enemies/EnemyChasingState.cs:41)
RPG.States.StateMachine:Update () (at Assets/Scripts/States/StateMachine.cs:18)

checked the sample version (doesn’t trigger an error), couldn’t pinpoint the source
made the updates in Mover.cs to my project (might be worth mentioning these in the tutorial post)

If the enemy doesn’t have a patrol path, only the set destination call error from the chasing state is called

What am I missing here?
Why doesn’t the sample version trigger these errors? (I actually think it should, no?)

Is this happening every time or just some of the times when the enemy is hit?

This was also an issue in the Third Person Course if the character got knocked off of the NavMesh. If that’s still happening, then perhaps my adjustments in EnemyBaseState.Move() aren’t doing the trick. I’ll sandbox it later and see if I can improve upon the movement testing.

1 Like

Privacy & Terms