Enemy Forge Wizard
The Enemy Forge is the foundation wizard of the entire Simple Enemy Forge ecosystem. Every enemy you create here becomes available to Squad Forge (as squad members), Spawn Forge (as spawn entries), Scaling Forge (as scaling targets), Wave Forge (as wave entries), Behavior Forge (as behavior subjects), and Faction Forge (as faction members). The Enemy Forge is always your starting point — define your enemies once, use them everywhere.
Open the wizard via Window › Simple Enemy Forge › Enemy Forge Wizard. It
walks you through a 5-step process to define your enemy properties, create enemies,
configure output paths, and generate a complete database with type-safe enums and a custom Inspector
editor.
The wizard produces a ScriptableObject-based enemy database that is fully data-driven. Nothing is hardcoded — there is no built-in "HP" stat, no predefined "Rank" dropdown, no assumed "Aggro Range" field. You define every property your enemies need using four flexible types, and the system works for any genre: RPG, soulslike, survival horror, tower defense, sci-fi, RTS, or anything else you can imagine.
The Dynamic Property System
At the heart of the Enemy Forge is a dynamic property system that lets you define the exact shape of your enemy data. Rather than working around a rigid, genre-specific schema, you build a property system that matches your game perfectly. A fantasy RPG might need "Enemy Type" and "Base HP"; a soulslike might need "Poise" and "Stagger Threshold"; a tower defense might need "Speed" and "Armor Type". The Enemy Forge handles all of these through four property types.
| Property Type | What It Is | Stored As | Example |
|---|---|---|---|
| Category | A dropdown menu. Each category has a label and a list of entries the user picks from. Can be single-select (pick one value) or multi-select (pick multiple values via checkboxes). | int[] / SimpleIntArray[] |
"Enemy Type" with entries [Humanoid, Undead, Beast, Dragon], "Rank" with entries [Minion, Elite, Boss] |
| Flag | A boolean on/off toggle with a configurable default value. Flags are perfect for binary properties that either apply to an enemy or do not. | bool[] |
"Is Boss" (default: false), "Is Flying" (default: false), "Has Shield" (default: false) |
| Numeric | A number value with min/max constraints. Can be a single value or a range (stores both a min and max value). Can be integer or float. | float[] |
"HP" (integer, 1–99999, default 100), "Aggro Range" (float, 0.0–50.0, default 10.0), "XP Reward" (integer, 0–9999) |
| Text | A free-form string field with a lineCount hint (1–6) that controls UI
height. lineCount=1 renders as a single-line field;
lineCount=2+ renders as a multiline text area. |
string[] |
"Lore" (lineCount: 3), "Weakness Hints" (lineCount: 2), "Battle Cry" (lineCount: 1) |
Internally, each enemy stores parallel arrays whose indices map to the definitions
you create in Step 2. For example, if you define three categories — "Enemy Type" at index 0,
"Rank" at index 1, and "Element" at index 2 — then every enemy has a
categoryValues[] array of length 3, where categoryValues[0] holds the
Enemy Type selection, categoryValues[1] holds the Rank selection, and so on. The same
pattern applies to flags, numerics, and texts.
CategoryLabels, FlagNames, NumericNames,
TextNames, and entry arrays for each category) so that property indices always resolve
to human-readable names. You never need to remember that "index 2" means "Element" — the
database tells you.
This architecture means you can add, remove, or reorder property definitions at any time during
development. When you add a new category, the SyncAllEnemiesWithDefinitions() method
automatically extends every enemy's arrays to match. When you remove a property, the arrays shrink.
The wizard keeps your data in sync so you never end up with mismatched array lengths.
Genre Templates
Step 1 of the wizard offers a template dropdown that pre-populates your property definitions with genre-appropriate categories, flags, numerics, and texts. Templates are a starting point — you can freely modify, add, or remove any property after applying a template. They are designed to save you the work of researching what properties a typical game in that genre needs.
Each template also includes example enemies that demonstrate realistic property values. These examples serve as reference data for AI content generation — when you export your schema, AI models can see how properties are used in practice and generate consistent, well-structured enemies.
| Template | Categories | Flags | Numerics | Texts | Examples | Highlights |
|---|---|---|---|---|---|---|
| None (Start Fresh) | 0 | 0 | 0 | 0 | 0 | Blank canvas — define everything from scratch |
| Generic RPG | 4 | 6 | 10 | 2 | 3 | Enemy Type, Rank, Element, base stats (HP, ATK, DEF, SPD) |
| Soulslike | 4 | 5 | 15 | 3 | 3 | Poise, stagger threshold, weakness system, attack patterns |
| Survival / Horror | 5 | 8 | 12 | 2 | 3 | Detection range, stealth modifier, fear factor, mutation tier |
| Tower Defense | 4 | 6 | 10 | 1 | 3 | Speed, armor type, wave group, path priority |
| Sci-Fi / Shooter | 5 | 5 | 14 | 2 | 3 | Shield type, tech level, faction allegiance, energy weapon resist |
| RTS / Strategy | 6 | 8 | 16 | 2 | 4 | Unit class, population cost, build time, supply cap |
All templates use generic, non-trademarked terminology and are safe for commercial use. No template references specific game names, trademarked abilities, or copyrighted content.
Step 1 — Setup
The Setup step configures the basic identity of your enemy database. Everything you set here determines the names of the generated files, the C# namespace they live in, and which genre template (if any) pre-populates your property definitions. Take a moment to choose meaningful names — they will appear throughout your codebase once generation is complete.
Database Configuration
A unique name for your enemy database (e.g., "GameEnemies", "DungeonMonsters"). This must be a valid C# identifier — letters, numbers, and underscores only, and it cannot start with a number. The database name is used as part of the generated asset file name.
The C# namespace for all generated scripts (e.g., "MyGame.Enemies", "RPG.Monsters"). If provided, all generated classes and enums are wrapped in this namespace, which is useful for avoiding naming collisions in larger projects. Leave this empty to generate code in the global namespace.
A short identifier (e.g., "Dungeon", "Fantasy", "SciFi") used to name all generated files. This prefix is prepended to every generated class name using PascalCase. For example, a prefix of
Dungeon generates DungeonType.cs, DungeonDatabase.cs,
Editor/DungeonDatabaseEditor.cs, and DungeonDatabase.asset. The prefix
must be a valid C# identifier if provided.
A toggle that inserts a configurable suffix between the class prefix and the type name. When enabled, a text field appears where you can type the suffix (e.g., "Enemy"). With prefix
MyGame and suffix Enemy, the generated names become
MyGameEnemyType.cs, MyGameEnemyDatabase.cs, and
MyGameEnemyDatabase.asset. This is useful when you want generated names to be more
descriptive without making the prefix itself long.
Template Selection
Below the database configuration, you will find the Template Selection section. Choose a genre template from the dropdown to pre-populate your definitions with genre-appropriate properties, or select None (Start Fresh) to define everything from scratch. When a template is selected, the wizard displays a description of the template, the number of categories, flags, numerics, texts, and example enemies it includes. Templates can be freely modified after selection — they are a starting point, not a constraint.
Simple Attribute Forge Integration
If the Simple Attribute Forge package is installed in your project, an additional section appears in Step 1 titled "Simple Attribute Forge Integration". When SAF is detected, enemies gain the ability to reference modifier assets — ScriptableObject references to modifier assets created with Simple Attribute Forge's Modifier Wizard. These modifiers represent buffs, debuffs, or status effects that the enemy can apply to the player (e.g., a "Poison" modifier on a snake enemy, a "Burning" modifier on a fire elemental).
Simple Item Forge Integration
If the Simple Item Forge package is installed in your project, an additional section
appears that enables loot table linking. Each enemy can be assigned a
lootTableCode that references a loot table from SIF's Loot Forge. This creates a direct
connection between enemies and their drop tables — when an enemy is defeated, your game logic
can look up the enemy's loot table code and roll against it to determine item drops.
Generated Names Preview
The bottom of Step 1 shows a Generated Names Preview that reflects your current
configuration. Based on your class prefix (and suffix, if enabled), it displays three generated
names: the Enum ({GP}Type), the Database ({GP}Database), and the Asset
({GP}Database.asset). The custom editor name is not shown here. This lets you verify
your naming before proceeding.
Validation
A validation panel at the very bottom checks your configuration in real time. It reports errors (empty database name, invalid C# identifiers) and warnings (empty namespace, existing files that will be overwritten). You cannot proceed to the next step until all errors are resolved.
Step 2 — Definitions
This is where you design the "shape" of your enemy data. Every property you define here becomes available on every enemy in Step 3. If you selected a genre template in Step 1, the definitions will already be populated — you can modify, add, or remove any of them. If you started fresh, this step begins empty and you build your property system from scratch.
Each section uses a ReorderableList with drag-and-drop reordering and a count field in the header for quick bulk creation. Type a number into the count field and press Enter to instantly create that many entries, which you can then fill in.
Categories
Categories are dropdown menus your enemies will use. They are the most structured property type, ideal for classification and filtering. Each category definition has three components:
- Label — The display name shown in the UI (e.g., "Enemy Type", "Rank", "Element", "Movement Type")
- Entries — The list of options the user picks from. Each entry is a string (e.g., "Humanoid", "Undead", "Beast"). Entries are displayed in a nested ReorderableList within each category, so you can drag to reorder them. The count field in the entries header lets you create many entries at once.
- Allow Multiple — A toggle that changes how the category behaves:
- OFF (default) — Single-select dropdown. The user picks exactly ONE value. A default entry applies to new enemies. The value is stored as a single integer index.
- ON — Multi-select checkboxes. The user can pick MULTIPLE values
simultaneously. There is no single default. The values are stored as an array of selected
indices (using
SimpleIntArrayfor Unity serialization).
For example, an "Element" category with Allow Multiple ON and entries [Fire, Ice, Lightning, Poison] lets an enemy have both "Fire" and "Ice" selected simultaneously, which is perfect for dual-element bosses. Meanwhile, an "Enemy Type" category with Allow Multiple OFF ensures every enemy is classified as exactly one type.
Flags
Flags are boolean on/off toggles. They are the simplest property type, perfect for binary states that either apply to an enemy or do not. Each flag definition has two components:
- Name — The display name (e.g., "Is Boss", "Is Flying", "Is Undead", "Has Shield", "Can Summon")
- Default Value — The initial on/off state for newly created enemies. Most
flags default to
false, but you might want a flag like "Is Hostile" to default totrue.
In Step 3, flags appear as a vertical list of toggle checkboxes (one flag per row, full-width ToggleLeft). They are also useful for Behavior Forge conditions — a behavior rule might check "Is Flying" to determine whether to use a ground attack or aerial attack pattern.
Numerics
Numeric properties store number values with configurable constraints. They are the most versatile property type, handling everything from HP to aggro range to XP rewards. Each numeric definition has these components:
- Name — The display name (e.g., "HP", "Attack", "Defense", "Aggro Range", "XP Reward")
- Type — Integer or Float. Integer properties show IntField in the editor; float properties show FloatField. Choose integer for whole numbers like HP, damage, or XP. Choose float for decimal values like speed multipliers, aggro range, or critical chance.
- Is Range — When OFF, the property stores a single value. When ON, the
property stores a min/max pair, which is useful for damage ranges (e.g., "10-25
damage"), patrol distances, or any property that naturally varies between two bounds. Range values
are stored in two parallel arrays:
numericValues[]for the min andnumericRangeMaxValues[]for the max. - Min / Max Constraints — Hard limits that the value(s) must stay within. For example, "HP" might be constrained to 1–99999, while "Critical Chance" might be constrained to 0.0–1.0. These constraints are enforced in the wizard UI with clamped fields.
- Default Value(s) — The starting value for new enemies. For range properties, there is a default min and a default max.
Texts
Text properties store free-form string content. They are ideal for lore, weakness hints, battle cries, ability descriptions, or any content that does not fit neatly into a category, flag, or number. Each text definition has two components:
- Name — The display name (e.g., "Lore", "Weakness Hints", "Battle Cry", "Special Ability")
- Line Count (1–6) — Controls the UI height of the text field in
Step 3 and in the generated custom editor. A lineCount of
1renders a compact single-lineTextField. A lineCount of2or higher renders a multilineTextAreawhose height scales with the lineCount value. Use1for short labels like "Battle Cry" or "Patrol Zone". Use3or higher for longer content like "Lore" or "Combat Strategy Notes".
Schema Export / Import
At the top of Step 2, four buttons provide the Schema Export/Import system for AI-assisted content generation:
- Export Full JSON — Exports a comprehensive JSON file containing all definitions, all existing enemies, comprehensive AI instructions (what it can do, what it cannot do, property guidance, balance tips, ecosystem overview), and SAF modifier data plus SIF loot table data if available. This is the most complete export — an AI model receiving this file has everything it needs to generate enemies that perfectly match your property system.
- Export Light JSON — Exports definitions and instructions only, with an empty enemies array and no integration data. The instructions tell the AI to ask you for context before generating. This mode is much smaller and useful when you want the AI to be interactive rather than just filling in data.
- Export Markdown — Exports a human-readable Markdown document ideal for pasting directly into ChatGPT, Claude, or any LLM chat interface. Contains the same information as Full JSON but formatted as tables, bullet points, and code blocks for easy reading.
- Import Schema (JSON) — Reads a JSON file and populates both definitions and enemies. Supports the schema format produced by the export buttons. The import system validates enemy codes, maps category/flag/numeric values by name, detects duplicates, and reports skip reasons for any entries that fail validation. After import, a popup shows the count of imported and skipped enemies.
See the AI Workflow page for the full schema export/import guide, including the exact JSON format, tips for working with AI models, and the phased generation workflow.
schemaInfo section with version, generation timestamp, template tracking (whether the
template was modified and what changed), and a structure guide explaining each section. The
definitions section contains all four property type arrays with their full metadata
(labels, entries, defaults, constraints).
Step 3 — Enemies
This is where you create and edit your enemies using the properties defined in Step 2. The interface uses a split-panel layout with an enemy list on the left and the enemy editor on the right. Select an enemy from the list to view and edit its properties. The wizard provides a rich set of tools for searching, filtering, sorting, and bulk-editing enemies.
Left Panel — Enemy List (280px)
The left panel contains the master enemy list with several tools above it:
- Search bar + Find button — Type a search term to filter enemies by name or code. The status text shows the match count (e.g., "12 matches of 87"). Click the Find button to cycle through matching enemies one by one, automatically selecting and scrolling to each match.
- Category filter — Two dropdown menus that work together. The first dropdown selects which category to filter by (e.g., "Enemy Type", "Rank"). The second dropdown selects which specific value within that category to show (e.g., "Undead", "Boss"). Only enemies matching the selected category value are displayed. Both dropdowns include an "(All)" option to show everything.
- Sort dropdown — Five options: None (original order), Name A-Z, Name Z-A, Code A-Z, Code Z-A. Sorting reorders the actual enemy data for consistent ordering.
- Multi-select toolbar — A row of bulk operation buttons:
- Select All toggle — Selects or deselects all currently visible (filtered) enemies
- Delete button — Deletes all selected enemies after a confirmation dialog
- Duplicate button — Duplicates all selected enemies, appending " (Copy)" to each name and "_COPY" to each code
- Set Icon button — Opens a sprite picker to assign the same icon to all selected enemies at once. This is invaluable for batch icon assignment — select all undead enemies, click Set Icon, pick a placeholder sprite.
- Status bar — Shows "Showing X of Y | Z selected" at the bottom of the list area, giving you a quick count of visible enemies, total enemies, and selected enemies.
- ReorderableList — The enemy list itself supports drag-and-drop reordering
and has a count field in the header for quick bulk creation. Each enemy row shows a checkbox
(for multi-select) and the enemy name. The
[+]button at the bottom adds a new empty enemy. - Pagination — A "Show All" toggle (on by default) controls pagination. When
unchecked, enemies are paginated with a configurable "Per Page" count and page navigation buttons
(
[<] Page X of Y [>]). This keeps the list responsive with large databases.
Right Panel — Enemy Editor
Select an enemy from the list to edit it in the right panel. The editor shows all of the enemy's properties organized into collapsible sections:
Identity Section (Always Visible)
- Name — The display name of the enemy (e.g., "Goblin Warrior", "Shadow Drake"). This is the name shown in-game.
- Code — The unique identifier used in code (e.g.,
GOBLIN_WARRIOR,SHADOW_DRAKE). Codes must be valid C# identifiers and are typically written in UPPER_SNAKE_CASE. The Auto button next to the code field converts the enemy name to UPPER_SNAKE_CASE automatically, handling spaces, invalid characters, and leading digits. - Description — A TextArea for the enemy's description or lore text.
- Icon — A Sprite ObjectField for the enemy's portrait or sprite, shown with a 70x70 preview thumbnail.
Categories Section (Collapsible)
Shows a header with the count (e.g., "Categories (4)") and a foldout arrow. When expanded, each category is displayed according to its Allow Multiple setting:
- Single-select categories show a dropdown menu with all entries
- Multi-select categories show a grid of checkboxes, one for each entry
The section is always visible regardless of how many categories exist.
Flags Section (Collapsible)
Shows all flags as a vertical list of toggle checkboxes — one flag per row, full-width ToggleLeft. Each toggle is labeled with the flag name. The header shows the count (e.g., "Flags (6)"). If no flags are defined, the section shows "No flags defined." as a placeholder. This is the only section in the wizard that displays a placeholder when its definition count is zero.
Numerics Section (Collapsible)
Shows each numeric property with the appropriate field type. Single values display as an IntField or FloatField (depending on the isInteger setting). Range values display with separate Min and Max fields arranged vertically, with the property name as a label above. All values are clamped to the constraints defined in Step 2. The header shows the count (e.g., "Numeric Properties (12)").
Texts Section (Collapsible)
Shows each text property with a UI field sized according to lineCount. Properties with
lineCount=1 display as a single-line TextField. Properties with lineCount=2+
display as a multiline TextArea whose height scales with the lineCount value. Text areas with
content exceeding the fixed height show an inner scrollbar for overflow. The header shows the count
(e.g., "Text Properties (2)").
SAF Modifiers Section (Collapsible, Conditional in Wizard)
In the wizard, this section only appears when Simple Attribute Forge is installed (hidden otherwise).
In the generated custom editor, the section is always emitted in the code and auto-adapts at
runtime via Type.GetType() — when SAF is installed, the ObjectField uses the
correct modifier base type; when SAF is removed, it falls back to ScriptableObject.
No regeneration is needed when SAF is installed or uninstalled. It contains a ReorderableList
of modifier references (stored as ScriptableObject[]). These are Unity
asset references that link to modifier assets created with Simple Attribute Forge's Modifier Wizard.
Each entry is an ObjectField where you drag and drop a modifier asset. Example: a "Poison" modifier
that applies damage over time when the enemy attacks, or a "Slow" modifier that reduces player
movement speed. Note that modifiers are Unity object references and cannot be set via JSON import
— they must be assigned manually or via the generated custom editor.
SIF Loot Table Section (Collapsible, Conditional in Wizard)
In the wizard, this section only appears when Simple Item Forge is installed (hidden otherwise).
In the generated custom editor, the section is always emitted and auto-adapts at runtime via
Type.GetType(), just like the SAF section — no regeneration needed. It contains
two fields:
- Loot Table Code — A string field for the loot table code from SIF's Loot Forge (e.g., "GOBLIN_DROPS", "BOSS_DRAGON_LOOT"). When SIF is detected, this field shows a dropdown populated with available loot table codes from your SIF database.
- Loot Table — An ObjectField for a direct reference to a SIF Loot Database ScriptableObject, provided as a convenience for Inspector-based workflows.
Duplicate Enemy Button
At the bottom of the right panel, a Duplicate Enemy button creates a copy of the currently selected enemy with " (Copy)" appended to the name and "_COPY" appended to the code.
Inline Validation
The editor validates enemies in real time and shows colored messages directly in the enemy editor:
- Error — Empty name or code (the enemy cannot be generated without these)
- Error — Code is not a valid C# identifier (must be letters, numbers, underscores; cannot start with a number)
- Warning — Duplicate name or code (two enemies share the same name or the same code, which will cause issues during generation)
Step 4 — Settings
Configure where generated files are saved and which files to generate. This step gives you full control over your project's file organization.
Output Paths
A single Output Folder field with a Browse button that opens a
folder picker dialog. The path must be within the Assets folder. The default is
Assets/Generated/Enemies. Scripts are automatically placed in a Scripts
subfolder, the custom editor in a nested Scripts/Editor subfolder, and the asset file
in the output folder itself.
A Custom Paths toggle below the output folder reveals separate Scripts Folder and Assets Folder fields when enabled, each with its own Browse button. This lets you place scripts and data assets in different locations if your project structure requires it. When Custom Paths is disabled, the resolved paths are shown as read-only labels beneath the output folder field.
Code Generation Options
Two toggles control which files are generated. Each toggle shows the exact file name that will be created based on your class prefix:
| Toggle | Generates | Description |
|---|---|---|
| Generate Enum | {GP}Type.cs |
A C# enum with one entry per enemy code. Provides compile-time safety and IntelliSense support for enemy references in your code. Recommended. |
| Generate Database | {GP}Database.cs + .asset |
The main database class implementing ISimpleEnemyDataSource and the populated
data asset. Required for runtime use. Also generates the custom editor
(Editor/{GP}DatabaseEditor.cs). |
DungeonType.cs, DungeonDatabase.cs, DungeonDatabase.asset,
Editor/DungeonDatabaseEditor.cs.
File Preview
Below the toggles, a Generated File Preview section shows the full list of files that will be created based on your current selections, including their complete paths. Checkmarks indicate which files are enabled. This lets you review exactly what will be written to disk before you proceed to generation.
Step 5 — Generate
The final step. Review your complete configuration and click Generate to create your enemy database. The wizard performs a two-phase generation process that handles Unity's domain reload automatically.
Generation Summary
A read-only summary panel at the top shows all key metrics at a glance:
- Database Name, Namespace, and Template used
- Total enemy count, category count (with total entries), flag count, numeric count, text count
- Integration status (SAF enabled with modifier count, SIF enabled with loot table link count)
Files to Generate
A list of every file that will be created, with full paths. This is your final chance to review before committing.
Phase 1 — Script Generation
When you click Generate, the wizard writes all C# files to disk:
After writing the files, the wizard saves all wizard data (enemies, definitions, metadata) to a
temporary JSON file at Temp/SimpleEnemyForge_PendingAssetData.json and sets a
SessionState flag. It then triggers AssetDatabase.Refresh() to compile the
new scripts.
Phase 2 — Asset Creation (Automatic)
Unity recompiles the new scripts, which causes a domain reload. All static
variables are reset, but the SessionState flag and temp file survive. An
[InitializeOnLoad] handler detects the pending flag and temp file, then uses
EditorApplication.delayCall to wait until Unity is fully ready. A retry loop checks
whether the generated database type is loaded, then creates the ScriptableObject asset and populates
it with all enemy data and metadata arrays.
Post-Generation Actions
After successful generation, the wizard displays action buttons:
- Open Scripts Folder — Opens the generated scripts directory in your file browser
- Select Database Asset — Selects and pings the generated
.assetfile in the Unity Project window - Create New Database — Resets the wizard to start fresh for a new database
What Gets Generated
The Enemy Forge generates up to 3 script files (depending on your settings in Step 4), plus the data asset. Each file serves a specific purpose in your runtime architecture.
{GP}Type.cs — Enum
A strongly-typed enum with one entry per enemy code. This provides compile-time safety and full IntelliSense support, so you never need to pass raw strings around your codebase. The enum values are generated from the enemy codes you defined in Step 3.
{GP}Database.cs — ScriptableObject
A ScriptableObject class that implements ISimpleEnemyDataSource. It contains all enemy
data in serialized arrays and metadata arrays for category labels (with entries), flag names, numeric
property names, and text property names. This single asset is the complete runtime representation of
your enemy database.
The generated class includes implementations of all ISimpleEnemyDataSource methods:
enemy access (GetEnemyByCode, GetEnemyByName), dynamic filtering
(GetEnemiesByCategory, GetEnemiesByFlag,
GetEnemiesByNumericRange), and metadata queries (GetCategoryLabels,
GetCategoryEntries, etc.).
Accessing Your Database in Code
The generated database ScriptableObject implements ISimpleEnemyDataSource, which provides
all methods you need for enemy access, filtering, and metadata queries. Assign the database asset to a
serialized field on your MonoBehaviour or ScriptableObject, then call methods directly:
You can also use the ISimpleEnemyDataSource interface for polymorphic access, which is
how the other forges (Squad, Spawn, Wave, etc.) interact with your enemy databases:
{GP}DatabaseEditor.cs — Custom Inspector
A custom editor generated alongside your database that replaces Unity's default Inspector (which
shows unhelpful "Element 0", "Element 1" labels) with a professional split-panel editor. This editor
is placed in an Editor/ subfolder so it is automatically excluded from runtime builds.
It provides a full-featured editing experience directly in the Inspector window.
Split Panel Layout
Enemy list on the left (280px), full editor on the right. Select any enemy from the list to view and edit all of its properties with proper field names and types.
Search, Sort & Filter
Search by name or code, sort by Name or Code (A-Z / Z-A), and filter by any category value using two dropdown menus. An X button clears all filters at once.
Multi-Select & Bulk Operations
Per-enemy checkboxes, a Select All toggle, and bulk buttons for Delete Selected, Duplicate Selected, and Set Icon (assign the same sprite to all selected enemies at once).
Pagination
A "Show All" toggle (on by default) controls pagination. When unchecked, enemies are paginated
with a configurable "Per Page" count and page navigation buttons
([<] Page X of Y [>]). This keeps the editor responsive with large databases.
All Properties By Name
Every property displays its human-readable name from your definitions — not array indices. Categories show dropdown menus (or checkbox grids), flags show labeled toggles, numerics show named fields with constraints, and texts show appropriately-sized text areas.
SAF & SIF Sections
The Modifiers section and Loot Table section are always emitted in the generated editor code.
They auto-adapt at runtime via Type.GetType(): when SAF or SIF is installed, the
ObjectFields use the correct types; when removed, they fall back to
ScriptableObject. No regeneration is needed when integration packages are installed
or uninstalled.
{GP}Database.asset — Data File
The ScriptableObject asset file containing all of your enemy data. This is the file you assign to a MonoBehaviour's serialized field or reference from any script that needs enemy data. It is a standard Unity asset that can be version-controlled, duplicated, and referenced from any scene or prefab. It is also the asset you assign to Squad Forge, Spawn Forge, Scaling Forge, Wave Forge, Behavior Forge, and Faction Forge as their linked enemy database.
Runtime Data Structures
The Enemy Forge uses a small set of runtime structs and an interface that live in the
SimpleEnemyForge namespace. These types are defined in the package's
Runtime/ folder and are available to all of your game scripts.
SimpleEnemyDefinition
The core enemy struct. Each enemy stores fixed identity fields and dynamic property arrays whose indices correspond to the definitions you created in Step 2.
SimpleIntArray
A wrapper struct for serializing arrays of int, since Unity cannot serialize jagged arrays
directly. Used by categoryMultiValues for multi-select categories.
ISimpleEnemyDataSource
The interface that all generated enemy databases implement. It provides methods for enemy access, metadata queries, and dynamic filtering. See the API Reference page for complete method documentation.
| Method Group | Key Methods |
|---|---|
| Enemy Access | GetEnemyDefinitions(), GetEnemyByCode(string),
GetEnemyByName(string), GetEnemyCodes(),
GetEnemyNames() |
| Metadata | EnemyCount, HasEnemy(string),
GetEnemyEnumType() |
| Property Definitions | GetCategoryLabels(), GetCategoryEntries(int),
GetFlagNames(), GetNumericNames(),
GetTextNames() |
| Dynamic Filtering | GetEnemiesByCategory(int, int), GetEnemiesByFlag(int, bool),
GetEnemiesByNumericRange(int, float, float) |
The interface is also used by the dependent forges for multi-database merging.
Squad Forge, Spawn Forge, Wave Forge, and others accept a List<ScriptableObject>
of enemy databases. Each database is cast to ISimpleEnemyDataSource using the
database is ISimpleEnemyDataSource pattern, and enemy codes are merged across all
databases (first-database-wins for duplicates). This means you can split your enemies across
multiple databases (e.g., one for dungeon enemies, another for world bosses) and link them all
to a single Squad or Spawn setup.
Tips & Best Practices
Start With a Template
Even if you plan to customize everything, starting with a genre template gives you a solid foundation. It shows how properties are typically structured for your genre and saves time on the initial setup. You can always modify, add, or remove properties afterward.
Use AI for Bulk Content
Define 3–5 enemies manually in Step 3 to establish your patterns, then export your schema (Full JSON or Markdown) and let an AI model generate the remaining enemies. Import the JSON back and review. This workflow can produce dozens or hundreds of well-structured enemies in minutes. See AI Workflow for details.
Auto-Generate Codes
Use the Auto button next to the Code field to convert enemy names to
UPPER_SNAKE_CASE automatically. This ensures consistent, valid C# identifiers and saves you
from typing codes manually. "Goblin Warrior" becomes GOBLIN_WARRIOR, "Shadow Drake
(Elder)" becomes SHADOW_DRAKE_ELDER.
Design for the Ecosystem
If you plan to use the other forges, design your enemies with those systems in mind. Squads need groups of enemies that make sense together (a patrol, a boss + minions). Spawn tables need variety across difficulty tiers. Waves need different enemy types for early, mid, and late game. Scaling needs numeric properties with reasonable base values to multiply. Think about the whole pipeline.
Use Flags for Combat Properties
Flags like "Is Boss", "Is Flying", "Has Shield", and "Can Summon" are directly useful to Behavior Forge. Behavior rules can check flag values as conditions — for example, a rule that triggers "SUMMON_MINIONS" when "Can Summon" is true and HP is below 50%. Design your flags with behavior conditions in mind.
Keep Codes Unique and Descriptive
Enemy codes are your primary identifiers across the entire ecosystem. Make them descriptive
enough to understand at a glance. Prefer GOBLIN_WARRIOR over ENEMY_01.
The Squad, Spawn, Wave, Scaling, Behavior, and Faction forges all reference enemies by code, so
clarity matters.
Batch Icon Assignment
Use the Set Icon bulk operation to assign icons efficiently. Select all enemies of a type (use the category filter to show only Undead, for example), click Select All, then click Set Icon to assign a placeholder sprite to all of them at once. Replace with final art later in the generated custom editor.
Regenerate Freely
You can regenerate your database at any time. The wizard overwrites existing files, so your generated code always matches your current wizard state. If you add enemies, change definitions, or update properties, just run Step 5 again. The only thing you lose is manual edits to generated files (which you should avoid).