mirror of
				https://github.com/Ukendio/jecs.git
				synced 2025-11-03 02:29:16 +00:00 
			
		
		
		
	Compare commits
	
		
			3 commits
		
	
	
		
			a3939cf083
			...
			4336e65633
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
							 | 
						4336e65633 | ||
| 
							 | 
						7b870e8f3c | ||
| 
							 | 
						e668371cc1 | 
					 9 changed files with 1125 additions and 2 deletions
				
			
		
							
								
								
									
										29
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								README.md
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -62,3 +62,32 @@ Can be found under /benches/visual/query.luau
 | 
			
		|||
Inserting 8 components to an entity and updating them over 50 times.
 | 
			
		||||

 | 
			
		||||
Can be found under /benches/visual/insertions.luau
 | 
			
		||||
 | 
			
		||||
## Installation
 | 
			
		||||
 | 
			
		||||
### Using Wally
 | 
			
		||||
 | 
			
		||||
Add jecs to your `wally.toml` file:
 | 
			
		||||
 | 
			
		||||
```toml
 | 
			
		||||
[dependencies]
 | 
			
		||||
jecs = "ukendio/jecs@0.1.0"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Then run `wally install` in your project directory.
 | 
			
		||||
 | 
			
		||||
### Manual Installation
 | 
			
		||||
 | 
			
		||||
Download the latest release from the [releases page](https://github.com/ukendio/jecs/releases).
 | 
			
		||||
 | 
			
		||||
## Documentation
 | 
			
		||||
 | 
			
		||||
For complete documentation, visit our [documentation site](https://ukendio.github.io/jecs/).
 | 
			
		||||
 | 
			
		||||
## Contributing
 | 
			
		||||
 | 
			
		||||
Contributions are welcome. Please feel free to submit a Pull Request.
 | 
			
		||||
 | 
			
		||||
## License
 | 
			
		||||
 | 
			
		||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,6 +16,12 @@ jecs.Wildcard: Entity
 | 
			
		|||
```
 | 
			
		||||
Builtin component type. This ID is used for wildcard queries.
 | 
			
		||||
 | 
			
		||||
## w
 | 
			
		||||
```luau
 | 
			
		||||
jecs.w: Entity
 | 
			
		||||
```
 | 
			
		||||
An alias for `jecs.Wildcard`. This ID is used for wildcard queries, providing a shorter syntax in query operations.
 | 
			
		||||
 | 
			
		||||
## Component
 | 
			
		||||
```luau
 | 
			
		||||
jecs.Component: Entity
 | 
			
		||||
| 
						 | 
				
			
			@ -28,6 +34,54 @@ jecs.ChildOf: Entity
 | 
			
		|||
```
 | 
			
		||||
Builtin component type. This ID is for creating parent-child hierarchies.
 | 
			
		||||
 | 
			
		||||
## Name
 | 
			
		||||
```luau
 | 
			
		||||
jecs.Name: Entity
 | 
			
		||||
```
 | 
			
		||||
Builtin component type. This ID is used to associate a string name with an entity, typically for debugging or display purposes.
 | 
			
		||||
 | 
			
		||||
## OnAdd
 | 
			
		||||
```luau
 | 
			
		||||
jecs.OnAdd: Entity<(entity: Entity) -> ()>
 | 
			
		||||
```
 | 
			
		||||
Builtin component hook. When set on a component, the provided function is called whenever that component is added to an entity.
 | 
			
		||||
 | 
			
		||||
## OnRemove
 | 
			
		||||
```luau
 | 
			
		||||
jecs.OnRemove: Entity<(entity: Entity) -> ()>
 | 
			
		||||
```
 | 
			
		||||
Builtin component hook. When set on a component, the provided function is called whenever that component is removed from an entity.
 | 
			
		||||
 | 
			
		||||
## OnSet
 | 
			
		||||
```luau
 | 
			
		||||
jecs.OnSet: Entity<(entity: Entity, data: any) -> ()>
 | 
			
		||||
```
 | 
			
		||||
Builtin component hook. When set on a component, the provided function is called whenever that component's value is set or changed on an entity.
 | 
			
		||||
 | 
			
		||||
## OnDelete
 | 
			
		||||
```luau
 | 
			
		||||
jecs.OnDelete: Entity
 | 
			
		||||
```
 | 
			
		||||
Builtin component trait. Used with `pair()` to define behavior when a component or entity is deleted. Must be paired with an action component like `jecs.Delete` or `jecs.Remove`.
 | 
			
		||||
 | 
			
		||||
## OnDeleteTarget
 | 
			
		||||
```luau
 | 
			
		||||
jecs.OnDeleteTarget: Entity
 | 
			
		||||
```
 | 
			
		||||
Builtin component trait. Used with `pair()` to define behavior when a relationship target is deleted. Must be paired with an action component like `jecs.Delete` or `jecs.Remove`.
 | 
			
		||||
 | 
			
		||||
## Delete
 | 
			
		||||
```luau
 | 
			
		||||
jecs.Delete: Entity
 | 
			
		||||
```
 | 
			
		||||
Builtin action component used with `OnDelete` or `OnDeleteTarget` to specify that entities should be deleted in the cleanup process.
 | 
			
		||||
 | 
			
		||||
## Remove
 | 
			
		||||
```luau
 | 
			
		||||
jecs.Remove: Entity
 | 
			
		||||
```
 | 
			
		||||
Builtin action component used with `OnDelete` or `OnDeleteTarget` to specify that components should be removed in the cleanup process.
 | 
			
		||||
 | 
			
		||||
## Rest
 | 
			
		||||
```luau
 | 
			
		||||
jecs.Rest: Entity
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										130
									
								
								docs/api/name.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								docs/api/name.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,130 @@
 | 
			
		|||
# Name Component
 | 
			
		||||
 | 
			
		||||
The `Name` component allows you to associate a string identifier with an entity.
 | 
			
		||||
 | 
			
		||||
## Overview
 | 
			
		||||
 | 
			
		||||
```luau
 | 
			
		||||
jecs.Name: Entity<string>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `Name` component is a built-in component in jecs that stores a string value. It has no special behavior beyond storing a name.
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
 | 
			
		||||
### Setting a Name
 | 
			
		||||
 | 
			
		||||
```luau
 | 
			
		||||
local world = jecs.World.new()
 | 
			
		||||
 | 
			
		||||
-- Create an entity
 | 
			
		||||
local entity = world:entity()
 | 
			
		||||
 | 
			
		||||
-- Assign a name to the entity
 | 
			
		||||
world:set(entity, jecs.Name, "Player")
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Getting an Entity's Name
 | 
			
		||||
 | 
			
		||||
```luau
 | 
			
		||||
-- Retrieve an entity's name
 | 
			
		||||
local name = world:get(entity, jecs.Name)
 | 
			
		||||
print("Entity name:", name) -- Outputs: "Entity name: Player"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Finding Entities by Name
 | 
			
		||||
 | 
			
		||||
```luau
 | 
			
		||||
-- Iterate over all entities with the Name component
 | 
			
		||||
for entity, name in world:query(jecs.Name) do
 | 
			
		||||
  if name == "Player" then
 | 
			
		||||
    -- Found the entity named "Player"
 | 
			
		||||
    -- Do something with entity...
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Using Names with Hierarchies
 | 
			
		||||
 | 
			
		||||
Names are particularly useful when working with entity hierarchies:
 | 
			
		||||
 | 
			
		||||
```luau
 | 
			
		||||
local world = jecs.World.new()
 | 
			
		||||
local pair = jecs.pair
 | 
			
		||||
 | 
			
		||||
-- Create a parent entity with a name
 | 
			
		||||
local parent = world:entity()
 | 
			
		||||
world:set(parent, jecs.Name, "Parent")
 | 
			
		||||
 | 
			
		||||
-- Create child entities with names
 | 
			
		||||
local child1 = world:entity()
 | 
			
		||||
world:set(child1, jecs.Name, "Child1")
 | 
			
		||||
world:add(child1, pair(jecs.ChildOf, parent))
 | 
			
		||||
 | 
			
		||||
local child2 = world:entity()
 | 
			
		||||
world:set(child2, jecs.Name, "Child2")
 | 
			
		||||
world:add(child2, pair(jecs.ChildOf, parent))
 | 
			
		||||
 | 
			
		||||
-- Print the hierarchy
 | 
			
		||||
print("Parent:", world:get(parent, jecs.Name))
 | 
			
		||||
for child in world:query(pair(jecs.ChildOf, parent)) do
 | 
			
		||||
  print("  Child:", world:get(child, jecs.Name))
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Output:
 | 
			
		||||
-- Parent: Parent
 | 
			
		||||
--   Child: Child1
 | 
			
		||||
--   Child: Child2
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Helper Function
 | 
			
		||||
 | 
			
		||||
For convenience, you can create a simple helper function to get an entity's name:
 | 
			
		||||
 | 
			
		||||
```luau
 | 
			
		||||
local function getName(world, entity)
 | 
			
		||||
  return world:get(entity, jecs.Name) or tostring(entity)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Usage
 | 
			
		||||
local name = getName(world, entity)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This function will return the entity's name if it has one, or fall back to the entity ID as a string.
 | 
			
		||||
 | 
			
		||||
## Best Practices
 | 
			
		||||
 | 
			
		||||
1. **Use Consistently**: Apply names to key entities systematically, especially for important game objects.
 | 
			
		||||
 | 
			
		||||
2. **Be Descriptive**: Use meaningful names that describe the entity's role or purpose.
 | 
			
		||||
 | 
			
		||||
3. **Handle Missing Names**: Always check if an entity has a name before trying to use it, or use a helper function like the one above.
 | 
			
		||||
 | 
			
		||||
4. **Namespacing**: Consider using prefixes or namespaces for different systems (e.g., "UI:MainMenu", "Enemy:Boss").
 | 
			
		||||
 | 
			
		||||
5. **Performance**: Remember that adding a Name component to every entity adds memory overhead. Use judiciously in performance-critical applications.
 | 
			
		||||
 | 
			
		||||
## Example: Entity Debugging System
 | 
			
		||||
 | 
			
		||||
Here's a simple debugging system that uses the Name component:
 | 
			
		||||
 | 
			
		||||
```luau
 | 
			
		||||
local function debugEntity(world, entity)
 | 
			
		||||
  local name = world:get(entity, jecs.Name) or "Unnamed"
 | 
			
		||||
  print("Entity", entity, "(" .. name .. ")")
 | 
			
		||||
  
 | 
			
		||||
  -- Print all components
 | 
			
		||||
  for componentId in world:query(jecs.pair(jecs.Component, jecs.Wildcard)) do
 | 
			
		||||
    if world:has(entity, componentId) then
 | 
			
		||||
      local componentName = world:get(componentId, jecs.Name) or "Unknown"
 | 
			
		||||
      local value = world:get(entity, componentId)
 | 
			
		||||
      print("  Component:", componentName, "=", value)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Usage
 | 
			
		||||
debugEntity(world, player)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This debugging function prints an entity's name along with all its components, making it easier to inspect entities during development. 
 | 
			
		||||
							
								
								
									
										215
									
								
								docs/api/world-entity-management.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								docs/api/world-entity-management.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,215 @@
 | 
			
		|||
# Entity Management
 | 
			
		||||
 | 
			
		||||
This section covers methods for managing entities in the jecs World.
 | 
			
		||||
 | 
			
		||||
## delete
 | 
			
		||||
 | 
			
		||||
Deletes an entity (and its components/relationships) from the world entirely.
 | 
			
		||||
 | 
			
		||||
```luau
 | 
			
		||||
function World:delete(entity: Entity): void
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Parameters
 | 
			
		||||
 | 
			
		||||
| Name | Type | Description |
 | 
			
		||||
|------|------|-------------|
 | 
			
		||||
| entity | Entity | The entity to delete from the world |
 | 
			
		||||
 | 
			
		||||
### Behavior
 | 
			
		||||
 | 
			
		||||
1. Invokes any `OnRemove` hooks for all components on the entity
 | 
			
		||||
2. Triggers any cleanup actions based on `OnDelete` and `OnDeleteTarget` relationships
 | 
			
		||||
3. Removes the entity from all archetypes
 | 
			
		||||
4. Recycles the entity ID for future use
 | 
			
		||||
 | 
			
		||||
### Example
 | 
			
		||||
 | 
			
		||||
::: code-group
 | 
			
		||||
 | 
			
		||||
```luau [luau]
 | 
			
		||||
local world = jecs.World.new()
 | 
			
		||||
 | 
			
		||||
-- Create an entity
 | 
			
		||||
local entity = world:entity()
 | 
			
		||||
world:set(entity, Position, {x = 0, y = 0})
 | 
			
		||||
 | 
			
		||||
-- Delete the entity
 | 
			
		||||
world:delete(entity)
 | 
			
		||||
 | 
			
		||||
-- The entity no longer exists in the world
 | 
			
		||||
assert(not world:contains(entity))
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```typescript [typescript]
 | 
			
		||||
import { World } from "@rbxts/jecs";
 | 
			
		||||
 | 
			
		||||
const world = new World();
 | 
			
		||||
 | 
			
		||||
// Create an entity
 | 
			
		||||
const entity = world.entity();
 | 
			
		||||
world.set(entity, Position, {x: 0, y: 0});
 | 
			
		||||
 | 
			
		||||
// Delete the entity
 | 
			
		||||
world.delete(entity);
 | 
			
		||||
 | 
			
		||||
// The entity no longer exists in the world
 | 
			
		||||
assert(!world.contains(entity));
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
### Child Entity Deletion
 | 
			
		||||
 | 
			
		||||
When an entity has children (via the `ChildOf` relationship), deleting the parent can also delete the children if the appropriate cleanup policy is set:
 | 
			
		||||
 | 
			
		||||
```luau
 | 
			
		||||
