Hello i have a few questions

Godot Version

4.4

Question

hello im making like a “base code” for my cards for a tcg game is there somthing i should take into consideration that im missing?

extends Node2D

@export var card_name:String = "card name"
@export var card_des:String = "card description"
@export var card_value:int = 1
@export var card_texture:Sprite2D
@export var card_class:String="class"

func _ready():
	pass

1 Like

is there somthing i should take into consideration that im missing?

It’s really too early to tell. Everyone runs into problems eventually when making games, it’s an unavoidable part of programming, and creation in general.

You’ll have no idea what you’re missing until you make something without it, then have to go back for it later. It’s impossible to prepare for everything in advance.

4 Likes

yeah its hard.
im thinking of ways to make the code check for this variables

don’t use a bunch of exports, use unexported variables and set them when the node is created. It would be preferred to get the cards from a text resource or an array created in code, containing all the cards.

this is resource consuming and kinda useless.
define the name once in an autoload and pass it to the text value of the label. don’t keep duplicate variables when you don’t need to.

same thing here.
keeping all your names and descriptions in an array or dictionary makes it easier to setup translation and also edit the text later.

this could be in the actual card if it’s something like health, that needs to change. but I would still store the default value of the card in an array.

don’t do this. you can use an ID (int) and retrieve the image or path from an autoload.

use an int for this. Strings are expensive and use a lot of memory.
you can define an enum to make things easier.

what I did in my card game was create a resource called CardData with a constructor, and set the values as I added them to an array in an autoload. I could replace this behavior with getting the values from a text file.
you get the resource and use the values to assign them to the card.
this also helps when you need the cards in a deck, so that they are not physical cards but a bunch of variables.

3 Likes

i did it this way because i want the game to check for this variables. the database i heard that is more complicated when you are making a tcg like game. (like mtg for example)
also i dont have labels or anything the card has a texture with all the info. the info in code i just need it for the code to know how the card reacts with other cards.

do you have a youtube channel?

For a trading card game, I would create resources for each card. The resource template I used would depend on the class type of the card. I would maintain a catalog of the cards to refer to the resources. Then a base scene for each card type would extend a base class for each card, for shared functionality for all cards, with each sub class for specific card-type functionality.

So card catalog:

class_name CardCatalog
extends Object

