No Experience. Trying to build a Bestiary/Glossary as my first major project

What would the best way to be to create a dynamic glossary?

Hello folks,

I have minimal coding experience. I did almost every lesson from GDQuest’s “Learn to Code from 0” and have an extremely rudimentary understanding of GDScript and Godot. I’ve followed a few other tutorials and have made a very basic platformer in 2D without burrowing too in-depth in other areas for coding.

I’ve spent the last few weeks looking up tutorials, studying the godot engine documents on the .org, fiddling with code and creating very small test runs of various things, so I understand GDscript enough to use it comfortably, but I’m still struggling with slightly more advanced concepts (and I’m still struggling with the basics but I’m making efforts).

I have a few very simple projects in mind to work on, but the one I’m most interested in and have been working on for almost a year or so now is my own personal Glossary / Bestiary / Pokedex like application that I can use to automatically sort my original creatures. My goal is to create an interactive bestiary that can toggle the order of the creatures presented, based on the various variables I apply to every creature I (hypothetically) introduce to the project.

Right now, I only have working buttons and screens for the title screen, start menu, settings, game closing, and a nebulous space where the “application” would be running as a 2D node with a GUI attached to it (that can close back to the start menu).

I know this is a big ask and I appreciate anybody who has taken the time to read and muse over my writing here. I’m actually an artist first and foremost well before I am a coder. I have a Master’s in Illustration and my work is quite good, so I’d be interested in trading my artistic skills for some assistance if that may be the case.

Let me know what you think, send tuts and resources if you can. Good luck on your projects!

~R.

UPDATE #1: You all are so helpful. I genuinely feel seen and confident. I will reply to everyone as soon as I make serviceable progress. Thank you all so much!

func _ready() -> void:
    print("hello world")

For those who can see this, I did another tutorial (the actual first-game tutorial by the Godot team themselves, I missed that one) and it opened up a lot of understanding for me.

I have a much better idea for how to layout my project, but I’m still going in mostly unaware. I’ve looked at a few monster-catching/monster-adjacent pieces of media to see how they handle their indexes.

I’m contemplating how to tackle it, but I’m replying to this to bump it in case somebody with some insight comes along!

What exactly is it that you are looking for or asking?

What do you mean by indexes? Just in which order by number they will appear in the bestiary?

I think that would depend on what you think fits the game best and there are probably not any strictly better or worse as long as the indexing is somewhat understandable.

Perhaps by region or by type would work. Or if you plan to have a lot of entries: separate by region and then within each region, separate by type within that region. In the end i wouldn’t worry too much. If for now you just sort them by order of encounter or alphabetically or whatever, it would be very easy to change it later on when you’ve come up with an idea you’re happy with. Just keep it in the back of your mind while doing other things

As I understand, you have the UI in place but your struggle with the logic for the data.

If you want a list of “compound” objects and to be able to sort them on different properties, here is a minimal solution example you can start from

1- create a class to represent your “collectibles” (I’ll take the examples of Pokemon’s)

In this class, declare the attributes you want to sort on. You can also declare other attributes and functions for other use.

class Pokemon:
    var name: String
    var size: int

2- create another class holding the list and sending signals when you add or remove collectibles

This class could hold the function for sorting too

class Pokedex:
    var pokemons: Array[Pokemon] = []
    
    # emitted when the list change
    signal updated() 

    func add(pokemon: Pokemon):
        pokemons.append(pokemon)
        updated.emit()

    func remove(pokemon: Pokemon):
        # I'm on phone,
        # I don't have the exact logic for removal right now
        updated.emit()

    func sort_by_attribute(attribute_name:String):
        #this part is tricky
        pokemons.sort_custom(func(a,b):
            # guard against errors
            if not a.get(attribute_name):
                return true # default sorting
            if a.get(attribute_name) < b.get(attribute_name):
                return true
            return false
        )
        updated.emit()

3- connect the list update to a view refresh (I let you work on this one)

var list = Pokedex.new()
list.updated.connect(refresh_view)

var Pikachu = Pokemon.new()
pikachu.name = "Pikachu"
pikachu.size = 4
list.add(pikachu)

var charmander = Pokemon.new()
charmander.name = "Charmander"
charmander.size = 2
list.add(Charmander)

list.sort("size")

Here, it’s only the base for the data logic I would implement. There are many other ways.

If you choose to follow this path, don’t forget to store a reference for the “abstract” Pokémon in the list, inside the UI object (list item, tree item…) so you can delete or manipulate it. Check metadata properties for this.

Hope this helps and good luck!

Actually i don’t know anything about bestiaries and never played pokemon, but i believe that learning about arrays, dictionaries and ui containers should help you because these are mostly used to create grids / indexes

To expand what @gui wrote:

If you want to structure your UI Control nodes for dynamic glossary to the point you can add new creatures and change the settings in-game directly then…


Supposedly, create a pokemon_viewer.tscn with Control node as the root. There you can add multiple Labels to show properties of your creature.

There you can add SubViewport with Node3D and Camera3D node in it so you could show off the 3D model of your creature directly. Or instead you could just put TextureRect or AnimatedSprite2D (yep they work here too) to show off your creature.

Now you can attach script to it that would be like this:

@tool
extends Control

# onready means that the path/to/your/label will be _ready() and not null in label_name
@onready var label_name = $path/to/your/label

@onready var image = $path/to/your/texturrect

# we use setter here. when creature_name is changed (from editor or in-game) then we dynamically change the label!
@export var creature_name : String:
	set(value):
		creature_name = value
		label_name.text = value

@export var creature_texture : Texture2D:
	set(value):
		creature_texture = value
		image.texture = value

# and so on

Notice on top @tool this means that if you changed some of the @export properties from Inspector window in editor then the changes will actually be reflected in editor.


Now you can use your pokemon_viewer.tscn in your other Control nodes.

Imagine pokemons.tscn with Control node as the root. There you could have HBoxContainer (to display pokemons in horizontal list). And in that container you can have as many pokemon_viewer.tscns as you want. You can change values of each pokemon_viewer.tscn node in Inspector and they would be unique!

This is actually very much in line with what I’m trying to do. I’m not making a monster catching game, JUST the bestiary/index (the index being a list of monsters).

My goal for this project is solely to make a simple app that automatically sorts monsters as i allot them values. Kind of already like what you’re saying, I have them organized by region first, but they are organized more specifically down to each detail.

The hierarchy of organization goes like this: Region > Rarity > Threat Level > and lastly Size.

Let’s say I have three regions: A Forest, A Desert, and the Ocean.

The way I want to organize these creatures is that the Forest is always first, then the Desert, and then the Ocean. Inside those environments however, the next priority would be rarity, from common, to uncommon, to rare, etc etc. So in every biome the most common monsters would be first and the least common would be at the very back.

I ideally would have this cascade down infinitely.

This is more like an application than a proper GAME project, but I’m still very interested in doing it.

My ultimate goal is to create this in such a way that whenever I added a new monster entry into the program it would automatically sort and number itself based on the hierarchy I’ve established. So if i wanted to add a new monster to the forest, it wouldn’t wind up at the very back of the index, but would land wherever it fit in my hierarchy tree.

Does that make sense? I appreciate your response.

Looking into it, thank you!

You know how pokemon or any other monster adjacent game has an encyclopedia of monsters? I’m trying to create JUST the encyclopedia.

My ultimate goal is to have a functional encyclopedia that

  1. loops to the front when it gets to the end

  2. Has a hierarchy breakdown for how it organizes monsters, automatically sorting them similarly to an alphabet like so: Region(A) > Rarity(B) > Threat(C) > Size(D). In this way, all of the monsters in one region would be organized together, and then the most common monsters would appear before the least common, and in the midst of their commonality, the least dangerous ones would appear before the most dangerous ones.

  3. I also need it programmed this way so that when I add more monsters to the index they automatically sort into the structure of the hierarchy rather than just become tacked onto the end.

Extremely helpful. I appreciate the attempt.

I will fiddle around with this for a while and return with results! Thank you!

Thank you so much! I appreciate the help.

I’m going to fiddle around with your solutions and get back to you later! This was incredibly insightful!

I may be a bit boring now but i believe that you could achieve the exact same effect but without the complexity. Just add a variable like index: int and let the bestiary display them in order. There would be no need for complex, error prone or difficult to debug logic. Just “ok i display monster #1 here, 2 here, 3 here, skip 4 since not unlocked, 5 here, skip 6, etc”. And for other ways of sorting, like rarity, size or whatever, just give them separate indexes, and tell the bestiary to update the list of monsters when switching modes.

Its not very exciting in itself, and i would not suggest it as a solution for a real world naturalist coding an app with scientific ambitions, but it is simple and gives you full control over exactly where to display any monster. Perhaps you want to break some rule and put a werewolf or zombie next to an entry for infected humans, but in the code the monster itself belongs to wolf or undead class or whatever. Just sorting by index would make it simpler.

Your “nested sorting” idea is interesting, and the algorithm for it isn’t so easy.

As always there are many ways of achieving it. I would try sorting the list multiple times, from the less priorized to the much priorized

list.sort_by_attribute("threat")
list.sort_by_attribute("place")

Logically you should have monsters sorted by place, and in a same place sorted by health… and so on