-- Set up parent-child relationship
 | 
			
		||||
local ChildOf = world:component()
 | 
			
		||||
world:add(ChildOf, jecs.pair(jecs.OnDeleteTarget, jecs.Delete))
 | 
			
		||||
 | 
			
		||||
local parent = world:entity()
 | 
			
		||||
local child = world:entity()
 | 
			
		||||
 | 
			
		||||
-- Make child a child of parent
 | 
			
		||||
world:add(child, jecs.pair(ChildOf, parent))
 | 
			
		||||
 | 
			
		||||
-- Deleting parent will also delete child
 | 
			
		||||
world:delete(parent)
 | 
			
		||||
assert(not world:contains(child))
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Component Deletion
 | 
			
		||||
 | 
			
		||||
The `delete` method can also be used to delete a component definition:
 | 
			
		||||
 | 
			
		||||
```luau
 | 
			
		||||
local Temporary = world:component()
 | 
			
		||||
world:add(Temporary, jecs.pair(jecs.OnDelete, jecs.Remove))
 | 
			
		||||
 | 
			
		||||
-- Add Temporary to entities
 | 
			
		||||
local e1 = world:entity()
 | 
			
		||||
local e2 = world:entity()
 | 
			
		||||
world:add(e1, Temporary)
 | 
			
		||||
world:add(e2, Temporary)
 | 
			
		||||
 | 
			
		||||
-- Delete the component definition
 | 
			
		||||
world:delete(Temporary)
 | 
			
		||||
 | 
			
		||||
-- Temporary is removed from all entities
 | 
			
		||||
assert(not world:has(e1, Temporary))
 | 
			
		||||
assert(not world:has(e2, Temporary))
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## remove
 | 
			
		||||
 | 
			
		||||
Removes a component from a given entity.
 | 
			
		||||
 | 
			
		||||
```luau
 | 
			
		||||
function World:remove(entity: Entity, component: Id): void
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Parameters
 | 
			
		||||
 | 
			
		||||
| Name | Type | Description |
 | 
			
		||||
|------|------|-------------|
 | 
			
		||||
| entity | Entity | The entity to modify |
 | 
			
		||||
| component | Id | The component or relationship to remove |
 | 
			
		||||
 | 
			
		||||
### Behavior
 | 
			
		||||
 | 
			
		||||
1. Invokes any `OnRemove` hook for the component being removed
 | 
			
		||||
2. Removes the component from the entity
 | 
			
		||||
3. May cause the entity to transition to another archetype
 | 
			
		||||
 | 
			
		||||
### Example
 | 
			
		||||
 | 
			
		||||
::: code-group
 | 
			
		||||
 | 
			
		||||
```luau [luau]
 | 
			
		||||
local world = jecs.World.new()
 | 
			
		||||
 | 
			
		||||
-- Create components
 | 
			
		||||
local Health = world:component()
 | 
			
		||||
local Shield = world:component()
 | 
			
		||||
 | 
			
		||||
-- Create an entity with both components
 | 
			
		||||
local entity = world:entity()
 | 
			
		||||
world:set(entity, Health, 100)
 | 
			
		||||
world:set(entity, Shield, 50)
 | 
			
		||||
 | 
			
		||||
-- Remove just the Shield component
 | 
			
		||||
world:remove(entity, Shield)
 | 
			
		||||
 | 
			
		||||
-- Entity still exists but no longer has Shield
 | 
			
		||||
assert(world:contains(entity))
 | 
			
		||||
assert(world:has(entity, Health))
 | 
			
		||||
assert(not world:has(entity, Shield))
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```typescript [typescript]
 | 
			
		||||
import { World } from "@rbxts/jecs";
 | 
			
		||||
 | 
			
		||||
const world = new World();
 | 
			
		||||
 | 
			
		||||
// Create components
 | 
			
		||||
const Health = world.component();
 | 
			
		||||
const Shield = world.component();
 | 
			
		||||
 | 
			
		||||
// Create an entity with both components
 | 
			
		||||
const entity = world.entity();
 | 
			
		||||
world.set(entity, Health, 100);
 | 
			
		||||
world.set(entity, Shield, 50);
 | 
			
		||||
 | 
			
		||||
// Remove just the Shield component
 | 
			
		||||
world.remove(entity, Shield);
 | 
			
		||||
 | 
			
		||||
// Entity still exists but no longer has Shield
 | 
			
		||||
assert(world.contains(entity));
 | 
			
		||||
assert(world.has(entity, Health));
 | 
			
		||||
assert(!world.has(entity, Shield));
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
### Removing Relationships
 | 
			
		||||
 | 
			
		||||
The `remove` method can also be used to remove relationship pairs:
 | 
			
		||||
 | 
			
		||||
