Enemy Types
Relevant source files
The following files were used as context for generating this wiki page:The enemy system in Souless is a data-driven architecture designed for creating and managing various adversaries for the player. All enemy characteristics, from stats and physics to animations and AI behavior, are defined in a central configuration file. This allows for easy creation of new enemy types without significant code changes.
The system is composed of a base class that provides common functionality, individual enemy classes that extend this base, a manager for spawning and lifecycle control, and dedicated systems for handling AI and skills. Enemies are categorized into two main types: normal and boss, each with distinct behaviors and UI elements.
Core Architecture
The enemy architecture is built upon a few key components that work together: a central data store for configuration, a base class for shared logic, and specific classes for each enemy type.
enemiesData.js: A configuration file containing a large JSON-like object that defines the properties for every enemy in the game.EnemyBase.js: The foundational class for all enemies. It reads data fromenemiesData.jsto initialize an enemy's sprite, physics, stats, animations, and AI.- Useable Enemy Classes (e.g.,
Slime.js,Bat.js): These are lightweight classes that extendEnemyBase. Their primary role is to call thesuperconstructor with their specificenemyTypestring, which links them to their configuration inenemiesData.js. EnemyManager.js: Responsible for spawning, tracking, and updating all active enemies within a scene based on the current map's configuration.
Sources: src/config/enemiesData.js, src/entities/enemies/base/EnemyBase.js, src/controllers/EnemyManager.js, src/entities/enemies/useable/Slime.js
Class Inheritance Structure
The following diagram illustrates the inheritance relationship between the base and specific enemy classes.
This diagram shows how specific enemy classes like Slime, Canine, and Bat inherit from the common EnemyBase class.
Sources: src/entities/enemies/base/EnemyBase.js, src/entities/enemies/useable/Slime.js:2-13, src/entities/enemies/useable/Canine.js:2-13, src/entities/enemies/useable/Bat.js:3-13
Enemy Configuration
All enemy properties are defined in EnemiesData within src/config/enemiesData.js. Each enemy is a key-value pair, where the key is the enemy's unique type string (e.g., slime, bat, assassin_boss).
Configuration Structure
The configuration for each enemy is a nested object with several key properties that define its appearance, behavior, and stats.
This diagram shows the top-level properties for an enemy configuration object.
Sources: src/config/enemiesData.js:1-1
The tables below detail the properties within each section of an enemy's configuration.
sprite and physics
| Property | Type | Description |
|---|---|---|
sprite.frameWidth | Number | The width of a single frame in the spritesheet. |
sprite.frameHeight | Number | The height of a single frame in the spritesheet. |
sprite.scale | Number | The scale multiplier for the enemy sprite. |
sprite.flipX | Boolean | Whether the sprite should be flipped horizontally by default. |
physics.width | Number | The width of the physics body's collision box. |
physics.height | Number | The height of the physics body's collision box. |
physics.offsetX | Number | The horizontal offset of the physics body relative to the sprite's top-left. |
physics.offsetY | Number | The vertical offset of the physics body relative to the sprite's top-left. |
physics.collideWorldBounds | Boolean | If true, the enemy cannot move outside the world boundaries. |
Sources: src/config/enemiesData.js:4-18, src/config/enemiesData.js:60-74
stats and assets
| Property | Type | Description |
|---|---|---|
stats.maxHP | Number | The maximum health points of the enemy. |
stats.speed | Object | An object with min and max values for the enemy's movement speed. |
stats.patrolRange | Object | An object with min and max values for the enemy's patrol distance. |
stats.expReward | Number | The amount of experience points awarded to the player upon defeat. |
stats.damageCooldown | Number | The minimum time in milliseconds between taking damage instances. |
assets.{state} | String | A path to the spritesheet for a specific state (e.g., idle, hit, death). |
Sources: src/config/enemiesData.js:20-26, src/config/enemiesData.js:28-33
animations and ai
| Property | Type | Description |
|---|---|---|
animations.{state} | Object | Defines animation properties: start frame, end frame, frameRate, and repeat behavior. |
ai.type | String | The AI type, such as patrol or boss. |
ai.detectRange | Number | The distance at which the enemy detects the player. |
ai.attack | Object | Defines properties for basic attacks, including range, damage, and cooldown. |
ai.skills | Object | A map of skill configurations, used by the EnemySkillSystem. |
ai.skillNames | Array | A list of skill names the AI is allowed to use. |
Sources: src/config/enemiesData.js:35-41, src/config/enemiesData.js:43-52
Enemy Implementation (EnemyBase.js)
The EnemyBase class is the heart of the enemy system, providing shared logic for all enemy types.
Initialization
When an enemy is instantiated (e.g., new Slime(scene, x, y)), the EnemyBase constructor is called.
- It retrieves the enemy's configuration from
EnemiesDatausing the providedenemyType. - It initializes stats like
maxHP,speed, andexpReward. - For bosses, it sets up a multi-phase health system if defined (
maxPhase,phaseMaxHPs). - It creates a Phaser sprite and sets up its physics body (size, offset, world collision) based on the configuration.
- It creates a health bar. Bosses get a large, fixed HP bar at the top of the screen, while normal enemies get a smaller one above their sprite.
- It calls
createAnimations()to register all animations from the configuration with Phaser's animation manager. - It calls
initializeAI()to set up the appropriate controller (EnemyControllerorBossController) and theEnemySkillSystem.
Sources: src/entities/enemies/base/EnemyBase.js:12-113
Damage and Death Flow
The takeDamage method manages an enemy's health and state transitions.
This diagram shows the logic flow when an enemy takes damage, including HP reduction, state checks, phase changes for bosses, and the death sequence.
Sources: src/entities/enemies/base/EnemyBase.js:411-477
Upon death, playDeath() is called, which plays the death animation. On animation completion, spawnSoul() is triggered to create a soul for the player to absorb, and finally, the destroy() method cleans up the enemy's resources and grants experience points to the player.
Sources: src/entities/enemies/base/EnemyBase.js:499-548
AI and Skills
Enemy behavior is managed by controllers and a dedicated skill system.
EnemyController/BossController: These classes, instantiated inEnemyBase.initializeAI, are responsible for high-level decision-making, such as patrolling, detecting the player, and deciding when to attack or use a skill. Bosses have a more complex controller that manages attack ranges, phases, and skill selection.EnemySkillSystem: This system, also created ininitializeAI, manages the execution of skills defined in theenemiesData.jsconfiguration. It handles cooldowns, animations, hit detection, and applying effects.
Sources: src/entities/enemies/base/EnemyBase.js:115-164, src/entities/enemies/systems/EnemySkillSystem.js
Skill Execution Sequence
When a controller decides to use a skill, it interacts with the EnemySkillSystem.
This diagram shows the sequence of events when an enemy uses a skill, from the controller's decision to the skill system handling animation and hitbox activation.
Sources: src/entities/enemies/systems/EnemySkillSystem.js:178-191, src/entities/enemies/systems/EnemySkillSystem.js:220-247
Spawning and Management
The EnemyManager class orchestrates the presence of enemies in a map.
Spawning Logic
The manager's behavior is dictated by the enemies configuration within each map's definition in mapData.js.
// Example from src/config/mapData.js
enemies: {
types: ['Slime', 'Bat'],
initialCount: 20,
maxCount: 35,
respawnInterval: 5000,
patrolRangeX: 100,
minPlayerDistance: 100,
},
Sources: src/config/mapData.js:43-51
The EnemyManager uses this configuration to:
- Create Initial Enemies: Spawns
initialCountenemies of the specifiedtypeswhen the map loads. - Respawn Enemies: In its
updateloop, if the current number of enemies is less thanmaxCountand therespawnIntervalhas passed, it spawns a new random enemy from thetypeslist. - Map Types to Classes: It uses a
enemyClassMapto associate the string type (e.g., "Slime") with its corresponding class (Slime).
Sources: src/controllers/EnemyManager.js:8-14, src/controllers/EnemyManager.js:48-73
Enemy Categories
Enemies are broadly divided into normal and boss types, specified in their configuration.
Normal Enemies
These are the common enemies found throughout the game's maps. They typically have a patrol AI type.
| Enemy Type | Max HP | Speed (min-max) | EXP Reward | AI Type |
|---|---|---|---|---|
slime | 20 | 40-40 | 10 | patrol |
canine | 50 | 40-60 | 8 | patrol |
bat | 20 | 80-120 | 12 | patrol |
monkey | 80 | 30-50 | 20 | patrol |
Sources: src/config/enemiesData.js:1-115
Boss Enemies
Bosses are unique, powerful enemies with boss AI type. They often feature complex skills, larger health pools, and multi-phase battles.
- Job-specific Bosses:
assassin_boss,bladekeeper_boss,monk_boss,princess_boss,fire_boss,mauler_boss. These are encountered in thetemple_1map, with the specific boss depending on the player's chosen job. - Story Bosses:
semi_bossandfinal_boss. These bosses have unique mechanics, such as multiple phases (maxPhase) with different health pools per phase (phaseMaxHPs). Thefinal_bossis alsoisStationary, meaning it does not move.
Sources: src/config/enemiesData.js:116-1044, src/config/mapData.js:414-436