Run a script when using an item from the hotbar?

Cheapshampoo

New member
I'm trying to set up my hotbar like Terraria. I want to use weapons and items from the hotbar. Is there a way to attach a script to items and run when an item is used?

Also, for some reason the hotbar shortcuts don't work. The ones that are "Equip First Item", "Equip Second Item", and so on.
 
You might be intersted in reading these pages:

I think the "Use Item Action Set Attribute" item Action might be what you are looking for. It allows you to set a function per itemDefinition.

As for the hotbar shortcuts not working I really don't know why that would be the case...
Can you check that those inputs exist in your InputManager? And add a debug ItemAction (it logs the item info in the console). That should ensure you know if the input is working on not
 
I'm definitely not getting it. I made an Item Action Set for a simple animation change to my Weapon object.

using System.Collections; using System.Collections.Generic; using UnityEngine; public class WeaponScript : MonoBehaviour { public Animator animWeapon; private string currentWeapon; // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { ChangeAnimationStateWeapon("WoodSwordRight"); } //===================================================== // ANIMATION //===================================================== void ChangeAnimationStateWeapon(string WeaponAnimation) { if (currentWeapon == WeaponAnimation) return; animWeapon.Play(WeaponAnimation); currentWeapon = WeaponAnimation; } }

And I've attached it to the item and item sets.

itemaction.jpgSlot.jpgitemDef.jpg
 
So what you are trying is playing an animation on the weapon or on the player?

There are a few issues here.

First, ItemActions are scriptable objects. They CANNOT reference object in scenes during edit time (That's a unity limitation).
So my understanding is that your script is trying to play an animation on the prefab of the weapon.
Although... the script you sent above is not an ItemAction, it's a Monobehavior. I'm guessing you pasted the wrong code but the logic is similar.

If you are trying to use equipped items (items that are spawned in the scene). I would suggest another approach:

If what you want, is animated the player and not the weapon. I would recommend a custom ItemAction or a Usable Item Action (like the example I sent you in the previous answer) that get the Character Animator from the itemInfo Inventory

(code not tested)
Code:
var characterAnimator = itemInfo.Inventory.gameobject.GetComponent<Animator>();
This code will only work if you call the item action for an item within your characters inventory.

I hope that points you in the right direction
 
Oh whoops that was the wrong script sorry. This is what I meant to paste.

using System.Collections; using System.Collections.Generic; using Opsive.UltimateInventorySystem.ItemActions; using Opsive.UltimateInventorySystem.Core.AttributeSystem; using Opsive.UltimateInventorySystem.Core.DataStructures; using UnityEngine; [System.Serializable] public class WeaponItemAction : ItemAction { public Animator animWeapon; private string currentWeapon; /// <summary> /// Can the item action be invoked. /// </summary> /// <param name="itemInfo">The item info.</param> /// <param name="itemUser">The item user (can be null).</param> /// <returns>True if it can be invoked.</returns> protected override bool CanInvokeInternal(ItemInfo itemInfo, ItemUser itemUser) { // Return true if the item can be invoked or false if it cannot. return true; } /// <summary> /// Consume the item. /// </summary> /// <param name="itemInfo">The item info.</param> /// <param name="itemUser">The item user (can be null).</param> protected override void InvokeActionInternal(ItemInfo itemInfo, ItemUser itemUser) { // Invoke the item action } void Update() { ChangeAnimationStateWeapon("WoodSwordRight"); } //===================================================== // ANIMATION //===================================================== void ChangeAnimationStateWeapon(string WeaponAnimation) { if (currentWeapon == WeaponAnimation) return; animWeapon.Play(WeaponAnimation); currentWeapon = WeaponAnimation; } }

So you are saying that I wont be able to use public Animator animWeapon;
I'm not able to link an animator that way? I want to be able to change the animator and sprite animation when I use the hotbar item.
I'm trying to use the weapon from the hotbar and not the equipped.
hotbar.png
My weapon object is under my Character object.
Weapon.jpeg

Hope that makes more sense.
 
The way I would do this is have a custom script on your character.
Call that WeaponController or whatever.

Then from your custom ItemAction, find the player character. Get the WeaponController from the player. Then call a function on that passing the ItemInfo as parameter. You could call it "UseItem(ItemInfo itemInfo)".
Then from there your WeaponController can choose what to do for that item.

Note all the code below is untested there could be typos.

So in your ItemAction, you need to get the weapon controller to pass it your item:
Code:
    /// <summary>
    /// Consume the item.
    /// </summary>
    /// <param name="itemInfo">The item info.</param>
    /// <param name="itemUser">The item user (can be null).</param>
    protected override void InvokeActionInternal(ItemInfo itemInfo, ItemUser itemUser)
    {
        // Either use the ItemUser
        itemUser.GetComponent<WeaponController>().UseItem(itemInfo);
        // Or use the itemInfo inventory
        itemInfo.Inventory.gameObject.GetComponent<WeaponController>().UseItem(itemInfo);
    }

Then on your WeaponController you can have somthing like this:
Code:
    void UseItem(ItemInfo itemInfo){
        var weaponAnimation = itemInfo.Item.GetAttributeValue<string>("WeaponAnimation");
        ChangeAnimationStateWeapon(weaponAnimation);
    }
    
    //=====================================================
    //                  ANIMATION
    //=====================================================
    void ChangeAnimationStateWeapon(string WeaponAnimation)
    {
        if (currentWeapon == WeaponAnimation) return;
        animWeapon.Play(WeaponAnimation);
        currentWeapon = WeaponAnimation;
    }

This assumes your animWeapon is the same for all weapons.
It also assumes that you store the WEaponAnimation string as an attribute on the itemDefinition.

Note this is not the only solution to solve this problem. It's just the first one that comes to mind so don't feel limited to this approach.

I hope that helps
 
Alright that sounds like it can work. I'm having a naming problem though I think.
//Had to change to a public void to have permission to be used.//
public void UseItem(ItemInfo itemInfo) { var weaponAnimation = itemInfo.Item.GetAttributeValue<string>("WeaponAnimation"); ChangeAnimationStateWeapon(weaponAnimation); }
this returns this error:
Assets\Scripts\WeaponController.cs(29,45): error CS1061: 'Item' does not contain a definition for 'GetAttributeValue' and no accessible extension method 'GetAttributeValue' accepting a first argument of type 'Item' could be found (are you missing a using directive or an assembly reference?)
I looked on the opsive site to find another way.

var weaponAnimation = itemInfo.Item.GetAttribute<string>("WeaponAnimation");
this returns this error:
Assets\Scripts\WeaponController.cs(29,45): error CS0311: The type 'string' cannot be used as type parameter 'T' in the generic type or method 'Item.GetAttribute<T>(string, bool, bool)'. There is no implicit reference conversion from 'string' to 'Opsive.UltimateInventorySystem.Core.AttributeSystem.AttributeBase'.

var weaponAnimation = itemInfo.Item.GetAttribute<Attribute<string>>("WeaponAnimation");
this returns this error:
Assets\Scripts\WeaponController.cs(30,36): error CS1503: Argument 1: cannot convert from 'Opsive.UltimateInventorySystem.Core.AttributeSystem.Attribute<string>' to 'string'


Also I want my item setup like this right?
String.jpg
 
Sorry for the delay, I missed your message.


Code:
var weaponAnimationAttribute = itemInfo.Item.GetAttribute<Attribute<string>>("WeaponAnimation");
var weaponAnimation = weaponAnimationAttribute.GetValue();
is a correct way of doing it.

Note how the value returned in an Attribute<string> not a string. So you have to get the value from the attribute before you can use it.

The code i gave you last time was untested code I wrote from memory. So turns out GetAttributeValue(...) does not exist. What I was thinking about was TryGetAttributeValue.
It can be used like so:
Code:
if(itemInfo.Item.TryGetAttributeValue("WeaponAnimation", out var weaponAnimation)){
    // The attribute and value exist. Do something with it.
}

When you aren't sure how to use a function or looking for a function to use. You can check the source code. It's fully commented.
If reading the comment is not enough, you can check where that function is used in the rest of the program to see real examples.

I hope that helps
 
Top