Merging the Third Person Controller Course with the RPG Course

Sometimes a file get’s “locked”… you can save it and save it and save it and the underlying file doesn’t actually update. It’s rare, but when it happens, you sometimes need to re-create the file. Fortunately, you’ve actually pasted the content of the file in this very thread.

oh nice… more weird, scary stuff that makes me doubt my existence :sweat_smile: (I deleted the old Generated file and re-created it, now I’m not sure what the interface name was)

If only you had a copy of InputReader in this thread…

Now I have a plethora of new errors, all complaining that it can’t find an ‘Input.GetMouseButtonDown()’ or some mouse and keyboard button issues… I wonder what library did we accidentally delete… (life really is giving me a run for my money with this project)

Here’s a screenshot of what I mean:

By the way, what do people usually do regarding this?

Did you turn off the both inputs in the Player settings (Project Settings | Player | Active Input)? It should be “Both” until all the old Input based code is fully removed.

Copy the version of the code in the file that seems to be locked
Quit Unity and your code editor
Open Unity and your code editor
Paste the code back into the file.

I just found out about this setting like right now (and it’s hidden under “Other Settings” in the 2021 LTS Version)… it was set to “Both” (but the issue still persists)

This is, by far, the wildest project I’ve ever had in my life… I’ve had a lot, but this one is… :flushed:

And it’s still saying Input.GetMouseButtonDown() doesn’t exist??? You’re filling me with impossible (and I’ve not managed to help another student tonight).

