Merging the Third Person Controller Course with the RPG Course

I have to go to work. Double check each step in the Pickup process. Compare it to the repo. Download the repo, and see the Pickup in action. The repo version does work.

Now I see why you all love URPā€¦ Iā€™ll update the comment as I go, with anything I find :slight_smile:
Edit: Reviewed the Pickup chapter again, thoroughly, in every single possible way I can think of (gitlab repo, your code, and the tutorial again), and I still canā€™t find where I went wrong yetā€¦ (Idk whatā€™s wrong, but the animation wonā€™t even get called to begin with)

After a bit more investigation, this function in ā€˜PlayerFreeLookState.csā€™ doesnā€™t even get called to begin withā€¦ Code seems perfectly similar to the other two states (the attacking and targeting states), so Iā€™m extremely confused why this one wonā€™t be called as well:

private void InputReader_HandlePickupItemEvent() 
        {
            
            // if there is a nearby pickup, switch to the 'PlayerPickupState.cs' State Machine:
            if (stateMachine.PickupFinder.GetNearestPickup() != null) 
            {
                Debug.Log("Found Some Pickup...");
                stateMachine.SwitchState(new PlayerPickupState(stateMachine, stateMachine.PickupFinder.CurrentTarget));
            }
        }

Copied directly from the Pickups page:

Now letā€™s head into PlayerFreeLookState. I think this is the only place where we actually need to worry about picking up an item. If weā€™re in the PlayerTargetingState, weā€™ve got a target, and weā€™re probably in dire peril for our very lives. Not the best time to bend down and pick up an item.

In PlayerFreeLookState.Enter, we want to subscribe to the InputReaderā€™s PickupEvent with a new method, I called mine InputReader_HandlePickupEvent

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

This method first checks to see if there is a PickupTarget within range. If there is, then we switch to a new state, PlayerPickupState.

Donā€™t forget to unsubscribe from the HandlePickupEvent in Exit!

Yup, went through that alreadyā€¦ Not sure if you missed out something at this point tbh :sweat_smile:

I did cheat my way through though, and I hacked my way into making something work, but Iā€™m not sure if this is legal or not, and why/why not

In ā€˜PlayerFreeLookState.csā€™, in ā€˜Tick()ā€™, I added this line:

if (Input.GetKeyDown(KeyCode.P)) 
            {
                InputReader_HandlePickupItemEvent();
            }

Itā€™s right under the if statement that takes care of switching to the ā€˜PlayerAttackingStateā€™, and it seems to be doing its job just fine (for now, even with multiple enemies tested)

(again, Iā€™m still not fully grasping the idea of how the input control code looks like, so I went the old fashion way). What risks does this carry, though?

In the meanwhile Iā€™ll go read the last slide before attempting to integrate this system into my game :slight_smile: (again, Iā€™m skipping the UI overhaul for now, as it seems to be causing more issues than help for now. If thatā€™s what Iā€™m doing though, then according to your final lecture so far, Iā€™m about to run into the major issue of ā€œmy controls are still responding whilst Iā€™m in pauseā€. Do I start a new topic for this?)

The controls responding while game is paused issue is handled in the Control Issues page.

Paste in your PlayerFreeLookState.csā€¦ and your InputReader.csā€¦

Yup, I read that, which is why I was asking if I should open a new topic for it (although now that I think of it, I just might do that, since the old foolproof mechanics are not going to be necessary for the new systemā€¦ this is a complete overhaul :sweat_smile:)

using UnityEngine;

namespace RPG.States.Player {

    public class PlayerFreeLookState : PlayerBaseState
    {
        public PlayerFreeLookState(PlayerStateMachine stateMachine) : base(stateMachine) {}

        private float timer = 0f;
        private static readonly int FreeLookBlendTreeHash = Animator.StringToHash("FreeLookBlendTree");
        private static readonly int FreeLookSpeedHash = Animator.StringToHash("FreeLookSpeed");

        public override void Enter()
        {
            stateMachine.InputReader.JumpEvent += InputReader_HandleJumpEvent;
            stateMachine.InputReader.TargetEvent += InputReader_HandleTargetEvent;
            stateMachine.InputReader.PickupItemEvent += InputReader_HandlePickupItemEvent;
            Debug.Log("Pickup Event Included");
            stateMachine.Animator.CrossFadeInFixedTime(FreeLookBlendTreeHash, stateMachine.CrossFadeDuration);
        }

