Compare commits

..

No commits in common. "52e03683db55da7762a1af6898cfa15c7c03fdcb" and "bacf05685174b7254ad54a8c764a8fefb191abe3" have entirely different histories.

11 changed files with 679 additions and 819 deletions

View file

@ -1,19 +1,19 @@
name: analysis name: Analysis
on: [push, pull_request, workflow_dispatch] on: [push, pull_request, workflow_dispatch]
jobs: jobs:
run: run:
name: Run Luau Analyze name: Run Luau Analyze
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Project - name: Checkout Project
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install Luau - name: Install Luau
uses: encodedvenom/install-luau@v2.1 uses: encodedvenom/install-luau@v2.1
- name: Analyze - name: Analyze
run: | run: |
output=$(luau-analyze src || true) # Suppress errors for now. output=$(luau-analyze src || true) # Suppress errors for now.

View file

@ -1,64 +1,64 @@
# Sample workflow for building and deploying a VitePress site to GitHub Pages # Sample workflow for building and deploying a VitePress site to GitHub Pages
# #
name: deploy-docs name: Deploy VitePress site to Pages
on: on:
# Runs on pushes targeting the `main` branch. Change this to `master` if you're # Runs on pushes targeting the `main` branch. Change this to `master` if you're
# using the `master` branch as the default branch. # using the `master` branch as the default branch.
push: push:
branches: [main] branches: [main]
# Allows you to run this workflow manually from the Actions tab # Allows you to run this workflow manually from the Actions tab
workflow_dispatch: workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions: permissions:
contents: read contents: read
pages: write pages: write
id-token: write id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency: concurrency:
group: pages group: pages
cancel-in-progress: false cancel-in-progress: false
jobs: jobs:
# Build job # Build job
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
fetch-depth: 0 # Not needed if lastUpdated is not enabled fetch-depth: 0 # Not needed if lastUpdated is not enabled
# - uses: pnpm/action-setup@v3 # Uncomment this if you're using pnpm # - uses: pnpm/action-setup@v3 # Uncomment this if you're using pnpm
# - uses: oven-sh/setup-bun@v1 # Uncomment this if you're using Bun # - uses: oven-sh/setup-bun@v1 # Uncomment this if you're using Bun
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 20 node-version: 20
cache: npm # or pnpm / yarn cache: npm # or pnpm / yarn
- name: Setup Pages - name: Setup Pages
uses: actions/configure-pages@v4 uses: actions/configure-pages@v4
- name: Install dependencies - name: Install dependencies
run: npm ci # or pnpm install / yarn install / bun install run: npm ci # or pnpm install / yarn install / bun install
- name: Build with VitePress - name: Build with VitePress
run: npm run docs:build # or pnpm docs:build / yarn docs:build / bun run docs:build run: npm run docs:build # or pnpm docs:build / yarn docs:build / bun run docs:build
- name: Upload artifact - name: Upload artifact
uses: actions/upload-pages-artifact@v3 uses: actions/upload-pages-artifact@v3
with: with:
path: docs/.vitepress/dist path: docs/.vitepress/dist
# Deployment job # Deployment job
deploy: deploy:
environment: environment:
name: github-pages name: github-pages
url: ${{ steps.deployment.outputs.page_url }} url: ${{ steps.deployment.outputs.page_url }}
needs: build needs: build
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Deploy name: Deploy
steps: steps:
- name: Deploy to GitHub Pages - name: Deploy to GitHub Pages
id: deployment id: deployment
uses: actions/deploy-pages@v4 uses: actions/deploy-pages@v4

View file

@ -1,17 +1,17 @@
name: publish-npm name: Publish to NPM
on: on:
push: push:
branches: [main] branches: main
jobs: jobs:
publish: publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: "20" node-version: "20"
- uses: JS-DevTools/npm-publish@v3 - uses: JS-DevTools/npm-publish@v3
with: with:
token: ${{ secrets.NPM_AUTH_TOKEN }} token: ${{ secrets.NPM_AUTH_TOKEN }}

