Enemy Configuration
Relevant source files
The following files were used as context for generating this wiki page:The enemy configuration system in Souless is a data-driven architecture designed for defining the properties and behaviors of all non-player characters. The core of this system is the EnemiesData object, a comprehensive data structure that dictates everything from an enemy's appearance and stats to its complex AI and skill sets.
This configuration is consumed by various parts of the engine, primarily the EnemyBase class, which acts as a factory for creating enemy instances. The EnemyManager handles spawning based on map-specific settings, while the EnemySkillSystem interprets and executes the detailed attack and skill logic defined in the configuration. This approach allows for rapid creation and modification of enemies without altering core game logic.
Core Data Structure
All enemy definitions are stored in the EnemiesData object within src/config/enemiesData.js. Each key in this object represents a unique enemy type (e.g., slime, assassin_boss), and its value is an object containing all configuration for that enemy.
The diagram below shows the high-level properties for a single enemy configuration.
Sources: src/config/enemiesData.js:3-375
Enemy Types
Enemies are categorized by a type property, which primarily distinguishes between standard mobs and unique bosses.
normal: Standard enemies that typically patrol and have simple attack patterns.boss: More complex enemies with advanced AI, multi-phase health bars, and sophisticated skill sets. TheisBossflag in theEnemyBaseclass is set based on this type.
Sources: src/config/enemiesData.js:4, src/config/enemiesData.js:218, src/entities/enemies/base/EnemyBase.js:63
Physical & Visual Properties
The sprite and physics objects define the enemy's visual representation and physical interaction with the game world. This data is used by EnemyBase during initialization to set up the Phaser sprite and its physics body.
Sources: src/entities/enemies/base/EnemyBase.js:77-96
sprite Object
| Property | Type | Description |
|---|---|---|
frameWidth | number | The width of a single frame in the spritesheet. |
frameHeight | number | The height of a single frame in the spritesheet. |
scale | number | The scale multiplier for the sprite. |
flipX | boolean | Whether the base sprite should be flipped horizontally by default. |
flipOffsetX | number | (Bosses only) An additional offset applied when the sprite is flipped. |
Sources: src/config/enemiesData.js:5-10, src/config/enemiesData.js:292-297
physics Object
| Property | Type | Description |
|---|---|---|
width | number | The width of the physics body (hitbox). |
height | number | The height of the physics body (hitbox). |
collideWorldBounds | boolean | If true, the enemy cannot move outside the world boundaries. |
offsetX | number | The horizontal offset of the physics body relative to the sprite frame. |
offsetY | number | The vertical offset of the physics body relative to the sprite frame. |
Sources: src/config/enemiesData.js:12-18
Core Statistics (stats)
The stats object contains fundamental gameplay attributes for the enemy.
| Property | Type | Description |
|---|---|---|
maxHP | number | The maximum health points of the enemy. For bosses, this can be overridden by phase-specific HP. |
speed | object | An object with min and max values for movement speed. |
runSpeed | number | (Bosses only) A higher speed used during specific AI states. |
patrolRange | object | An object with min and max values defining the enemy's patrol distance. |
expReward | number | The amount of experience granted to the player upon defeating the enemy. |
damageCooldown | number | The minimum time in milliseconds between taking damage instances. |
Sources: src/config/enemiesData.js:20-26, src/config/enemiesData.js:225-231
Assets and Animations
The assets and animations objects are used to load the necessary visual resources and define how they animate. The static EnemyBase.preload method iterates through the assets object to load spritesheets, and EnemyBase.createAnimations uses the animations data to create the corresponding animations in Phaser's animation manager.
The animation keys are automatically prefixed with the enemy's type, e.g., slime_idle.
// src/entities/enemies/base/EnemyBase.js:338-350
static preload(scene, enemyType) {
const data = EnemiesData[enemyType];
// ...
const { frameWidth, frameHeight } = data.sprite;
const assets = data.assets;
// 모든 assets 키(idle, hit, death, attack 등)를 순회하며 로드
Object.entries(assets).forEach(([key, path]) => {
scene.load.spritesheet(`${enemyType}_${key}`, path, { frameWidth, frameHeight });
});
// ...
}
Sources: src/entities/enemies/base/EnemyBase.js:326-363
AI and Behavior (ai)
The ai object is the brain of the enemy, defining its behavior, attack patterns, and special skills. The structure of this object varies significantly between normal and boss type enemies.
Normal Enemy AI
Normal enemies use a simple patrol AI. They move back and forth within their patrolRange until a player is detected.
| Property | Type | Description |
|---|---|---|
type | string | Set to 'patrol'. |
detectRange | number | The distance in pixels at which the enemy will detect and pursue the player. |
attack | object | An object defining the enemy's basic attack. |
The nested attack object has the following properties:
| Property | Type | Description |
|---|---|---|
range | number | The range in pixels for the attack to trigger. |
damage | number | The amount of damage the attack inflicts. |
cooldown | number | The time in milliseconds between attacks. |
hitDelay | number | The delay in ms from animation start to when the hit is registered. |
Sources: src/config/enemiesData.js:40-48, src/entities/enemies/base/EnemyBase.js:169-175
Boss AI and Skills
Boss AI is significantly more complex, featuring multiple phases, movement states, and a robust skill system.
Key boss AI properties include:
maxPhase/phaseMaxHPs: Defines multi-phase boss fights, where the boss's HP is reset to a new maximum value upon depletion.EnemyBasemanages phase transitions.attackranges: IncludesattackRange,walkRange, andrunRangeto control movement behavior relative to the player.skillNames: An array of skill keys from theskillsobject that this boss can use.skills: A detailed object defining all available skills.
Sources: src/config/enemiesData.js:241-251, src/config/enemiesData.js:1044-1050, src/entities/enemies/base/EnemyBase.js:31-36
Skill System
The skills object is interpreted by the EnemySkillSystem. Each key is a skill name, and the value is a configuration object that defines the skill's execution.
This diagram shows the execution flow when a boss uses a skill.
This diagram illustrates the process from the AI controller deciding to use a skill to the skill's hitbox dealing damage. Sources: src/entities/enemies/systems/EnemySkillSystem.js:143-150, src/entities/enemies/systems/EnemySkillSystem.js:255-261
Skill Configuration Structure
A single skill is defined by properties like type, animation, cooldown, and hitboxSequence. The hitboxSequence is particularly powerful, allowing for multi-part attacks with different timings, damages, and effects.
This diagram shows the structure of a skill definition, highlighting the hitboxSequence array which contains one or more steps for a complex attack. Sources: src/config/enemiesData.js:255-321
Enemy Spawning
Enemies are spawned on a per-map basis, as defined in src/config/mapData.js. Each map configuration can specify an enemies object that dictates which types of enemies appear, how many, and how often they respawn. The EnemyManager class is responsible for reading this configuration and managing the lifecycle of enemies in a scene.
// Example from src/config/mapData.js
enemies: {
types: ['Slime', 'Bat', 'Monkey', 'Canine'],
initialCount: 20,
maxCount: 35,
respawnInterval: 5000,
patrolRangeX: 100,
minPlayerDistance: 100,
},
Sources: src/config/mapData.js:123-130
The spawning process is managed by EnemyManager as follows:
This flowchart shows how EnemyManager first populates the map with an initial set of enemies and then continues to spawn new ones during the game loop to maintain the population, based on rules from mapData.js. Sources: src/controllers/EnemyManager.js:33-44, src/controllers/EnemyManager.js:46-72
Conclusion
The enemy configuration system is a cornerstone of the game's architecture, providing a highly modular and data-driven way to define and manage enemies. By centralizing all enemy data in enemiesData.js and creating a set of systems (EnemyBase, EnemyManager, EnemySkillSystem) to interpret that data, developers can easily introduce new enemies or tweak existing ones with minimal code changes. The detailed skill and AI configuration, especially for bosses, allows for the creation of unique and challenging encounters.