Chu Edit: for some reason, the spaces are not properly shown for code sections, so I added these {} for clarity.
First, for the queue_free()
error:
It basically means giving the queue_free() order several times. Since it's already freed, it's trying to free "null" (although it's not really null, the message is kind of misleading... it's rather an "invalid instance"), hence the error. It doesn't really damage things but indicates something wrong with the code (could cause slowdown though). It happened to me when I once put the command inside the func _process(delta):
, which caused the code to run every frame. To solve it:
A) Make sure you only call the command once (maybe by some made-up variable check).
OR
B) Add this simple check:
if is_instance_valid(slot.item): slot.item.queue_free()
TIP: Usually, finding out what's causing the error on your own is easy, since there are probably other people who had the same error. Just google the error...
Chu "Attempt to call queue_free() in base previously_free on a null"
...and you should find something that will help explain things in detail, like this:
https://gamedev.stackexchange.com/questions/192362/what-is-happening-during-queue-free-process
As for the "setItem()" role, it's obviously a made-up function. To understand that, you should know how made-up functions work first. They can be called whenever and assigned a value, for example:
_some_words_representing_a_function(*value, could be anything from a number to a whole scene instanced)
Then, here's how to define what the function actually does:
func _some_words_representing_a_function(something):
*some lines of code doing something)
Now, whatever value you sent is represented by the exact word something
.
NOTE: There are also void functions that do NOT send any values when called, e.g. _some_words_representing_another_function()
By this understanding, here's what the function setItem(newItem)
does:
func setItem(newItem):{
add_child(newItem);
item = newItem;
item.itemSlot = self;
}
This is obviously NOT a void function, it receives a certain variable represented by newItem
. This variable is supposed to be an instanced scene (of a particular item's icon) because it's added as a child of the ItemSlot node in add_child(newItem);
. This is apparent in this slot.setItem(ItemClass.new(itemName, itemIcon));
code line, in "Inventory.gd".
The next line of code is simply assigning whatever variable newItem represents to the previously defined variable item
. Despite being simple, this here is the key to the solution to your problem.
The last line of code is again defining the variable itemSlot
in "Item.gd" to self
, which represents the node to which "ItemSlot.gd" is attached. What this is used for is not very clear... maybe I'm missing something. Anyway, this shouldn't affect how to solve your problem.
Now here is the solution that I believe will do the trick, though there is a chance I'm still missing something. It's in 'spoiler', in case you want to try on your own given the above explanation and my previous answer.
The only thing that defines whether a "slot" is full or not is the variable item
. If it's null, then the slot is empty. If it's not null, the slot is full. Here's the catch, when the instanced scene is freed, the variable is still NOT NULL (as mentioned above); it's only "invalid". To make it null...
Click to reveal
Click to hide
Add the following line of code to the _on_button_pressed()
function of the DISCARD BUTTON:
slot.item = null
, so the overall code becomes something like:
func _on_button_pressed():{
for slot in slotList:{
if is_instance_valid(slot.item):{
slot.item.queue_free();
call_deffered("nullSlotItem");
}}}
func nullSlotItem():{
slot.item = null
}
I hope this actually works... If it does work, then you can ask me why I wrote the code this way.