Three Major Coding Challenges (RPG Core Combat Creator)

Hi all, here are the challenges I was hoping to overcome in the RPG Core Combat Creator:

  1. Randomizing my Enemy hits on me - long story short, I want my enemies to be able to randomly hit me values instead of constant numbers. To try and solve that, I went to Health.TakeDamage() and tried accumulating the GetStat(Stat.Damage) damage, and putting it into a Random.Range(0.75, 1.25) bound, but that failed. Some enemies can hit me up to 3x the max damage I gave them in the progression bar, hence I need some help here

  2. Enemy Respawn After death - In very simple terms, when I kill my enemy, I want to make him disappear from the game world, wait for a few seconds, and then reappear… Kind of like the health pickup in lecture number 178. I am aware of how complex the Enemy file is, hence I came here for help for a robust algorithm to help me with that

  3. Walking to Pick things off the ground - My character can pick stuff up miles away with just clicking on it. I want him to run to it instead, because if I want something for example behind a NavMesh that he can’t walk through, I want him blocked instead of being able to walk to it

I’m still not sure what’s going on there… Without the critical hit portion of the code I gave you on Udemy, the highest the max damage can be is 1.25 * the damage in the progression.

That one will take a bit more work, and I’ll work up a tutorial for making that work, as it will require a SpawnManager that can also serve as a SaveableEntity. I’ve actually done this in another project, it’s just a matter of putting together a good tutorial for it.

This one will be easier to implement after you complete the Inventory course, as otherwise you’ll be be writing this class twice. The secret sauce, however, is to have an ItemCollector class that is an IAction like the Fighter and Mover class. The best place for this is in the Inventory class introduced in the final section of the Inventory course.
The pattern here will also work for the PlayerConversants in Dialogues and Quests as well as Shoppers in Shops and Abilties.

The basic idea is introduced in the Fighter component.

We start with a target. In Fighter, this is a Health or CombatTarget component (depending on where you are in the course).

In Update(), if the Fighter has a target, then the distance to the target is tested, and if it’s too far away, the Mover is instructed to move the character until it’s close enough, and then the target is attacked.

Similarly, in the Inventory (or perhaps a new class, ItemCollector) will have a Pickup as a target. An Update() method will check for a target, check the distance. If it’s too far away, instruct Mover to move to the pickup, and if it’s close enough, then pick up the item (and clear the target). You’ll need to make the class an IAction that Starts an action with the ActionScheduler (with Cancel() clearing the target).

For a quick and dirty solution before completing the Inventory course, you have the Pickup actually collect in an OnTriggerEnter method, and then the Pickup’s HandleRaycast() method would call

controller.GetComponent<Mover>().StartMoveAction(transform.position);

Here is a completed version of an ItemCollector class (so that we’re not actually modifying the Inventory class). This would go on the PlayerController once you have an Inventory component in place.

ItemCollector.cs
using GameDevTV.Inventories;
using RPG.Core;
using RPG.Movement;
using UnityEngine;

namespace RPG.Inventories
{
    public class ItemCollector : MonoBehaviour, IAction
    {
        private Pickup pickup;


        private void Update()
        {
            if (pickup == null) return;
            if (Vector3.Distance(transform.position, pickup.transform.position) < 3.0f)
            {
                GetComponent<Mover>().MoveTo(pickup.transform.position, 1f);
            }
            else
            {
                GetComponent<Mover>().Cancel();
                pickup.PickupItem();
                pickup = null;
            }
        }

        public void CollectItem(Pickup pickup)
        {
            GetComponent<ActionScheduler>().StartAction(this);
            this.pickup = pickup;
        }

        public void Cancel()
        {
            pickup = null;
        }
    }
}

Hi Brian, apologies for the late response. I put the code in a new script called ‘ItemCollector.cs’, and then placed the script on my player, and although it makes the player run to the item, the player still grabs the item before he gets to it, which is not what I’m looking for. Is the code supposed to be tuned, or should I delete other scripts off my player to get it to work as expected, or anything else?

Is it grabbing it right away or when it gets “close”? For the “close”, change the distance in the Vector3.Distance check in Update (you might make a [SerializeField] with an acceptanceRadius).
If it’s picking it up right away, then your IHandleRaycast in Pickup is likely wrong.

