Recently Unity has fallen out of favor with software developers. No, let me rephrase, they screwed up big time. If you missed the news then let me just say that the board and CEO made a pricing change that was communicated in the most damaging way possible to gamers, developers and publishers trust in Unity.
Now, I’m usually one to ignore the news, videos of train wrecks, and other sensational trends. This time I couldn’t look away. I think because a few months ago, a co-developer and I decided to throw all our chips into Godot. I had previous Unity experience for developing games and he did not, but the wealth of material out there to pick it up is staggering compared to Godot.
What made our decision back then was the open source factor. We knew we could learn any software we wanted, but we loved the open source model of Godot. We believe in open source as a great tool in the short term, but also a catalyst for true societal impact and growth in the long term.
Now, learning Godot hasn’t been easy, but it has been fun. For example, I come from a C# background and love the LINQ framework. So when approaching a problem of how to store modeled data in Godot and retrieve or modify it, I was thrilled to learn about Resources and Dictionaries.
I’ll share an example from our game in development now, which is inspired by Tamagotchi and Drug Wars (PC).
When instantiating a new vendor in our transaction system, there needed to be random price fluctuations for the items being sold. It also required flexibility for future items to be added. Godot uses GDscript, which is loosely connected to C++, but also has indentation-based syntax we find in Python. Below I can walk you through how this code snippet solves that problem and meets requirements.
@export var inventory_data: InventoryData
const stock_inventory: Resource = preload("res://Scripts/inventory/instances/vendor.tres")
var random = RandomNumberGenerator.new()
func populate_vendor_inv_data() -> InventoryData:
random.randomize()
var new_inventory = stock_inventory.duplicate(true)
var loop = 0
for slot in new_inventory.slot_datas:
slot.item_data = item_list[loop]
slot.quantity = random.randi_range(1,99)
item_list[loop].price = random.randi_range(item_list[loop].priceMin, item_list[loop].priceMax)
loop +=1
return new_inventory
const item_list:Array[ItemData] = [
preload("res://Scripts/item/items/item1.tres"),
preload("res://Scripts/item/items/item2.tres"),
preload("res://Scripts/item/items/item3.tres"),
preload("res://Scripts/item/items/item4.tres"),
preload("res://Scripts/item/items/item5.tres"),
preload("res://Scripts/item/items/item6.tres")
]
Firstly on line one you’re seeing a reference to a class called InventoryData. That’s defined in a separate script and functions as a model for the inventory itself. This is based on a great tutorial that goes in depth into how to create your own inventory: https://www.youtube.com/watch?v=V79YabQZC1s&t=3155s
Next, we had created a resource file in our project named “vendor.tres” which contained the basic inventory a standard vendor would start with. Since we don’t want vendors to always carry stock items, we need further logic below. My solution here was to create a function that would return six items of random pricing based on the individual min/max those items could go.
If you remember Drug Wars on PC or Palm Pilot (yes I remember those), it had a minimum and maximum price that each drug could be bought or sold for. So in our GDscript, we instantiate a random generator, then create our populate_vendor_inv_data() function. You’ll notice the -> expression which may appear to be a lambda, but is actually just signifying this function will return your defined type. Here we defined our class “InventoryData,” but you could have used any type either built in or that you had defined.
The next couple of lines deal specifically with resources in Godot. We must create a duplicate of the original, otherwise it will not instantiate and will always remain null. The use of a for loop allows me to grow this in the future and I may refactor, but for now we want to use the counter to match our below array’s index location. So the loop counter is declared, then we run our for loop and define our items.
The next few lines are a little project specific, but essentially they are setting the properties of the items. In my case, there are slot level properties to define, such as quantity and item_data; but, there are also item properties to define, like the price of each item. There is a hierarchy of inheritance going on here that looks like this: InventoryData > SlotData > ItemData.
Using that we can see that when the loop defines the price, it is digging all the way into the item level to find those priceMin and priceMax variables.
What I loved about this solution was obviously that it worked, but also that I can refactor later when I want to add dozens or hundreds of items. I can also expand it to include new slot level or item level properties and define those, such as the rarity of the items or the floor or ceiling being modified.
I would love to say that this game is ready to ship, but it is still very much under development. Subscribe to the newsletter if you want to stay informed on progress, and feel free to reach out using the contact form. I would love to chat and help with your project or see your game built in Godot.