peter-kish / gloot

A universal inventory system for the Godot game engine.
MIT License
564 stars 21 forks source link

Add methods into InventoryItem #170

Closed Nordsoft91 closed 5 months ago

Nordsoft91 commented 6 months ago

Suggest to add methods into InventoryItem class:

Also, suggest to change signature of item_equipped() signal from slot to item_equipeed(item) to get infotmation about item was equipped

LeeWannacott commented 6 months ago

@peter-kish Maybe item_slot_cleared() should give you the slot which is clearing as well like item_slot_cleared(slot)?

Also, suggest to change signature of item_equipped() signal from slot to item_equipeed(item) to get infotmation about item was equipped.

@Nordsoft91 or should it be item_equipped(slot) and then you can slot.get_item() on it.

I guess technically I can just bind the slots myself like: head_slot.connect("item_equipped",_on_slot_item_equipped.bind(head_slot)) chest_slot.connect("item_equipped",_on_slot_item_equipped.bind(chest_slot))

However I would imagine most users would be connecting the signal from within the Godot editor :thinking: .

This is my current code to give you an idea:

Note: I was just trying to get something working; so its very much copy-pasta :spaghetti: . I think doing the bind slot thing should simplify the code.

        @onready var head_slot := %head_slot
        @onready var chest_slot := %chest_slot
        @onready var boots_slot := %boots_slot
        @onready var neck_slot := %neck_slot
        @onready var belt_slot := %belt_slot
        @onready var gloves_slot := %gloves_slot
        @onready var main_weapon_slot := %main_weapon_slot
        @onready var right_ring_slot := %right_ring_slot
        @onready var offhand_slot := %offhand_slot
        @onready var left_ring_slot := %left_ring_slot
    head_slot.connect("item_equipped",_on_head_slot_item_equipped)
    chest_slot.connect("item_equipped",_on_chest_slot_item_equipped)
    boots_slot.connect("item_equipped",_on_boots_slot_item_equipped)
    neck_slot.connect("item_equipped",_on_neck_slot_item_equipped)
    belt_slot.connect("item_equipped",_on_belt_slot_item_equipped)
    gloves_slot.connect("item_equipped",_on_gloves_slot_item_equipped)
    main_weapon_slot.connect("item_equipped",_on_main_weapon_slot_item_equipped)
    offhand_slot.connect("item_equipped",_on_offhand_slot_item_equipped)

    left_ring_slot.connect("item_equipped",_on_left_ring_slot_item_equipped)
    right_ring_slot.connect("item_equipped",_on_right_ring_slot_item_equipped)

    head_slot.connect("cleared",_on_head_slot_cleared)
    chest_slot.connect("cleared",_on_chest_slot_cleared)
    boots_slot.connect("cleared",_on_boots_slot_cleared)
    neck_slot.connect("cleared",_on_neck_slot_cleared)
    belt_slot.connect("cleared",_on_belt_slot_cleared)
    gloves_slot.connect("cleared",_on_gloves_slot_cleared)
    main_weapon_slot.connect("cleared",_on_main_weapon_slot_cleared)
    offhand_slot.connect("cleared",_on_offhand_slot_cleared)

    left_ring_slot.connect("cleared",_on_left_ring_slot_cleared)
    right_ring_slot.connect("cleared",_on_right_ring_slot_cleared)

func _on_head_slot_item_equipped() -> void:
    var equpped_helm:InventoryItem =  head_slot.get_item()
    match equpped_helm.get_property("id"):
        "wolf_cape":
            print("wolfcape")
            add_item_to_character(wolf_cape,player_head,manikan_head)
    clear_item_if_no_match_type(["helm"],equpped_helm,head_slot)
    pass

func _on_chest_slot_item_equipped() -> void:
    var equipped_chest:InventoryItem =  chest_slot.get_item()
    match equipped_chest.get_property("id"):
        "wolf_cape":
            print("wolfcape")
            add_item_to_character(wolf_cape,player_chest,manikan_chest)
    clear_item_if_no_match_type(["helm"],equipped_chest,chest_slot)
    pass

func _on_boots_slot_item_equipped() -> void:
    var equipped_boots:InventoryItem =  boots_slot.get_item()
    match equipped_boots.get_property("id"):
        "wolf_cape":
            print("wolfcape")
            add_item_to_character(wolf_cape,player_boots,manikan_boots)
    clear_item_if_no_match_type(["helm"],equipped_boots,boots_slot)
    pass

func _on_neck_slot_item_equipped() -> void:
    var equipped_neck:InventoryItem =  neck_slot.get_item()
    match equipped_neck.get_property("id"):
        "wolf_cape":
            add_item_to_character(wolf_cape,player_neck,manikan_neck)
    clear_item_if_no_match_type(["helm"],equipped_neck,neck_slot)
    pass

func _on_belt_slot_item_equipped() -> void:
    var equipped_belt:InventoryItem =  belt_slot.get_item()
    match equipped_belt.get_property("id"):
        "wolf_cape":
            add_item_to_character(wolf_cape,player_belt,manikan_belt)
    clear_item_if_no_match_type(["helm"],equipped_belt,belt_slot)
    pass

func _on_gloves_slot_item_equipped() -> void:
    var equipped_gloves:InventoryItem =  gloves_slot.get_item()
    match equipped_gloves.get_property("id"):
        "wolf_cape":
            add_item_to_character(wolf_cape,player_gloves,manikan_gloves)
    clear_item_if_no_match_type(["helm"],equipped_gloves,gloves_slot)
    pass

func _on_main_weapon_slot_item_equipped() -> void:
    var equipped_main_weapon:InventoryItem =  main_weapon_slot.get_item()
    match equipped_main_weapon.get_property("id"):
        "wolf_cape":
            add_item_to_character(wolf_cape,player_main_weapon,manikan_main_weapon)
    clear_item_if_no_match_type(["helm"],equipped_main_weapon,main_weapon_slot)
    pass

func _on_offhand_slot_item_equipped() -> void:
    var equipped_offhand:InventoryItem =  offhand_slot.get_item()
    match equipped_offhand.get_property("id"):
        "wolf_cape":
            add_item_to_character(wolf_cape,player_offhand,manikan_offhand)
    clear_item_if_no_match_type(["helm"],equipped_offhand,offhand_slot)
    pass

func _on_left_ring_slot_item_equipped() -> void:
    var equipped_left_ring:InventoryItem =  left_ring_slot.get_item()
    match equipped_left_ring.get_property("id"):
        "wolf_cape":
            add_item_to_character(wolf_cape,player_ring_left,manikan_ring_left)
    clear_item_if_no_match_type(["helm"],equipped_left_ring,left_ring_slot)
    pass

func _on_right_ring_slot_item_equipped() -> void:
    var equipped_right_ring:InventoryItem =  right_ring_slot.get_item()
    match equipped_right_ring.get_property("id"):
        "wolf_cape":
            add_item_to_character(wolf_cape,player_ring_right,manikan_ring_right)
    clear_item_if_no_match_type(["helm"],equipped_right_ring,right_ring_slot)
    pass

func _on_head_slot_cleared() -> void:
    remove_items_from_character(player_head,manikan_head)
    pass # Replace with function body.
func _on_chest_slot_cleared() -> void:
    remove_items_from_character(player_chest,manikan_chest)
    pass # Replace with function body.
func _on_boots_slot_cleared() -> void:
    remove_items_from_character(player_boots,manikan_boots)
    pass # Replace with function body.
func _on_neck_slot_cleared() -> void:
    remove_items_from_character(player_neck,manikan_neck)
    pass
func _on_belt_slot_cleared() -> void:
    remove_items_from_character(player_belt,manikan_belt)
    pass
func _on_gloves_slot_cleared() -> void:
    remove_items_from_character(player_gloves,manikan_gloves)
    pass
func _on_main_weapon_slot_cleared() -> void:
    remove_items_from_character(player_main_weapon,manikan_main_weapon)
    pass
func _on_offhand_slot_cleared() -> void:
    remove_items_from_character(player_offhand,manikan_offhand)
    pass
func _on_right_ring_slot_cleared() -> void:
    remove_items_from_character(player_ring_right,manikan_ring_right)
    pass
func _on_left_ring_slot_cleared() -> void:
    remove_items_from_character(player_ring_left,manikan_ring_left)
    pass

func clear_item_if_no_match_type(match_types:Array[String],equipped_item:InventoryItem,slot:ItemSlot)->void:
    for match_type in match_types:
        if equipped_item.get_property("item_type") != match_type:
            slot.clear()
peter-kish commented 6 months ago
peter-kish commented 6 months ago

Maybe item_slot_cleared() should give you the slot which is clearing as well like item_slot_cleared(slot)?

Not sure if I understand this. ItemSlot defines the cleared signal and you would definitely know which slot emitted the signal (the one you called connect on). Or are you talking about a global signal?

LeeWannacott commented 6 months ago

Maybe item_slot_cleared() should give you the slot which is clearing as well like item_slot_cleared(slot)?

Not sure if I understand this. ItemSlot defines the cleared signal and you would definitely know which slot emitted the signal (the one you called connect on). Or are you talking about a global signal?

How do you know which slot was cleared?; when cleared signal is triggered/emitted if is using the same callback (assuming signals were connected to slots via editor not hard coded like below):

head_slot.connect("cleared",_on_slot_cleared)
chest_slot.connect("cleared",_on_slot_cleared)
boots_slot.connect("cleared",_on_slot_cleared)
neck_slot.connect("cleared",_on_slot_cleared)
belt_slot.connect("cleared",_on_slot_cleared)
gloves_slot.connect("cleared",_on_slot_cleared)
main_weapon_slot.connect("cleared",_on_slot_cleared)
offhand_slot.connect("cleared",_on_slot_cleared)
left_ring_slot.connect("cleared",_on_slot_cleared)
right_ring_slot.connect("cleared",_on_slot_cleared)

func _on_slot_cleared() -> void:
    remove_item_from_character(slot.get_item())
    pass
peter-kish commented 6 months ago

How do you know which slot was cleared?

The same way as with other Godot signals. If you're connecting signals from the editor then each object gets its own callback.

func _on_btn1_pressed():
    pass # Replace with function body.

func _on_btn2_pressed():
    pass # Replace with function body.

If you're connecting signals from code (your example) then you also have the options to bind parameters to the callback:

obj1.connect("signal", _on_signal.bind(obj1))
obj2.connect("signal", _on_signal.bind(obj2))

func _on_signal(obj):
    pass # Replace with function body.

Maybe I'm missing something but this is not really different from native Godot signals.

LeeWannacott commented 6 months ago

Maybe I'm missing something but this is not really different from native Godot signals.

Well some signals do give you arguments. Like for example; area_shape_entered gives you four of them: image

I think you can connect to the same callback from the editor as well. Like lets say you have two Area2D nodes and you connect them to the same callback:

You can do this by typing into the receiver method box the same callback name. image

In this case you would get the Body entered from either Area2D nodes in the one callback function.

All I'm saying is, if you give the slot then you could achieve the same from the editor as connecting and binding the slots to the same callback from code.

The use case is that you probably have some of the same logic, so you probably don't need multiple different callbacks with the same logic.

Either way, I'm not worried, I'll just connect and bind them in code; but newbies might not know how to do this.

peter-kish commented 6 months ago

Well some signals do give you arguments. Like for example; area_shape_entered gives you four of them

Sure, signal arguments in general are totally fine. I'm just saying that it makes no sense to add them for values that are easily obtainable in other ways (e.g. the Control.resized and Button.pressed signals I mentioned previously). It only clutters the interface.

As for newbie friendliness, I prefer being consistent with the existing Godot API. I agree that the interface should be simple to use, but adding unnecessary parameters doesn't really contribute to its simplicity.

peter-kish commented 5 months ago

InventoryItem.get_slot() is now available in v2.4.6. I'm still unsure about InventoryItem.remove_from_inventory() and decided to leave it out for now for the sake of a minimal interface. I will keep it in mind and might add it in a later release if it turns out to be super useful.