mirror of
				https://github.com/Ukendio/jecs.git
				synced 2025-10-31 01:09:16 +00:00 
			
		
		
		
	Add comprehensive documentation for jecs library
This commit is contained in:
		
							parent
							
								
									e668371cc1
								
							
						
					
					
						commit
						7b870e8f3c
					
				
					 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. | Inserting 8 components to an entity and updating them over 50 times. | ||||||
|  |  | ||||||
| Can be found under /benches/visual/insertions.luau | 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. | 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 | ## Component | ||||||
| ```luau | ```luau | ||||||
| jecs.Component: Entity | jecs.Component: Entity | ||||||
|  | @ -28,6 +34,54 @@ jecs.ChildOf: Entity | ||||||
| ``` | ``` | ||||||
| Builtin component type. This ID is for creating parent-child hierarchies. | 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 | ## Rest | ||||||
| ```luau | ```luau | ||||||
| jecs.Rest: Entity | 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: | extra_javascript: | ||||||
|   - assets/scripts/smooth-scroll.js |   - 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: | nav: | ||||||
|   - Home: index.md |   - 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: |   - Tutorials: | ||||||
|     - Get Started: tutorials/index.md |     - Get Started: tutorials/index.md | ||||||
|     - Installing Fusion: tutorials/get-started/installing-fusion.md |     - Installing Fusion: tutorials/get-started/installing-fusion.md | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue