Inventory Container (UI or Programming?)

Hello, newer user here, trying to figure out how to display an inventory system in a roguelike deckbuilder ala Balatro.

The initial premise is that every card is an array of 3 values / var. These are organized as a custom class that I named CarD, because I’m a psycho.

class_name CarD

var base:int
var face:int
var suit:int

var card:Array = [base, face, suit]

These values dictate which of the 4 traditional suits the card is, it’s “power” level Ace - King, and the card’s condition / durability out of 100.
At the moment, I have created a control scene that has several Sprite2D children and a script in the root node that has a couple of functions that use the Sprite2D children to display the appropriate png according to these 3 variables stored in the card array.

oControl_Node
Lbase_sprite_2d
Lface_sprite_2d

if base >= 75:
$base_sprite_2d = load("full_health_sprite.png")
if face == 1 and suit == 1:
$face_sprite_2d = load("ace_of_clubs_sprite.png")

etc

I also have an autoload script which houses a variable that contains 52 arrays which each represent a unique card in a standard playing card deck, created with a function that calls on the custom card class, though I have tried just doing it manually as well.

var playerdeck: Array

func create_startdeck():
	for suit in range (1,5):
		for face in range(1,14):
			var startcard = CarD.new()
			startcard.base = 100
			startcard.face = face
			startcard.suit = suit
			playerdeck.append(startcard)

My plan / hope was that I would be able to call on a specific index in the var playerdeck (typically [0], representing the top card, and the one drawn after discards and played hands), apply it to the control node with the sprite scripting, and then display the sprite control scene in a container according to the game need. In the current case, I’d just like to display the deck in it’s entirety in a sort of inventory display using a grid container.

I originally planned to do this by creating a grid container, attaching a script to it, then use the script to parse the playerdeck from the autoload, apply the variables to the sprite scene, then .add_child or somehow populate the grid with that instantiated scene. Repeat for each card in the deck. I know how to pull the CarD arrays from the playerdeck, in this case by index[0] and by .front, but I am unsure how to transfer this information to the sprite control scene I preloaded in an @onready, and finally how to instantiate this scene into the grid container.

@onready var inventory_card = preload("AforementionedControlScene.tscn")

var topcard = Autoload.playerdeck[0] 

I have gotten as far as:

$grid_container.add_child(inventory_card)

but the only way it shows anything is if I hard-code in the base, face, suit values into the preloaded control script.

extends Control
var base = 100
var face = 1
var suit = 1

func ready():
if base >= 75:
$base_sprite_2d = load("full_health_sprite.png")
if face == 1 and suit == 1:
$face_sprite_2d = load("ace_of_clubs_sprite.png")

etc

but I get the error:
‘GridContainer’, already has a parent ‘GridContainer’

Which I think means that the .add_child() is an inappropriate function, and so is .add_sibling(). I might be able to sus this one out on my own, but since I’m here…

This is the direction I have been led by most tutorials before they begin to implement their own custom resources which seem to exclusively be static items with set values rather than more fluid, “breakable” ones. Stuff like swords and health potions, with a single unique sprite, and some set values that don’t seem to change. Since the tutorials only cover initial setup, I am unsure if or how they might implement a durability system that impacts the sprite texture, and the item’s very existence within the inventory. This is essential to my gameloop, and so I figured it must be handled immediately.
I have worked a bit with custom resources on this project, but I am having a hard time understanding how to implement them in this scenario, as I don’t know if the Resource class can accommodate images, and I am unsure if I can use them to apply the texturing function efficiently.
I have also seen some work done with Dictionaries, and it is probably a symptom of my inexperience, but I struggle to see the benefit to a Dictionary in this scenario, and their utility honestly confuse me to an extent. Arrays are simple for me, all I have to do is worry about a position, not a bunch of keys .
I am basically hoping to keep the CarD arrays stored in the playerdeck autoload unique, and rather than shallow or deep copying them into other scenes as necessary, doing all of the durability damage and other effects to the one copy of the card in the autoload. I understand this might be the setup for disaster, but it also seemed a lot lighter on the coding side (at the time).
As for displaying the deck as a whole, there is a definite chance that the size of the deck will change due to the durability system. The deck will not always be 52 cards, and it may be more at some point, so I am hesitant to try and create a system with a set number of slots, and instead hoping that a grid container would be able to dynamically accommodate and display them in a set number of columns, in this case 13.