const CARDS: Dictionary = {
	"Bearded Monster": preload("res://cards/monster_cards/bearded_monster.tres"),
	"Fuzzy Rabbit": preload("res://cards/monster_cards/fuzy_rabbit.tres"),
	"Power Shield": preload("res://cards/power_up_cards/power_shield.tres"),
	"Machine Gun": preload("res://cards/weapon_cards/machine_gun.tres"),
        # etc

Then each card type would use a resource template to create the card resource:

class_name MonsterCard
extends Resource

@export var display_name: String = ""
@export var monster_family: String = ""
@export var power_modifier: int = 0
@export var speed_modifier: int = 0
@export var health_modifier: int = 0

Then you might have a base card class:

class_name CardClass
extends Node2D

func get_card_name() -> String:
   ....

func make_card_active() -> Void:
   ....

func set_card_belongs_to() -> Void:
   ....

Then a sub class…

class_name MonsterCard
extends CardClass

func get_monster_affects() -> Dictionary:
   -- interigates resource for monster affect values

Then you would have a deck created from the card catalog, put it through a shuffle function, deal the card references out to players. Have a turn manager decide who is acting, get them to select a card, use the card resource to decide its affects, implement those effects and then move on to the next turn.

Then adding a new card to your game is as simple as creating the resource and adding it to the card catalog.

Something like that anyway.

Now say you wanted to add ‘gold_acquired’ to the monster cards. You would change your resource template and add that variable and a default value. Now every monster card has that variable. To change the value for each card you edit the resource in the editor. Add the functionality into your card processing loop and you are done. Want to add a new card class, create a new template, create a resource, create a card in the catalog, and then add the code to deal with any new actions. All your base card functionality will already be included.

2 Likes

i think i understand this, basically but for example for this part can i do it that it checks if the card is a creature or something else and only display the creature stats if its one

class_name MonsterCard
extends Resource

@export var display_name: String = ""
@export var monster_family: String = ""
@export var power_modifier: int = 0
@export var speed_modifier: int = 0
@export var health_modifier: int = 0



like this i make one script for every card and then using that script i extend it for other cards and then i only need to code what they do

The name MonsterCard should now appear as a property when you create a new script.

So pick a folder in the file system that you want to create your resources in. Right click and ‘create new’ and choose ‘resource’. Name that, say, test_card, and create your new resource (whilch will be based on the MonsterCard resource template above).

Now when you double click that resource (it will not open in the script editor) and you will see it in the inspector (where you normally see your node info). You will see all and any values you have in the template, ready for you to complete. Do this for say three cards initially. Then make your card catalog. Now suppose you want to add some artwork, you can add the card_picture_file to the resource and it will now appear in all your card resources automatically set to whatever default you put in there (say a blank image or default placeholder image).

Now lets say you want to display a card. You have one single general card scene. You instantiate it, read the required resource from the catalog, set your vars in the basic card_scene like card_title, etc, and you are away. One scene for all cards, one catalog for all cards etc.

Even better if you make your catalog a const, you can just access it from anywhere with the catalogs class name:

var all_cards = CardCatalog.CARDS
# now you can loop through all cards if you want

var card_data = CardCatalog.CARDS["Bearded Monster"]
# now you have access ot all the data related to a particular card
print(card_data.display_name)

Anyway, just so you know, this is just how I would do it. There may be even more powerful ways that I do not know about!

You should have a good read about resources in the docs. They are incredibly useful and fast and powerful.

Hope that helped a bit.

why are you extending object?
if this is an autoload it should be Node, otherwise use a Resource since it’s memory safe.

It is not an autoload. It is just a dictionary to list resources by reference. That is why I call it a catalog. It is also not a node so that is why I don’t extend node or node2D. They themselves extend objects too. This catalog does not appear in the tree ever.

Here is an example of one of my own tile catalogs. When I am generating a tilemap I use this to control which tiles to set.

class_name TerrainCatalog
extends Object

const TERRAIN_TILES: Dictionary = {
	"grass_short": preload("res://environment/map_tiles/tile_data/grass_short.tres"),
	"grass_normal": preload("res://environment/map_tiles/tile_data/grass_normal.tres"),
	"grass_long": preload("res://environment/map_tiles/tile_data/grass_long.tres"),
	"mud_dry": preload("res://environment/map_tiles/tile_data/mud_dry.tres"),
	"mud_normal": preload("res://environment/map_tiles/tile_data/mud_normal.tres"),
	"mud_wet": preload("res://environment/map_tiles/tile_data/mud_wet.tres"),
	"rock_gravelly": preload("res://environment/map_tiles/tile_data/rock_gravelly.tres"),
	"rock_normal": preload("res://environment/map_tiles/tile_data/rock_normal.tres"),
	"rock_solid": preload("res://environment/map_tiles/tile_data/rock_solid.tres"),
	"sand_deep": preload("res://environment/map_tiles/tile_data/sand_deep.tres"),
	"sand_light": preload("res://environment/map_tiles/tile_data/sand_light.tres"),
	"sand_normal": preload("res://environment/map_tiles/tile_data/sand_normal.tres"),
	"water_deep": preload("res://environment/map_tiles/tile_data/water_deep.tres"),
	"water_normal": preload("res://environment/map_tiles/tile_data/water_normal.tres"),
	"water_shallow": preload("res://environment/map_tiles/tile_data/water_shallow.tres"),
        etc etc

And just for completeness here is the template for the tile terrain resource:

class_name TerrainResourceTemplate
extends Resource

@export var cell_atlas: Vector2i = Vector2i.ZERO
@export var display_name: String = ""
@export var tile_family: String = ""
@export var tile_family_type: String = ""
@export var min_altitude: int = 0
@export var max_altitude: int = 0
@export var min_moisture: int = 0
@export var max_moisture: int = 0
@export var min_temperature: int = 0
etc etc

It may be that extending object is not correct, but it is working beautifully at the moment and it is so fast! Blazingly fast. I use the same method for my plants, and creatures, and collectables and despite the lengthy setup it is so easy to maintain and use.

I just thought this would be an ideal approach for the OPs card trading game as well.

As I said though, there are many ways to approach this and no single right way. This is just the way I would do it. My last game ended up with about 20 autoloads in it and I just thought that my use of singletons was going too far.

What would you use for a system wide catalog reference system? Like when my player enounters a plant, I look up the reference in the catalog and access the properties to see if it is poisonous, or if I can hide in it etc.

@jesusemora
Oh. Actually you may be right. I didn’t know that Objects are not memory safe.

Now I am not sure what to extend for my catalogs. I was using objects for my queue management as well.

damn. And thanks for pointing that out.

I changed them:

class_name TerrainCatalog
extends Resource

class_name TerrainResourceTemplate
extends Resource

There seems to be no downside to it at the moment!

@itamarstaroselski123 I think @jesusemora was right, don’t extend object.

so i make the base one a resource and then i extend from there.

1 Like

Or a refcounted which is just like extending an object but is reference counted. The only idea here is to use a node without any unused additional weight that a resource node or a node2D would bring if you don’t need it.

Yeah I recommend extending a Resource. It’s got a lot of benefits. For example, when they are stored , they are .tres files which are text resources. You can open and read them for debugging, and change values easily in the editor. When the game is exported, they are stored as binary files with a smaller footprint and more secure.

They also implement ResourceSave and ResourceLoad, which isn’t something you need now, but when your data structures get more complex, it’s a lot easier to save objects inside a Resource than to try and convert them to JSON using Godot. (In my experience.)

Did I mention it is really easy to edit a Resource in the Editor? Double-click and it and change what you want. Set a custom icon for it if you want. You can also store them in Dictionaries.

I also agree with @jesusemora about not using all those export variables, but I recommend you make that change later. Early on it’s a lot easier to test and change things with Export variables. Also, you can combine the advice, and make a Resource for your cards and then an export variable for that resource. For example if you have a resource called Card.

@export card_info: Card

This can replace your example code from the beginning.

1 Like