Hello! Welcome back to our JRPG development journey.
In our previous lesson, we established a robust, data-driven Class system. We designed a Class data structure that dictates a character's stat growth, what equipment they can use, and, crucially, a skill_learnset that maps specific levels to skills. We also sketched out a checkForNewSkills method to be triggered on level up.
This lesson will build directly on that foundation to fully implement the skill learning mechanics tied to leveling up within a class. We'll move from a simple array of skillId strings to a complete system where those IDs correspond to actual, defined abilities. This process is fundamental to making character progression feel meaningful and rewarding, as each level-up can now grant the player new tools for their strategic arsenal.
1. What is a Skill? Designing the Skill Database
In our last session, the skill_learnset in our classes.json looked like this: [{ "level": 5, "skillId": "power_strike" }]. This is a great start, but the game engine doesn't know what "power_strike" means. Is it a healing spell? A powerful attack? We need to define it.
Just as we created data files for characters and classes, we'll now create a data/skills.json. This file will serve as our central database for all abilities in the game. Your experience with data modeling for front-end applications will make this structure feel very natural. It's another example of a data-driven approach, separating the game's logic from its content.
Here's a sample structure for skills.json:
{
"power_strike": {
"id": "power_strike",
"name": "Power Strike",
"description": "A powerful blow that costs a small amount of MP.",
"mpCost": 5,
"type": "physical",
"power": 150,
"target": "single_enemy",
"animationId": "slash_effect"
},
"fire": {
"id": "fire",
"name": "Fire",
"description": "Engulfs one enemy in flames.",
"mpCost": 4,
"type": "magic",
"element": "fire",
"power": 120,
"target": "single_enemy",
"animationId": "fire_effect"
},
"cure": {
"id": "cure",
"name": "Cure",
"description": "Restores a small amount of HP to one ally.",
"mpCost": 3,
"type": "magic",
"element": "healing",
"power": 100,
"target": "single_ally",
"animationId": "heal_effect"
}
}
Let's break down the fields:
id: The unique identifier we've been using.name&description: Text for display in menus and battle.mpCost: How many Magic Points are consumed to use the skill.type: Broad category (e.g.,physical,magic). This can affect how damage is calculated or defended against.element: (Optional) An elemental affinity likefireorice, used for calculating weaknesses and resistances.power: A base value used in the damage/healing formula. We'll implement this formula in the combat module, but for now, think of it as the skill's relative strength.target: Defines who the skill can be used on (single_enemy,all_allies, etc.).animationId: A reference to the visual effect to play when the skill is used in battle.
With this structure, a skillId is no longer just a string; it's a key that unlocks a rich set of data defining a complete game mechanic.
2. Visualizing the Concept in RPG Maker
Before refining our code, let's see how this exact concept is implemented in RPG Maker, a tool central to your learning goals. This will help bridge the gap between our abstract data structures and a tangible game development interface.
RPG Maker MZ: Basics EP-5: How to make a Custom Class
The video 'RPG Maker MZ: Basics EP-5: How to make a Custom Class' provides a clear look at the engine's interface for this system. It directly visualizes the relationship we are building between classes and skills.
Please watch from 02:50 to 03:50 and then from 08:35 to 09:30. Pay close attention to the 'Skills to Learn' list in the Class tab. Notice how the user selects a level and then chooses a skill from a dropdown. This is the UI representation of creating one of the { level, skillId } objects in our skill_learnset array.
As you can see, the data we're designing in JSON files mirrors the database-driven architecture of established game-making tools. A "Class" contains a list of skills, and each entry in that list specifies the level at which the skill is learned.
3. Refining the Implementation
In the last lesson, we added a placeholder checkForNewSkills method. Let's refine our Character class logic to be more robust. A key consideration is handling characters who don't start at level 1. If a character joins the party at level 10, they should already know all the skills their class would have learned from levels 1 through 10.
Good software design practice suggests that an object's constructor should be responsible for setting up its complete initial state, while other methods handle state transitions (like levelUp).
Here is the refined logic for our Character class:
// Assume GameData.skills is loaded from our new skills.json
class Character {
constructor(definition) {
this.definition = definition;
this.class = GameData.classes[definition.classId];
this.level = definition.initialLevel;
this.xp = 0; // Or calculate based on level
// This is where we'll store the skillId strings
this.skills = [];
// Set up base stats...
this.stats = { ...definition.baseStats };
// ...then correctly initialize skills and stats for the starting level
this.initializeSkills();
this.recalculateStats();
this.xpToNextLevel = this.calculateXpForLevel(this.level + 1);
}
// New method to handle the initial skill set
initializeSkills() {
const learnset = this.class.skill_learnset;
for (const learnable of learnset) {
if (learnable.level <= this.level) {
// Ensure no duplicates are added
if (!this.skills.includes(learnable.skillId)) {
this.skills.push(learnable.skillId);
}
}
}
console.log(`${this.definition.name} starts with skills: ${this.skills.map(id => GameData.skills[id].name).join(', ')}`);
}
levelUp() {
this.level++;
console.log(`${this.definition.name} is now Level ${this.level}!`);
this.recalculateStats();
// Check for new skills learned AT THIS SPECIFIC LEVEL
const learnset = this.class.skill_learnset;
for (const learnable of learnset) {
if (learnable.level === this.level && !this.skills.includes(learnable.skillId)) {
this.skills.push(learnable.skillId);
const skillName = GameData.skills[learnable.skillId].name;
console.log(`🎉 ${this.definition.name} learned ${skillName}!`);
}
}
this.xpToNextLevel = this.calculateXpForLevel(this.level + 1);
// ... and other level-up logic like healing ...
}
// recalculateStats, addXP, etc. remain as they were.
}
This approach is clean and robust:
- The
constructorcallsinitializeSkills(), which populates the character's skill list with everything they should know up to their starting level. - The
levelUp()method handles the simple case of checking for skills learned at the new level only.
This cleanly separates initialization from state updates, a principle you're likely familiar with from managing component lifecycles in front-end development.
Test your understanding!
Imagine your classes.json for a "Knight" has the following skill_learnset:[{ "level": 1, "skillId": "defend" }, { "level": 5, "skillId": "power_strike" }, { "level": 10, "skillId": "protect" }]
A new party member, "Gideon", who is a Knight, joins the party. His initialLevel is 7. According to our refined logic, which method (initializeSkills or levelUp) is called, and what will the contents of his skills array be immediately after he is created?
Show answer
The constructor will be called, which in turn calls initializeSkills(). This method will loop through the skill_learnset and add any skills with a level less than or equal to 7.
Therefore, Gideon's skills array will be ["defend", "power_strike"]. He will not have "protect" yet, as he is not level 10.
4. Design Patterns for Skill Progression
The system we've just implemented—learning specific skills automatically at set levels—is a cornerstone of classic JRPG design. It provides a steady, predictable sense of progression and makes every level-up an exciting event. But it's not the only way.
How you tackle Classes and Skills Progression ...
To understand where our system fits in the broader landscape of game design, let's look at a forum thread where different developers discuss their approaches to skill progression. This provides valuable insight into alternative patterns.
Please read the post by the user 'Wavelength' (it's post #5 in the thread). They outline five different systems they've used. Pay special attention to their description of the 'Learn by Leveling Up' system, as it perfectly describes what we have just implemented.
As Wavelength notes, this tried-and-true system makes "every level-up feel exciting!" This is our primary design goal here. The other systems mentioned, like skill trees or designing your own skills, offer more player choice but also introduce more complexity in terms of balance and implementation.
Our current system provides a strong, reliable foundation. We can always build upon it later by introducing skill trees or other mechanics, but mastering this core progression loop is the essential first step.

Conclusion
In this lesson, we have successfully implemented a complete, data-driven skill learning system. By connecting our Class definitions to a new Skill database, we've given tangible meaning to character progression.
Key Takeaways:
- A skill database (e.g.,
skills.json) is essential for defining the properties of abilities, such as their cost, power, and target. - The
Characterconstructor is the correct place to handle the initial state of a character, including populating their list of known skills based on their starting level. - The
levelUpmethod should handle the state transition, checking for and adding only the skills learned at that specific new level. - Automatic, level-based skill learning is a classic and effective design pattern for making player progression feel consistently rewarding.
Preview of the next lesson:
Now that our characters have stats, classes, and skills, they need things to hold and use! In our next lesson, we will design a database structure for items (consumable, equipment, key) and an inventory data structure. This will involve creating items.json and deciding how to represent the party's shared inventory, setting the stage for using potions in battle and equipping the swords and armor our classes are now permitted to use.
Can't find a good explanation? Sign up and we'll make it for you
Sign up