```luau
 | 
			
		||||
local ChildOf = world:component()
 | 
			
		||||
local parent = world:entity()
 | 
			
		||||
local child = world:entity()
 | 
			
		||||
 | 
			
		||||
-- Establish parent-child relationship
 | 
			
		||||
world:add(child, jecs.pair(ChildOf, parent))
 | 
			
		||||
 | 
			
		||||
-- Remove the relationship
 | 
			
		||||
world:remove(child, jecs.pair(ChildOf, parent))
 | 
			
		||||
 | 
			
		||||
-- Child is no longer related to parent
 | 
			
		||||
assert(not world:has(child, jecs.pair(ChildOf, parent)))
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Differences Between delete and remove
 | 
			
		||||
 | 
			
		||||
| Method | What It Affects | Entity Existence | Cleanup Policies |
 | 
			
		||||
|--------|-----------------|------------------|------------------|
 | 
			
		||||
| delete | Entity and all its components | Entity no longer exists | Triggers all cleanup policies |
 | 
			
		||||
| remove | Only the specified component | Entity still exists | Only triggers component-specific OnRemove hook |
 | 
			
		||||
 | 
			
		||||
### When to Use Each Method
 | 
			
		||||
 | 
			
		||||
- Use `delete` when you want to completely remove an entity from the world
 | 
			
		||||
- Use `remove` when you want to keep the entity but remove specific components
 | 
			
		||||
- Use `delete` on a component definition to remove that component from all entities
 | 
			
		||||
 | 
			
		||||
### Performance Considerations
 | 
			
		||||
 | 
			
		||||
Both operations may cause archetype transitions, which have performance implications:
 | 
			
		||||
 | 
			
		||||
- `delete` typically has more overhead because it has to remove all components
 | 
			
		||||
- `remove` is generally faster for individual component removal
 | 
			
		||||
- Both methods are optimized in jecs to be as efficient as possible
 | 
			
		||||
 | 
			
		||||
For performance-critical code dealing with many entities, consider batching operations to minimize archetype transitions. 
 | 
			
		||||
| 
						 | 
				
			
			@ -1,3 +1,84 @@
 | 
			
		|||
## TODO
 | 
			
		||||
# Contributing to jecs
 | 
			
		||||
 | 
			
		||||
This is a TODO stub.
 | 
			
		||||
This document provides guidelines for contributing to the project.
 | 
			
		||||
 | 
			
		||||
## Getting Started
 | 
			
		||||
 | 
			
		||||
1. Fork the repository
 | 
			
		||||
2. Clone your fork
 | 
			
		||||
3. Set up the development environment
 | 
			
		||||
4. Create a branch for your changes
 | 
			
		||||
 | 
			
		||||
## Development Setup
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# Clone your fork
 | 
			
		||||
git clone https://github.com/your-username/jecs.git
 | 
			
		||||
cd jecs
 | 
			
		||||
 | 
			
		||||
# Install dependencies
 | 
			
		||||
wally install
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Making Changes
 | 
			
		||||
 | 
			
		||||
1. Create a branch:
 | 
			
		||||
   ```bash
 | 
			
		||||
   git checkout -b feature/your-feature-name
 | 
			
		||||
   ```
 | 
			
		||||
 | 
			
		||||
2. Make your changes
 | 
			
		||||
 | 
			
		||||
3. Add tests if applicable
 | 
			
		||||
 | 
			
		||||
4. Run tests:
 | 
			
		||||
   ```bash
 | 
			
		||||
   lune run test
 | 
			
		||||
   ```
 | 
			
		||||
 | 
			
		||||
5. Commit your changes:
 | 
			
		||||
   ```bash
 | 
			
		||||
   git commit -m "Add feature: description"
 | 
			
		||||
   ```
 | 
			
		||||
 | 
			
		||||
## Submitting Changes
 | 
			
		||||
 | 
			
		||||
1. Push your changes:
 | 
			
		||||
   ```bash
 | 
			
		||||
   git push origin feature/your-feature-name
 | 
			
		||||
   ```
 | 
			
		||||
 | 
			
		||||
2. Create a Pull Request
 | 
			
		||||
 | 
			
		||||
3. Explain the changes and reference related issues
 | 
			
		||||
 | 
			
		||||
## Code Style
 | 
			
		||||
 | 
			
		||||
- Follow the existing code style
 | 
			
		||||
- Use meaningful variable and function names
 | 
			
		||||
- Write clear comments for complex logic
 | 
			
		||||
- Keep functions focused on a single responsibility
 | 
			
		||||
 | 
			
		||||
## Testing
 | 
			
		||||
 | 
			
		||||
- Add tests for new features
 | 
			
		||||
- Ensure all tests pass before submitting
 | 
			
		||||
- Consider edge cases
 | 
			
		||||
 | 
			
		||||
## Documentation
 | 
			
		||||
 | 
			
		||||
- Update documentation for changed functionality
 | 
			
		||||
- Document new features or APIs
 | 
			
		||||
- Use clear and concise language
 | 
			
		||||
 | 
			
		||||
## Issue Reporting
 | 
			
		||||
 | 
			
		||||
1. Check if the issue already exists in the [Issues](https://github.com/ukendio/jecs/issues) section
 | 
			
		||||
2. Create a new issue with a descriptive title and detailed information
 | 
			
		||||
 | 
			
		||||
## Code of Conduct
 | 
			
		||||
 | 
			
		||||
- Be respectful in communications
 | 
			
		||||
- Provide constructive feedback
 | 
			
		||||
- Accept constructive criticism
 | 
			
		||||
- Focus on what is best for the community
 | 
			
		||||
							
								
								
									
										94
									
								
								docs/learn/faq/index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								docs/learn/faq/index.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,94 @@
 | 
			
		|||
# Frequently Asked Questions
 | 
			
		||||
 | 
			
		||||
This section addresses common questions about jecs.
 | 
			
		||||
 | 
			
		||||
## General Questions
 | 
			
		||||
 | 
			
		||||
### What is jecs?
 | 
			
		||||
 | 
			
		||||
jecs is a high-performance Entity Component System (ECS) library for Luau/Roblox.
 | 
			
		||||
 | 
			
		||||
### How does jecs compare to other ECS libraries?
 | 
			
		||||
 | 
			
		||||
jecs uses an archetype-based storage system (SoA) which is more cache-friendly than traditional approaches. For a detailed comparison with Matter, see the [Migration from Matter](../migration-from-matter.md) guide.
 | 
			
		||||
 | 
			
		||||
### Can I use jecs outside of Roblox?
 | 
			
		||||
 | 
			
		||||
Yes, jecs can be used in any Lua/Luau environment as it has zero dependencies.
 | 
			
		||||
 | 
			
		||||
## Technical Questions
 | 
			
		||||
 | 
			
		||||
### How many entities can jecs handle?
 | 
			
		||||
 | 
			
		||||
jecs can handle up to 800,000 entities at 60 frames per second.
 | 
			
		||||
 | 
			
		||||
### What are archetypes?
 | 
			
		||||
 | 
			
		||||
Archetypes are groups of entities that have the exact same set of components. When you add or remove components from an entity, it moves to a different archetype.
 | 
			
		||||
 | 
			
		||||
### How do I optimize performance with jecs?
 | 
			
		||||
 | 
			
		||||
- Group entity operations to minimize archetype transitions
 | 
			
		||||
- Use cached queries for frequently accessed data
 | 
			
		||||
- Define components that are frequently queried together
 | 
			
		||||
- Use tags instead of empty tables
 | 
			
		||||
- Be mindful of archetype transitions
 | 
			
		||||
 | 
			
		||||
### What are relationship pairs?
 | 
			
		||||
 | 
			
		||||
Relationship pairs allow you to create connections between entities using the `pair()` function.
 | 
			
		||||
 | 
			
		||||
## Common Issues
 | 
			
		||||
 | 
			
		||||
### My entity disappeared after adding a component
 | 
			
		||||
 | 
			
		||||
Check if you have cleanup policies set up with `OnDelete` or `OnDeleteTarget`.
 | 
			
		||||
 | 
			
		||||
### Queries are returning unexpected results
 | 
			
		||||
 | 
			
		||||
Make sure you're querying for the exact components you need. Use modifiers like `.with()` or `.without()` to refine queries.
 | 
			
		||||
 | 
			
		||||
### Performance degrades over time
 | 
			
		||||
 | 
			
		||||
This could be due to:
 | 
			
		||||
- Memory leaks from not properly deleting entities
 | 
			
		||||
- Excessive archetype transitions
 | 
			
		||||
- Too many entities or components
 | 
			
		||||
- Inefficient queries
 | 
			
		||||
 | 
			
		||||
### How do I debug entity relationships?
 | 
			
		||||
 | 
			
		||||
Use the `Name` component to give entities meaningful names:
 | 
			
		||||
 | 
			
		||||
```lua
 | 
			
		||||
