Create your own
Lesson illustration

Item and Inventory Database Design

Hello! Welcome back to your JRPG creation course.

In our last lesson, we built a system for characters to learn skills as they level up, connecting our Class definitions to a skills.json database. This brought a critical element of character progression to life. Now, we'll apply the same data-driven principles to another cornerstone of any JRPG: items and inventory.

This lesson directly addresses the learning outcome: Design a database structure for items (consumable, equipment, key) and an inventory data structure. We will architect the "what" (the item database) and the "where" (the inventory that holds them), separating the definition of an item from its possession by the player. This is a foundational step before we can implement the logic for using potions or equipping swords.

1. Items as Data Models

In modern development, we separate data from the logic that uses it. Your experience as a front-end developer has surely involved fetching structured data (like JSON) from an API and then rendering it in a UI. We will apply the exact same principle here. An item, whether it's a Potion or the legendary Masamune sword, is fundamentally a collection of data.

To start, let's explore this idea of an item as a "data model."

Data models - using data to create extensible, maintainable games in Godot

The video 'Data models - using data to create extensible, maintainable games' from Godotneers explains this concept very clearly. Although it uses the Godot engine, the architectural principle of separating an item's data from its in-game representation is universal and core to our task.

Please watch from 04:38 to 06:30. The presenter introduces the problem of managing item information and proposes a 'data model'—a simple object that just stores information. This is precisely what we will build for our item database.

As the video explains, we need a central, authoritative source for what an item is. This will be our items.json file. This file will act as the game's item catalog, defining every item that can possibly exist.

2. Designing the Item Database

Our items.json needs to be flexible enough to describe three distinct categories of items mentioned in our learning outcome:

  1. Consumables: Items that are used up, like Potions or Ethers.
  2. Equipment: Items that are worn by characters to boost their stats, like swords, armor, and accessories.
  3. Key Items: Plot-critical items that enable progress, like a "Sewer Key" or a "Dragon's Gem".

Let's design a structure that can accommodate all three. For a given item, we can define a set of common properties and then add category-specific ones.

Here is a potential structure for our items.json, which you can think of as a schema for our item "documents":

{
  "potion_sm": {
    "id": "potion_sm",
    "name": "Potion",
    "description": "Restores 50 HP.",
    "type": "consumable",
    "price": 50,
    "effects": [{
      "type": "hp_recovery",
      "value": 50
    }]
  },
  "bronze_sword": {
    "id": "bronze_sword",
    "name": "Bronze Sword",
    "description": "A basic sword forged from bronze.",
    "type": "equipment",
    "price": 200,
    "equipSlot": "main_hand",
    "statBonuses": {
      "atk": 5
    }
  },
  "cellar_key": {
    "id": "cellar_key",
    "name": "Cellar Key",
    "description": "An old, rusty key.",
    "type": "key_item",
    "price": null
  }
}

Let's break down the fields:

  • Common Properties:
    • id: The unique identifier, just like with skills and classes.
    • name & description: Text for display in menus.
    • type: The crucial field that tells our game engine how to handle this item: consumable, equipment, or key_item.
    • price: The item's value in shops. Can be null for items that can't be sold.
  • Consumable-specific:
    • effects: An array of objects describing what happens when the item is used. This is extensible; you could add effects for MP recovery, curing poison, etc.
  • Equipment-specific:
    • equipSlot: Defines where the item can be equipped (e.g., main_hand, off_hand, head, body, accessory).
    • statBonuses: An object containing the stat modifications the item provides.
  • Key Item-specific:
    • These items are often the simplest. Their power comes from their mere existence in the inventory, which our event system will check for.

This structure is highly analogous to the database schemas used in larger-scale RPGs.

jgoodman/MySQL-RPG-Schema

To see how our JSON design maps to a more traditional database, let's examine the 'MySQL-RPG-Schema' repository. It provides a formal SQL-based schema for a classic RPG.

Scan through the page to find the descriptions for the item_type, item, and item_attribute tables. Notice how their schema separates these concerns: item holds the name, item_type defines the category (like our type field), and item_attribute links items to stat bonuses (like our statBonuses object).

Our single JSON file effectively combines these related tables into a single, easy-to-manage document-oriented database, a pattern very common in web development.

3. Designing the Inventory Data Structure

Now that we have our item "catalog," we need a structure to represent the player's actual possessions. This is the "shopping cart" to our "product list." A simple array of item IDs won't work, as we couldn't store a quantity (e.g., "99 Potions").

The classic JRPG approach is to use an array of objects, where each object tracks an itemId and its quantity.

A player's inventory might look like this:

let playerInventory = [
    { itemId: "potion_sm", quantity: 12 },
    { itemId: "bronze_sword", quantity: 1 },
    { itemId: "cellar_key", quantity: 1 }
];

This structure is simple, efficient, and gives us everything we need:

  • We can easily find if the player has an item.
  • We can check and update the quantity.
  • We can remove an item by filtering it out of the array if its quantity drops to zero.

This separation of a static database (items.json) from a dynamic state object (playerInventory) is a crucial architectural decision.

The 3 ways to make inventory items in Unity

The video 'The 3 ways to make inventory items in Unity' offers more perspective on this. It discusses the difference between items as data versus items as objects, which reinforces why our data-centric approach is so effective.

Please watch from 09:07 to 11:43. The key takeaway is that for items that spend most of their time in a menu (which is most JRPG items), representing them purely as data in a container like our inventory is the most sensible approach.

Once again, let's look at how a formal database would handle this. The structure we've chosen for our playerInventory directly mirrors standard database design.

Rpg Character Creator Database Structure and Schema

The article 'Rpg Character Creator Database Structure and Schema' provides another clear example of a database schema. Pay close attention to how it defines the 'Items' and 'Inventory' tables.

First, find the 'Items' table definition in the schema at the bottom of the page. You'll see it has columns for Name, Description, Type, etc., just like our items.json design. Then, look for the 'Inventory' table. It contains ItemID and Quantity. This is a one-to-one match with the object structure we designed for our inventory.

Test your understanding!

Using the items.json schema we designed, a character finds a "Leather Shield" which grants +4 DEF, and they already have 5 "Potions". What would the playerInventory array look like after they acquire the shield? Assume the shield's id is "shield_leather".

Show answer

The inventory would be an array of two objects. The existing Potion entry remains, and a new entry for the shield is added with a quantity of 1.

let playerInventory = [
    { itemId: "potion_sm", quantity: 5 },
    { itemId: "shield_leather", quantity: 1 }
];

The definition of the Leather Shield (its name, description, and statBonuses) would reside in items.json, not in the inventory itself.

4. A Note on Equipment Slots

Our inventory structure tells us what the player has, but not what they are actively using. A character can own five swords, but they can only wield one at a time.

To handle this, we will need another data structure, separate from the main inventory, to track equipped items. A simple object mapping equipSlot names to an itemId is a great starting point:

let characterEquipment = {
    main_hand: "bronze_sword",
    off_hand: null,
    body: "leather_armor",
    head: null,
    accessory: "power_wrist"
};

This neatly separates the "backpack" from the "body". The MySQL-RPG-Schema resource you looked at earlier shows this exact separation with its character_item (inventory) and character_equipment tables. We will dive deep into implementing the logic for this in a future lesson, but it's important to see how it fits into the overall architecture now.

Conclusion

In this lesson, we have laid the data-driven groundwork for all items and inventory management in our game. By thinking in terms of data models and schemas, a concept familiar from your web development background, we've designed a system that is robust, scalable, and easy to manage.

Key Takeaways:

  • Separation of Concerns: We've separated the static item database (items.json), which defines all possible items, from the dynamic inventory structure, which tracks the items a player currently possesses.
  • Data-Driven Design: An item's type property (consumable, equipment, key_item) will drive the game's logic, allowing us to treat different items in different ways.
  • Inventory Structure: A list of objects containing itemId and quantity is an effective and standard way to represent a JRPG inventory.
  • Equipment is a separate concern: While equipped items are drawn from the inventory, tracking what is equipped requires a distinct data structure.

Preview of the next lesson:
We have designed the blueprints; now it's time to build the machinery. In our next lesson, we will implement an API to add, remove, and query items in the player's inventory. This will involve writing functions like inventory.addItem(itemId, quantity) and inventory.hasItem(itemId) that will become the backbone of everything from picking up treasure to buying goods in a shop.

Can't find a good explanation? Sign up and we'll make it for you

Sign up