I’m lost, I don’t know what is wrong… and no, it has nothing to do with the version, the way the system works, if you have input handling set to BOTH then you should be able to use both (though it’s not as efficient.

Can I make a suggestion? This might be a good time to step back and start the tutorial over… There were a lot of things that you didn’t grasp the first time around (that were quite literally in Nathan’s course!)… You’re at the end of the content I have. Take your time. It took me around 100 hours to write this tutorial, and you went through the entire thing in three days, meaning you likely didn’t rewatch Nathan’s videos along the way to reinforce what we were doing.

I sincerely apologize for that Brian.

I’ll go ahead and give this whole thing a second go (will update if anything new pops up)

Remember, it’s a marathon, NOT a sprint. Don’t take this the wrong way, but you went through the Third Person course at a breakneck clip (faster than most of our students). The faster you go through the course, the less likely you are to grasp concepts. Most of the things you missed in this tutorial weren’t in the tutorial because they were already in Nathan’s lectures… And repeating is not a bad thing. I do it with every course I take, it reenforces learning.

Oh I trust you, don’t worry about it :slight_smile: - Here’s a little bit of good news though:

I eliminated the mouse input commands (well since we’re shuffling it out, I may as well go ahead and do that now), and the pickup worked perfectly fine, without the hack code

and miraculously, so did the inventory

I would go ahead and strip out all of the legacy input code from… everywhere. It’s going away.

Yup, life already took me that way :stuck_out_tongue_winking_eye: - anyway, I’ll finish off the unfinished lectures on this course and then go ahead with my redo in the main project. I’m praying so hard nothing goes wrong this time :slight_smile:

Understand, this tutorial won’t be complete for a while… so if you do this in your main project, it may be in an unplayable state for… :::shudder:::

I am fully aware of that. However, I have other prototype concepts I’d like to try implement as well, and this might take some time to properly implement. They heavily rely on the player being in third person mode

Just curious though, does ‘a while’ mean a month, or more like 6 months? :stuck_out_tongue_winking_eye:

Can’t just leave without one last error… I’m getting an NRE, and my controls won’t work for some reason when I apply the last step of the ‘Control Issues’ lecture:

NullReferenceException: Object reference not set to an instance of an object
RPG.InputReading.InputReader.Start () (at Assets/Scripts/InputReading/InputReader.cs:34)

And this is the line causing the error (in the ‘Start’ Function):

newUIActionMap.UI.SetCallbacks(this); // line 34

and if needed, this is my (supposedly) final ‘InputReader.cs’ script:

using System;
using RPG.Input;
using RPG.UI;
using UnityEngine;
using UnityEngine.InputSystem;

namespace RPG.InputReading
{
    public class InputReader : MonoBehaviour, PlayerControls.IPlayerActions, NewUIActionMap.IUIActions
    {
        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 PauseEvent;
        public event Action InventoryEvent;
        public event Action TraitStoreEvent;

        public event Action PickupItemEvent;

        private PlayerControls controls;
        private NewUIActionMap newUIActionMap;

        private void Start()
        {
            controls = new PlayerControls();
            controls.Player.SetCallbacks(this);
            newUIActionMap.UI.SetCallbacks(this);
            controls.Player.Enable();

            WindowController.OnAnyWindowOpened += DisableControls;
            WindowController.OnAllWindowsClosed += EnableControls;

        }

        void EnableControls() 
        {
            controls.Player.Enable();
        }

        void DisableControls() 
        {
            controls.Player.Disable();
        }

        private void OnDestroy()
        {
            WindowController.OnAnyWindowOpened -= DisableControls;
            WindowController.OnAllWindowsClosed -= EnableControls;
            controls.Player.Disable();
            newUIActionMap.UI.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();
        }

        public void OnPause(InputAction.CallbackContext context) 
        {
            if (context.performed) PauseEvent?.Invoke();
        }

        public void OnTrait(InputAction.CallbackContext context) 
        {
            if (context.performed) TraitStoreEvent?.Invoke();
        }

    }
}

This is not my code… What is newUIActionMap.UI??

The tutorial has you create a new Action Map within the same Control asset… if you’re using a different asset for the UI, then you’ll need to assign them…

controls = new PlayerControls();    //We create a PlayerControls
controls.Player.SetCallbacks(this); //We assign callbacks
newActionMap = new NewUIActionMap(); //Because you're using a completely different asset, you'll have to create it like PlayerControls
newActionMap.UI.SetCallbacks(this); //Now that it's created, you can assign to it

that’s where I messed up… now your code makes sense to me :sweat_smile: (apologies, I thought we were creating an entirely new map)

Anyway, works well now :slight_smile: (time to repeat all of this, on THE REAL project)

hey Brian, quick question. When developing the ‘dealing damage’ section of my code, I’m trying to integrate the Skilling system, and I’m low-key copying a lot of information from ‘hit’. Just a quick check-up, does this code make sense? (It has no syntax errors, but I’m not sure of it). This is my version of the ‘TryHit()’ function:

// For the brand new Attack Array System (part of the Point-And-Click -> Third Person System implementation)
    // this function is called by animations to perform hits, based on the hand doing the hit:
    void TryHit(int slot) 
    {

        // if no current attack (or follow up) exists, return null:
        if (currentAttack == null) return;

        // To trigger this animation, the event in the animation takes the 1 and 2 values in 'Int' slot
        Vector3 transformPoint;
        switch (slot) 
        {
            case 1: transformPoint = rightHandTransform.position;   // for right-handed cases
            break;
            case 2: transformPoint = leftHandTransform.position;    // for left-handed cases
            break;
            default: transformPoint = rightHandTransform.position;  // for cases when things make no sense
            break;
        }
        Debug.Log($"Attacking with slot {slot}, position {transformPoint}");

            float damageRadius = 0.5f;

            foreach (Collider other in Physics.OverlapSphere(transformPoint, damageRadius)) 
            {
                if (other.gameObject == gameObject) continue;

                if (other.TryGetComponent(out Health otherHealth)) 
                {
                    float damage = GetDamage();
                    damage *= currentAttack.DamageModifier;

                    if (other.TryGetComponent(out BaseStats otherBaseStats)) 
                    {
                        float defence;
                        if (other.TryGetComponent(out SkillStore skillStore))
                        {
                            defence = otherBaseStats.GetStatBySpecifiedLevel(Stat.Defence, skillStore.GetSkillLevel(Skill.Defence));
                        }
                        else defence = otherBaseStats.GetStat(Stat.Defence);
                        damage /= 1 + defence/damage;
                    }
                    otherHealth.TakeDamage(gameObject, damage, currentWeaponConfig.GetSkill());

                }
            }
        }

The damage calculation itself can be the same as the damage calculation from your project. All that’s different is determining the Target(s).

Not exactly… doing so just gets him to attack like crazy :sweat_smile:

We’ll deal with this later, for now I’m trying to figure out something else… but I don’t even remember what I’m looking for now :confused:

Privacy & Terms