-- Print all parent-child relationships
 | 
			
		||||
for entity, target in world:query(jecs.pair(jecs.ChildOf, jecs.Wildcard)) do
 | 
			
		||||
  print(world:get(entity, jecs.Name), "is a child of", world:get(target, jecs.Name))
 | 
			
		||||
end
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Best Practices
 | 
			
		||||
 | 
			
		||||
### When should I use component lifecycle hooks?
 | 
			
		||||
 | 
			
		||||
Use lifecycle hooks (`OnAdd`, `OnRemove`, `OnSet`) for:
 | 
			
		||||
- Initializing resources
 | 
			
		||||
- Cleaning up resources
 | 
			
		||||
- Reacting to data changes
 | 
			
		||||
 | 
			
		||||
### How should I structure my ECS code?
 | 
			
		||||
 | 
			
		||||
- Separate data (components) from behavior (systems)
 | 
			
		||||
- Keep components small and focused
 | 
			
		||||
- Design systems for specific component combinations
 | 
			
		||||
- Use relationships to model connections
 | 
			
		||||
- Document cleanup policies
 | 
			
		||||
 | 
			
		||||
### Should I use multiple worlds?
 | 
			
		||||
 | 
			
		||||
Multiple worlds are useful for:
 | 
			
		||||
- Separating client and server logic
 | 
			
		||||
- Creating isolated test environments
 | 
			
		||||
- Managing different game states
 | 
			
		||||
 | 
			
		||||
Component IDs may conflict between worlds if not registered in the same order. 
 | 
			
		||||
							
								
								
									
										218
									
								
								docs/learn/migration-from-matter.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										218
									
								
								docs/learn/migration-from-matter.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,218 @@
 | 
			
		|||
# Migrating from Matter to jecs
 | 
			
		||||
 | 
			
		||||
This guide is intended to help developers migrate from the Matter ECS library to jecs.
 | 
			
		||||
 | 
			
		||||
## Key Differences
 | 
			
		||||
 | 
			
		||||
### Architectural Differences
 | 
			
		||||
 | 
			
		||||
- **Storage Implementation**: jecs uses an archetype-based storage system (SoA - Structure of Arrays). Matter uses a simpler component-based storage approach.
 | 
			
		||||
- **Performance**: jecs is designed with a focus on performance, particularly for large-scale systems with hundreds of thousands of entities.
 | 
			
		||||
- **Relationship Model**: jecs treats entity relationships as first-class citizens. Matter doesn't have built-in relationship features.
 | 
			
		||||
- **Memory Usage**: jecs typically uses less memory for the same number of entities and components due to its optimized storage structure.
 | 
			
		||||
 | 
			
		||||
### API Differences
 | 
			
		||||
 | 
			
		||||
#### World Creation and Management
 | 
			
		||||
 | 
			
		||||
**Matter:**
 | 
			
		||||
```lua
 | 
			
		||||
local Matter = require("Matter")
 | 
			
		||||
local world = Matter.World.new()
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**jecs:**
 | 
			
		||||
```lua
 | 
			
		||||
local jecs = require("jecs")
 | 
			
		||||
local world = jecs.World.new()
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Component Definition
 | 
			
		||||
 | 
			
		||||
**Matter:**
 | 
			
		||||
```lua
 | 
			
		||||
local Position = Matter.component("Position")
 | 
			
		||||
local Velocity = Matter.component("Velocity") 
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**jecs:**
 | 
			
		||||
```lua
 | 
			
		||||
local Position = world:component()
 | 
			
		||||
local Velocity = world:component()
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Entity Creation
 | 
			
		||||
 | 
			
		||||
**Matter:**
 | 
			
		||||
```lua
 | 
			
		||||
local entity = world:spawn(
 | 
			
		||||
  Position({x = 0, y = 0}),
 | 
			
		||||
  Velocity({x = 10, y = 5})
 | 
			
		||||
)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**jecs:**
 | 
			
		||||
```lua
 | 
			
		||||
local entity = world:entity()
 | 
			
		||||
world:set(entity, Position, {x = 0, y = 0})
 | 
			
		||||
world:set(entity, Velocity, {x = 10, y = 5})
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Queries
 | 
			
		||||
 | 
			
		||||
**Matter:**
 | 
			
		||||
```lua
 | 
			
		||||
for id, position, velocity in world:query(Position, Velocity) do
 | 
			
		||||
  -- Update position based on velocity
 | 
			
		||||
  position.x = position.x + velocity.x * dt
 | 
			
		||||
  position.y = position.y + velocity.y * dt
 | 
			
		||||
end
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**jecs:**
 | 
			
		||||
```lua
 | 
			
		||||
for entity, position, velocity in world:query(Position, Velocity) do
 | 
			
		||||
  -- Update position based on velocity
 | 
			
		||||
  position.x = position.x + velocity.x * dt
 | 
			
		||||
  position.y = position.y + velocity.y * dt
 | 
			
		||||
end
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### System Definition
 | 
			
		||||
 | 
			
		||||
**Matter:**
 | 
			
		||||
```lua
 | 
			
		||||
local function movementSystem(world)
 | 
			
		||||
  for id, position, velocity in world:query(Position, Velocity) do
 | 
			
		||||
    position.x = position.x + velocity.x * dt
 | 
			
		||||
    position.y = position.y + velocity.y * dt
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**jecs:**
 | 
			
		||||
```lua
 | 
			
		||||
local function movementSystem(world, dt)
 | 
			
		||||
  for entity, position, velocity in world:query(Position, Velocity) do
 | 
			
		||||
    position.x = position.x + velocity.x * dt
 | 
			
		||||
    position.y = position.y + velocity.y * dt
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Entity Removal
 | 
			
		||||
 | 
			
		||||
**Matter:**
 | 
			
		||||
```lua
 | 
			
		||||
world:despawn(entity)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**jecs:**
 | 
			
		||||
```lua
 | 
			
		||||
world:delete(entity)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Component Removal
 | 
			
		||||
 | 
			
		||||
**Matter:**
 | 
			
		||||
```lua
 | 
			
		||||
world:remove(entity, Position)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**jecs:**
 | 
			
		||||
```lua
 | 
			
		||||
world:remove(entity, Position)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### jecs-Specific Features
 | 
			
		||||
 | 
			
		||||
#### Relationships
 | 
			
		||||
 | 
			
		||||
jecs has built-in support for entity relationships:
 | 
			
		||||
 | 
			
		||||
