Tutorial: Building an AI-Powered RPG Level Generator#
This tutorial demonstrates how to build a dynamic RPG game level generator using Large Language Models (LLMs) and Jaclang's by llm
syntax. The tutorial covers creating a system that uses AI to generate balanced, progressively challenging game levels.
Overview#
This tutorial covers building an AI-driven RPG level generator using Jaclang's by llm
syntax. The system creates game levels automatically through structured data types for spatial positioning and game elements, progressive difficulty scaling that adapts to player progress, and dynamic map rendering from AI-generated data.
Prerequisites#
Required dependencies:
OpenAI API key configuration:
- Basic knowledge of Jaclang syntax
- Familiarity with game development concepts (optional)
Implementation Steps#
The implementation consists of the following components:
- Define Game Data Structures - Create the building blocks for the game world
- Implement AI-Powered Methods - Use
by llm
to delegate level creation to AI - Build the Level Manager - Coordinate the generation process
- Create Map Conversion Logic - Transform AI output into playable levels
- Test and Iterate - Run the system and validate AI-generated levels
Step 1: Define Game Data Structures#
The first step involves creating the fundamental data types that represent the game world. These structures serve as a vocabulary that the AI uses to understand and generate game content.
Basic Position and Wall Objects#
Create a new file called level_manager.jac
and add these basic structures:
Implementation details:
- Position
represents any point in 2D space with x, y coordinates
- Wall
defines a barrier using start and end positions
Game Configuration Objects#
Add the main game configuration objects:
Structure functions:
- Level
defines the game rules (difficulty, time limits, constraints)
- Map
contains the actual layout (where everything is positioned)
- The AI uses these types to understand what constitutes a valid, balanced level
Step 2: Implement AI-Powered Generation Methods#
This step creates the core AI methods that generate game content. First, import and configure the AI model, then add the LevelManager
object:
AI configuration:
- Import the Model
class from the byllm
module
- The global llm
variable configures the AI model (GPT-4o in this case)
- verbose=True
enables detailed output during generation
AI Method Implementation#
The by llm
methods work as follows:
Level Creation Method
def create_next_level (last_levels: list[Level], difficulty: int, level_width: int, level_height: int)
-> Level by llm();
Method parameters:
- Historical Context: last_levels
- Previous levels for ensuring variety
- Difficulty Guidance: difficulty
- Scale the challenge appropriately
- Spatial Constraints: level_width, level_height
- Boundary parameters
- Expected Output: Return a complete Level
object
Map Generation Method
Method function:
- Takes a high-level
Level
configuration - Generates specific positions for walls, enemies, and the player
- Creates a balanced, playable layout
- Returns a detailed
Map
object
AI Data Structure Understanding
The AI automatically understands data structures. When you pass a Level
object, the AI knows about all its properties (difficulty, dimensions, enemy count, etc.) and uses this context to make intelligent decisions.
Step 3: Build the Level Generation Logic#
Implement the coordination logic that manages the AI generation process. Add this method to the LevelManager
:
def get_next_level -> tuple(Level, Map) {
self.current_level += 1;
# Keeping Only the Last 3 Levels
if len(self.prev_levels) > 3 {
self.prev_levels.pop(0);
self.prev_level_maps.pop(0);
}
# Generating the New Level
new_level = self.create_next_level(
self.prev_levels,
self.current_difficulty,
20, 20
);
self.prev_levels.append(new_level);
# Generating the Map of the New Level
new_level_map = self.create_next_map(new_level);
self.prev_level_maps.append(new_level_map);
# Increasing the Difficulty for end of every 2 Levels
if self.current_level % 2 == 0 {
self.current_difficulty += 1;
}
return (new_level, new_level_map);
}
Generation Flow#
The get_next_level()
method executes the following sequence:
- Level Counter: Increments the current level number
- Memory Management: Keeps only the last 3 levels to provide recent context without overwhelming the AI
- AI Level Generation: Calls the AI to create a new level configuration
- AI Map Generation: Requests the AI to create specific positioning for the level
- Difficulty Progression: Increases difficulty every 2 levels for natural progression
- Return Results: Provides both the level config and detailed map
Step 4: Convert AI Output to Game Format#
The AI generates structured data that must be converted to a visual representation. Create a function that converts the AI-generated Map
into game tiles:
def get_map(map: Map) -> str {
map_tiles = [['.' for _ in range(map.level.width)] for _ in range(map.level.height)];
# Place walls
for wall in map.walls {
for x in range(wall.start_pos.x, wall.end_pos.x + 1) {
for y in range(wall.start_pos.y, wall.end_pos.y + 1) {
map_tiles[y-1][x-1] = 'B';
}
}
}
# Place obstacles, enemies, and player
for obs in map.small_obstacles {
map_tiles[obs.y-1][obs.x-1] = 'B';
}
for enemy in map.enemies {
map_tiles[enemy.y-1][enemy.x-1] = 'E';
}
map_tiles[map.player_pos.y-1][map.player_pos.x-1] = 'P';
# Add border walls
map_tiles = [['B'] + row + ['B'] for row in map_tiles];
map_tiles = [['B' for _ in range(map.level.width + 2)]] + map_tiles + [['B' for _ in range(map.level.width + 2)]];
return [''.join(row) for row in map_tiles];
}
Map Conversion Process#
The conversion function executes these operations:
- Initialize Grid: Creates a 2D array filled with '.' (empty space)
- Place Walls: Converts
Wall
objects into 'B' (block) characters - Add Obstacles: Places small obstacles as additional 'B' characters
- Position Enemies: Places 'E' characters at enemy positions
- Place Player: Sets 'P' character at the player's starting position
- Add Borders: Surrounds the entire map with walls for boundaries
Game Symbols:
.
= Empty space (walkable)B
= Block/Wall (impassable)E
= Enemy (dangerous)P
= Player (starting position)
Step 5: Test the AI Level Generator#
Create a test file to validate the AI functionality. Create a new file called test_generator.jac
:
import from level_manager { LevelManager }
with entry {
level_manager = LevelManager();
print("Generating 3 AI-powered levels...\n");
for i in range(3) {
level, map_obj = level_manager.get_next_level();
visual_map = level_manager.get_map(map_obj);
print(f"=== LEVEL {i+1} ===");
print(f"Difficulty: {level.difficulty}");
print(f"Enemies: {level.num_enemies}");
print(f"Walls: {level.num_wall}");
print("Map:");
for row in visual_map {
print(row);
}
print("\n");
}
}
Running the Generator#
Execute the test with:
Expected output:
=== LEVEL 1 ===
Difficulty: 1
Enemies: 2
Walls: 3
Map:
BBBBBBBBBBBBBBBBBBBBBB
B..................B
B.....B............B
B..................B
B........E.........B
B..................B
B..........P.......B
B..................B
B.E................B
BBBBBBBBBBBBBBBBBBBBBB
Summary#
This tutorial demonstrates building an AI-powered RPG level generator that implements:
- AI Integration: Using
by llm
syntax to delegate complex generation tasks - Structured Data Design: Creating types that guide AI understanding
- Progressive Systems: Building difficulty curves and variety mechanisms
- Practical Application: Converting AI output into usable game content
The approach combines structured programming with AI creativity. The developer provides the framework and constraints, while the AI handles the creative details.
For more details access the full documentation of MTP.