        public override void Tick(float deltaTime)
        {

            // Only allow attacking if the player is locked on an enemy:
            if (stateMachine.InputReader.IsAttacking)
            {
                stateMachine.SwitchState(new PlayerAttackingState(stateMachine, 0));
                return;
            }

            if (Input.GetKeyDown(KeyCode.P))
            {
                InputReader_HandlePickupItemEvent();
            }

            Vector3 movement = CalculateMovement();
            Move(movement * stateMachine.FreeLookMovementSpeed, deltaTime);
            if (stateMachine.InputReader.IsAttacking) 
            {
                HandleAttackButtonPressed();
                return;
            }
            if (stateMachine.InputReader.MovementValue == Vector2.zero) 
            {
                stateMachine.Animator.SetFloat(FreeLookSpeedHash, 0, AnimatorDampTime, deltaTime);
                if (stateMachine.Animator.GetFloat(FreeLookSpeedHash) < 0.1f) 
                {
                    stateMachine.Animator.SetFloat(FreeLookSpeedHash, 0f);
                }
                return;
            }

            stateMachine.Animator.SetFloat(FreeLookSpeedHash, movement.magnitude, AnimatorDampTime, deltaTime);
            FaceMovementDirection(movement, deltaTime);

        }

        public override void Exit()
        {
            stateMachine.InputReader.JumpEvent -= InputReader_HandleJumpEvent;
            stateMachine.InputReader.TargetEvent -= InputReader_HandleTargetEvent;
            stateMachine.InputReader.PickupItemEvent -= InputReader_HandlePickupItemEvent;
            Debug.Log("Pickup Event Excluded");
        }

        private void FaceMovementDirection(Vector3 forward, float deltaTime)
        {
            if (forward == Vector3.zero) return;
            Quaternion desiredRotation = Quaternion.LookRotation(forward, Vector3.up);
            stateMachine.transform.rotation = Quaternion.Slerp(stateMachine.transform.rotation, desiredRotation, stateMachine.FreeLookRotationSpeed * deltaTime);
        }

        private Vector3 CalculateMovement() 
        {
            Vector3 forward = stateMachine.MainCameraTransform.forward;
            Vector3 right = stateMachine.MainCameraTransform.right;
            forward.y = 0;
            right.y = 0;
            forward.Normalize();
            right.Normalize();
            Vector3 movement = right * stateMachine.InputReader.MovementValue.x;
            movement += forward * stateMachine.InputReader.MovementValue.y;
            return Vector3.Min(movement, movement.normalized);
        }

        private void InputReader_HandleJumpEvent() 
        {
            Debug.Log($"I got up, and nothing gets me down");
            // stateMachine.SwitchState(new PlayerFreeLookState(stateMachine));
        }

        private void InputReader_HandleTargetEvent() 
        {
            if (stateMachine.Targeter.SelectTarget()) 
            {
                stateMachine.SwitchState(new PlayerTargetingState(stateMachine));
            }

        }

        private void InputReader_HandlePickupItemEvent() 
        {
            
            // if there is a nearby pickup, switch to the 'PlayerPickupState.cs' State Machine:
            if (stateMachine.PickupFinder.GetNearestPickup() != null) 
            {
                Debug.Log("Found Some Pickup...");
                stateMachine.SwitchState(new PlayerPickupState(stateMachine, stateMachine.PickupFinder.CurrentTarget));
            }
        }

        private void HandleAttackButtonPressed() 
        {
            if (stateMachine.Targeter.HasTargets) 
            {
                stateMachine.SwitchState(new PlayerAttackingState(stateMachine, 0));
                return;
            }

            if (stateMachine.PickupFinder.HasTargets) 
            {
                InputReader_HandlePickupItemEvent();
                return;
            }

            stateMachine.SwitchState(new PlayerAttackingState(stateMachine, 0));

        }

    }

}
using System;
using UnityEngine;
using UnityEngine.InputSystem;

namespace RPG.InputReading
{
    public class InputReader : MonoBehaviour, Controls.IPlayerActions
    {
        public bool IsAttacking { get; private set; }
        public bool IsBlocking { get; private set; }
        public Vector2 MovementValue { get; private set; }

        public event Action JumpEvent;
        public event Action DodgeEvent;
        public event Action TargetEvent;

        public event Action AttackDownEvent;

        public event Action CancelEvent;
        public event Action InventoryEvent;

        public event Action PickupItemEvent;

        private Controls controls;

        private void Start()
        {
            controls = new Controls();
            controls.Player.SetCallbacks(this);

            controls.Player.Enable();
        }

        private void OnDestroy()
        {
            controls.Player.Disable();
        }

        public void OnJump(InputAction.CallbackContext context)
        {
            if (!context.performed) { return; }

            JumpEvent?.Invoke();
        }

        public void OnDodge(InputAction.CallbackContext context)
        {
            if (!context.performed) { return; }

            DodgeEvent?.Invoke();
        }

