Pick Up issue and question

nathanj

Active member
Hi Justin,

Two things. First, I'm having an issue with item pickups that use button down. What's happening is that if my player walks by one item that is collectable but doesn't collect it, when they walk by a second collectable item they can not interact with it. I have modifed the demo scene (click to dl) to show this. On start there is a knife and a gun, if you walk up to one you can click on it and collect it and then walk to the other item and click on it and collect it. However, if you walk to the gun and do not collect it and then walk to the knife you can not collect the knife. If you walk back to the gun and collect it you can then walk to the knife to collect it.

Second question is more directional. I am hoping to make a modified pickup ability that detects if an item is consumable (i.e. food that satiates the player) - i need to also make a consume ability. But what I am hoping with my modified pickup ability is that if the item is consumable I would like to give the player two options, either add the item to their inventory or consume it straight away. I imagine that when the ItemPickup is detected the modified PickupItem ability it will check it's ItemType, if its consuamble it would give the option of, something like, "Press A to collect" or "Press B to Consume'. I'm guessing that this will be easily covered with the new inventory system but unfortunately we're using the PUN integration and I need to do this myself. Any suggestion on how to go about this?

Much thanks in advance,
Nathan
 
Last edited:
Hi Nathan, looks like you haven't set that file you've linked to be accessible by anyone with the link. I've requested access, so if you could allow me in or just make the file public then I can take a look at your setup.

As for your second question, this should be easily doable with a minimal amount of custom scripting/UI. But maybe best to get to that after solving your first issue!
 
Setting the 'Object Detection' to 'Trigger' in the character's Pickup Item ability solved your first problem at my end, so try that.

Your second question may be a little more involved than I first thought, since consumable items are not normally expected to be added to the inventory (the PickupItem ability just skips adding a consumable item type to the inventory). So you may want to start by creating a new "Consumables" item category, as well as subclassing the PickupItem ability, within which you'd check what item type is being picked up, and if it's one of your consumable item types, move it into this new item category.
 
Hi Andrew,

1. This worked, thanks. However, it's not exactly the result I was hoping for. I was intending to use the Spherecast or Charactercast so the player would be facing the object so their pickup animation would be directed at the object. Using the Trigger detection mode, if the player is within the range but looking 180 degrees away they will play the pickup animation facing the wrong way. Setting the "Use Look Position" and/or "Use Look Direction" doesn't make a difference here.
I think this has to do with the TriggerExit Override in the PickupItem.cs script. Is there any way to have the same functionality when the raycast exits the trigger area?

2. I've got a different approach that is kind of working. I made a ObjectDetection subclass that contains all the necessary info and have stripped a good portion of a modified PickupItem ability that reads this info. The one thing I'm srtruggling with is how to disable the object once it's been consumed.
I've lifted the code from ObjectPickedUp in the ObjectPickup.cs to and it looks like this:

Code:
 private void PickUP()
        {
            // The object may not have been instantiated within the scene.
            if (m_GameObject == null)
            {
                return;
            }

            // Send an event notifying of the pickup.
            EventHandler.ExecuteEvent(m_TargetGameObject, "OnObjectPickedUp", this);

            // Optionally play a pickup sound if the object picking up the item is attached to a camera.
            // A null GameObject indicates that the clip will play from the AudioManager.
            //var camera = Utility.UnityEngineUtility.FindCamera(this);
            //if (camera != null)
            //{
            //    m_PickupAudioClipSet.PlayAudioClip(null);
            //}

            if (ObjectPool.InstantiatedWithPool(m_TargetGameObject))
            {
#if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER
                if (NetworkObjectPool.IsNetworkActive())
                {
                    NetworkObjectPool.Destroy(m_TargetGameObject);
                    return;
                }
#endif
                ObjectPool.Destroy(m_TargetGameObject);
            }
            else
            {
                // Deactivate the pickup for now. It can appear again if a Respawner component is attached to the GameObject.
                m_TargetGameObject.SetActive(false);
            }
        }

But intead of disabling the object it's disabling the player. I'm not sure if that code will give you enough info to go on, just hoping you can spot something obvious I'm missing.

Thank you for your time and help
Nathan
 