It picks it up right away, and the Pickup.cs code is what Sam used in his project. Here is the Pickup.cs script, if that helps in anyway:

using UnityEngine;

namespace GameDevTV.Inventories
{
    /// <summary>
    /// To be placed at the root of a Pickup prefab. Contains the data about the
    /// pickup such as the type of item and the number.
    /// </summary>
    public class Pickup : MonoBehaviour
    {
        // STATE
        InventoryItem item;
        int number = 1;

        // CACHED REFERENCE
        Inventory inventory;

        // LIFECYCLE METHODS

        private void Awake()
        {
            var player = GameObject.FindGameObjectWithTag("Player");
            inventory = player.GetComponent<Inventory>();
        }

        // PUBLIC

        /// <summary>
        /// Set the vital data after creating the prefab.
        /// </summary>
        /// <param name="item">The type of item this prefab represents.</param>
        /// <param name="number">The number of items represented.</param>
        public void Setup(InventoryItem item, int number)
        {
            this.item = item;
            if (!item.IsStackable())
            {
                number = 1;
            }
            this.number = number;
        }

        public InventoryItem GetItem()
        {
            return item;
        }

        public int GetNumber()
        {
            return number;
        }

        public void PickupItem()
        {
            bool foundSlot = inventory.AddToFirstEmptySlot(item, number);
            if (foundSlot)
            {
                Destroy(gameObject);
            }
        }

        public bool CanBePickedUp()
        {
            return inventory.HasSpaceFor(item);
        }
    }
}

I forgot, Pickup isn’t handling the IHandleRaycast, that’s in whatever class you had inherit it like ClickablePickup or RunoverPickup. There’s actually no code in Pickup to pickup the item. I need the subclass, sorry.

Sure, here is the ‘ClickablePickup.cs’ script you asked for:

using System.Collections;
using System.Collections.Generic;
using GameDevTV.Inventories;
using UnityEngine;

namespace RPG.Control
{
    [RequireComponent(typeof(Pickup))]
    public class ClickablePickup : MonoBehaviour, IRaycastable
    {
        Pickup pickup;

        private void Awake()
        {
            pickup = GetComponent<Pickup>();
        }

        public CursorType GetCursorType()
        {
            if (pickup.CanBePickedUp())
            {
                return CursorType.Pickup;
            }
            else
            {
                return CursorType.FullPickup;
            }
        }

        public bool HandleRaycast(PlayerController callingController)
        {
            if (Input.GetMouseButtonDown(0))
            {
                pickup.PickupItem();
            }
            return true;
        }
    }
}

Change HandleRaycast to

Hi Brian, the compiler complains that ‘this’ (the script holding the code) is of type ‘RPG.Control.ClickablePickup’, and it’s trying to utilize ‘GameDevTV.Inventories.Pickup’. Even after changing ‘this’ to ‘this.pickup’ (which supposedly helps fix the glitch), my character still picks pickups off the ground before reaching them. Any other solution around this please?

The pickup line was my mistake… in my personal projects, I just subclass Pickup for the ClickablePickup, so CollectItem(pickup) is the correct version.

Once again, off the ground like immediately, or off the ground like a few meters away after walking to it?
For the former, you’ve once again stumped me, seems impossible. For the latter, adjust the distance in ItemCollector. I think have it at 3 units… you can reduce that or better yet make it a SerializeField so you can adjust it in the inspector.

Hi Brian. After laughing a bit so hard about the fact that I can’t pick items up unless I’m more than 3.0f distance away (apologies, it was just a bit too funny), The script actually worked (after changing ‘this’ to ‘pickup’). I added the ‘ItemCollector.cs’ script to my player, flipped the ‘<’ sign to ‘>’ in the following line:

if (Vector3.Distance(transform.position, pickup.transform.position) > 3.0f)

and it actually worked to make my player run to the item before picking it up. Once again, thank you so much for bearing with me and my errors. Now I just need to optimize that value to ensure that nothing glitches out when the player tries to pick stuff off the ground :slight_smile:

Privacy & Terms