```lua
 | 
			
		||||
local ChildOf = world:component()
 | 
			
		||||
local Name = world:component()
 | 
			
		||||
 | 
			
		||||
local parent = world:entity()
 | 
			
		||||
world:set(parent, Name, "Parent")
 | 
			
		||||
 | 
			
		||||
local child = world:entity()
 | 
			
		||||
world:add(child, jecs.pair(ChildOf, parent))
 | 
			
		||||
world:set(child, Name, "Child")
 | 
			
		||||
 | 
			
		||||
-- Query for all children of parent
 | 
			
		||||
for e in world:query(jecs.pair(ChildOf, parent)) do
 | 
			
		||||
  local name = world:get(e, Name)
 | 
			
		||||
  print(name, "is a child of Parent")
 | 
			
		||||
end
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Wildcards
 | 
			
		||||
 | 
			
		||||
jecs supports wildcard queries for relationships:
 | 
			
		||||
 | 
			
		||||
```lua
 | 
			
		||||
-- Query for all parent-child relationships
 | 
			
		||||
for entity, target in world:query(jecs.pair(ChildOf, jecs.Wildcard)) do
 | 
			
		||||
  print(world:get(entity, Name), "is a child of", world:get(target, Name))
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Alternative using the shorter 'w' alias
 | 
			
		||||
for entity, target in world:query(jecs.pair(ChildOf, jecs.w)) do
 | 
			
		||||
  print(world:get(entity, Name), "is a child of", world:get(target, Name))
 | 
			
		||||
end
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Observer Hooks
 | 
			
		||||
 | 
			
		||||
jecs provides component lifecycle hooks:
 | 
			
		||||
 | 
			
		||||
```lua
 | 
			
		||||
world:set(Position, jecs.OnAdd, function(entity)
 | 
			
		||||
  print("Position added to entity", entity)
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
world:set(Position, jecs.OnRemove, function(entity)
 | 
			
		||||
  print("Position removed from entity", entity)
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
world:set(Position, jecs.OnSet, function(entity, value)
 | 
			
		||||
  print("Position set on entity", entity, "with value", value)
 | 
			
		||||
end)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Automatic Cleanup with OnDelete and OnDeleteTarget
 | 
			
		||||
 | 
			
		||||
jecs offers automated cleanup of related entities:
 | 
			
		||||
 | 
			
		||||
```lua
 | 
			
		||||
-- When a parent is deleted, all its children will be deleted too
 | 
			
		||||
world:add(ChildOf, jecs.pair(jecs.OnDeleteTarget, jecs.Delete))
 | 
			
		||||
 | 
			
		||||
-- When Health component is deleted, remove the entity's Shield component
 | 
			
		||||
world:add(Health, jecs.pair(jecs.OnDelete, jecs.Remove))
 | 
			
		||||
world:add(Shield, jecs.pair(jecs.OnDelete, jecs.Remove))
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Performance Considerations
 | 
			
		||||
 | 
			
		||||
When migrating from Matter to jecs, consider these performance tips:
 | 
			
		||||
 | 
			
		||||
1. **Batch Entity Operations**: Group entity operations when possible to minimize archetype transitions.
 | 
			
		||||
2. **Use Cached Queries**: For frequently used queries, create cached versions.
 | 
			
		||||
3. **Consider Component Layout**: Components frequently queried together should be defined together.
 | 
			
		||||
4. **Use Tags When Appropriate**: For components with no data, use tags instead of empty tables.
 | 
			
		||||
5. **Be Aware of Archetype Transitions**: Adding/removing components causes archetype transitions, which have performance implications for large-scale operations.
 | 
			
		||||
 | 
			
		||||
## Migration Strategy
 | 
			
		||||
 | 
			
		||||
1. **Start with World Creation**: Replace Matter's world creation with jecs.
 | 
			
		||||
2. **Migrate Component Definitions**: Update component definitions to use jecs's approach.
 | 
			
		||||
3. **Update Entity Creation**: Modify entity spawning code to use jecs's entity and set methods.
 | 
			
		||||
4. **Adapt Queries**: Update queries, noting that iteration patterns are similar.
 | 
			
		||||
5. **Implement Relationships**: Take advantage of jecs's relationship features where applicable.
 | 
			
		||||
6. **Add Observer Hooks**: Implement lifecycle hooks to replace custom event handling in Matter.
 | 
			
		||||
7. **Optimize**: Refine your implementation using jecs-specific features for better performance.
 | 
			
		||||
 | 
			
		||||
By following this guide, you should be able to migrate your Matter ECS application to jecs while taking advantage of jecs's enhanced performance and features. 
 | 
			
		||||
							
								
								
									
										246
									
								
								docs/learn/observers.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								docs/learn/observers.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,246 @@
 | 
			
		|||
# Observer APIs
 | 
			
		||||
 | 
			
		||||
jecs provides observer hooks that allow you to respond to component lifecycle events and implement cleanup policies.
 | 
			
		||||
 | 
			
		||||
## Component Lifecycle Hooks
 | 
			
		||||
 | 
			
		||||
Component lifecycle hooks let you execute code when components are added, removed, or modified.
 | 
			
		||||
 | 
			
		||||
### OnAdd
 | 
			
		||||
 | 
			
		||||
The `OnAdd` hook is called when a component is added to an entity.
 | 
			
		||||
 | 
			
		||||
```lua
 | 
			
		||||
-- Define a component
 | 
			
		||||
local Transform = world:component()
 | 
			
		||||
 | 
			
		||||
-- Set an OnAdd hook for the Transform component
 | 
			
		||||
world:set(Transform, jecs.OnAdd, function(entity)
 | 
			
		||||
  print("Transform component added to entity", entity)
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- The hook will be called when Transform is added to any entity
 | 
			
		||||
local entity = world:entity()
 | 
			
		||||
world:add(entity, Transform) -- OnAdd hook is triggered
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
TypeScript signature:
 | 
			
		||||
```typescript
 | 
			
		||||
type OnAddHook = (entity: Entity) => void;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### OnRemove
 | 
			
		||||
 | 
			
		||||
The `OnRemove` hook is called when a component is removed from an entity.
 | 
			
		||||
 | 
			
		||||
```lua
 | 
			
		||||
-- Set an OnRemove hook for the Transform component
 | 
			
		||||
world:set(Transform, jecs.OnRemove, function(entity)
 | 
			
		||||
  print("Transform component removed from entity", entity)
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- The hook will be called when Transform is removed from any entity
 | 
			
		||||
world:remove(entity, Transform) -- OnRemove hook is triggered
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
TypeScript signature:
 | 
			
		||||
```typescript
 | 
			
		||||
type OnRemoveHook = (entity: Entity) => void;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### OnSet
 | 
			
		||||
 | 
			
		||||
The `OnSet` hook is called when a component's value is set or changed on an entity.
 | 
			
		||||
 | 
			
		||||
