jecs/docs/learn/concepts/entities-and-components.md

160 lines
4.9 KiB
Markdown
Raw Normal View History

2025-01-17 23:13:34 +00:00
# Entities and Components
2025-02-19 16:10:38 +00:00
## What are Entities?
2025-01-17 23:13:34 +00:00
2025-02-19 16:10:38 +00:00
Entities are the fundamental building blocks in Jecs. An entity represents any object in your game - a character, a building, a projectile, or even abstract concepts like game rules or spawn points.
2025-01-17 23:13:34 +00:00
2025-02-19 16:10:38 +00:00
By itself, an entity is just a unique identifier (a number) without any data. Entities become useful when you add components to them.
2025-01-17 23:13:34 +00:00
2025-02-19 16:10:38 +00:00
## What are Components?
2025-01-17 23:13:34 +00:00
2025-02-19 16:10:38 +00:00
Components are reusable pieces of data that can be attached to entities. They serve three main purposes:
2025-01-17 23:13:34 +00:00
2025-02-19 16:10:38 +00:00
1. **Data Storage**: Hold data for an entity (e.g., Position, Health)
2. **Tagging**: Mark an entity as having certain properties (e.g., IsPlayer, IsEnemy)
3. **Relationships**: Create connections between entities (e.g., ChildOf, Owns)
2025-01-17 23:13:34 +00:00
2025-02-19 16:10:38 +00:00
### Example Components
```lua
-- Data component
local Position = world:component() :: jecs.Entity<Vector3>
local Health = world:component() :: jecs.Entity<number>
-- Tag component
local IsEnemy = world:component()
-- Relationship component
local ChildOf = world:component()
```
## Component Operations
2025-01-17 23:13:34 +00:00
2025-02-19 16:10:38 +00:00
Jecs provides several operations for working with components:
2025-01-17 23:13:34 +00:00
2025-02-19 16:10:38 +00:00
| Operation | Description | Example |
|-----------|------------------------------------------------------------|-|
| `add` | Adds a component to an entity (no value) | `world:add(entity, IsEnemy)` |
| `set` | Sets a component's value on an entity | `world:set(entity, Health, 100)` |
| `get` | Gets a component's value from an entity | `local health = world:get(entity, Health)` |
| `remove` | Removes a component from an entity | `world:remove(entity, IsEnemy)` |
| `clear` | Removes all components from an entity | `world:clear(entity)` |
2025-01-17 23:13:34 +00:00
2025-02-19 16:10:38 +00:00
### Example Usage
2025-01-17 23:13:34 +00:00
::: code-group
2025-02-19 16:10:38 +00:00
```lua [luau]
local world = jecs.World.new()
2025-01-17 23:13:34 +00:00
2025-02-19 16:10:38 +00:00
-- Create components
2025-01-17 23:13:34 +00:00
local Position = world:component() :: jecs.Entity<Vector3>
2025-02-19 16:10:38 +00:00
local Health = world:component() :: jecs.Entity<number>
local IsEnemy = world:component()
-- Create an entity
local enemy = world:entity()
-- Add components and data
world:set(enemy, Position, Vector3.new(0, 0, 0))
world:set(enemy, Health, 100)
world:add(enemy, IsEnemy)
2025-01-17 23:13:34 +00:00
2025-02-19 16:10:38 +00:00
-- Get component data
local pos = world:get(enemy, Position)
print(`Enemy position: {pos}`)
-- Check if entity has component
if world:has(enemy, IsEnemy) then
print("This is an enemy!")
end
```
2025-01-17 23:13:34 +00:00
```typescript [typescript]
2025-02-19 16:10:38 +00:00
const world = new World();
// Create components
2025-01-17 23:13:34 +00:00
const Position = world.component<Vector3>();
2025-02-19 16:10:38 +00:00
const Health = world.component<number>();
const IsEnemy = world.component();
// Create an entity
const enemy = world.entity();
// Add components and data
world.set(enemy, Position, new Vector3(0, 0, 0));
world.set(enemy, Health, 100);
world.add(enemy, IsEnemy);
// Get component data
const pos = world.get(enemy, Position);
print(`Enemy position: ${pos}`);
2025-01-17 23:13:34 +00:00
2025-02-19 16:10:38 +00:00
// Check if entity has component
if (world.has(enemy, IsEnemy)) {
print("This is an enemy!");
}
```
2025-01-17 23:13:34 +00:00
:::
2025-02-19 16:10:38 +00:00
## Components are Entities
2025-01-17 23:13:34 +00:00
2025-02-19 16:10:38 +00:00
In Jecs, components themselves are entities with a special `Component` component. This means you can add components to components! This enables powerful features like:
2025-01-17 23:13:34 +00:00
2025-02-19 16:10:38 +00:00
1. Adding metadata to components
2. Creating component hierarchies
3. Defining component relationships
Example:
```lua
local Position = world:component() :: jecs.Entity<Vector3>
2025-01-17 23:13:34 +00:00
local Networked = world:component()
local Type = world:component()
2025-02-19 16:10:38 +00:00
-- Add metadata to Position component
2025-01-17 23:13:34 +00:00
world:add(Position, Networked)
2025-02-19 16:10:38 +00:00
world:set(Position, Type, { size = 12, type = "Vector3" })
2025-01-17 23:13:34 +00:00
```
2025-02-19 16:10:38 +00:00
## Best Practices
2025-01-17 23:13:34 +00:00
2025-02-19 16:10:38 +00:00
1. **Keep Components Simple**
- Components should store related data
- Avoid complex nested structures
- Use multiple components instead of one complex component
2. **Use Tags Effectively**
- Tags are components without data
- Great for marking entity states or categories
- More efficient than components with boolean values
3. **Component Naming**
- Use clear, descriptive names
- Consider using noun-based names for data (Position, Health)
- Consider using adjective-based names for tags (IsEnemy, IsDead)
4. **Data Organization**
- Group related data in components
- Split unrelated data into separate components
- Use relationships for entity connections
2025-01-17 23:13:34 +00:00
## Singletons
Singletons are components for which only a single instance
exists on the world. They can be accessed on the
world directly and do not require providing an entity.
Singletons are useful for global game resources, such as
game state, a handle to a physics engine or a network socket. An example:
::: code-group
```luau [luau]
local TimeOfDay = world:component() :: jecs.Entity<number>
world:set(TimeOfDay, TimeOfDay, 0.5)
local t = world:get(TimeOfDay, TimeOfDay)
```
```typescript [typescript]
const TimeOfDay = world.component<number>();
world.set(TimeOfDay, TimeOfDay, 0.5);
const t = world.get(TimeOfDay, TimeOfDay);
```
:::