ie (pardon the terrible ascii)

▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯
▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯
a 26 card deck

▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯ ▯
_______________▯ ▯
a 15 card deck

_____________▯ ▯ ▯
a 3 card deck

I am still trying to do my due diligence and research as many available tutorials as I can. Unfortunately at this point, I have tried to follow more than a few line for line and been left hanging because they use methods that I do not think are effective in my usecase. Though at this point I would be (somewhat) happy to learn that custom resources are what I should be using, I’m just hoping that I can cut to the quick here and get some learned advice.
I think I could bumble my way through this, writing specific code for every instance, making each possible card sprite and loading them specifically instead of in 3 parts. It just feels like there should be an easier way to strip the front element out of an autoloaded array, use the variables stored within that front element to inform three sprite nodes in a preload, then .add_child / instantiate them into a container.
I appreciate your time and patience in reading this novella and any advice you can offer.
Thank you so much!

It would be nice if you could boil the problem down to something that is easily digestible. Keep it to one topic. And provide a little more context around the problem.

This error means you are trying to add a node that has already been added to the tree. We will need a little more code to pinpoint the issue.


They can hold anything.

Dictionaries are Key-value pairs, great for no search lookup using keys. Best for unique values/resources that can be referenced by their unique key. And of course, data types have strengths and weaknesses.

Arrays would be good for a shuffled deck. Dictionaries can hold arrays or cards based on value or suit, no need to remember position if you know the suit or value you want. In other words great for caching a sorted category.

Well resources are usually meant for data only ( or for a nodeless system), the data can change, but UI/sprite nodes needs to handle the texture and visual representation. I.e. resources should not be responsible for behavior in this case. I would argue you dont need resource abstraction at all. Just make one CarD scene that can be all cards and have its stats select the textures at runtime. You have one thing to create and set and you can pass the card around.

Godot docs has some good pointers on how to think in Godot. The link should hit on most of your topics here. And making designs before you start to code is good engineering.

1 -

don’t mix Node2D and Controls. Controls should always have children that are also controls, they are designed to adjust their size and position automatically, given their anchor presets and containers.
use a TextureRect instead of Sprite2D.

2 -

you need a scene for previewing cards, one for playing, and one for each different thing the cards can be used for.
the preview_card scene has to be instantiated in the grid and it will prevent the player from using them while still displaying data. this can also be used to edit or rearrange the deck.

of course dealing with a deck builder game is all about data, so you should read a book or two on the data side of programming. you will need it to do things with the array that represents the deck.
think of this as an app that displays patients in a hospital or inventory for a store.

3 -

tutorials are not enough for this kinda game. you need more programming knowledge and experience, these games will get abstract, you are not dealing with concrete swords and potions anymore.

for something that changes, all you need to do is have an object to replace the previous one.
think of this: when the bucky card is destroyed, it is replaced by the winter soldier card. both cards were defined previously and you are just swapping one for the other.

durability is just a number, like health. you check the number and alter it.

for a game, you are gonna need more than just one array.
in my card game I had an array with the deck, and another one called temp_deck. when the game started the deck was duplicated and assigned to temp_deck.
this way cards can be deleted from temp_deck during game.
you can delete a card by deleting it from the array with erase(card).

4 -

you need an autoload to hold all the images or load them. you assign the images using an ID (a number) that will correspond to the image in the autoload, and assign it in your card Node.

5 -

Arrays are better for cards. arrays have everything a deck needs, including a sort method. and you want the deck to be unchanging until you say so and to be able to rearrange the items.


yes, this is the way to go.

1 Like

thank you both very much for your time and advice, the issue was a conflict between 2d and control scenes
i appreciate your help, have a great week