Merging the Third Person Controller Course with the RPG Course

It appears to be happening some of the times

I think I see what’s going on there… When the character is still in knockback, the Chase State is trying to move the character, but ForceReceiver is holding the NavMeshAgent disabled (as it should).

See if this fixes it in Chasing State

        private void MoveToPlayer(float deltaTime)
        {
            if (stateMachine.Agent.enabled)
            {
                stateMachine.Agent.destination = stateMachine.Player.transform.position;
                Vector3 desiredVelocity = stateMachine.Agent.desiredVelocity.normalized;
                Move(desiredVelocity * stateMachine.MovementSpeed, deltaTime);
                stateMachine.Agent.velocity = stateMachine.CharacterController.velocity;
                stateMachine.Agent.nextPosition = stateMachine.transform.position;
            }
            else
            {
                Move(deltaTime);
            }
        }
1 Like

Thanks,
It does fix the error in Chasing state.
Now the errors seem more consistent and only in Patrolling state, only when the player is knocked back

So the next step would be to fix the handling of the state switching?

At the moment it goes:
(finish) Attacking
Idle
Patrolling if has path, else it skips this step. (This is where the error happens)
Chasing

Either adding a IsInChaseRange() check on Enter() and SwitchState there as first check,
or extract the handling to BaseState

Is this correct?

EDIT:
Gave it a try,
added this to EnemyPatrolState enter:

IsInChaseRange check
		if (IsInChaseRange())
		{
			stateMachine.SwitchState(new EnemyChasingState(stateMachine));
			return;
		}

It only got rid of the SetDestination error, the ResetPath error persisted obviously as we are still calling an Exit method that resets path

SetDestination error
"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)
Error after adding IsInChaseRange check
"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:114)
RPG.States.StateMachine:SwitchState (RPG.States.State) (at Assets/Scripts/States/StateMachine.cs:11)
RPG.States.Enemies.EnemyPatrollingState:Enter () (at Assets/Scripts/States/Enemies/EnemyPatrollingState.cs:32)
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)

So here’s your challenge… :slight_smile:
Both of these errors are occuring because the agent is disabled when the method is called… What did we do in the earlier instances to avoid this? :slight_smile:

Well I added a statemachine.Agent.Enabled check before any ResetPath or SetDestination calls on either of the state.

1 Like

meanwhile I deleted my entire NavMeshAgent off my player, and programmed a simple teleporter

:stuck_out_tongue_winking_eye:

this exact same rare bug happens occasionally as well when trying to gather resources from time to time, and the only way out is to restart the scene, by quitting to the main menu, and then returning to the game… I’ll try fix this on my own and keep you updated as we go (if this comment is not edited later, the bug still exists)

Just to be extremely clear, it’s the bug where the input does not get taken into consideration because of a Restoring State issue in ‘ResourceSpawner.cs’ (probably that or ‘ResourceGathering.cs’, although it doesn’t have a saving system in that script), so the computer thinks it’s probably a consumed resource, but it’s actually not…

and here is my latest version of ‘ResourceRespawner.cs’ if that helps:

using System;
using System.Collections;
using GameDevTV.Saving;
using Newtonsoft.Json.Linq;
using UnityEngine;

// Advanced Resource Respawning System, for the Third Person Implementation

namespace RPG.ResourceManager {

[RequireComponent(typeof(JSONSaveableEntity))]
public class ResourceRespawner : MonoBehaviour, IJsonSaveable
{
    [SerializeField] ResourceGathering resourceToSpawn;
    [SerializeField] int hideTime;

    private double destroyedTime;
    private TimeKeeper timeKeeper;

    private void Awake()
    {
        timeKeeper = TimeKeeper.GetTimeKeeper();
        SpawnResource();
    }

    public ResourceGathering GetResource()
    {
        return GetComponentInChildren<ResourceGathering>();
    }

    public bool IsDestroyed()
    {
        return GetResource() == null;
    }

    public int GetQuantityLeft() 
    {
        if (GetResource() == null) return 0;
        return GetResource().GetQuantityLeft();
    }

    private void SpawnResource()
    {
        var resourceObject = Instantiate(resourceToSpawn, transform.position, Quaternion.identity);
        resourceObject.transform.SetParent(transform);
        resourceObject.OnResourceDestroyed += OnResourceDestroyed;
    }