1.
This is actually a bug that should be fixed in next update, but you can fix it yourself quickly. In PickupItem.cs, find the CanStartAbility override and add the following code:
C#:
            if (!base.CanStartAbility()) {
                if (m_AvailablePickupCount > 0) { // START NEW
                    for (int i = 0; i < m_AvailablePickupCount; ++i) {
                        m_AvailableItemPickups[i] = null;
                    }
                    m_AvailablePickupCount = 0;
                } // END NEW
                return false;
            }

2.
Looks like the culprit line is m_TargetGameObject.SetActive(false);. Not sure where/how you're calling this, so you'll need to verify exactly what m_TargetGameObject is. You can log it and Unity will tell you where it's being called from in the debug log stack.
 
Hi Andrew

1: Thanks! I can now use the Spherecast! Perfect.
2: Thanks for the suggestion, the issue was easy to resolve from there.

One more question, and it's more of another 'how would you approach this?' I hope I'm not taking up too much of your time.
I would like to display the object name when the PickUp abilities message is displayed. So rather than just a "Pick Up" messahe, I would like to have, say "pick up Firewood". Is there any way you can think of to do this?

Thanks again!
Nathan
 
Try this...

In DetectObjectAbilityBase.CanStartAbility, find the spherecast check and assign to m_AbilityMessageText just before it returns true. For example:

Code:
            // Use a spherecast to detect if the character is near the object.
            if ((m_ObjectDetection & ObjectDetectionMode.Spherecast) != 0) {
                if (Physics.SphereCast(castTransform.TransformPoint(m_CastOffset) - castTransform.forward * m_SpherecastRadius, m_SpherecastRadius, castDirection, out m_RaycastResult,
                                        m_CastDistance, m_DetectLayers, m_TriggerInteraction)) {
                    var hitObject = m_RaycastResult.collider.gameObject;
                    if (ValidateObject(hitObject, false)) {
                        m_DetectedObject = hitObject;
                        m_AbilityMessageText = "Pick Up " + m_DetectedObject; // NEW LINE
                        return true;
                    }
                }
            }

This will get called every frame the character remains within the spherecast, so you may want to do a check before assigning to m_AbilityMessageText.
 
Hi Again,

Thank you! This is starting to shape into my hopes!

One more question then I promise to leave you alone for a while.

I have made a new script VS_ObjectIdentifier that inherits from the ObjectIdentifier class. Why can I only access the ObjectIdentifier script in the DetectObjectAbilityBase script?

I ask because I have made this custom script to contain a bunch of additional information I would like to access from collectable items. Being able to access it here would be extremely useful.

Thanks again, all of your help has been fantastic!

Nathan
 
I'm not sure if I 100% understand what you're going for, but this may help: ObjectIdentifier.cs is a MonoBehaviour and exists inside of the Opsive.UltimateCharacterController.Objects namespace. So if you include that namespace, you should be able to access the ObjectIdentifier component directly.
 
Hey again,

Yeah, sorry for the vague question.

Here is my subclass that inherits from ObjectIdentifier.cs

Code:
// ---------------------------------------------

namespace Opsive.UltimateCharacterController.Objects
{
    using UnityEngine;

    public class VS_ObjectIdentifier : ObjectIdentifier
    {
        
        [Tooltip("Objects display name.")]
        [SerializeField] protected string m_ObjectName;
        [Tooltip("Is the item consumable.")]
        [SerializeField] protected bool m_isConsumable;
        [Tooltip("What attribute to affect.")]
        [SerializeField] protected string m_attributeName;
        [Tooltip("By how much.")]
        [SerializeField] protected uint m_attributeValue;
        [Tooltip("The value of the identifier.")]
        [SerializeField] protected string m_pickupText = "Press E to consume; Press F to collect";

      
        public bool IsConsumable { get { return m_isConsumable; } set { m_isConsumable = value; } }
        public string AttributeName { get { return m_attributeName; } set { m_attributeName = value; } }
        public string ObjectName { get { return m_ObjectName; } set { m_ObjectName = value; } }
        public uint AttributeValue { get { return m_attributeValue; } set { m_attributeValue = value; } }
        public string PickupText { get { return m_pickupText; } set { m_pickupText = value; } }

    }

  
}

And then this is the issue I'm having with that script not being referenceable from the DetectObjectAbilityBase script.
ObjIdent1.PNG

Is there a way to be able to reference my custom script in the DetectObjectAbilityBase?

Thank you again.

Nathan
 
@Justin

It seems to be. I'm a little lost though, honestly. Is there any way I can add an Assembly Definition reference so that my Subclass of ObjectIdentifier can be read?
 
Top