Merging the Third Person Controller Course with the RPG Course

Let’s add a Debug.Log here to ensure that we’re getting called

protected override void RemoveTarget(PickupTarget target)
{
    Debug.Log($"Removing {target.gameObject} from the list");
    base.RemoveTarget(target);
    target.OnPickedUp-=RemoveTarget;
}

You should see this message whenever you get out of range of a target, or whenever the target is picked up.

Alright, I followed through a bit and I think It’s working now - not entirely sure, though I haven’t been able to reproduce the bug.

I had a script (which I completely forgot about, sorry @Brian_Trotter :pray: :pray: :pray:) that handled picking up gold on trigger enter (filter player tag). I think that it got picked up, but didn’t call the remove event - which caused it to be stuck as current target.

After I added the print,
noticed the bug happens mostly when I fight and kill enemies near the loot.
and that I often had some gold (not a lot though) in my inventory but nothing else. :flushed:

For anyone who might find this useful (as simple as it might be ):
Here is an updated version I created for my OnEnterPickup.cs,

OnEnterPickup.cs
using RPG.Inventories;
using UnityEngine;

[RequireComponent(typeof(PickupTarget))]
public class OnEnterPickup : MonoBehaviour
{
	[SerializeField] private PickupTarget pickupTarget;

	private void OnEnable()
	{
		pickupTarget = GetComponent<PickupTarget>();
	}

	private void OnTriggerEnter(Collider other)
	{
		if (other.CompareTag("Player"))
		{
			pickupTarget.PickupItem();
		}
	}
}

I made it so it calls the method from “PickupTarget” so It doesn’t have to subscribe to the event itself just call the method from the target to handle everything - and still be a component that I can throw on any item I think should be picked up automatically

1 Like

Hi @Brian_Trotter , sorry to bother again

It appears that enemy animators are sort of bugged at the moment - Pausing the game causes their forward speed to become NaaN, and they dont recover from that automatically on state transitions.

here are the prints from deltaMovement calculation on PatrollingState / Chasing State + animator window:

while unpausing makes gross speed update, it doesn’t update the “FreeLookSpeed” parameter
(recreated on demo project as well)

Any takes on a fix?

EnemyPatrollingState.Tick():
	public override void Tick(float deltaTime)
		{
			if (IsInChaseRange())
			{
				//Clearing key to ensue that at the end of the battle, the enemy finds the enarest wayopoint
				stateMachine.Blackboard.Remove(NextPatrolPointIndexKey);
				stateMachine.SwitchState(new EnemyChasingState(stateMachine));
				return;
			}

			if (IsInAcceptanceRange())
			{
				//Once were close enough t the waypoint we head to a Dwell state
				stateMachine.SwitchState(new EnemyDwellState(stateMachine, dwellTime));
				return;
			}

			//This code is the same as out chase state
			Vector3 lastPosition = stateMachine.transform.position;
			MoveToWayPoint(deltaTime);
			Vector3 deltaMovement = lastPosition - stateMachine.transform.position;
			float deltaMagnitude = deltaMovement.magnitude;
			float grossSpeed = deltaMagnitude / deltaTime;
			stateMachine.Animator.SetFloat(FreeLookSpeedHash, grossSpeed / stateMachine.MovementSpeed,
				stateMachine.AnimatorDampTime, deltaTime);

			Debug.Log(
				$"FreeLookSpeed: {grossSpeed / stateMachine.MovementSpeed}  grossSpeed: {grossSpeed} , movementSpeed: {stateMachine.MovementSpeed}");

			if (deltaMagnitude > 0)
			{
				FaceTarget(stateMachine.transform.position - deltaMovement, deltaTime);
			}

			else
			{
				FaceTarget(targetPatrolPoint, deltaTime);
			}
		}

EDIT:
Video

(also enemies hit eachother :sweat_smile:)

This is how I did the enemies hitting each other thing fix,

On Fighter.cs
var:

private bool isEnemy;

Start:

  isEnemy = gameObject.CompareTag("Enemy");

TryHit foreachloop (after the self gameobject check):

if (isEnemy && other.gameObject.CompareTag("Enemy")) continue;

still thinking how should I fix the NaaN thing, maybe listen to WindowController OnAllWindowsClosed and put .5f in the FreeLookSpeed?

Ok, I took a look, and as it turns out, even when TimeScale is set to 0, Update() is still called, but deltaTime is zero, and this is where our issue lies.
If deltaTime is zero, then dividing the magnitude/deltaTime creates the NaN.
Simply starting the Tick() in Patrol and Chasing State with

if(deltaTime==0.f) return; 

fixes the issue.

1 Like

I was going to touch on that at a certain point, but I was going to point out that it is a creative decision. In reality, if you throw a punch at the bad guy and it hits your best buddy by accident, your best buddy still gets a black eye. Friendly fire is unfortunately the way of reality.

In my personal project, each character (including the player) gets a Team, and the teams have allies and enemies (a bit like the Physics Layer overlaps). That lets me have NPCs actually attacking each other (sort of like in World of Warcraft).

1 Like

This sound incredible! Seems like a very cool way to set up player and npcs getting into random events together (i.e. ambushes, camp attacks etc)
I just might yoink that idea in the future :sweat_smile:

Thanks for the help Brian, I have a midterm showcase today and Im crunching to get some stuff working after the merge (No, I did not heed the warnings. :skull: The horror! )

Meanwhile I got my dodge and AOE Stun ability working for now, and worked on some animations.
Had to make a state specific SwitchState Effect strategy to get the player stomping, but for now it’s good enough