    private IEnumerator WaitAndRespawn()
    {
        var elapsedTime = (float)(timeKeeper.GetGlobalTime() - destroyedTime);
        // yield return new WaitForSeconds(hideTime - elapsedTime);
        yield return new WaitForSecondsRealtime(hideTime - elapsedTime);
        SpawnResource();
    }

    private void OnResourceDestroyed(ResourceGathering resourceNode)
    {
        resourceNode.OnResourceDestroyed -= OnResourceDestroyed;
        destroyedTime = timeKeeper.GetGlobalTime();
        StartCoroutine(WaitAndRespawn());
    }

    public JToken CaptureAsJToken()
    {
        var data = new ResourceData(destroyedTime, IsDestroyed(), GetQuantityLeft());
        return JToken.FromObject(data);
    }

    public void RestoreFromJToken(JToken state)
    {
        var data = state.ToObject<ResourceData>();
        destroyedTime = data.DestroyedTime;

        var shouldBeDestroyed = data.ShouldBeDestroyed;
        var quantityLeft = data.QuantityLeft;

        if (shouldBeDestroyed && !IsDestroyed())
        {
            // Should be destroyed, but isn't... destroy it
            var resourceObject = GetResource();
            resourceObject.OnResourceDestroyed -= OnResourceDestroyed;
            resourceObject.DestroyResource();
            StartCoroutine(WaitAndRespawn());
        }
        else if (!shouldBeDestroyed && IsDestroyed())
        {
            // Shouldn't be destroyed, but it is... spawn it
            SpawnResource();
            GetResource().quantityLeft = quantityLeft;
        }
        else if (shouldBeDestroyed && IsDestroyed()) 
        {
            // Should be destroyed, and is indeed destroyed... reset the timer
            StopAllCoroutines();
            StartCoroutine(WaitAndRespawn());
        }
        else 
        {
            // Shouldn't be destroyed, and isn't destroyed... reset the quantity
            var resourceObject = GetResource();
            GetResource().quantityLeft = quantityLeft;
        }
    }
}

[Serializable]
public struct ResourceData
{
    public double DestroyedTime;
    public bool ShouldBeDestroyed;
    public int QuantityLeft;

    public ResourceData(double destroyedTime, bool shouldBeDestroyed, int quantityLeft)
    {
        DestroyedTime = destroyedTime;
        ShouldBeDestroyed = shouldBeDestroyed;
        QuantityLeft = quantityLeft;
    }
}

}

didn’t fix the previous bug and just kinda squandered into nilly willy again, trying to make a pickaxe for my player… (apologies, xD)

My question for now is (along with my previous issue above :sweat_smile:), where was the function responsible for assigning the integer of ‘AnimatorWeaponType’ again…?! (not the “TryHit()” one in Fighter.cs that uses it, but the one that assigns it. I want to create a fourth weaponType for my animations (I literally just don’t remember where that function went to), so I play a different blend tree when I’m holding a pickaxe, hatchet or spear).

Long story short, I have a new nested blend tree I set up for long weapons in the ‘FreeLookState’ Blend Tree, and I can’t access it because I don’t know where the function that assigns them is at, or what the name even was… (I just need to remember the name, that’s all I seek)

I fried my brain trying to figure these two problems out…

It’s the ResourceGathering that should be the ITarget for the ResourceFinder. I thought we covered this issue in another thread weeks ago. The ResourceFinder should be subscribing to OnResourceDestroyed() and removing the object from the list if that method is called

Review this page: https://gitlab.com/tkraindesigns/rpgthirdperson/-/wikis/Blend%20Tree%20Madness

we did actually, we introduced an ‘OnResourceDestroyed’ event of some sort. However, that issue still pops up occasionally when I return to the game scene, and from recent experience with the pickup system, I automatically knew this was a restoring system issue with the respawner

Hence why I have provided you with my ‘ResourceRespawner.cs’ script to have a quick look at :smiley:

Yup, fixed that, through personal try and error. Thanks again Brian :slight_smile:

This bug drove me wild-nuts today… once we get the resource respawn occasional glitch done, I’m more likely than not going straight up on this one, because it’s been annoying for months now (and I’m 99% sure it’s a race condition, because no bug happens this frequently without something being a major headache because of it…)

Edit: Another bug I noticed (and this isn’t a bug, it’s just a system override), is that ‘Attack Force’ from ‘Attack.cs’ and ‘Weapon Damage’ in ‘WeaponConfig.cs’ are both dealing damage, so it adds them up… which one is safer to delete? I don’t want a mix and mash here :sweat_smile:

please don’t forget to have a look at this bug, it’s a crucial one, and it’s been a real buzzy bug as of recently

I literally thought the respawning the player to the respawn point was fixed already… With the Malbers and all the other extra stuff, I’m not sure if I CAN figure out what’s going on… You’re in uncharted territory again…

Try not passing the weapon damage in GetAdditiveModifiers within the WeaponConfig.

the Malbers stuff honestly has nothing to do with the respawning, that system was a mess before hand as well anyway, and it has about 50% chance of working and another 50% of not working (it’s acting like a race condition as we speak, and I don’t know with what…). All I did there was to avoid teleportation just “delete” (didn’t really delete it permanently, just off the player in the scene, but this was easily reversible), and then instead of warping, I used a transform.position. Again, the Malbers system has its own namespace, and it does not interrupt with my code in any way shape or form :slight_smile:

Any other NavMesh-independent approaches for respawning you can possibly think of?

Make sure both your NavMeshAgent (if you have one) and your CharacterController(you have one) are disabled, and then set transform.position to the respawn point. Then you can re-enable the CharacterController and NavMeshAgent (if you have one).

OK I’m giving that a bit of a try. Again, it’s a random bug, so sometimes it’ll happen and sometimes it won’t (does respawning on a position off a NavMeshAgent really make a difference in how it works, though? I just noticed this was a potential issue)

For now, here’s the extra code I placed in my script (for tracking purposes):

private CharacterController playerCharacterController;

// in 'Awake():'
playerCharacterController = GetComponent<CharacterController>();

// in 'RespawnPlayer():'
playerCharacterController.enabled = false;
// teleport
playerCharacterController.enabled = true;

(no NavMeshAgents for now as we speak)

That code looks correct.
It shouldn’t matter if you’re not on the NavMesh, because you’re not using a NavMeshAgent. The only issue is if you respawn off of the NavMesh, the enemies can’t get to you until you get on the NavMesh, and that may throw some warnings for the enemy if they try to chase you.

If it does happen, an error message (related to the player) would be extremely helpful.

No warnings when they’re chasing me.

However, when they try to swing a hit against me, here’s two errors:

"ResetPath" can only be called on an active agent that has been placed on a NavMesh.
UnityEngine.StackTraceUtility:ExtractStackTrace ()
RPG.States.Enemies.EnemyPatrolState:Exit () (at Assets/Project Backup/Scripts/State Machines/Enemy/EnemyPatrolState.cs:115)
RPG.States.StateMachine:SwitchState (RPG.States.State) (at Assets/Project Backup/Scripts/State Machines/StateMachine.cs:11)
RPG.States.Enemies.EnemyPatrolState:Tick (single) (at Assets/Project Backup/Scripts/State Machines/Enemy/EnemyPatrolState.cs:77)
RPG.States.StateMachine:Update () (at Assets/Project Backup/Scripts/State Machines/StateMachine.cs:18)
"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.EnemyPatrolState:Enter () (at Assets/Project Backup/Scripts/State Machines/Enemy/EnemyPatrolState.cs:61)
RPG.States.StateMachine:SwitchState (RPG.States.State) (at Assets/Project Backup/Scripts/State Machines/StateMachine.cs:13)
EnemyIdleState:Enter () (at Assets/Project Backup/Scripts/State Machines/Enemy/EnemyIdleState.cs:17)
RPG.States.StateMachine:SwitchState (RPG.States.State) (at Assets/Project Backup/Scripts/State Machines/StateMachine.cs:13)
RPG.States.Enemies.EnemyAttackingState:Tick (single) (at Assets/Project Backup/Scripts/State Machines/Enemy/EnemyAttackingState.cs:54)
RPG.States.StateMachine:Update () (at Assets/Project Backup/Scripts/State Machines/StateMachine.cs:18)

They do NOT affect the gameplay in anyway, but they’re there

These are enemy-relevant errors, and they do NOT happen when the enemy is moving around, they only occur when he tries to swing an attack

I don’t know what I recently fixed as well (just re-baked the NavMesh), but fortunately they are no longer able to chase me off the NavMesh. It’s only me with the superpower of being able to walk on non-NavMeshAgent surfaces anymore :sweat_smile:

my guess is, based on what the errors say, it’s because they’re trying to be way-too close to the player…?

These errors are happening when the enemy is exiting and entering the Patrol State.
Paste in your EnemyPatrolState.cs…

I doubt it, they should stop chasing you when they are within attack range.

Privacy & Terms