        public void OnMove(InputAction.CallbackContext context)
        {
            MovementValue = context.ReadValue<Vector2>();
        }

        public void OnLook(InputAction.CallbackContext context)
        {

        }

        public void OnTarget(InputAction.CallbackContext context)
        {
            if (!context.performed) { return; }

            TargetEvent?.Invoke();
        }

        public void OnAttack(InputAction.CallbackContext context)
        {
            if (context.performed)
            {
                IsAttacking = true;
                AttackDownEvent?.Invoke();
            }
            else if (context.canceled)
            {
                IsAttacking = false;
            }
        }

        public void OnBlock(InputAction.CallbackContext context)
        {
            if (context.performed)
            {
                IsBlocking = true;
            }
            else if (context.canceled)
            {
                IsBlocking = false;
            }
        }

        public void OnInventory(InputAction.CallbackContext context) 
        {
            if (context.performed) InventoryEvent?.Invoke();
        }

        public void OnCancel(InputAction.CallbackContext context) 
        {
            if (context.performed) CancelEvent?.Invoke();
        }

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

    }
}

And youā€™ve bound a key to the Pickup in the Controls?? Because with this code, if HandlePickupEvent isnā€™t being called, then you may need to contact UNITY right away to report a serious bugā€¦

The Debug y ou have in the event handler only fires if there is a pickup nearby, which may create the illusion that it isnā€™t being calledā€¦

        private void InputReader_HandlePickupItemEvent() 
        {
            Debug.Log("Pickup Pressed!");   
            // if there is a nearby pickup, switch to the 'PlayerPickupState.cs' State Machine:
            if (stateMachine.PickupFinder.GetNearestPickup() != null) 
            {
                Debug.Log("Found Some Pickup...");
                stateMachine.SwitchState(new PlayerPickupState(stateMachine, stateMachine.PickupFinder.CurrentTarget));
            } else Debug.Log("No pickups in range");
        }


Voila (it was there the whole timeā€¦)

I tried firing the event a hundred times (literally) so far, before injecting the little hack code I did, and it never worked for god knows what reason

So itā€™s still not firing without the hack code???

the hack code fires itā€¦ but without the input hack, it wonā€™t work. Thatā€™s why Iā€™m asking if something was missing in the tutorial or not, and what risks does this carry on the long run :sweat_smile: (and if the hack code fires it, then whatā€™s the point of the entire Input Control system?)

At this point in time, Iā€™m starting to believe something went missing with the Unity 2021 LTS version

I have NO idea whatā€™s going on. Quite literally.
Can you show me a screenshot of the controls with the Pickup highlighted (not the P), I want to see that inspector


Sure, here you go

        public void OnPickup(InputAction.CallbackContext context) 
        {
            if (context.performed) 
            {
                 Debug.Log($"OnPickup");
                 PickupItemEvent?.Invoke();
            }
        }

Assuming that goes into ā€˜InputReader.csā€™, the Debug never gets calledā€¦ (Iā€™ll be back in 5 minutes)

It does, and at this point, Iā€™m not sure if youā€™re pulling a prank or somethingā€¦

Do you see the two methods above OnPickup? They are doing the exact same thingā€¦ responding to the key being pressedā€¦ but they workā€¦ so Iā€™m unsure why doing the exact same thing in Pickupā€¦

A couple of testing thingsā€¦ (and at this point, Iā€™m LOST, and youā€™ll need to contact Unity Support if these donā€™t yield some results)ā€¦

  • Comment out the entire OnPickup method. When you return to Unity, the game shouldnā€™t compile, complaining that the IPlayer interface isnā€™t implementing OnPickup
  • (after uncommenting the method) - Bind the action to a different keystroke.
  • Close Unity and your code editor completely and go into your projectā€™s Library folder. Delete the entire contents and restart Unity

As much as Iā€™d love to say thatā€™s true, itā€™s not a prank. It genuinely isnā€™t working for some reason

This one didnā€™t complain by even a single bitā€¦ it just ignored it entirely (and the same went for my ā€œOnInventory()ā€ and ā€œOnCancel()ā€ methods)

You buried the leadā€¦ were THOSE keys not working either?

Delete the contents of the Library folder.

I didā€¦ now itā€™s taking decades to restart the projectā€¦ Will be back when it opens (if it ever does :sweat_smile:)

And yes, these keys were not working eitherā€¦

This was information that could have saved a LOT LOT LOT of time debuggingā€¦

LET ME TAKE AN INCREDIBLY WILD GUESSā€¦ I need to regenerate the C# file? Because last time I checked, literally ALL of these functions were in the file

Privacy & Terms