This is from yesterday + this last hour’s work (it’s 7:30AM here)

Go to your nearest blackboard and write the following 200 times :rofl:

Git is my friend, I will use Source Control...
1 Like

:rofl: :rofl: :rofl: :rofl: :rofl: :rofl:

I had just enough sanity left to do that

1 Like

lol don’t be surprised, but this idea was on my radar for a while… just that my project is in no way stable to even think of implementing this (or any new ideas in general) anytime soon :stuck_out_tongue_winking_eye:

SPOILER ALERT

Good day Brian. After the agent disabling line of code, which script do we integrate the ‘minimumImpactVelocity’ and ‘smoothDamping’ scripts into? Instructions unclear, apologies :slight_smile: (P.S: It’ll probably be a while before I can test this out. My laptop recently became insanely slow, and I have no idea why…)

And since we’re already here, what’s the next step? :slight_smile:

Bahaa, right above where you quoted the tutorial, it says to add this to ForceReciever. If you look at the bottom of the page, there is a link to a complete list of all the changes Brian made in this lesson. Scroll down to the ForceReciever.cs entry and it shows every line that is added or removed. This is one of many amazing benefits of using source control. Also at the bottom of the page it shows the title of what is next. In this case, it is impact states. He is still basically following the order from the 3rd person class.

he did mention the Force Receiver for the first part, but looking at the bottom function of the image I quoted, there’s no declaration of where exactly does the impact (or the lines that follow along) go to… hence why I’m confused

lol I’m not sure if my page is somehow different,but at the end of the screenshot I uploaded, there’s… well… no git changes or any indication of what’s next :slight_smile:

Edit: I REFRESHED the page, now I see what you’re talking about… :sweat_smile:

All of the code in the drop down section goes in ForceReceiver. BTW, you probably should have put that screen shot in a spoiler. It is the answer to a challenge and other students might not want to see it.

How do you put it in a spoiler? Never used that before :sweat_smile:

Summary

Use the gear icon above.

There are two options!

fixed it :slight_smile: - time to go back to figuring out where the code goes…

1 Like

Everything in that image goes in the ForceReceiver. A quick hint for that is if you look in ForceReceiver.Update, you’ll find the line

impact = Vector3.SmoothDamp(impact, Vector3.zero, ref dampingVelocity, drag);

This line is the last line in the Update() method. The rest of the lines in that code are added.

As a rule of thumb, if I switch to a different script in a section, I will say so in the text.

So if I say “In ForceReceiver”, everything after that will be in ForceReceiver until I say something like, “Now in EnemyBaseState” (or some other script).

For the most part, going forward, this will be the format, rather than wholesale pasting of the entire method. Three reasons:

  • It makes you look more closely at your existing code to piece in what we’re adding
  • Some of these scripts are getting pretty long, so it seems a bit silly to keep posting the entire text.
  • The completed scripts are available in each page’s GitLab commit.
1 Like

understood. I also managed to test it recently :smiley:

I also agree with the approach you’re taking

this is an occasional bug that currently exists

If you kill an enemy, quit to the main menu and return, and then kill another enemy, or maybe even get close to any sort of pickup and hit the ‘P’ key (the one assigned to pickup items off the ground), you’ll get this error from time to time:

MissingReferenceException while executing 'performed' callbacks of 'Player/Pickup[/Keyboard/p]'
UnityEngine.InputSystem.LowLevel.NativeInputRuntime/<>c__DisplayClass7_0:<set_onUpdate>b__0 (UnityEngineInternal.Input.NativeInputUpdateType,UnityEngineInternal.Input.NativeInputEventBuffer*)
UnityEngineInternal.Input.NativeInputSystem:NotifyUpdate (UnityEngineInternal.Input.NativeInputUpdateType,intptr)
MissingReferenceException while executing 'performed' callbacks of 'Player/Pickup[/Keyboard/p]'
UnityEngine.InputSystem.LowLevel.NativeInputRuntime/<>c__DisplayClass7_0:<set_onUpdate>b__0 (UnityEngineInternal.Input.NativeInputUpdateType,UnityEngineInternal.Input.NativeInputEventBuffer*)
UnityEngineInternal.Input.NativeInputSystem:NotifyUpdate (UnityEngineInternal.Input.NativeInputUpdateType,intptr)

If I’m not mistaken, I think last time I dealt with something like this, when working on the Resource Gathering System, it was fixed by unsubscribing from an event of some sort, but… that’s not the case for me now, and here’s what I currently have in ‘PickupFinder.cs’:

using System.Linq;
using RPG.Core;
using UnityEngine;

namespace RPG.Inventories 
{
    public class PickupFinder : RangeFinder<PickupTarget> 
    {

        public PickupTarget GetNearestPickup() 
        {
            CurrentTarget = Targets.OrderBy(t => Vector3.Distance(transform.position, t.transform.position)).FirstOrDefault();
            return CurrentTarget;
        }

        protected override void AddTarget(PickupTarget target)
        {
            base.AddTarget(target);
            target.OnPickedUp += RemoveTarget;
            Debug.Log($"Pickup Finder: Adding {target.name}");
        }

        protected override void RemoveTarget(PickupTarget target)
        {
            base.RemoveTarget(target);
            target.OnPickedUp -= RemoveTarget;
            Debug.Log($"Pickup Finder: Removing {target.name}");
        }

    }

}

Any idea where else do I need to change my code to fix this?

Privacy & Terms