```lua
 | 
			
		||||
-- Set an OnSet hook for the Transform component
 | 
			
		||||
world:set(Transform, jecs.OnSet, function(entity, value)
 | 
			
		||||
  print("Transform component set on entity", entity, "with value", value)
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- The hook will be called when Transform's value is set on any entity
 | 
			
		||||
world:set(entity, Transform, { position = {x = 10, y = 20} }) -- OnSet hook is triggered
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
TypeScript signature:
 | 
			
		||||
```typescript
 | 
			
		||||
type OnSetHook<T> = (entity: Entity, value: T) => void;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Automatic Cleanup Policies
 | 
			
		||||
 | 
			
		||||
jecs provides automatic cleanup policies through the `OnDelete` and `OnDeleteTarget` hooks paired with action components.
 | 
			
		||||
 | 
			
		||||
### OnDelete
 | 
			
		||||
 | 
			
		||||
The `OnDelete` trait specifies what happens when a component or entity is deleted. It must be paired with an action component like `Delete` or `Remove`.
 | 
			
		||||
 | 
			
		||||
#### (OnDelete, Delete)
 | 
			
		||||
 | 
			
		||||
When paired with `Delete`, this policy deletes entities that have the component when the component itself is deleted.
 | 
			
		||||
 | 
			
		||||
```lua
 | 
			
		||||
-- Define a component
 | 
			
		||||
local Health = world:component()
 | 
			
		||||
 | 
			
		||||
-- Add the (OnDelete, Delete) cleanup policy to Health
 | 
			
		||||
world:add(Health, jecs.pair(jecs.OnDelete, jecs.Delete))
 | 
			
		||||
 | 
			
		||||
-- Create entities
 | 
			
		||||
local entity1 = world:entity()
 | 
			
		||||
local entity2 = world:entity()
 | 
			
		||||
 | 
			
		||||
-- Add Health component to entities
 | 
			
		||||
world:add(entity1, Health)
 | 
			
		||||
world:add(entity2, Health)
 | 
			
		||||
 | 
			
		||||
-- When Health component is deleted, all entities with Health will be deleted
 | 
			
		||||
world:delete(Health) -- Deletes entity1 and entity2
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### (OnDelete, Remove)
 | 
			
		||||
 | 
			
		||||
When paired with `Remove`, this policy removes a component from entities when the component itself is deleted.
 | 
			
		||||
 | 
			
		||||
```lua
 | 
			
		||||
-- Define components
 | 
			
		||||
local Poison = world:component()
 | 
			
		||||
local PoisonEffect = world:component()
 | 
			
		||||
 | 
			
		||||
-- Add the (OnDelete, Remove) cleanup policy to Poison
 | 
			
		||||
world:add(Poison, jecs.pair(jecs.OnDelete, jecs.Remove))
 | 
			
		||||
world:add(PoisonEffect, jecs.pair(jecs.OnDelete, jecs.Remove))
 | 
			
		||||
 | 
			
		||||
-- Create entity
 | 
			
		||||
local entity = world:entity()
 | 
			
		||||
world:add(entity, Poison)
 | 
			
		||||
world:add(entity, PoisonEffect)
 | 
			
		||||
 | 
			
		||||
-- When Poison component is deleted, PoisonEffect will be removed from all entities
 | 
			
		||||
world:delete(Poison) -- Removes PoisonEffect from entity
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### OnDeleteTarget
 | 
			
		||||
 | 
			
		||||
The `OnDeleteTarget` trait specifies what happens when a relationship target is deleted. It must be paired with an action component like `Delete` or `Remove`.
 | 
			
		||||
 | 
			
		||||
#### (OnDeleteTarget, Delete)
 | 
			
		||||
 | 
			
		||||
When paired with `Delete`, this policy deletes entities that have a relationship with the deleted target.
 | 
			
		||||
 | 
			
		||||
```lua
 | 
			
		||||
-- Define a ChildOf component for parent-child relationships
 | 
			
		||||
local ChildOf = world:component()
 | 
			
		||||
 | 
			
		||||
-- Add the (OnDeleteTarget, Delete) cleanup policy
 | 
			
		||||
world:add(ChildOf, jecs.pair(jecs.OnDeleteTarget, jecs.Delete))
 | 
			
		||||
 | 
			
		||||
-- Create parent and child entities
 | 
			
		||||
local parent = world:entity()
 | 
			
		||||
local child1 = world:entity()
 | 
			
		||||
local child2 = world:entity()
 | 
			
		||||
 | 
			
		||||
-- Establish parent-child relationships
 | 
			
		||||
world:add(child1, jecs.pair(ChildOf, parent))
 | 
			
		||||
world:add(child2, jecs.pair(ChildOf, parent))
 | 
			
		||||
 | 
			
		||||
-- When the parent is deleted, all its children will be deleted too
 | 
			
		||||
world:delete(parent) -- Deletes child1 and child2
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### (OnDeleteTarget, Remove)
 | 
			
		||||
 | 
			
		||||
When paired with `Remove`, this policy removes a relationship component when its target is deleted.
 | 
			
		||||
 | 
			
		||||
```lua
 | 
			
		||||
-- Define a Likes component for relationships
 | 
			
		||||
local Likes = world:component()
 | 
			
		||||
 | 
			
		||||
-- Add the (OnDeleteTarget, Remove) cleanup policy
 | 
			
		||||
world:add(Likes, jecs.pair(jecs.OnDeleteTarget, jecs.Remove))
 | 
			
		||||
 | 
			
		||||
-- Create entities
 | 
			
		||||
local bob = world:entity()
 | 
			
		||||
local alice = world:entity()
 | 
			
		||||
local charlie = world:entity()
 | 
			
		||||
 | 
			
		||||
-- Establish relationships
 | 
			
		||||
world:add(bob, jecs.pair(Likes, alice))
 | 
			
		||||
world:add(charlie, jecs.pair(Likes, alice))
 | 
			
		||||
 | 
			
		||||
-- When alice is deleted, all Likes relationships targeting her will be removed
 | 
			
		||||
world:delete(alice) -- Removes Likes relationship from bob and charlie
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Best Practices
 | 
			
		||||
 | 
			
		||||
1. **Use hooks for reactive logic**: Component hooks are perfect for synchronizing game state with visual representations or external systems.
 | 
			
		||||
 | 
			
		||||
2. **Keep hook logic simple**: Hooks should be lightweight and focused on a single concern.
 | 
			
		||||
 | 
			
		||||
3. **Consider cleanup policies carefully**: The right cleanup policies can prevent memory leaks and simplify your codebase by automating entity management.
 | 
			
		||||
 | 
			
		||||
4. **Avoid infinite loops**: Be careful not to create circular dependencies with your hooks and cleanup policies.
 | 
			
		||||
 | 
			
		||||
5. **Document your policies**: When using cleanup policies, document them clearly so other developers understand the entity lifecycle in your application.
 | 
			
		||||
 | 
			
		||||
