Hmmm… rather than using an underlying bool for IsAggro()… you really want there to be a timer… so he’s only mad for so long…
If only we had some sort of CooldownTokenManager…
Hmmm… rather than using an underlying bool for IsAggro()… you really want there to be a timer… so he’s only mad for so long…
If only we had some sort of CooldownTokenManager…
I’m leaving this comment as a personal reminder to return to this in a bit. This code goes into the ‘EnemyStateMachine.cs’ and later on called in ‘EnemyBaseState.cs’, right?
I’m a little confused on what the cooldown has to do with aggro to be honest…
When the enemy takes damage, set a timer “Aggro” on the CooldownTokenTimer for some amount… say 2 minutes.
When you want to know if isAggro, check to see if the CooldownTokenTimer.HasCooldown(“Aggro”)
does this go into ‘EnemyAttackingState.cs’ by any chance? I’m struggling a little bit to understand what’s going on here… please bear with me
I have this function in ‘EnemyStateMachine.cs’, I’m guessing we set the cooldown timer in there?
private void OnTakenHit(GameObject instigator)
{
if (instigator.TryGetComponent(out Fighter fighter))
{
IsAggro = true;
}
}
and then reverse ‘IsAggro’ to false in the end? This is what I tried doing:
// in 'EnemyStateMachine.cs':
[field: SerializeField] public float aggroTimer {get; private set;} = 3.0f;
private void OnTakenHit(GameObject instigator)
{
if (instigator.TryGetComponent(out Fighter fighter))
{
aggroTimer -= Time.deltaTime;
while (aggroTimer > 0f) {
IsAggro = true;
}
IsAggro = false;
}
}
needless to say, the while loop works as expected. It permanently froze my project - back to trying again…
Did you read the Cooldown timer stuff in the throttling section or just paste in the code and zip along?
In EnemyStateMachine:
private void OnTakenHit(GameObject instigator)
{
//no need to see if the instigator has a Fighter, because the Instigator cant' damage you without a fighter
CooldownTokenManager.SetTimer("Aggro", 2f);
}
public bool IsAggro()=>CooldownTokenManager.HasCooldown("Aggro");
I read it - just not enough experience with it yet
did we create that “Aggro” token out of thin-air?
And… that did not work. I made the ‘IsAggro’ an || statement in ‘EnemyPatrolState.cs’, but he still won’t patrol if the player dealt him damage, and he still acts like he’s in complete shock that he just got hit, and is permanently thinking over his life decisions…
Keep playing with it. I’m past my daily expiration date.
The biggest lesson I learned out of this, is that duplicating an enemy is as simple as throwing his prefab into the spawn manager, change his weapon in the prefab itself accordingly, and his SCENE patrol path into the Respawn Manager’s patrol path box. We can safely ignore his own patrol path box. Anyway…
OK so… I found out where the issue basically starts from
I created a clone for my warrior for testing purposes, and gave him the sword weapon at first. No patrolling issues, no problems so far… Then I gave him a bow instead of the sword he was wielding.
From my own tests, the problems begin when I give him a bow under his ‘Fighter.cs’ Script on the hierarchy. Basically, it’s not a duplication issue, it’s an issue that starts when I hand the enemy a bow instead of a sword to deal with… do I need to change anything about my bow settings to get that to work again? Here’s a screenshot of my NPC Bow Configurator (if that helps in anyway). Changing the ‘AnimatorWeaponType’ did not work, neither have I set something up for it in the blend tree:
If not, how do we fix the fact that his patrolling becomes a severe problem only when he has a bow in his hand? (for simplicity’s sake, my major complain is that THE ENEMY won’t patrol ever again if he was in a fight with the player that hurt his (the enemy’s) health), IF HE WAS WIELDING A BOW. With a sword, that’s not the case). I don’t know what the weapon and the patrol path have in common, but I know something is going on that needs to be addressed (I’m just not sure where, who or how…)
That, and I know that I’m getting no experience for dealing ranged attacks as of yet. That’ll probably be the next problem I want to deal with
As I’ve mentioned several times the bow is incomplete… I’m not sure yet if this is your issue or not, but the Aggro() is complicating things…
I can’t think of a single reason in a million years that the enemy won’t patrol after he’s been hit if and only if he’s wielding a bow. There’s no change from the StateMachine perspective between a bow and sword. The issue I’ll be addressing is that the characters don’t attack until you’re within melee range. Hopefully, though, those adjustments might lead to figuring out the other.
Here’s the deal, though… The Aggro is not part of the tutorial, and I’m not putting it in my code because, not being part of the tutorial, I don’t want to confuse the other 300 students following it. If the Aggro is breaking something from the tutorial, take it out and deal with it later.
I completely understand that, and I don’t expect you to. However, I just wanted to make sure that I’m not the only one suffering with this issue, because if I am then that’s a major problem for me
By all means, I’ll work on something else in the meanwhile until the bow’s second tutorial is released. Only then can we judge, and only then will I place my Aggro back in (again, I highly doubt that this is a reason for this issue, but I will keep it outside for now )
Here’s what I came up with on my way to work, for the Aggro
In StateMachine
[field: SerializeField] public bool IsHostile {get; private set;} = true; //Is character always hostile?
public bool IsAggro => CooldownTokenManager.HasCooldown("Aggro");
private void OnTakenHit(GameObject instigator)
{
//no need to see if the instigator has a Fighter, because the Instigator cant' damage you without a fighter
CooldownTokenManager.SetTimer("Aggro", 2f);
}
In PlayerBaseState
public bool ShouldPursue()
{
if(stateMachine.IsAggro) return true;
if(!stateMachine.IsHostile) return false;
return IsInChaseRange();
}
Then in PatrolState, IdleState, and DwellState, you can simply use
if(ShouldPursue())
{
stateMachine.SwitchState(new EnemyChaseState(stateMachine));
return;
}
why didn’t I get a notification of that… I had no clue this was even out here
I’ll give this a go and keep you updated
are you sure this goes into ‘PlayerBaseState’ and not ‘EnemyBaseState’?
Pretty sure you’re right on that one. Silly things happen when you’re free writing code/posts without the project in your hands.
haha
Oh, I almost forgot to ever mention this. This was how I used to call ‘IsAggro()’ from my State Machines:
protected bool IsAggro()
{
return stateMachine.IsAggro;
}
Do I need this, or it can go away as well?
Dealer’s choice.
not a single clue what that means
English slang for “that’s entirely up to you”. Either way works.
fair enough. Alright I’ll go give that a test and update you
soo… I’m guessing this code replaces this section, correct?:
if (IsInChaseRange()) // && IsAggro()) This line failed when we introduced projectiles, which kinda messed with patrolling for a bit...
{
// if you want the vision system to work, uncomment the if statement below:
// if (CanSeePlayer()) {
// Clearing key to ensure that at the end of the battle, the enemy finds the nearest waypoint
stateMachine.Blackboard.Remove(NextPatrolPointIndexKey);
stateMachine.SwitchState(new EnemyChasingState(stateMachine));
return;
// }
}
Obviously I’ll need to add in the blackboard line as well before switching states
Welp, almost there. The last part is, can we get that cooldown timer (P.S: I added it as a property named “CooldownTimer” instead of a 2-second magic string) to only work when the player is out of combat range for the enemy? Basically, when he’s out of the targeting state
It’s not a big dealbreaker, I just find it weird that the player can be having a boss fight, and if the player didn’t hit the boss for a whole 3 seconds, the boss would forget he was in a fight to begin with - that would be too easy