RPG => 3rd Person tutorial chap 36 few errors with the Handle_ForceApplied

Hello BRian.

I’ve an error since few days according the Handle_ForceApplied method you had in chapter 36.

it happened when I added this line in the PlayerStateMachine ‘s Start method :

ForceReceiver.OnForceApplied += Handle_ForceApplied;

The console says me:

Assets\Scripts\States\Player\PlayerStateMachine.cs(61,13): error CS0123: No overload for ‘Handle_ForceApplied’ matches delegate ‘Action’

And the some in the EnemyStateMachine ‘s Start Method.

I’ve double check with the wike script database but don’t understand where I’m wrong.

Here are my 2 scripts, Player an enemy StateMachine.

using System;
using RPG.Abilities;
using RPG.Attributes;
using RPG.Combat;
using RPG.Control;
using RPG.Core;
using RPG.Movement;
using RPG.Stats;
using UnityEngine;
using UnityEngine.AI;
using Random = UnityEngine.Random;

namespace RPG.States.Enemies
{
    public class EnemyStateMachine : StateMachine
    {
        [field: SerializeField] public Animator Animator { get; private set; }
        [field: SerializeField] public CharacterController CharacterController { get; private set; }
        [field: SerializeField] public ForceReceiver ForceReceiver { get; private set; }
        [field: SerializeField] public NavMeshAgent Agent { get; private set; }
        [field: SerializeField] public PatrolPath PatrolPath { get; private set; }
        [field: SerializeField] public Fighter Fighter { get; private set; }
        [field: SerializeField] public BaseStats BaseStats { get; private set; }
        [field: SerializeField] public Health Health { get; private set; }

        [field: SerializeField] public CooldownTokenManager CooldownTokenManager { get; private set; }
       
        [field: SerializeField] public float PlayerChasingRange { get; private set; } = 10.0f;
        [field: SerializeField] public float MovementSpeed { get; private set; } = 4.0f;
        [field: SerializeField] public float RotationSpeed { get; private set; } = 45f;
        [field: SerializeField] public float CrossFadeDuration { get; private set; } = .1f;
        [field: SerializeField] public float AnimatorDampTime { get; private set; } = .1f;
        [field: SerializeField] public float Cooldown { get; private set; } = 1f;
        [field: SerializeField] public float ImpactCooldown { get; private set; } = 2.0f;

        public float PlayerChasingRangedSquared { get; private set; }
        public GameObject Player { get; private set; }

        public Blackboard Blackboard = new Blackboard();

        private void OnValidate()
        {
            if (!Animator) Animator = GetComponentInChildren<Animator>();
            if (!CharacterController) CharacterController = GetComponent<CharacterController>();
            if (!ForceReceiver) ForceReceiver = GetComponent<ForceReceiver>();
            if (!Agent) Agent = GetComponent<NavMeshAgent>();
            if (!Fighter) Fighter = GetComponent<Fighter>();
            if (!BaseStats) BaseStats = GetComponent<BaseStats>();
            if (!Health) Health = GetComponent<Health>();
        }

        private void Start()
        {
            Agent.updatePosition = false;
            Agent.updateRotation = false;
            PlayerChasingRangedSquared = PlayerChasingRange * PlayerChasingRange;
            Player = GameObject.FindGameObjectWithTag("Player");
            Blackboard["Level"] = BaseStats.GetLevel(); //Le niveau de l'enemi est maintenant stocké dans le blackboard

            SwitchState(new EnemyIdleState(this));
            if (Health.IsDead())
            {
                SwitchState(new EnemyIdleState(this));
            }
            Health.onDie.AddListener(() =>
            {
                SwitchState(new EnemyDeathState(this));
            }); Health.onResurrection.AddListener(() =>
            {
                SwitchState(new EnemyIdleState(this)); //or EnemyIdleState() in EnemyStateMachine
            });
            Health.onResurrection.AddListener(() =>
            {
                SwitchState(new EnemyIdleState(this)); //or EnemyIdleState() in EnemyStateMachine
            });
            ForceReceiver.OnForceApplied += Handle_ForceApplied;
        }
        private void OnDrawGizmosSelected()
        {
            Gizmos.color = Color.yellow;
            Gizmos.DrawWireSphere(transform.position, PlayerChasingRange);
        }
        private void Handle_ForceApplied(Vector3 force)
        {
            if (Health.IsDead()) return;
            float forceAmount = Random.Range(0f, force.sqrMagnitude);
            if (forceAmount > Random.Range(0f, BaseStats.GetLevel()))
            {
                SwitchState(new EnemyImpactState(this));
            }
        }
    }
}

using RPG.Attributes;
using RPG.Combat;
using RPG.Combat.Targeting;
using RPG.Control;
using RPG.Core;
using RPG.Dialogue;
using RPG.InputReading;
using RPG.Inventories;
using RPG.Movement;
using RPG.Shops;
using RPG.Stats;
using UnityEngine;

namespace RPG.States.Player
{
    public class PlayerStateMachine : StateMachine
    {
        [field: SerializeField] public InputReader InputReader { get; private set; }
        [field: SerializeField] public CharacterController CharacterController { get; private set; }
        [field: SerializeField] public Animator Animator { get; private set; }
        [field: SerializeField] public AnimationEventRelay AnimationEventRelay { get; private set; }//oubli dans le tuto chap 26
        [field: SerializeField] public ForceReceiver ForceReceiver { get; private set; }
        [field: SerializeField] public Targeter Targeter { get; private set; }
        [field: SerializeField] public Fighter Fighter { get; private set; }
        [field: SerializeField] public PickupFinder PickupFinder { get; private set; }
        [field: SerializeField] public ConversantFinder ConversantFinder { get; private set; }
        [field: SerializeField] public PlayerConversant PlayerConversant { get; private set; }
        [field: SerializeField] public ShopFinder ShopFinder { get; private set; }
        [field: SerializeField] public Shopper Shopper { get; private set; }
        [field: SerializeField] public Health Health { get; private set; }
        [field: SerializeField] public BaseStats BaseStats { get; private set; }

        [field: SerializeField] public CooldownTokenManager CooldownTokenManager { get; private set; }

        [field: SerializeField] public float FreeLookMovementSpeed { get; private set; } = 6.0f;
        [field: SerializeField] public float FreeLookRotationSpeed { get; private set; } = 15f;
        [field: SerializeField] public float TargetingMovementSpeed { get; private set; } = 5.0f;
        [field: SerializeField] public float CrossFadeDuration { get; private set; } = .15f;
        [field: SerializeField] public float ImpactCooldown { get; private set; } = 2.0f;

        public Transform MainCameraTransform { get; private set; }
        void Start()
        {
            MainCameraTransform = Camera.main.transform;
            if (Health.IsDead())
            {
                SwitchState(new PlayerDeathState(this));
            }
            else
            {
                SwitchState(new PlayerFreeLookState(this));
            }
            Health.onDie.AddListener(() =>
            {
                SwitchState(new PlayerDeathState(this));
            });
            Health.onResurrection.AddListener(() =>
            {
                SwitchState(new PlayerFreeLookState(this)); //or EnemyIdleState() in EnemyStateMachine
            });
            ForceReceiver.OnForceApplied += Handle_ForceApplied;
        }
        private void Handle_ForceApplied(Vector3 force)
        {
            if (Health.IsDead()) return;
            if (CooldownTokenManager.HasCooldown("Impact")) return;
            float forceAmount = force.magnitude;
            if (forceAmount > Random.Range(0f, BaseStats.GetLevel()))
            {
                SwitchState(new PlayerImpactState(this));
            }
        }

        private void OnValidate()
        {
            if (InputReader == null) InputReader = GetComponent<InputReader>();
            if (CharacterController == null) CharacterController = GetComponent<CharacterController>();
            if (Animator == null) Animator = GetComponentInChildren<Animator>();
            if (AnimationEventRelay == null) AnimationEventRelay = GetComponentInChildren<AnimationEventRelay>();
            if (ForceReceiver == null) ForceReceiver = GetComponent<ForceReceiver>();
            if (Targeter == null) Targeter = GetComponentInChildren<Targeter>();
            if (PickupFinder == null) PickupFinder = GetComponentInChildren<PickupFinder>();
            if (ConversantFinder == null) ConversantFinder = GetComponentInChildren<ConversantFinder>();
            if (PlayerConversant == null) PlayerConversant = GetComponentInChildren<PlayerConversant>();
            if (Shopper == null) Shopper = GetComponentInChildren<Shopper>();
            if (ShopFinder == null) ShopFinder = GetComponentInChildren<ShopFinder>();
            if (Health == null) Health = GetComponent<Health>();
            if (BaseStats == null) BaseStats = GetComponent<BaseStats>();
        }
    }
}

If you have an idea ?

I can’t actually test the rest of the tips you wrote like the cooldown and other.
Thanks for your help.

François

The issue is directly related to the other topic, in the declaration of OnForceApplied in ForceReceiver.
It’s declaration needs to have a Vector3

public event System.Action<Vector3> OnForceApplied;

Hello Brian.

I’m back in the game :wink:

I add to the System.Action for OnforceApplied.

Indeed it fixes all the error messages.

But I think in this chapter in the GitHub we should add too to your answer.

You wrotte:

Let’s add two events to ForceReceiver ```csharp public event System.Action OnForceApplied; public event System.Action OnForceCompleted; ```

It what i added in my code, without the after public event System.Action OnForceApplied.

Do i am able to update the code in the gitHub with your agreement Obviously ?

Thanks for your help, again :slight_smile:

I wish you and all the staff (Hello Nina) an happy new year.

Take care of you.

François

I figured out what went wonky there, it was a formatting error… On the Wiki, you have to put a line between the last line of text and the ``` marks to start a code block, and I missed the line. When not in a code block, System.Action<Vector3> looks like System.Action (believe it or not, the 2nd System.Action in that last sentence contains the <Vector3> but Markdown discarded it, demonstrating what I mean).

Yes it appears correctly now :

image

It looks that this ForceReceiver (not reciever :wink: ) focus all of my rescent problem :slight_smile:

Thanks for the help.

François

I’m a native speaker, and sometimes I mess up the i before e thing. It’s i before e except after c, making ForceReceiver correct, but there are exceptions which can throw even native speakers off… i.e. protein, financier, etc.

Don’t worry, Brian, I also struggle with French accents; there are so many different kinds :slight_smile: My comment was meant to be humorous and in no way intended to make fun of you. Absolutely not. I’m sorry if I offended you; it was the least of my intentions. But in any case, thank you again for your help and patience with me and my many questions :wink: Have a good day, sincerely. François