Update documentation
Some checks are pending
analysis / Run Luau Analyze (push) Waiting to run
deploy-docs / build (push) Waiting to run
deploy-docs / Deploy (push) Blocked by required conditions
publish-npm / publish (push) Waiting to run
unit-testing / Run Luau Tests (push) Waiting to run

This commit is contained in:
Ukendio 2025-01-15 19:59:07 +01:00
parent 753adf884d
commit 52e03683db
2 changed files with 610 additions and 490 deletions

View file

@ -1,88 +1,110 @@
# Query # Query
A World contains entities which have components. The World is queryable and can be used to get entities with a specific set of components. A World contains entities which have components. The World is queryable and can be used to get entities with a specific set of components.
# Methods # Methods
## with ## iter
Adds components (IDs) to query with, but will not use their data. This is useful for Tags or generally just data you do not care for.
Returns an iterator that can be used to iterate over the query.
```luau
function query:with( ```luau
...: Entity -- The IDs to query with function Query:iter(): () -> (Entity, ...)
): Query ```
```
## with
Example:
::: code-group Adds components (IDs) to query with, but will not use their data. This is useful for Tags or generally just data you do not care for.
```luau [luau] ```luau
for id, position in world:query(Position):with(Velocity) do function Query:with(
-- Do something ...: Entity -- The IDs to query with
end ): Query
``` ```
```ts [typescript] Example:
for (const [id, position] of world.query(Position).with(Velocity)) { ::: code-group
// Do something
} ```luau [luau]
``` for id, position in world:query(Position):with(Velocity) do
-- Do something
::: end
```
:::info
Put the IDs inside of `world:query()` instead if you need the data. ```ts [typescript]
::: for (const [id, position] of world.query(Position).with(Velocity)) {
// Do something
## without }
Removes entities with the provided components from the query. ```
```luau :::
function query:without(
...: Entity -- The IDs to filter against. :::info
): Query -- Returns the Query Put the IDs inside of `world:query()` instead if you need the data.
``` :::
Example: ## without
::: code-group Removes entities with the provided components from the query.
```luau [luau]
for entity, position in world:query(Position):without(Velocity) do ```luau
-- Do something function Query:without(
end ...: Entity -- The IDs to filter against.
``` ): Query -- Returns the Query
```
```ts [typescript]
for (const [entity, position] of world.query(Position).without(Velocity)) { Example:
// Do something
} ::: code-group
```
::: ```luau [luau]
for entity, position in world:query(Position):without(Velocity) do
## archetypes -- Do something
Returns the matching archetypes of the query. end
```luau ```
function query:archetypes(): { Archetype }
``` ```ts [typescript]
for (const [entity, position] of world.query(Position).without(Velocity)) {
Example: // Do something
}
```luau [luau] ```
for i, archetype in world:query(Position, Velocity):archetypes() do
local columns = archetype.columns :::
local field = archetype.records
## archetypes
local P = field[Position]
local V = field[Velocity] Returns the matching archetypes of the query.
for row, entity in archetype.entities do ```luau
local position = columns[P][row] function Query:archetypes(): { Archetype }
local velocity = columns[V][row] ```
-- Do something
end Example:
end
``` ```luau [luau]
for i, archetype in world:query(Position, Velocity):archetypes() do
:::info local columns = archetype.columns
This function is meant for people who want to really customize their query behaviour at the archetype-level local field = archetype.records
:::
local P = field[Position]
local V = field[Velocity]
for row, entity in archetype.entities do
local position = columns[P][row]
local velocity = columns[V][row]
-- Do something
end
end
```
:::info
This function is meant for people who want to really customize their query behaviour at the archetype-level
:::
## cached
Returns a cached version of the query. This is useful if you want to iterate over the same query multiple times.
```luau
function Query:cached(): Query -- Returns the cached Query
```

View file

@ -1,402 +1,500 @@
# World # World
A World contains entities which have components. The World is queryable and can be used to get entities with a specific set of components and to perform different kinds of operations on them.
A World contains entities which have components. The World is queryable and can be used to get entities with a specific set of components and to perform different kinds of operations on them.
# Functions
## new # Functions
`World` utilizes a class, meaning JECS allows you to create multiple worlds.
```luau ## new
function World.new(): World
``` `World` utilizes a class, meaning JECS allows you to create multiple worlds.
Example: ```luau
function World.new(): World
::: code-group ```
```luau [luau]
local world = jecs.World.new() Example:
local myOtherWorld = jecs.World.new()
``` ::: code-group
```ts [typescript] ```luau [luau]
import { World } from "@rbxts/jecs"; local world = jecs.World.new()
local myOtherWorld = jecs.World.new()
const world = new World(); ```
const myOtherWorld = new World();
``` ```ts [typescript]
::: import { World } from "@rbxts/jecs";
# Methods const world = new World();
## entity const myOtherWorld = new World();
Creates a new entity. ```
```luau
function World:entity(): Entity :::
```
# Methods
Example:
## entity
::: code-group
```luau [luau] Creates a new entity.
local entity = world:entity()
``` ```luau
function World:entity(): Entity
```ts [typescript] ```
const entity = world.entity();
``` Example:
:::
::: code-group
## component
Creates a new component. Do note components are entities as well, meaning JECS allows you to add other components onto them. ```luau [luau]
local entity = world:entity()
These are meant to be added onto other entities through `add` and `set` ```
```luau
function World:component<T>(): Entity<T> -- The new componen. ```ts [typescript]
``` const entity = world.entity();
```
Example:
:::
::: code-group
```luau [luau] ## component
local Health = world:component() :: jecs.Entity<number> -- Typecasting this will allow us to know what kind of data the component holds!
``` Creates a new component. Do note components are entities as well, meaning JECS allows you to add other components onto them.
```ts [typescript] These are meant to be added onto other entities through `add` and `set`
const Health = world.component<number>();
``` ```luau
::: function World:component<T>(): Entity<T> -- The new componen.
```
## get
Returns the data present in the component that was set in the entity. Will return nil if the component was a tag or is not present. Example:
```luau
function World:get<T>( ::: code-group
entity: Entity, -- The entity
id: Entity<T> -- The component ID to fetch ```luau [luau]
): T? local Health = world:component() :: jecs.Entity<number> -- Typecasting this will allow us to know what kind of data the component holds!
``` ```
Example: ```ts [typescript]
const Health = world.component<number>();
::: code-group ```
```luau [luau]
local Health = world:component() :: jecs.Entity<number> :::
local Entity = world:entity() ## get
world:set(Entity, Health, 100)
Returns the data present in the component that was set in the entity. Will return nil if the component was a tag or is not present.
print(world:get(Entity, Health))
```luau
-- Outputs: function World:get<T>(
-- 100 entity: Entity, -- The entity
``` id: Entity<T> -- The component ID to fetch
): T?
```ts [typescript] ```
const Health = world.component<number>();
Example:
const Entity = world.entity();
world.set(Entity, Health, 100); ::: code-group
print(world.get(Entity, Health)) ```luau [luau]
local Health = world:component() :: jecs.Entity<number>
// Outputs:
// 100 local Entity = world:entity()
``` world:set(Entity, Health, 100)
:::
print(world:get(Entity, Health))
## has
Returns whether an entity has a component (ID). Useful for checking if an entity has a tag or if you don't care of the data that is inside the component. -- Outputs:
```luau -- 100
function World:has( ```
entity: Entity, -- The entity
id: Entity<T> -- The component ID to check ```ts [typescript]
): boolean const Health = world.component<number>();
```
const Entity = world.entity();
Example: world.set(Entity, Health, 100);
::: code-group print(world.get(Entity, Health));
```luau [luau]
local IsMoving = world:component() // Outputs:
local Ragdolled = world:entity() -- This is a tag, meaning it won't contain data // 100
local Health = world:component() :: jecs.Entity<number> ```
local Entity = world:entity() :::
world:set(Entity, Health, 100)
world:add(Entity, Ragdolled) ## has
print(world:has(Entity, Health)) Returns whether an entity has a component (ID). Useful for checking if an entity has a tag or if you don't care of the data that is inside the component.
print(world:has(Entity, IsMoving)
```luau
print(world:get(Entity, Ragdolled)) function World:has(
print(world:has(Entity, Ragdolled)) entity: Entity, -- The entity
id: Entity<T> -- The component ID to check
-- Outputs: ): boolean
-- true ```
-- false
-- nil Example:
-- true
``` ::: code-group
```ts [typescript] ```luau [luau]
const IsMoving = world.component(); local IsMoving = world:component()
const Ragdolled = world.entity(); // This is a tag, meaning it won't contain data local Ragdolled = world:entity() -- This is a tag, meaning it won't contain data
const Health = world.component<number>(); local Health = world:component() :: jecs.Entity<number>
const Entity = world.entity(); local Entity = world:entity()
world.set(Entity, Health, 100); world:set(Entity, Health, 100)
world.add(Entity, Ragdolled); world:add(Entity, Ragdolled)
print(world.has(Entity, Health)); print(world:has(Entity, Health))
print(world.has(Entity, IsMoving)); print(world:has(Entity, IsMoving)
print(world.get(Entity, Ragdolled)); print(world:get(Entity, Ragdolled))
print(world.has(Entity, Ragdolled)); print(world:has(Entity, Ragdolled))
// Outputs: -- Outputs:
// true -- true
// false -- false
// nil -- nil
// true -- true
``` ```
:::
```ts [typescript]
## add const IsMoving = world.component();
Adds a component (ID) to the entity. Useful for adding a tag to an entity, as this adds the component to the entity without any additional values inside const Ragdolled = world.entity(); // This is a tag, meaning it won't contain data
const Health = world.component<number>();
```luau
function World:add( const Entity = world.entity();
entity: Entity, -- The entity world.set(Entity, Health, 100);
id: Entity<T> -- The component ID to add world.add(Entity, Ragdolled);
): void
``` print(world.has(Entity, Health));
print(world.has(Entity, IsMoving));
::: info
This function is idempotent, meaning if the entity already has the id, this operation will have no side effects. print(world.get(Entity, Ragdolled));
::: print(world.has(Entity, Ragdolled));
## set // Outputs:
Adds or changes data in the entity's component. // true
```luau // false
function World:set( // nil
entity: Entity, -- The entity // true
id: Entity<T>, -- The component ID to set ```
data: T -- The data of the component's type
): void :::
```
## add
Example:
Adds a component (ID) to the entity. Useful for adding a tag to an entity, as this adds the component to the entity without any additional values inside
::: code-group
```luau [luau] ```luau
local Health = world:component() :: jecs.Entity<number> function World:add(
entity: Entity, -- The entity
local Entity = world:entity() id: Entity<T> -- The component ID to add
world:set(Entity, Health, 100) ): void
```
print(world:get(Entity, Health))
::: info
world:set(Entity, Health, 50) This function is idempotent, meaning if the entity already has the id, this operation will have no side effects.
print(world:get(Entity, Health)) :::
-- Outputs: ## set
-- 100
-- 50 Adds or changes data in the entity's component.
```
```luau
```ts [typescript] function World:set(
const Health = world.component<number>(); entity: Entity, -- The entity
id: Entity<T>, -- The component ID to set
const Entity = world.entity(); data: T -- The data of the component's type
world.set(Entity, Health, 100); ): void
```
print(world.get(Entity, Health))
Example:
world.set(Entity, Health, 50);
print(world.get(Entity, Health)) ::: code-group
// Outputs: ```luau [luau]
// 100 local Health = world:component() :: jecs.Entity<number>
// 50
``` local Entity = world:entity()
::: world:set(Entity, Health, 100)
## query print(world:get(Entity, Health))
Creates a [`query`](query) with the given components (IDs). Entities that satisfies the conditions of the query will be returned and their corresponding data.
```luau world:set(Entity, Health, 50)
function World:query( print(world:get(Entity, Health))
...: Entity -- The components to query with
): Query -- Outputs:
``` -- 100
-- 50
Example: ```
::: code-group ```ts [typescript]
```luau [luau] const Health = world.component<number>();
-- Entity could also be a component if a component also meets the requirements, since they are also entities which you can add more components onto
for entity, position, velocity in world:query(Position, Velocity) do const Entity = world.entity();
world.set(Entity, Health, 100);
end
``` print(world.get(Entity, Health));
```ts [typescript] world.set(Entity, Health, 50);
// Roblox-TS allows to deconstruct tuples on the act like if they were arrays! print(world.get(Entity, Health));
// Entity could also be a component if a component also meets the requirements, since they are also entities which you can add more components onto
for (const [entity, position, velocity] of world.query(Position, Velocity) { // Outputs:
// Do something // 100
} // 50
``` ```
:::
:::
:::info
Queries are uncached by default, this is generally very cheap unless you have high fragmentation from e.g. relationships. ## query
::: Creates a [`query`](query) with the given components (IDs). Entities that satisfies the conditions of the query will be returned and their corresponding data.
## target
Get the target of a relationship. ```luau
This will return a target (second element of a pair) of the entity for the specified relationship. The index allows for iterating through the targets, if a single entity has multiple targets for the same relationship. function World:query(
If the index is larger than the total number of instances the entity has for the relationship or if there is no pair with the specified relationship on the entity, the operation will return nil. ...: Entity -- The components to query with
```luau ): Query
function World:target( ```
entity: Entity, -- The entity
relation: Entity, -- The relationship between the entity and the target Example:
nth: number, -- The index
): Entity? -- The target for the relationship at the specified index. ::: code-group
```
```luau [luau]
## parent -- Entity could also be a component if a component also meets the requirements, since they are also entities which you can add more components onto
Get parent (target of ChildOf relationship) for entity. If there is no ChildOf relationship pair, it will return nil. for entity, position, velocity in world:query(Position, Velocity) do
```luau
function World:parent( end
child: Entity -- The child ID to find the parent of ```
): Entity? -- Returns the parent of the child
``` ```ts [typescript]
// Roblox-TS allows to deconstruct tuples on the act like if they were arrays!
This operation is the same as calling: // Entity could also be a component if a component also meets the requirements, since they are also entities which you can add more components onto
for (const [entity, position, velocity] of world.query(Position, Velocity) {
```luau // Do something
world:target(entity, jecs.ChildOf, 0) }
``` ```
## contains :::
Checks if an entity or component (id) exists in the world.
```luau :::info
function World:contains( Queries are uncached by default, this is generally very cheap unless you have high fragmentation from e.g. relationships.
entity: Entity,
): boolean :::
```
## target
Example:
Get the target of a relationship.
::: code-group This will return a target (second element of a pair) of the entity for the specified relationship. The index allows for iterating through the targets, if a single entity has multiple targets for the same relationship.
```luau [luau] If the index is larger than the total number of instances the entity has for the relationship or if there is no pair with the specified relationship on the entity, the operation will return nil.
local entity = world:entity()
print(world:contains(entity)) ```luau
print(world:contains(1)) function World:target(
print(world:contains(2)) entity: Entity, -- The entity
relation: Entity, -- The relationship between the entity and the target
-- Outputs: nth: number, -- The index
-- true ): Entity? -- The target for the relationship at the specified index.
-- true ```
-- false
``` ## parent
```ts [typescript] Get parent (target of ChildOf relationship) for entity. If there is no ChildOf relationship pair, it will return nil.
const entity = world.entity();
print(world.contains(entity)); ```luau
print(world.contains(1)); function World:parent(
print(world.contains(2)); child: Entity -- The child ID to find the parent of
): Entity? -- Returns the parent of the child
// Outputs: ```
// true
// true This operation is the same as calling:
// false
``` ```luau
::: world:target(entity, jecs.ChildOf, 0)
```
## remove
Removes a component (ID) from an entity ## contains
```luau
function World:remove( Checks if an entity or component (id) exists in the world.
entity: Entity,
component: Entity<T> ```luau
): void function World:contains(
``` entity: Entity,
): boolean
Example: ```
::: code-group Example:
```luau [luau]
local IsMoving = world:component() ::: code-group
local entity = world:entity() ```luau [luau]
world:add(entity, IsMoving) local entity = world:entity()
print(world:contains(entity))
print(world:has(entity, IsMoving)) print(world:contains(1))
print(world:contains(2))
world:remove(entity, IsMoving)
print(world:has(entity, IsMoving)) -- Outputs:
-- true
-- Outputs: -- true
-- true -- false
-- false ```
```
```ts [typescript]
```ts [typescript] const entity = world.entity();
const IsMoving = world.component(); print(world.contains(entity));
print(world.contains(1));
const entity = world.entity(); print(world.contains(2));
world.add(entity, IsMoving);
// Outputs:
print(world.has(entity, IsMoving)); // true
// true
world.remove(entity, IsMoving); // false
print(world.has(entity, IsMoving)); ```
// Outputs: :::
// true
// false ## remove
```
::: Removes a component (ID) from an entity
## delete ```luau
Deletes an entity and all of its related components and relationships. function World:remove(
```luau entity: Entity,
function World:delete( component: Entity<T>
entity: Entity ): void
): void ```
```
Example:
Example:
::: code-group
::: code-group
```luau [luau] ```luau [luau]
local entity = world:entity() local IsMoving = world:component()
print(world:has(entity))
local entity = world:entity()
world:delete(entity) world:add(entity, IsMoving)
print(world:has(entity)) print(world:has(entity, IsMoving))
-- Outputs: world:remove(entity, IsMoving)
-- true print(world:has(entity, IsMoving))
-- false
``` -- Outputs:
-- true
```ts [typescript] -- false
const entity = world.entity(); ```
print(world.has(entity));
```ts [typescript]
world.delete(entity); const IsMoving = world.component();
print(world.has(entity)); const entity = world.entity();
world.add(entity, IsMoving);
// Outputs:
// true print(world.has(entity, IsMoving));
// false
``` world.remove(entity, IsMoving);
::: print(world.has(entity, IsMoving));
## clear // Outputs:
Clears all of the components and relationships of the entity without deleting it. // true
```luau // false
function World:clear( ```
entity: Entity
): void :::
```
## delete
Deletes an entity and all of its related components and relationships.
```luau
function World:delete(
entity: Entity
): void
```
Example:
::: code-group
```luau [luau]
local entity = world:entity()
print(world:has(entity))
world:delete(entity)
print(world:has(entity))
-- Outputs:
-- true
-- false
```
```ts [typescript]
const entity = world.entity();
print(world.has(entity));
world.delete(entity);
print(world.has(entity));
// Outputs:
// true
// false
```
:::
## clear
Clears all of the components and relationships of the entity without deleting it.
```luau
function World:clear(
entity: Entity
): void
```
## each
Iterate over all entities with the specified component.
Useful when you only need the entity for a specific ID and you want to avoid creating a query.
```luau
function World:each(
id: Entity -- The component ID
): () -> Entity
```
Example:
::: code-group
```luau [luau]
local id = world:entity()
for entity in world:each(id) do
-- Do something
end
```
```ts [typescript]
const id = world.entity();
for (const entity of world.each(id)) {
// Do something
}
```
:::
## children
Iterate entities in root of parent
```luau
function World:children(
parent: Entity -- The parent entity
): () -> Entity
```
This is the same as calling:
```luau
world:each(pair(ChildOf, parent))
```