But I can’t be sure, needs testing

Separate your gui from your data. On the data side, you can have a single resource class that holds all properties of a creature. In the gui side, you can have a scene that can configures itself to display any given resource object.

That way, any grouping / sorting becomes trivial. You just get all of the resource objects into an array, write a custom sorting predicate and pass it to Array::sort_custom(). Then feed the sorted items sequentially to the gui scene to display.

Update #2

I’ve made slow and steady progress on this project. I have yet to implement any visible features but my code is starting to take shape. I have yet to properly stitch together scene transitions to get to the gui’s space and I haven’t gotten the gui to function just yet.

class_name Monster
extends Node2D

@export_subgroup("Classification Data")
@export_enum("-", "Any", "Forest", "Mountain","Ocean") var Environs: int
@export_enum("-", "Common", "Uncommon", "Rare") var Rarity : int
@export_enum("-", "Low", "Moderate", "High") var ThreatLvl : int
@export_enum("-", "Small", "Medium", "Large") var Size : int
@export_enum("-", "Beast", "Cephalopod", "Dragon",) var Category : int

#This is an example of the code I've been using to start my monster class. It works so that I can select Monster Settings within a drop-down when I create a new monster instance.

Here’s one of the first monster instances I made so far. For some reason, I’m really taken to the idea of Kelpies and “Water Horses”, and will be implementing a few of them sort of as a mascot for this project I think.

I’ve made at least ONE monster for each “Environs” enumerated variable and plan to make more.

I’ve hard coded some soft scene-transitions that directly target different scenes, but I have yet to make a fully functional “MAIN” or “GAME” scene that houses ALL the assets and/or sub-nodes inside of it. More research is required.

I also basically haven’t touched the hypothetical “monster viewer/pokemon viewer” in depth yet. I’ve set up a few test scenes with control nodes but I’m struggling with the scripting. More research is required. This is not a bad thing, though!

Please feel free to reply directly to this if you can see it. All thoughts and opinions are appreciated. Sometime next week I will be replying to specific people in this thread with progress reports and further questions.

Thanks all for your help so far!

~ R.

Hello! Good progress on your glossary @raineworker but I would like to add something…

The hierarchy of organization goes like this: Region > Rarity > Threat Level > and lastly Size.


Your current code would be problematic later on for “custom sort” based on specific variables (the one @gui proposed). I would recommend doing this:

class_name Monster
extends Node2D

enum GlossaryRegion {
	FOREST,
	DESERT,
	MOUNTAIN,
	OCEAN
}

enum GlossaryRarity {
	COMMON,
	UNCOMMON,
	RARE,
	LEGENDARY,
	MYTHICAL
}

enum GlossaryThreatLevel {
	LOW,
	MODERATE,
	HIGH
}

# ... and other enums

# doesn't really matter if you choose @export_subgroup or @export_category
@export_category("Classification data")

# this matters
@export var environs : GlossaryRegion = GlossaryRegion.FOREST
@export var rarity : GlossaryRarity = GlossaryRarity.COMMON
@export var threat_lvl : GlossaryThreatLevel = GlossaryThreatLevel.LOW

# ...
# this way you have explicit enum data (that can be also re-used from other scripts later on. so you don't have to keep in your head everything)
# and easy @export variables change from inspector.

Hey, thanks for looking out!

I implemented this now and it’s already way cleaner. I added a “NULL” category to the beginning of every enum and so far it seems all of my monster instances are able to be changed from the lists in the drop down without any trouble.

enum GlossaryRegion {
	NULL,
	ANY,
	FOREST,
	MOUNTAIN,
    OCEAN,
}

enum GlossaryRarity {
	NULL,
	COMMON,
	UNCOMMON,
	RARE
}

enum GlossaryThreatLevel {
	NULL,
	LOW,
	MODERATE,
	HIGH
}

@export_category("Classification data")

@export var environs : GlossaryRegion = GlossaryRegion.NULL
@export var rarity : GlossaryRarity = GlossaryRarity.NULL
@export var threat_lvl : GlossaryThreatLevel = GlossaryThreatLevel.NULL
@export var size : GlossarySize = GlossarySize.NULL
@export var category : GlossaryCategory = GlossaryCategory.NULL

# etc. etc. etc.

I still have to properly implement the “monster viewer.” I fear that will be the most complex part of this entire operation, but I feel a lot more confident about it now knowing that this method you’ve given me is more conducive to this kind of “modularity” or however we want to describe it.

Thanks again!! Going to tuck my chin back in and try figuring that out. Might update this thread again sometime soon after I fuss with it for a moment.

Hello! I am glad that my advice on modular Control nodes have helped you. If you have any questions you can always ask!