Guide: Creating a New Character
Relevant source files
The following files were used as context for generating this wiki page:This guide provides a comprehensive walkthrough for adding a new playable character to the Souless game. The process involves defining the character's properties in a central configuration file, creating a corresponding class that inherits from a base implementation, and registering the new character within the game's factory and asset loading systems.
Following these steps ensures that a new character is correctly integrated into the game's core systems, including instantiation in game scenes, asset preloading, and data management.
Character Creation Workflow
The overall process for creating a new character can be visualized as a four-step flow, from configuration to final integration.
This diagram shows the sequential steps required to add a new character.
Sources: src/config/characterData.js, src/entities/characters/base/CharacterBase.js, src/entities/characters/base/CharacterFactory.js, src/utils/CharacterAssetLoader.js
Step 1: Define Character in characterData.js
All character-specific data is centralized in src/config/characterData.js. To create a new character, you must add a new top-level key with the character's name (e.g., my_new_character). This object contains all the necessary definitions for the character's appearance, physics, combat abilities, skills, and animations.
Sources: src/config/characterData.js
Configuration Structure
The configuration object for a character has several key properties. Below is a breakdown of the main sections.
| Property | Description |
|---|---|
sprite | Defines the spritesheet, frame dimensions, and default scale. |
base | Default spawn coordinates (though often overridden). |
physics | Defines the collision box size, movement speeds, and jump properties. |
combat | Defines the basic attack hitbox and combo timing. |
skills | A map of all skills available to the character, including attacks and special moves. |
animations | An array defining all animation sequences, mapping them to frames in the spritesheet. |
Sources: src/config/characterData.js:2-20
Example: soul Character Configuration
// src/config/characterData.js:1413-1418
soul: {
sprite: {
key: 'soul',
frameWidth: 32,
frameHeight: 32,
scale: 2.0,
},
// ... other properties
}
skills Object Structure
Each key within the skills object represents a specific action (e.g., attack, q_skill). The structure of a skill definition is critical for the SkillSystem.
| Skill Property | Description |
|---|---|
type | The type of skill (e.g., melee, instant, movement, channeling). |
icon | Path to the skill's UI icon. |
animation | The animation key (from the animations array) to play when the skill is used. |
hitboxSequence | An array of hitbox definitions, each with properties like delay, hitbox (size, offset, duration), damage, and knockback. |
cooldown | The cooldown time in milliseconds. |
cost | The resource cost to use the skill (e.g., { mana: 20 }). |
targetType | Determines if the skill hits a single or multi target. |
Sources: src/config/characterData.js:21-41, 1429-1447
Step 2: Create the Character Class
Each character requires a dedicated class file that extends CharacterBase. This class is responsible for loading its own assets and providing its animation configuration.
Sources: src/entities/characters/base/CharacterBase.js, src/entities/characters/playable/Soul.js
Class Inheritance Diagram
The following diagram illustrates the inheritance structure for playable characters.
This diagram shows that new characters like Soul must inherit from CharacterBase.
Sources: src/entities/characters/base/CharacterBase.js, src/entities/characters/playable/Soul.js
Implementation Example (Soul.js)
Create a new file in src/entities/characters/playable/. The class must implement a static preload method and an instance getAnimationConfig method.
constructor: The constructor should callsuper()with a configuration object built byCharacterDataAdapter. It also initializes character-specific systems likeSkillSystem.preload(scene): A static method to load the character's spritesheet.getAnimationConfig(): An instance method that returns the animation definitions fromcharacterData.js.
// src/entities/characters/playable/Soul.js:5-24
import CharacterBase from '../base/CharacterBase.js';
import { CharacterDataAdapter } from '../../../utils/CharacterDataAdapter.js';
import { SkillSystem } from '../../../models/skill_refactoring/SkillSystem.js';
export default class Soul extends CharacterBase {
constructor(scene, x, y, options = {}) {
const config = CharacterDataAdapter.buildConfig('soul', options);
super(scene, x, y, config);
const skillsData = CharacterDataAdapter.getSkillsData('soul');
this.skillSystem = new SkillSystem(scene, this, skillsData);
this.maxHealth = 100;
this.health = 100;
this.maxMana = 80;
this.mana = 80;
// ...
}
static preload(scene) {
scene.load.spritesheet('soul', '/assets/characters/soul_spritesheet.png', {
frameWidth: 32,
frameHeight: 32,
});
}
getAnimationConfig() {
return CharacterDataAdapter.getAnimationConfig('soul');
}
// ...
}
Sources: src/entities/characters/playable/Soul.js:5-32
Step 3: Register in CharacterFactory.js
The CharacterFactory is a central class responsible for creating instances of characters. To make a new character available in the game, it must be registered here.
Sources: src/entities/characters/base/CharacterFactory.js
- Import the Class: Add an import statement for your new character class at the top of the file.
- Add to
CHARACTER_MAP: Add a new entry to theCHARACTER_MAPobject. The key should be the character's name (lowercase string), and the value should be the imported class. - Add to
ALL_CHARACTERS: Add the character's name (string) to theALL_CHARACTERSarray. This array defines the order in the character selection UI.
// src/entities/characters/base/CharacterFactory.js:1-10, 13-27
import Soul from '../playable/Soul.js';
import Monk from '../playable/Monk.js';
// ... import YourNewCharacter from '../playable/YourNewCharacter.js';
export default class CharacterFactory {
// ...
static CHARACTER_MAP = {
soul: Soul,
monk: Monk,
// ...
// yournewcharacter: YourNewCharacter,
};
static ALL_CHARACTERS = [
'soul',
'assassin',
'monk',
// ...
// 'yournewcharacter',
];
static create(scene, type, x, y, options = {}) {
const CharacterClass = this.CHARACTER_MAP[type.toLowerCase()];
// ...
}
}
Sources: src/entities/characters/base/CharacterFactory.js:1-34
Character Instantiation Flow
The GameScene uses the CharacterFactory to create the player character instance.
This diagram shows how GameScene initiates character creation via PlayerSpawnSystem, which in turn uses CharacterFactory to instantiate the correct character class.
Sources: src/scenes/GameScene.js:315-330, src/entities/characters/base/CharacterFactory.js:29-35
Step 4: Add to CharacterAssetLoader.js
To ensure the character's assets are preloaded when the game starts, you must add its static preload method to the CharacterAssetLoader.
Sources: src/utils/CharacterAssetLoader.js
- Import the Class: Import your new character's class at the top of
src/utils/CharacterAssetLoader.js. - Call
preload: In the staticpreloadmethod ofCharacterAssetLoader, add a call to your character's staticpreloadmethod.
// src/utils/CharacterAssetLoader.js
import Soul from '../entities/characters/playable/Soul';
// ...
// import YourNewCharacter from '../entities/characters/playable/YourNewCharacter.js';
export default class CharacterAssetLoader {
static preload(scene) {
Soul.preload(scene);
// ...
// YourNewCharacter.preload(scene);
SkillIconLoader.preload(scene);
}
}
Sources: src/utils/CharacterAssetLoader.js:1-18
Summary
Adding a new character is a structured process that touches on configuration, class implementation, and registration. By defining all character data in characterData.js, creating a class that extends CharacterBase, and registering it in both CharacterFactory and CharacterAssetLoader, the new character will be fully integrated and ready for use within the game engine. This modular approach keeps character logic and data well-organized and easy to manage.