View file

@ -1,71 +1,71 @@
name: release name: Release
on: on:
push: push:
tags: ["v*"] tags: ["v*"]
jobs: jobs:
build: build:
name: Build name: Build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Project - name: Checkout Project
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install Rokit - name: Install Rokit
uses: CompeyDev/setup-rokit@v0.1.2 uses: CompeyDev/setup-rokit@v0.1.2
- name: Install Dependencies - name: Install Dependencies
run: wally install run: wally install
- name: Build - name: Build
run: rojo build --output build.rbxm default.project.json run: rojo build --output build.rbxm default.project.json
- name: Upload Build Artifact - name: Upload Build Artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: build name: build
path: build.rbxm path: build.rbxm
release: release:
name: Release name: Release
needs: [build] needs: [build]
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
contents: write contents: write
steps: steps:
- name: Checkout Project - name: Checkout Project
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Download Jecs Build - name: Download Jecs Build
uses: actions/download-artifact@v3 uses: actions/download-artifact@v3
with: with:
name: build name: build
path: build path: build
- name: Rename Build - name: Rename Build
run: mv build/build.rbxm jecs.rbxm run: mv build/build.rbxm jecs.rbxm
- name: Create Release - name: Create Release
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
with: with:
name: Jecs ${{ github.ref_name }} name: Jecs ${{ github.ref_name }}
files: | files: |
jecs.rbxm jecs.rbxm
publish: publish:
name: Publish name: Publish
needs: [release] needs: [release]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Project - name: Checkout Project
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install Rokit - name: Install Rokit
uses: CompeyDev/setup-rokit@v0.1.2 uses: CompeyDev/setup-rokit@v0.1.2
- name: Wally Login - name: Wally Login
run: wally login --token ${{ secrets.WALLY_AUTH_TOKEN }} run: wally login --token ${{ secrets.WALLY_AUTH_TOKEN }}
- name: Publish - name: Publish
run: wally publish run: wally publish

View file

@ -1,31 +1,31 @@
name: unit-testing name: Unit Testing
on: [push, pull_request, workflow_dispatch] on: [push, pull_request, workflow_dispatch]
jobs: jobs:
run: run:
name: Run Luau Tests name: Run Luau Tests
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 2 timeout-minutes: 2
steps: steps:
- name: Checkout Project - name: Checkout Project
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Install Luau - name: Install Luau
uses: encodedvenom/install-luau@v4.3 uses: encodedvenom/install-luau@v4.3
with: with:
version: "latest" version: 'latest'
verbose: "true" verbose: 'true'
- name: Run Unit Tests - name: Run Unit Tests
id: run_tests id: run_tests
run: | run: |
output=$(luau test/tests.luau) output=$(luau test/tests.luau)
echo "$output" echo "$output"
if [[ "$output" == *"0 fails"* ]]; then if [[ "$output" == *"0 fails"* ]]; then
echo "Unit Tests Passed" echo "Unit Tests Passed"
else else
echo "Error: One or More Unit Tests Failed." echo "Error: One or More Unit Tests Failed."
exit 1 exit 1
fi fi

View file