6. **Use OnAdd for initialization**: The OnAdd hook is ideal for initializing component-specific resources.
 | 
			
		||||
 | 
			
		||||
7. **Use OnRemove for cleanup**: The OnRemove hook ensures resources are properly released when components are removed.
 | 
			
		||||
 | 
			
		||||
8. **Use OnSet for synchronization**: The OnSet hook helps keep different aspects of your game in sync when component values change.
 | 
			
		||||
 | 
			
		||||
## Example: Complete Entity Lifecycle
 | 
			
		||||
 | 
			
		||||
This example shows how to use all observer hooks together to manage an entity's lifecycle:
 | 
			
		||||
 | 
			
		||||
```lua
 | 
			
		||||
local world = jecs.World.new()
 | 
			
		||||
local pair = jecs.pair
 | 
			
		||||
 | 
			
		||||
-- Define components
 | 
			
		||||
local Model = world:component()
 | 
			
		||||
local Transform = world:component()
 | 
			
		||||
local ChildOf = world:component()
 | 
			
		||||
 | 
			
		||||
-- Set up component hooks
 | 
			
		||||
world:set(Model, jecs.OnAdd, function(entity)
 | 
			
		||||
    print("Model added to entity", entity)
 | 
			
		||||
    -- Create visual representation
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
world:set(Model, jecs.OnRemove, function(entity)
 | 
			
		||||
    print("Model removed from entity", entity)
 | 
			
		||||
    -- Destroy visual representation
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
world:set(Model, jecs.OnSet, function(entity, model)
 | 
			
		||||
    print("Model set on entity", entity, "with value", model)
 | 
			
		||||
    -- Update visual representation
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- Set up cleanup policies
 | 
			
		||||
world:add(ChildOf, pair(jecs.OnDeleteTarget, jecs.Delete))
 | 
			
		||||
world:add(Transform, pair(jecs.OnDelete, jecs.Remove))
 | 
			
		||||
 | 
			
		||||
-- Create entities
 | 
			
		||||
local parent = world:entity()
 | 
			
		||||
local child = world:entity()
 | 
			
		||||
 | 
			
		||||
-- Set up relationships and components
 | 
			
		||||
world:add(child, pair(ChildOf, parent))
 | 
			
		||||
world:set(child, Model, "cube")
 | 
			
		||||
world:set(child, Transform, {position = {x = 0, y = 0, z = 0}})
 | 
			
		||||
 | 
			
		||||
-- Updating a component triggers the OnSet hook
 | 
			
		||||
world:set(child, Model, "sphere")
 | 
			
		||||
 | 
			
		||||
-- Removing a component triggers the OnRemove hook
 | 
			
		||||
world:remove(child, Model)
 | 
			
		||||
 | 
			
		||||
-- Deleting the parent triggers the OnDeleteTarget cleanup policy
 | 
			
		||||
-- which automatically deletes the child
 | 
			
		||||
world:delete(parent)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
By effectively using observer hooks and cleanup policies, you can create more maintainable and robust ECS-based applications with less manual resource management. 
 | 
			
		||||
							
								
								
									
										56
									
								
								mkdocs.yml
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								mkdocs.yml
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -51,8 +51,64 @@ extra_css:
 | 
			
		|||
extra_javascript:
 | 
			
		||||
  - assets/scripts/smooth-scroll.js
 | 
			
		||||
 | 
			
		||||
plugins:
 | 
			
		||||
  - search
 | 
			
		||||
  - mike:
 | 
			
		||||
      version_selector: true
 | 
			
		||||
      canonical_version: latest
 | 
			
		||||
  - mkdocstrings:
 | 
			
		||||
      default_handler: python
 | 
			
		||||
      handlers:
 | 
			
		||||
        python:
 | 
			
		||||
          import:
 | 
			
		||||
            - https://installer.github.io/docs/python-objects.inv
 | 
			
		||||
            - https://docs.python.org/3/objects.inv
 | 
			
		||||
          selection:
 | 
			
		||||
            members: true
 | 
			
		||||
          rendering:
 | 
			
		||||
            show_source: true
 | 
			
		||||
            show_submodules: true
 | 
			
		||||
          paths: [src]
 | 
			
		||||
 | 
			
		||||
nav:
 | 
			
		||||
  - Home: index.md
 | 
			
		||||
  - Learn:
 | 
			
		||||
    - learn/index.md
 | 
			
		||||
    - Getting Started:
 | 
			
		||||
      - Installation: learn/getting-started/installation.md
 | 
			
		||||
      - Quick start: learn/getting-started/quick-start.md
 | 
			
		||||
    - Concepts:
 | 
			
		||||
      - Entities & Components: learn/concepts/entities-components.md
 | 
			
		||||
      - Queries: learn/concepts/queries.md
 | 
			
		||||
      - Component Traits: learn/concepts/component-traits.md
 | 
			
		||||
      - Command line: learn/concepts/command-line.md
 | 
			
		||||
      - Addons: learn/concepts/addons.md
 | 
			
		||||
    - Guides:
 | 
			
		||||
      - learn/guides/index.md
 | 
			
		||||
      - Hello, World: learn/guides/hello-world.md
 | 
			
		||||
      - Reading Queries: learn/guides/reading-queries.md
 | 
			
		||||
      - Pair Rules: learn/guides/pair-rules.md
 | 
			
		||||
      - Tagging: learn/guides/tagging.md
 | 
			
		||||
      - Removing Components: learn/guides/removing-components.md
 | 
			
		||||
      - Bulk Operations: learn/guides/bulk.md
 | 
			
		||||
      - Bulk Queries: learn/guides/bulk-queries.md
 | 
			
		||||
      - Debugging: learn/guides/debugging.md
 | 
			
		||||
      - Naming: learn/guides/naming.md
 | 
			
		||||
      - Building Applications: learn/guides/building-applications.md
 | 
			
		||||
      - Troubleshoot: learn/guides/troubleshoot.md
 | 
			
		||||
    - Migration from Matter: learn/migration-from-matter.md
 | 
			
		||||
    - Observer APIs: learn/observers.md
 | 
			
		||||
    - FAQ: learn/faq/index.md
 | 
			
		||||
  - API:
 | 
			
		||||
    - api/jecs.md
 | 
			
		||||
    - World: api/world.md
 | 
			
		||||
    - Query: api/query.md
 | 
			
		||||
    - Entity Management: api/world-entity-management.md 
 | 
			
		||||
    - Name Component: api/name.md
 | 
			
		||||
  - Contributing:
 | 
			
		||||
    - contributing/index.md
 | 
			
		||||
    - Roadmap: contributing/roadmap.md
 | 
			
		||||
    - How to Contribute: learn/faq/contributing.md
 | 
			
		||||
  - Tutorials:
 | 
			
		||||
    - Get Started: tutorials/index.md
 | 
			
		||||
    - Installing Fusion: tutorials/get-started/installing-fusion.md
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue