I’m trying to add tabs at the top of my inventory menu I’ve set up that can filter the viewable inventory by category. I’ve added category as a parameter of the items and can read the category of the item the cursor is on. The way I thought of for doing what I want to do is to duplicate the inventory arrays (plural because there’s an array of resources and an array of slots in the scene) for each category, then loop through each array and remove the elements that don’t match the category in question. Then I could update the shown inventory using of these new filtered arrays. Not sure if there’s a better way of doing that (if there is I’m all ears), but here’s the current code I have for my items_menu:
extends Control
@onready var category_cursor = $category_cursor
@onready var menu_cursor = $menu_cursor
@onready var pause_menu = get_parent()
@onready var pause_menu_holder = pause_menu.get_node("menu_holder")
@onready var inv : Inv = preload("res://inventory/player_inventory.tres")
@onready var inv_panel = get_node("menu_holder/VBoxContainer/inventory_panel")
@onready var inv_container = inv_panel.get_node("HBoxContainer/left_panel/MarginContainer/ScrollContainer/GridContainer")
@onready var slots : Array = inv_container.get_children()
@onready var item_slot = preload("res://inventory/inv_UI_slot.tscn")
@onready var focused_slot
@onready var focused_slot_name
@onready var canvas_layer = $CanvasLayer
@onready var use_item_confirmation = canvas_layer.get_node("use_item_confirmation")
@onready var confirmation_cursor = use_item_confirmation.get_node("menu_cursor")
@onready var sel_category : String
@onready var inv_beneficial : Array
@onready var inv_harmful : Array
@onready var inv_materials : Array
@onready var inv_tomes : Array
@onready var inv_weapons : Array
@onready var inv_armor : Array
@onready var inv_key : Array
@onready var beneficial : Array
@onready var harmful : Array
@onready var materials : Array
@onready var tomes : Array
@onready var weapons : Array
@onready var armor : Array
@onready var key : Array
func _ready():
inv.update.connect(update_slots)
inv.new_item_obtained.connect(add_new_slot)
menu_cursor.focus_changed.connect(focus_on_new_slot)
#get_viewport().gui_focus_changed.connect(focus_on_new_slot)
focus_on_new_slot()
visible = false
category_cursor.cursor_active = false
set_process(false)
func _process(_delta):
update_slots()
if inv.slots.size() > 1:
inv.slots.sort_custom(sort_items_by_item_index)
if slots.size() > 1:
slots.sort_custom(sort_nodes_by_item_index)
get_inv_categories()
get_selected_category()
update_slots()
if Input.is_action_just_pressed("cancel") and !menu_cursor.cursor_waiting:
category_cursor.cursor_active = false
menu_cursor.cursor_active = false
var pause_cursor = pause_menu.get_node("menu_cursor")
pause_cursor.cursor_active = true
pause_cursor.cursor_waiting = true
pause_menu_holder.show()
pause_menu_holder.set_process(true)
hide()
set_process(false)
func sort_items_by_item_index(a, b):
if a.item.item_index < b.item.item_index:
return true
return false
func sort_nodes_by_item_index(a, b):
if a.item_index < b.item_index:
return true
return false
func update_slots():
if inv.slots.size() > slots.size():
add_new_slot()
slots = inv_container.get_children()
if sel_category == "All":
for i in range(min(inv.slots.size(), slots.size())):
slots[i].update(inv.slots[i])
if sel_category == "Beneficial":
for i in range(min(inv.slots.size(), inv_beneficial.size())):
slots[i].update(inv_beneficial[i])
#print(inv_beneficial)
func add_new_slot():
var instance = item_slot.instantiate()
inv_container.add_child(instance)
slots = inv_container.get_children()
# Runs when focus changes
func focus_on_new_slot():
focused_slot = menu_cursor.menu_item
if focused_slot:
focused_slot_name = focused_slot.item_name
for i in range(slots.size()):
if slots[i].item_name == focused_slot_name:
if !slots[i].cursor_selected.is_connected(item_selected):
slots[i].cursor_selected.connect(item_selected)
if !slots[i].purge_slot.is_connected(purge_slot):
slots[i].purge_slot.connect(purge_slot)
else:
if slots[i].cursor_selected.is_connected(item_selected):
slots[i].cursor_selected.disconnect(item_selected)
if slots[i].purge_slot.is_connected(purge_slot):
slots[i].purge_slot.disconnect(purge_slot)
func purge_slot(slot):
var slot_index = inv.slots.find(slot, 0)
inv.slots.remove_at(slot_index)
# Runs when an ite is selected
func item_selected():
if !focused_slot.usable_from_field:
return
menu_cursor.cursor_active = false
use_item_confirmation.show()
use_item_confirmation.set_process(true)
confirmation_cursor.cursor_active = true
confirmation_cursor.cursor_waiting = true
set_process(false)
func get_inv_categories():
beneficial = slots.duplicate()
for i in range(beneficial.size() - 1):
if beneficial[i].item_category != "Beneficial":
beneficial.remove_at(i)
inv_beneficial = inv.slots.duplicate()
for i in range(inv_beneficial.size() - 1):
if inv_beneficial[i].item.category != "Beneficial":
inv_beneficial.remove_at(i)
func get_selected_category():
sel_category = category_cursor.menu_item.text
The most relevant parts of the code are the get_inventory_categories() and update_slots() functions, as that’s where I currently have my attempt at implementing this category system. With this code I can still see all my items with any category selected. Any help is appreciated!
Alrighty, after some more learning and experimenting I think I have it figured out. Got rid of one of the sets of arrays, only ended up needing one. For anyone who comes across a similar situation, here’s my code now that has been working so far:
extends Control
@onready var category_cursor = $category_cursor
@onready var menu_cursor = $menu_cursor
@onready var pause_menu = get_parent()
@onready var pause_menu_holder = pause_menu.get_node("menu_holder")
@onready var inv : Inv = preload("res://inventory/player_inventory.tres")
@onready var inv_panel = get_node("menu_holder/VBoxContainer/inventory_panel")
@onready var inv_container = inv_panel.get_node("HBoxContainer/left_panel/MarginContainer/ScrollContainer/GridContainer")
@onready var slots : Array = inv_container.get_children()
@onready var shown_inv : Array = inv.slots
@onready var current_cat : String
@onready var empty_item_slot = preload("res://inventory/empty_inv_UI_slot.tscn")
@onready var item_slot = preload("res://inventory/inv_UI_slot.tscn")
@onready var focused_slot
@onready var focused_slot_name
@onready var canvas_layer = $CanvasLayer
@onready var use_item_confirmation = canvas_layer.get_node("use_item_confirmation")
@onready var confirmation_cursor = use_item_confirmation.get_node("menu_cursor")
@onready var sel_category : String = current_cat
@onready var inv_empty : bool = true
@onready var inv_beneficial : Array
@onready var inv_harmful : Array
@onready var inv_materials : Array
@onready var inv_tomes : Array
@onready var inv_weapons : Array
@onready var inv_armor : Array
@onready var inv_key : Array
func _ready():
inv.new_item_obtained.connect(add_new_slot)
menu_cursor.focus_changed.connect(focus_on_new_slot)
update_categories()
focus_on_new_slot()
visible = false
category_cursor.cursor_active = false
set_process(false)
func on_open():
pass
func _process(_delta):
slots = inv_container.get_children()
# Function that adds or subtracts 'empty slots' as necessary
adjust_empties()
# Function that filters slots into a new array for each category
get_inv_categories()
# Function that updates sel_category to be what the cursor is on
get_selected_category()
# Update shown_inv to match the category's array
update_categories()
# Sort shown inventory if it contains more than 1 item
if shown_inv.size() > 1:
shown_inv.sort_custom(sort_items_by_item_index)
# Correct slots size, then update contents to match shown_inv
update_slots()
if Input.is_action_just_pressed("cancel") and !menu_cursor.cursor_waiting:
menu_cursor.set_cursor_from_index(0)
category_cursor.set_cursor_from_index(0)
category_cursor.cursor_active = false
menu_cursor.cursor_active = false
var pause_cursor = pause_menu.get_node("menu_cursor")
pause_cursor.cursor_active = true
pause_cursor.cursor_waiting = true
pause_menu_holder.show()
pause_menu_holder.set_process(true)
hide()
set_process(false)
func get_selected_category():
sel_category = category_cursor.menu_item.text
func sort_items_by_item_index(a, b):
if a.item.item_index < b.item.item_index:
return true
return false
func sort_nodes_by_item_index(a, b):
if a.item_index < b.item_index:
return true
return false
func update_slots():
if inv_empty:
return
if slots.size() < shown_inv.size():
while slots.size() < shown_inv.size():
var instance = item_slot.instantiate()
inv_container.add_child(instance)
slots = inv_container.get_children()
if slots.size() > shown_inv.size():
if inv_empty:
while slots.size() > 1:
inv_container.get_child(-1).free()
slots = inv_container.get_children()
slots[0].update(empty_item_slot)
if !inv_empty:
while slots.size() > shown_inv.size():
inv_container.get_child(-1).free()
slots = inv_container.get_children()
for i in range(shown_inv.size()):
slots[i].update(shown_inv[i])
func update_categories():
if sel_category == "All":
shown_inv = inv.slots
if sel_category == "Beneficial":
shown_inv = inv_beneficial
if sel_category == "Harmful":
shown_inv = inv_harmful
if sel_category == "Materials":
shown_inv = inv_materials
if sel_category == "Tomes":
shown_inv = inv_tomes
if sel_category == "Weapons":
shown_inv = inv_weapons
if sel_category == "Armor":
shown_inv = inv_armor
if sel_category == "Key":
shown_inv = inv_key
current_cat = sel_category
func add_new_slot():
var instance = item_slot.instantiate()
inv_container.add_child(instance)
slots = inv_container.get_children()
focus_on_new_slot()
# Runs when focus changes
func focus_on_new_slot():
menu_cursor.menu_item = menu_cursor.get_menu_item_at_index(menu_cursor.cursor_index)
focused_slot = menu_cursor.menu_item
if focused_slot:
focused_slot_name = focused_slot.item_name
for i in range(slots.size()):
if slots[i].item_name == focused_slot_name:
if !slots[i].cursor_selected.is_connected(item_selected):
slots[i].cursor_selected.connect(item_selected)
if !slots[i].purge_slot.is_connected(purge_slot):
slots[i].purge_slot.connect(purge_slot)
else:
if slots[i].cursor_selected.is_connected(item_selected):
slots[i].cursor_selected.disconnect(item_selected)
if slots[i].purge_slot.is_connected(purge_slot):
slots[i].purge_slot.disconnect(purge_slot)
func purge_slot():
var slot_index = inv.slots.find(focused_slot.slot_to_purge, 0)
inv.slots.remove_at(slot_index)
# Runs when an item is selected
func item_selected():
focus_on_new_slot()
if !focused_slot.usable_from_field:
return
menu_cursor.cursor_active = false
use_item_confirmation.show()
use_item_confirmation.set_process(true)
confirmation_cursor.cursor_active = true
confirmation_cursor.cursor_waiting = true
set_process(false)
func get_inv_categories():
inv_beneficial = inv.slots.filter(filter_for_beneficial)
inv_harmful = inv.slots.filter(filter_for_harmful)
inv_materials = inv.slots.filter(filter_for_materials)
inv_tomes = inv.slots.filter(filter_for_tomes)
inv_weapons = inv.slots.filter(filter_for_weapons)
inv_armor = inv.slots.filter(filter_for_armor)
inv_key = inv.slots.filter(filter_for_key)
func filter_for_beneficial(item):
if item and item.item:
return item.item.category == "Beneficial"
return false
func filter_for_harmful(item):
if item and item.item:
return item.item.category == "Harmful"
return false
func filter_for_materials(item):
if item and item.item:
return item.item.category == "Materials"
return false
func filter_for_tomes(item):
if item and item.item:
return item.item.category == "Tomes"
return false
func filter_for_weapons(item):
if item and item.item:
return item.item.category == "Weapons"
return false
func filter_for_armor(item):
if item and item.item:
return item.item.category == "Armor"
return false
func filter_for_key(item):
if item and item.item:
return item.item.category == "Key"
return false
func adjust_empties():
if slots.size() == 0:
slots.append(empty_item_slot.instantiate())
inv_empty = true
if slots.size() == 1:
if slots[0].is_empty == true:
inv_empty = true
else:
inv_empty = false
if slots.size() > 1:
if slots.any(check_for_empties):
var empty_node = inv_container.get_node("empty_inv_UI_slot")
empty_node.free()
inv_empty = false
slots = inv_container.get_children()
func check_for_empties(slot):
if slot:
return slot.is_empty == true
return false