@ -1,110 +1,88 @@
# 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
## iter ## with
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
```luau function query:with(
function Query:iter(): () -> (Entity, ...) ...: Entity -- The IDs to query with
``` ): Query
```
## with
Example:
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. ::: code-group
```luau ```luau [luau]
function Query:with( for id, position in world:query(Position):with(Velocity) do
...: Entity -- The IDs to query with -- Do something
): Query end
``` ```
Example: ```ts [typescript]
::: code-group for (const [id, position] of world.query(Position).with(Velocity)) {
// Do something
```luau [luau] }
for id, position in world:query(Position):with(Velocity) do ```
-- Do something
end :::
```
:::info
```ts [typescript] Put the IDs inside of `world:query()` instead if you need the data.
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(
:::info ...: Entity -- The IDs to filter against.
Put the IDs inside of `world:query()` instead if you need the data. ): Query -- Returns the Query
::: ```
## without Example:
Removes entities with the provided components from the query. ::: code-group
```luau [luau]
```luau for entity, position in world:query(Position):without(Velocity) do
function Query:without( -- Do something
...: Entity -- The IDs to filter against. end
): Query -- Returns the Query ```
```
```ts [typescript]
Example: for (const [entity, position] of world.query(Position).without(Velocity)) {
// Do something
::: code-group }
```
```luau [luau] :::
for entity, position in world:query(Position):without(Velocity) do
-- Do something ## archetypes
end Returns the matching archetypes of the query.
``` ```luau
function query:archetypes(): { Archetype }
```ts [typescript] ```
for (const [entity, position] of world.query(Position).without(Velocity)) {
// Do something Example:
}
``` ```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]
Returns the matching archetypes of the query. local V = field[Velocity]
```luau for row, entity in archetype.entities do
function Query:archetypes(): { Archetype } local position = columns[P][row]
``` local velocity = columns[V][row]
-- Do something
Example: end
end
```luau [luau] ```
for i, archetype in world:query(Position, Velocity):archetypes() do
local columns = archetype.columns :::info
local field = archetype.records This function is meant for people who want to really customize their query behaviour at the archetype-level
:::
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,500 +1,402 @@
# 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
# Functions ## new
`World` utilizes a class, meaning JECS allows you to create multiple worlds.
## new ```luau
function World.new(): World
`World` utilizes a class, meaning JECS allows you to create multiple worlds. ```
```luau Example:
function World.new(): World
``` ::: code-group
```luau [luau]
Example: local world = jecs.World.new()
local myOtherWorld = jecs.World.new()
::: code-group ```
```luau [luau] ```ts [typescript]
local world = jecs.World.new() import { World } from "@rbxts/jecs";
local myOtherWorld = jecs.World.new()
``` const world = new World();
const myOtherWorld = new World();
```ts [typescript] ```
import { World } from "@rbxts/jecs"; :::
const world = new World(); # Methods
const myOtherWorld = new World(); ## entity
``` Creates a new entity.
```luau
::: function World:entity(): Entity
```
# Methods
Example:
## entity
::: code-group
Creates a new entity. ```luau [luau]
local entity = world:entity()
```luau ```
function World:entity(): Entity
``` ```ts [typescript]
const entity = world.entity();
Example: ```
:::
::: code-group
## component
```luau [luau] Creates a new component. Do note components are entities as well, meaning JECS allows you to add other components onto them.
local entity = world:entity()
``` These are meant to be added onto other entities through `add` and `set`
```luau
```ts [typescript] function World:component<T>(): Entity<T> -- The new componen.
const entity = world.entity(); ```
```
Example:
:::
::: code-group
## component ```luau [luau]
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. ```
These are meant to be added onto other entities through `add` and `set` ```ts [typescript]
const Health = world.component<number>();
```luau ```
function World:component<T>(): Entity<T> -- The new componen. :::
```
## get
Example: 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.
```luau
::: code-group function World:get<T>(
entity: Entity, -- The entity
```luau [luau] id: Entity<T> -- The component ID to fetch
local Health = world:component() :: jecs.Entity<number> -- Typecasting this will allow us to know what kind of data the component holds! ): T?
``` ```
```ts [typescript] Example:
const Health = world.component<number>();
``` ::: code-group
```luau [luau]
::: local Health = world:component() :: jecs.Entity<number>
## get local Entity = world:entity()
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
function World:get<T>( -- Outputs:
entity: Entity, -- The entity -- 100
id: Entity<T> -- The component ID to fetch ```
): T?
``` ```ts [typescript]
const Health = world.component<number>();
Example:
const Entity = world.entity();
::: code-group world.set(Entity, Health, 100);
```luau [luau] print(world.get(Entity, Health))
local Health = world:component() :: jecs.Entity<number>
// Outputs:
local Entity = world:entity() // 100
world:set(Entity, Health, 100) ```
:::
print(world:get(Entity, Health))
## has
-- Outputs: 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.
-- 100 ```luau
``` function World:has(
entity: Entity, -- The entity
```ts [typescript] id: Entity<T> -- The component ID to check
const Health = world.component<number>(); ): boolean
```
const Entity = world.entity();
world.set(Entity, Health, 100); Example:
print(world.get(Entity, Health)); ::: code-group
```luau [luau]
// Outputs: local IsMoving = world:component()
// 100 local Ragdolled = world:entity() -- This is a tag, meaning it won't contain data
``` local Health = world:component() :: jecs.Entity<number>
::: local Entity = world:entity()
world:set(Entity, Health, 100)
## has world:add(Entity, Ragdolled)
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, Health))
print(world:has(Entity, IsMoving)
```luau
function World:has( print(world:get(Entity, Ragdolled))
entity: Entity, -- The entity print(world:has(Entity, Ragdolled))
id: Entity<T> -- The component ID to check
): boolean -- Outputs:
``` -- true
-- false
Example: -- nil
-- true
::: code-group ```
```luau [luau] ```ts [typescript]
local IsMoving = world:component() const IsMoving = world.component();
local Ragdolled = world:entity() -- This is a tag, meaning it won't contain data const Ragdolled = world.entity(); // This is a tag, meaning it won't contain data
local Health = world:component() :: jecs.Entity<number> const Health = world.component<number>();
local Entity = world:entity() const 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]
const IsMoving = world.component(); ## add
const Ragdolled = world.entity(); // This is a tag, meaning it won't contain data 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 Health = world.component<number>();
```luau
const Entity = world.entity(); function World:add(
world.set(Entity, Health, 100); entity: Entity, -- The entity
world.add(Entity, Ragdolled); id: Entity<T> -- The component ID to add
): void
print(world.has(Entity, Health)); ```
print(world.has(Entity, IsMoving));
::: info
print(world.get(Entity, Ragdolled)); This function is idempotent, meaning if the entity already has the id, this operation will have no side effects.
print(world.has(Entity, Ragdolled)); :::
// Outputs: ## set
// true Adds or changes data in the entity's component.
// false ```luau
// nil function World:set(
// true entity: Entity, -- The entity
``` 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]
function World:add( local Health = world:component() :: jecs.Entity<number>
entity: Entity, -- The entity
id: Entity<T> -- The component ID to add local Entity = world:entity()
): void world:set(Entity, Health, 100)
```
print(world:get(Entity, Health))
::: info
This function is idempotent, meaning if the entity already has the id, this operation will have no side effects. world:set(Entity, Health, 50)
::: print(world:get(Entity, Health))
## set -- Outputs:
-- 100
Adds or changes data in the entity's component. -- 50
```
```luau
function World:set( ```ts [typescript]
entity: Entity, -- The entity const Health = world.component<number>();
id: Entity<T>, -- The component ID to set
data: T -- The data of the component's type const Entity = world.entity();
): void world.set(Entity, Health, 100);
```
print(world.get(Entity, Health))
Example:
world.set(Entity, Health, 50);
::: code-group print(world.get(Entity, Health))
```luau [luau] // Outputs:
local Health = world:component() :: jecs.Entity<number> // 100
// 50
local Entity = world:entity() ```
world:set(Entity, Health, 100) :::
print(world:get(Entity, Health)) ## 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.
world:set(Entity, Health, 50) ```luau
print(world:get(Entity, Health)) function World:query(
...: Entity -- The components to query with
-- Outputs: ): Query
-- 100 ```
-- 50
``` Example:
```ts [typescript] ::: code-group
const Health = world.component<number>(); ```luau [luau]
-- 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
const Entity = world.entity(); for entity, position, velocity in world:query(Position, Velocity) do
world.set(Entity, Health, 100);
end
print(world.get(Entity, Health)); ```
world.set(Entity, Health, 50); ```ts [typescript]
print(world.get(Entity, Health)); // Roblox-TS allows to deconstruct tuples on the act like if they were arrays!
// 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
// Outputs: for (const [entity, position, velocity] of world.query(Position, Velocity) {
// 100 // Do something
// 50 }
``` ```
:::
:::
:::info
## query Queries are uncached by default, this is generally very cheap unless you have high fragmentation from e.g. relationships.
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
```luau Get the target of a relationship.
function World:query( 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.
...: Entity -- The components to query with 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.
): Query ```luau
``` function World:target(
entity: Entity, -- The entity
Example: relation: Entity, -- The relationship between the entity and the target
nth: number, -- The index
::: code-group ): Entity? -- The target for the relationship at the specified index.
```
```luau [luau]
-- 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 ## parent
for entity, position, velocity in world:query(Position, Velocity) do Get parent (target of ChildOf relationship) for entity. If there is no ChildOf relationship pair, it will return nil.
```luau
end function World:parent(
``` 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!
// 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 This operation is the same as calling:
for (const [entity, position, velocity] of world.query(Position, Velocity) {
// Do something ```luau
} world:target(entity, jecs.ChildOf, 0)
``` ```
::: ## contains
Checks if an entity or component (id) exists in the world.
:::info ```luau
Queries are uncached by default, this is generally very cheap unless you have high fragmentation from e.g. relationships. function World:contains(
entity: Entity,
::: ): boolean
```
## target
Example:
Get the target of a relationship.
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. ::: code-group
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. ```luau [luau]
local entity = world:entity()
```luau print(world:contains(entity))
function World:target( print(world:contains(1))
entity: Entity, -- The entity print(world:contains(2))
relation: Entity, -- The relationship between the entity and the target
nth: number, -- The index -- Outputs:
): Entity? -- The target for the relationship at the specified index. -- true
``` -- true
-- false
## parent ```
Get parent (target of ChildOf relationship) for entity. If there is no ChildOf relationship pair, it will return nil. ```ts [typescript]
const entity = world.entity();
```luau print(world.contains(entity));
function World:parent( print(world.contains(1));
child: Entity -- The child ID to find the parent of print(world.contains(2));
): Entity? -- Returns the parent of the child
``` // Outputs:
// true
This operation is the same as calling: // true
// false
```luau ```
world:target(entity, jecs.ChildOf, 0) :::
```
## remove
## contains Removes a component (ID) from an entity
```luau
Checks if an entity or component (id) exists in the world. function World:remove(
entity: Entity,
```luau component: Entity<T>
function World:contains( ): void
entity: Entity, ```
): boolean
``` Example:
Example: ::: code-group
```luau [luau]
::: code-group local IsMoving = world:component()
```luau [luau] local entity = world:entity()
local entity = world:entity() world:add(entity, IsMoving)
print(world:contains(entity))
print(world:contains(1)) print(world:has(entity, IsMoving))
print(world:contains(2))
world:remove(entity, IsMoving)
-- Outputs: print(world:has(entity, IsMoving))
-- true
-- true -- Outputs:
-- false -- true
``` -- false
```
```ts [typescript]
const entity = world.entity(); ```ts [typescript]
print(world.contains(entity)); const IsMoving = world.component();
print(world.contains(1));
print(world.contains(2)); const entity = world.entity();
world.add(entity, IsMoving);
// Outputs:
// true print(world.has(entity, IsMoving));
// true
// false world.remove(entity, IsMoving);
``` print(world.has(entity, IsMoving));
::: // Outputs:
// true
## remove // false
```
Removes a component (ID) from an entity :::
```luau ## delete
function World:remove( Deletes an entity and all of its related components and relationships.
entity: Entity, ```luau
component: Entity<T> function World:delete(
): void entity: Entity
``` ): void
```
Example:
Example:
::: code-group
::: code-group
```luau [luau] ```luau [luau]
local IsMoving = world:component() local entity = world:entity()
print(world:has(entity))
local entity = world:entity()
world:add(entity, IsMoving) world:delete(entity)
print(world:has(entity, IsMoving)) print(world:has(entity))
world:remove(entity, IsMoving) -- Outputs:
print(world:has(entity, IsMoving)) -- true
-- false
-- Outputs: ```
-- true
-- false ```ts [typescript]
``` const entity = world.entity();
print(world.has(entity));
```ts [typescript]
const IsMoving = world.component(); world.delete(entity);
const entity = world.entity(); print(world.has(entity));
world.add(entity, IsMoving);
// Outputs:
print(world.has(entity, IsMoving)); // true
// false
world.remove(entity, IsMoving); ```
print(world.has(entity, IsMoving)); :::
// Outputs: ## clear
// true Clears all of the components and relationships of the entity without deleting it.
// false ```luau
``` 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))
```

View file

@ -1995,7 +1995,6 @@ local function world_each(world: World, id): () -> ()
archetype = archetypes[archetype_id] archetype = archetypes[archetype_id]
entities = archetype.entities entities = archetype.entities
row = #entities row = #entities
entity = entities[row]
end end
row -= 1 row -= 1
return entity return entity

View file

@ -1,6 +1,6 @@
{ {
"name": "@rbxts/jecs", "name": "@rbxts/jecs",
"version": "0.5.2", "version": "0.5.1",
"description": "Stupidly fast Entity Component System", "description": "Stupidly fast Entity Component System",
"main": "jecs.luau", "main": "jecs.luau",
"repository": { "repository": {

View file

@ -900,39 +900,20 @@ end)
TEST("world:children", function() TEST("world:children", function()
local world = world_new() local world = world_new()
local C = world:component()
local T = world:entity()
local e1 = world:entity() local e1 = world:entity()
world:set(e1, C, true)
local e2 = world:entity() local e2 = world:entity()
world:add(e2, T)
world:add(e2, pair(ChildOf, e1))
local e3 = world:entity() local e3 = world:entity()
world:add(e2, pair(ChildOf, e1))
world:add(e3, pair(ChildOf, e1)) world:add(e3, pair(ChildOf, e1))
local count = 0 for entity in world:children(pair(ChildOf, e1)) do
for entity in world:children(e1) do
count += 1
if entity == e2 or entity == e3 then if entity == e2 or entity == e3 then
CHECK(true) CHECK(true)
continue continue
end end
CHECK(false) CHECK(false)
end end
CHECK(count == 2)
world:remove(e2, pair(ChildOf, e1))
count = 0
for entity in world:children(e1) do
count += 1
end
CHECK(count == 1)
end) end)
TEST("world:clear()", function() TEST("world:clear()", function()
@ -1581,9 +1562,9 @@ TEST("repro", function()
local world = world_new() local world = world_new()
local component1 = world:component() local component1 = world:component()
local tag1 = world:entity() local tag1 = world:entity()
local query = world:query(component1):with(tag1):cached() local query = world:query(component1):with(tag1):cached()
local entity = world:entity() local entity = world:entity()
world:set(entity, component1, "some data") world:set(entity, component1, "some data")

View file

@ -1,6 +1,6 @@
[package] [package]
name = "ukendio/jecs" name = "ukendio/jecs"
version = "0.5.2" version = "0.5.1"
registry = "https://github.com/UpliftGames/wally-index" registry = "https://github.com/UpliftGames/wally-index"
realm = "shared" realm = "shared"
license = "MIT" license = "MIT"