mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-25 09:30:03 +00:00
Merge with main branch
This commit is contained in:
commit
ce2bb6b8f2
25 changed files with 2375 additions and 334 deletions
22
.github/ISSUE_TEMPLATE/BUG-REPORT.md
vendored
Normal file
22
.github/ISSUE_TEMPLATE/BUG-REPORT.md
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: File a bug report for any behavior that you believe is unintentional or problematic
|
||||||
|
title: "[BUG]"
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Describe the bug
|
||||||
|
Put a clear and concise description of what the bug is. This should be short and to the point, not to exceed more than a paragraph. Put the details inside your reproduction steps.
|
||||||
|
|
||||||
|
## Reproduction
|
||||||
|
Make an easy-to-follow guide on how to reproduce it. Does it happen all the time? Will specific features affect reproduction? All these questions should be answered for a good issue.
|
||||||
|
|
||||||
|
This is a good place to put rbxl files or scripts that help explain your reproduction steps.
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
What you expect to happen
|
||||||
|
|
||||||
|
## Actual Behavior
|
||||||
|
What actually happens
|
27
.github/ISSUE_TEMPLATE/FEATURE-REQUEST.md
vendored
Normal file
27
.github/ISSUE_TEMPLATE/FEATURE-REQUEST.md
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
name: Feature Request
|
||||||
|
about: File a feature request for something you believe should be added to Jecs
|
||||||
|
title: "[FEATURE]"
|
||||||
|
labels: feature
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Describe your Feature
|
||||||
|
|
||||||
|
You should explain your feature here, and the motivation for why you want it.
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
Explain how you would implement your feature here. Provide relevant API examples and such here (if applicable).
|
||||||
|
|
||||||
|
## Alternatives
|
||||||
|
|
||||||
|
What other alternative implementations or otherwise relevant information is important to why you decided to go with this specific implementation?
|
||||||
|
|
||||||
|
## Considerations
|
||||||
|
|
||||||
|
Some questions that need to be answered include the following:
|
||||||
|
- Will old code break in response to this feature?
|
||||||
|
- What are the performance impacts with this feature (if any)?
|
||||||
|
- How is it useful to include?
|
15
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
15
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
## Brief Description of your Changes.
|
||||||
|
|
||||||
|
Describe what you did here. Additionally, you should link any relevant issues within this section. If there is no corresponding issue, you should include relevant information (repro steps, motivation, etc) here.
|
||||||
|
|
||||||
|
## Impact of your Changes
|
||||||
|
|
||||||
|
What implications will this have on the project? Will there be altered behavior or performance with this change?
|
||||||
|
|
||||||
|
## Tests Performed
|
||||||
|
|
||||||
|
What have you done to ensure this change has the least possible impact on the project?
|
||||||
|
|
||||||
|
## Additional Comments
|
||||||
|
|
||||||
|
Anything else you feel is relevant.
|
64
.github/workflows/deploy-docs.yaml
vendored
Normal file
64
.github/workflows/deploy-docs.yaml
vendored
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
# Sample workflow for building and deploying a VitePress site to GitHub Pages
|
||||||
|
#
|
||||||
|
name: Deploy VitePress site to Pages
|
||||||
|
|
||||||
|
on:
|
||||||
|
# Runs on pushes targeting the `main` branch. Change this to `master` if you're
|
||||||
|
# using the `master` branch as the default branch.
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
# Allows you to run this workflow manually from the Actions tab
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
concurrency:
|
||||||
|
group: pages
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Build job
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Not needed if lastUpdated is not enabled
|
||||||
|
# - 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
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
cache: npm # or pnpm / yarn
|
||||||
|
- name: Setup Pages
|
||||||
|
uses: actions/configure-pages@v4
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci # or pnpm install / yarn install / bun install
|
||||||
|
- name: Build with VitePress
|
||||||
|
run: npm run docs:build # or pnpm docs:build / yarn docs:build / bun run docs:build
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
with:
|
||||||
|
path: docs/.vitepress/dist
|
||||||
|
|
||||||
|
# Deployment job
|
||||||
|
deploy:
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Deploy
|
||||||
|
steps:
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v4
|
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -54,3 +54,11 @@ WallyPatches
|
||||||
roblox.toml
|
roblox.toml
|
||||||
sourcemap.json
|
sourcemap.json
|
||||||
drafts/*.lua
|
drafts/*.lua
|
||||||
|
|
||||||
|
# Cached Vitepress (docs)
|
||||||
|
|
||||||
|
/docs/.vitepress/cache
|
||||||
|
/docs/.vitepress/dist
|
||||||
|
|
||||||
|
.vitepress/cache
|
||||||
|
.vitepress/dist
|
57
docs/.vitepress/config.mts
Normal file
57
docs/.vitepress/config.mts
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
import { defineConfig } from 'vitepress'
|
||||||
|
|
||||||
|
// https://vitepress.dev/reference/site-config
|
||||||
|
export default defineConfig({
|
||||||
|
title: "Jecs",
|
||||||
|
base: "/jecs/",
|
||||||
|
description: "A VitePress Site",
|
||||||
|
themeConfig: {
|
||||||
|
// https://vitepress.dev/reference/default-theme-config
|
||||||
|
nav: [
|
||||||
|
{ text: 'Home', link: '/' },
|
||||||
|
{ text: 'Examples', link: '/markdown-examples' }
|
||||||
|
],
|
||||||
|
|
||||||
|
sidebar: [
|
||||||
|
{
|
||||||
|
text: 'Overview',
|
||||||
|
items: [
|
||||||
|
{ text: 'Getting Started', link: '/overview/get-started' },
|
||||||
|
{ text: 'First Jecs Project', link: '/overview/first-jecs-project' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Concepts',
|
||||||
|
items: [
|
||||||
|
{ text: 'Entities', link: '/concepts/entities' },
|
||||||
|
{ text: 'Static Components', link: '/concepts/static-components' },
|
||||||
|
{ text: 'Queries', link: '/concepts/queries' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'References',
|
||||||
|
items: [
|
||||||
|
{ text: 'API Reference', link: '/api' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "FAQ",
|
||||||
|
items: [
|
||||||
|
{ text: 'How can I contribute?', link: '/faq/contributing' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Contributing',
|
||||||
|
items: [
|
||||||
|
{ text: 'Contribution Guidelines', link: '/contributing/guidelines'},
|
||||||
|
{ text: 'Submitting Issues', link: '/contributing/issues'},
|
||||||
|
{ text: 'Submitting Pull Requests', link: '/contributing/pull-requests'},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
socialLinks: [
|
||||||
|
{ icon: 'github', link: 'https://github.com/vuejs/vitepress' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
|
@ -1,45 +0,0 @@
|
||||||
# World
|
|
||||||
|
|
||||||
A World contains all ECS data
|
|
||||||
Games can have multiple worlds, although typically only one is necessary. These worlds are isolated from each other, meaning they donot share the same entities nor component IDs.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Entity
|
|
||||||
|
|
||||||
An unique id.
|
|
||||||
|
|
||||||
Entities consist out of a number unique to the entity in the lower 32 bits, and a counter used to track entity liveliness in the upper 32 bits. When an id is recycled, its generation count is increased. This causes recycled ids to be very large (>4 billion), which is normal.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# QueryIter
|
|
||||||
|
|
||||||
A result from the `World:query` function.
|
|
||||||
|
|
||||||
Queries are used to iterate over entities that match against the set collection of components.
|
|
||||||
|
|
||||||
Calling it in a loop will allow iteration over the results.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
for id, enemy, charge, model in world:query(Enemy, Charge, Model) do
|
|
||||||
-- Do something
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
### QueryIter.without
|
|
||||||
|
|
||||||
QueryIter.without(iter: QueryIter
|
|
||||||
...: [Entity](#Entity)): QueryIter
|
|
||||||
|
|
||||||
|
|
||||||
Create a new Query Iterator from the filter
|
|
||||||
|
|
||||||
#### Parameters
|
|
||||||
world The world.
|
|
||||||
... The collection of components to filter archetypes against.
|
|
||||||
|
|
||||||
#### Returns
|
|
||||||
|
|
||||||
The new query iterator.
|
|
||||||
|
|
59
docs/api.md
Normal file
59
docs/api.md
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
# API
|
||||||
|
|
||||||
|
## World
|
||||||
|
|
||||||
|
### World.new() -> `World`
|
||||||
|
Creates a new world.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
::: code-group
|
||||||
|
|
||||||
|
```luau [luau]
|
||||||
|
local world = jecs.World.new()
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts [typescript]
|
||||||
|
import { World } from "@rbxts/jecs";
|
||||||
|
|
||||||
|
const world = new World();
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
### world:entity() -> `Entity<T>`
|
||||||
|
Creates a new entity.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
::: code-group
|
||||||
|
|
||||||
|
```luau [luau]
|
||||||
|
local entity = world:entity()
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts [typescript]
|
||||||
|
const entity = world.entity();
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
### world:component() -> `Entity<T>`
|
||||||
|
Creates a new static component. Keep in mind that components are also entities.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
::: code-group
|
||||||
|
|
||||||
|
```luau [luau]
|
||||||
|
local Health = world:component()
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts [typescript]
|
||||||
|
const Health = world.component<number>();
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
::: info
|
||||||
|
You should use this when creating static components.
|
||||||
|
|
||||||
|
For example, a generic Health entity should be created using this.
|
||||||
|
:::
|
|
@ -1,187 +0,0 @@
|
||||||
# World
|
|
||||||
|
|
||||||
### World.new
|
|
||||||
|
|
||||||
World.new(): [World](../api-types.md#World)
|
|
||||||
|
|
||||||
Create a new world.
|
|
||||||
|
|
||||||
#### Returns
|
|
||||||
A new world
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### World.entity
|
|
||||||
|
|
||||||
World.entity(world: [World](../api-types.md#World)): [Entity](../api-types.md#Entity)
|
|
||||||
|
|
||||||
Creates an entity in the world.
|
|
||||||
|
|
||||||
#### Returns
|
|
||||||
A new entiity id
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### World.target
|
|
||||||
|
|
||||||
World.target(world: [World](../api-types.md#World),
|
|
||||||
entity: [Entity](../api-types.md#Entity),
|
|
||||||
rel: [Entity](../api-types.md#Entity)): [Entity](../api-types.md#Entity)
|
|
||||||
|
|
||||||
Get the target of a relationship.
|
|
||||||
|
|
||||||
This will return a target (second element of a pair) of the entity for the specified relationship.
|
|
||||||
|
|
||||||
#### Parameters
|
|
||||||
world The world.
|
|
||||||
entity The entity.
|
|
||||||
rel The relationship between the entity and the target.
|
|
||||||
|
|
||||||
#### Returns
|
|
||||||
|
|
||||||
The first target for the relationship
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### World.add
|
|
||||||
|
|
||||||
World.add(world: [World](../api-types.md#World),
|
|
||||||
entity: [Entity](../api-types.md#Entity),
|
|
||||||
id: [Entity](../api-types.md#Entity)): [Entity](..#api-types.md#Entity)
|
|
||||||
|
|
||||||
Add a (component) id to an entity.
|
|
||||||
|
|
||||||
This operation adds a single (component) id to an entity.
|
|
||||||
If the entity already has the id, this operation will have no side effects.
|
|
||||||
|
|
||||||
#### Parameters
|
|
||||||
world The world.
|
|
||||||
entity The entity.
|
|
||||||
id The id to add.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### World.remove
|
|
||||||
|
|
||||||
World.remove(world: [World](../api-types#World),
|
|
||||||
entity: [Entity](../api-types#Entity),
|
|
||||||
id: [Entity](../api-types#Entity)): [Entity](../api-types#Entity)
|
|
||||||
|
|
||||||
Remove a (component) id to an entity.
|
|
||||||
|
|
||||||
This operation removes a single (component) id to an entity.
|
|
||||||
If the entity already has the id, this operation will have no side effects.
|
|
||||||
|
|
||||||
#### Parameters
|
|
||||||
world The world.
|
|
||||||
entity The entity.
|
|
||||||
id The id to add.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### World.get
|
|
||||||
|
|
||||||
World.get(world: [World](../api-types.md#World),
|
|
||||||
entity: [Entity](../api-types.md#Entity),
|
|
||||||
id: [Entity](../api-types.md#Entity)): any
|
|
||||||
|
|
||||||
Gets the component data.
|
|
||||||
|
|
||||||
#### Parameters
|
|
||||||
world The world.
|
|
||||||
entity The entity.
|
|
||||||
id The id of component to get.
|
|
||||||
|
|
||||||
#### Returns
|
|
||||||
The component data, nil if the entity does not have the componnet.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### World.set
|
|
||||||
|
|
||||||
World.set(world: [World](../api-types.md#World),
|
|
||||||
entity: [Entity](../api-types.md#Entity),
|
|
||||||
id: [Entity](../api-types.md#Entity)
|
|
||||||
data: any)
|
|
||||||
|
|
||||||
Set the value of a component.
|
|
||||||
|
|
||||||
#### Parameters
|
|
||||||
world The world.
|
|
||||||
entity The entity.
|
|
||||||
id The id of the componment set.
|
|
||||||
data The data to the component.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### World.query
|
|
||||||
|
|
||||||
World.query(world: [World](../api-types.md#World),
|
|
||||||
...: [Entity](../api-types.mdEntity)): [QueryIter](../api-types.md#QueryIter)
|
|
||||||
|
|
||||||
Create a QueryIter from the list of filters.
|
|
||||||
|
|
||||||
#### Parameters
|
|
||||||
world The world.
|
|
||||||
... The collection of components to match entities against.
|
|
||||||
|
|
||||||
#### Returns
|
|
||||||
|
|
||||||
The query iterator.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Pair
|
|
||||||
|
|
||||||
### pair
|
|
||||||
|
|
||||||
pair(first: [Entity](../api-types#Entity), second: [Entity](../api-types#Entity)): [Entity](../api-types#Entity)
|
|
||||||
|
|
||||||
Creates a composite key.
|
|
||||||
|
|
||||||
#### Parameters
|
|
||||||
first The first element.
|
|
||||||
second The second element.
|
|
||||||
|
|
||||||
#### Returns
|
|
||||||
|
|
||||||
The pair of the two elements
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### IS_PAIR
|
|
||||||
|
|
||||||
jecs.IS_PAIR(id: [Entity](../api-types#Entity)): boolean
|
|
||||||
|
|
||||||
Creates a composite key.
|
|
||||||
|
|
||||||
#### Parameters
|
|
||||||
id The id to check.
|
|
||||||
|
|
||||||
#### Returns
|
|
||||||
|
|
||||||
If id is a pair.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Constants
|
|
||||||
|
|
||||||
### OnAdd
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### OnRemove
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Rest
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### OnSet
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Wildcard
|
|
||||||
|
|
||||||
Matches any id, returns all matches.
|
|
3
docs/concepts/entities.md
Normal file
3
docs/concepts/entities.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
This is a TODO stub.
|
3
docs/concepts/queries.md
Normal file
3
docs/concepts/queries.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
This is a TODO stub.
|
3
docs/concepts/static-components.md
Normal file
3
docs/concepts/static-components.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
This is a TODO stub.
|
3
docs/contributing/guidelines.md
Normal file
3
docs/contributing/guidelines.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
This is a TODO stub.
|
3
docs/contributing/issues.md
Normal file
3
docs/contributing/issues.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
This is a TODO stub.
|
3
docs/contributing/pull-requests.md
Normal file
3
docs/contributing/pull-requests.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
This is a TODO stub.
|
3
docs/faq/contributing.md
Normal file
3
docs/faq/contributing.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
This is a TODO stub.
|
29
docs/index.md
Normal file
29
docs/index.md
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
# https://vitepress.dev/reference/default-theme-home-page
|
||||||
|
layout: home
|
||||||
|
|
||||||
|
hero:
|
||||||
|
name: "Jecs"
|
||||||
|
tagline: Just a stupidly fast ECS
|
||||||
|
image:
|
||||||
|
src: /jecs_logo.svg
|
||||||
|
alt: Jecs logo
|
||||||
|
actions:
|
||||||
|
- theme: brand
|
||||||
|
text: Get Started
|
||||||
|
link: /overview/get-started.md
|
||||||
|
- theme: alt
|
||||||
|
text: API Examples
|
||||||
|
link: /api.md
|
||||||
|
|
||||||
|
features:
|
||||||
|
- title: Stupidly Fast
|
||||||
|
icon: 🔥
|
||||||
|
details: Iterates 500,000 entities at 60 frames per second.
|
||||||
|
- title: Strictly Typed API
|
||||||
|
icon: 🔒
|
||||||
|
details: Has typings for both Luau and Typescript.
|
||||||
|
- title: Zero-Dependencies
|
||||||
|
icon: 📦
|
||||||
|
details: Jecs doesn't rely on anything other than itself.
|
||||||
|
---
|
3
docs/overview/first-jecs-project.md
Normal file
3
docs/overview/first-jecs-project.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
This is a TODO stub.
|
130
docs/overview/get-started.md
Normal file
130
docs/overview/get-started.md
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
# Getting Started
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Installing Standalone
|
||||||
|
|
||||||
|
Navigate to the [releases page](https://github.com/Ukendio/jecs/releases) and download `jecs.rbxm` from the assets.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
### Using Wally
|
||||||
|
|
||||||
|
Add the following to your wally configuration:
|
||||||
|
|
||||||
|
::: code-group
|
||||||
|
|
||||||
|
```toml [wally.toml]
|
||||||
|
jecs = "ukendio/jecs@0.2.3"
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
### Using npm (roblox-ts)
|
||||||
|
|
||||||
|
Use one of the following commands on your root project directory:
|
||||||
|
|
||||||
|
::: code-group
|
||||||
|
```bash [npm]
|
||||||
|
npm i https://github.com/Ukendio/jecs.git
|
||||||
|
```
|
||||||
|
```bash [yarn]
|
||||||
|
yarn add https://github.com/Ukendio/jecs.git
|
||||||
|
```
|
||||||
|
```bash [pnpm]
|
||||||
|
pnpm add https://github.com/Ukendio/jecs.git
|
||||||
|
```
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
::: code-group
|
||||||
|
|
||||||
|
```luau [Luau]
|
||||||
|
local world = jecs.World.new()
|
||||||
|
local pair = jecs.pair
|
||||||
|
local Wildcard = jecs.Wildcard
|
||||||
|
|
||||||
|
local Name = world:component()
|
||||||
|
|
||||||
|
local function getName(e)
|
||||||
|
return world:get(e, Name)
|
||||||
|
end
|
||||||
|
|
||||||
|
local Eats = world:component()
|
||||||
|
|
||||||
|
-- Relationship objects
|
||||||
|
local Apples = world:component()
|
||||||
|
-- components are entities, so you can add components to components
|
||||||
|
world:set(Apples, Name, "apples")
|
||||||
|
local Oranges = world:component()
|
||||||
|
world:set(Oranges, Name, "oranges")
|
||||||
|
|
||||||
|
local bob = world:entity()
|
||||||
|
-- Pairs can be constructed from two entities
|
||||||
|
|
||||||
|
world:set(bob, pair(Eats, Apples), 10)
|
||||||
|
world:set(bob, pair(Eats, Oranges), 5)
|
||||||
|
world:set(bob, Name, "bob")
|
||||||
|
|
||||||
|
local alice = world:entity()
|
||||||
|
world:set(alice, pair(Eats, Apples), 4)
|
||||||
|
world:set(alice, Name, "alice")
|
||||||
|
|
||||||
|
for id, amount in world:query(pair(Eats, Wildcard)) do
|
||||||
|
-- get the second target of the pair
|
||||||
|
local food = world:target(id, Eats)
|
||||||
|
print(string.format("%s eats %d %s", getName(id), amount, getName(food)))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Output:
|
||||||
|
-- bob eats 10 apples
|
||||||
|
-- bob eats 5 pears
|
||||||
|
-- alice eats 4 apples
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```ts [Typescript]
|
||||||
|
import { Wildcard, pair, World } from "@rbxts/jecs"
|
||||||
|
|
||||||
|
|
||||||
|
const world = new World()
|
||||||
|
const Name = world.component()
|
||||||
|
function getName(e) {
|
||||||
|
return world.get(e, Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
const Eats = world.component()
|
||||||
|
|
||||||
|
// Relationship objects
|
||||||
|
const Apples = world.component()
|
||||||
|
// components are entities, so you can add components to components
|
||||||
|
world.set(Apples, Name, "apples")
|
||||||
|
const Oranges = world.component()
|
||||||
|
world.set(Oranges, Name, "oranges")
|
||||||
|
|
||||||
|
const bob = world.entity()
|
||||||
|
// Pairs can be constructed from two entities
|
||||||
|
|
||||||
|
world.set(bob, pair(Eats, Apples), 10)
|
||||||
|
world.set(bob, pair(Eats, Oranges), 5)
|
||||||
|
world.set(bob, Name, "bob")
|
||||||
|
|
||||||
|
const alice = world.entity()
|
||||||
|
world.set(alice, pair(Eats, Apples), 4)
|
||||||
|
world.set(alice, Name, "alice")
|
||||||
|
|
||||||
|
for (const [id, amount] of world.query(pair(Eats, Wildcard))) {
|
||||||
|
// get the second target of the pair
|
||||||
|
const food = world:target(id, Eats)
|
||||||
|
print(string.format("%s eats %d %s", getName(id), amount, getName(food)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// bob eats 10 apples
|
||||||
|
// bob eats 5 pears
|
||||||
|
// alice eats 4 apples
|
||||||
|
|
||||||
|
```
|
||||||
|
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
41
docs/public/jecs_logo.svg
Normal file
41
docs/public/jecs_logo.svg
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1080" height="1080" viewBox="0 0 1080 1080" xml:space="preserve">
|
||||||
|
<desc>Created with Fabric.js 5.2.4</desc>
|
||||||
|
<defs>
|
||||||
|
</defs>
|
||||||
|
<rect x="0" y="0" width="100%" height="100%" fill="transparent"></rect>
|
||||||
|
<g transform="matrix(1 0 0 1 540 540)" id="09ac800d-29f3-4193-b9f5-faf19e8b1726" >
|
||||||
|
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1; visibility: hidden;" vector-effect="non-scaling-stroke" x="-540" y="-540" rx="0" ry="0" width="1080" height="1080" />
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(Infinity NaN NaN Infinity 0 0)" id="619f0364-53a0-4caa-97e3-8f543e0cc17f" >
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(NaN NaN NaN NaN 0 0)" >
|
||||||
|
<g style="" >
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(17.7 0 0 17.7 540 540)" >
|
||||||
|
<g style="" vector-effect="non-scaling-stroke" >
|
||||||
|
<g transform="matrix(1 0 0 1 -18.25 0)" >
|
||||||
|
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(52,81,178); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-5, -9)" d="M 5 14 C 5.8 14 6 13.3333 6 13 L 6 4 L 0 4 L 0 0 L 6 0 L 10 0 L 10 13 C 10 17 6.66667 18 5 18 L 0 18 L 0 14 L 5 14 Z" stroke-linecap="round" />
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1 0 0 1 16.75 0)" >
|
||||||
|
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(52,81,178); fill-rule: nonzero; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-40, -9)" d="M 46.5 4 L 46.5 0 L 39 0 C 37.1667 0 33.5 1.1 33.5 5.5 C 33.5 9.9 36.8333 11 38.5 11 L 41 11 C 41.5 11 42.5 11.3 42.5 12.5 C 42.5 13.7 41.5 14 41 14 L 33.5 14 L 33.5 18 L 41.5 18 C 43.1667 18 46.5 16.9 46.5 12.5 C 46.5 8.1 43.1667 7 41.5 7 L 39 7 C 38.5 7 37.5 6.7 37.5 5.5 C 37.5 4.3 38.5 4 39 4 L 46.5 4 Z" stroke-linecap="round" />
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1 0 0 1 3.25 0)" >
|
||||||
|
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(52,81,178); fill-rule: evenodd; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-26.5, -9)" d="M 32.5 0 L 32.5 4 L 30.5 4 C 28.5 4 24.5 5 24.5 9 C 24.5 11.0835 25.5853 12.3531 26.9078 13.0914 L 22.4606 14.661 C 21.2893 13.3156 20.5 11.4775 20.5 9 C 20.5 1.8 27.1667 0 30.5 0 L 32.5 0 Z M 24.4656 16.3357 C 26.5037 17.5803 28.8905 18 30.5 18 L 32.5 18 L 32.5 14 L 31.0833 14 L 24.4656 16.3357 Z" stroke-linecap="round" />
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(1 0 0 1 -5 0)" >
|
||||||
|
<path style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(52,81,178); fill-rule: evenodd; opacity: 1;" vector-effect="non-scaling-stroke" transform=" translate(-18.25, -9)" d="M 25.3793 0 C 24.766 0.241156 24.1568 0.53354 23.571 0.885014 C 22.1712 1.72492 20.9038 2.91123 20.0606 4.5 L 11 4.5 L 11 0 L 25.3793 0 Z M 25.5 4.39421 C 25.445 4.42876 25.3906 4.46402 25.3368 4.5 L 25.5 4.5 L 25.5 4.39421 Z M 20.0606 13.5 C 20.9038 15.0888 22.1712 16.2751 23.571 17.115 C 24.1568 17.4665 24.766 17.7588 25.3793 18 L 11 18 L 11 13.5 L 20.0606 13.5 Z M 19.1854 7 C 19.0649 7.62348 19 8.28956 19 9 C 19 9.71044 19.0649 10.3765 19.1854 11 L 11 11 L 11 7 L 19.1854 7 Z" stroke-linecap="round" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(NaN NaN NaN NaN 0 0)" >
|
||||||
|
<g style="" >
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g transform="matrix(NaN NaN NaN NaN 0 0)" >
|
||||||
|
<g style="" >
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.9 KiB |
|
@ -1,19 +0,0 @@
|
||||||
# Getting Started
|
|
||||||
This section will provide a walk through setting up your development environment and a quick overview of the different features and concepts in Jecs with short examples.
|
|
||||||
|
|
||||||
## Installing Jecs
|
|
||||||
|
|
||||||
To use Jecs, you will need to add the library to your project's source folder.
|
|
||||||
|
|
||||||
## Installing as standalone
|
|
||||||
Head over to the [Releases](https://github.com/ukendio/jecs/releases/latest) page and install the rbxm file.
|
|
||||||

|
|
||||||
|
|
||||||
## Installing with Wally
|
|
||||||
Jecs is available as a package on [wally.run](https://wally.run/package/ukendio/jecs)
|
|
||||||
|
|
||||||
Add it to your project's Wally.toml like this:
|
|
||||||
```toml
|
|
||||||
[dependencies]
|
|
||||||
jecs = "0.1.0" # Make sure this is the latest version
|
|
||||||
```
|
|
1818
package-lock.json
generated
1818
package-lock.json
generated
File diff suppressed because it is too large
Load diff
82
package.json
82
package.json
|
@ -1,38 +1,44 @@
|
||||||
{
|
{
|
||||||
"name": "@rbxts/jecs",
|
"name": "@rbxts/jecs",
|
||||||
"version": "0.2.3",
|
"version": "0.2.3",
|
||||||
"description": "Stupidly fast Entity Component System",
|
"description": "Stupidly fast Entity Component System",
|
||||||
"main": "src",
|
"main": "src",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/ukendio/jecs.git"
|
"url": "https://github.com/ukendio/jecs.git"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "Ukendio",
|
"author": "Ukendio",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
"Ukendio",
|
"Ukendio",
|
||||||
"EncodedVenom"
|
"EncodedVenom"
|
||||||
],
|
],
|
||||||
"homepage": "https://github.com/ukendio/jecs",
|
"homepage": "https://github.com/ukendio/jecs",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"types": "src/index.d.ts",
|
"types": "src/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
"src/"
|
"src/"
|
||||||
],
|
],
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rbxts/compiler-types": "^2.3.0-types.1",
|
"@rbxts/compiler-types": "^2.3.0-types.1",
|
||||||
"@rbxts/types": "^1.0.781",
|
"@rbxts/types": "^1.0.781",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.8.0",
|
"@typescript-eslint/eslint-plugin": "^5.8.0",
|
||||||
"@typescript-eslint/parser": "^5.8.0",
|
"@typescript-eslint/parser": "^5.8.0",
|
||||||
"eslint": "^8.5.0",
|
"eslint": "^8.5.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
"eslint-plugin-roblox-ts": "^0.0.32",
|
"eslint-plugin-roblox-ts": "^0.0.32",
|
||||||
"prettier": "^2.5.1",
|
"prettier": "^2.5.1",
|
||||||
"roblox-ts": "^2.3.0",
|
"roblox-ts": "^2.3.0",
|
||||||
"typescript": "^5.4.2"
|
"typescript": "^5.4.2",
|
||||||
}
|
"vitepress": "^1.3.0"
|
||||||
}
|
},
|
||||||
|
"scripts": {
|
||||||
|
"docs:dev": "vitepress dev docs",
|
||||||
|
"docs:build": "vitepress build docs",
|
||||||
|
"docs:preview": "vitepress preview docs"
|
||||||
|
}
|
||||||
|
}
|
|
@ -514,22 +514,22 @@ TEST("world", function()
|
||||||
end
|
end
|
||||||
|
|
||||||
do CASE "should not find any entities"
|
do CASE "should not find any entities"
|
||||||
local world = jecs.World.new()
|
local world = jecs.World.new()
|
||||||
|
|
||||||
local Hello = world:component()
|
local Hello = world:component()
|
||||||
local Bob = world:component()
|
local Bob = world:component()
|
||||||
|
|
||||||
local helloBob = world:entity()
|
local helloBob = world:entity()
|
||||||
world:add(helloBob, ECS_PAIR(Hello, Bob))
|
world:add(helloBob, ECS_PAIR(Hello, Bob))
|
||||||
world:add(helloBob, Bob)
|
world:add(helloBob, Bob)
|
||||||
|
|
||||||
local withoutCount = 0
|
local withoutCount = 0
|
||||||
for _ in world:query(ECS_PAIR(Hello, Bob)):without(Bob) do
|
for _ in world:query(ECS_PAIR(Hello, Bob)):without(Bob) do
|
||||||
withoutCount += 1
|
withoutCount += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
CHECK(withoutCount == 0)
|
CHECK(withoutCount == 0)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
@ -580,43 +580,43 @@ TEST("changetracker", function()
|
||||||
end
|
end
|
||||||
|
|
||||||
function changes.changed()
|
function changes.changed()
|
||||||
local q = world:query(component, previous)
|
local q = world:query(component, previous)
|
||||||
|
|
||||||
return function()
|
return function()
|
||||||
local id, new, old = q:next()
|
local id, new, old = q:next()
|
||||||
while true do
|
while true do
|
||||||
if not id then
|
if not id then
|
||||||
return nil
|
return nil
|
||||||
end
|
|
||||||
|
|
||||||
if not isTrivial then
|
|
||||||
if not shallowEq(new, old) then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
elseif new ~= old then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
id, new, old = q:next()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
addedComponents[id] = new
|
if not isTrivial then
|
||||||
|
if not shallowEq(new, old) then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
elseif new ~= old then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
return id, old, new
|
id, new, old = q:next()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
addedComponents[id] = new
|
||||||
|
|
||||||
|
return id, old, new
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function changes.removed()
|
function changes.removed()
|
||||||
removed = true
|
removed = true
|
||||||
|
|
||||||
local q = world:query(previous):without(component)
|
local q = world:query(previous):without(component)
|
||||||
return function()
|
return function()
|
||||||
local id = q:next()
|
local id = q:next()
|
||||||
if id then
|
if id then
|
||||||
table.insert(removedComponents, id)
|
table.insert(removedComponents, id)
|
||||||
end
|
|
||||||
return id
|
|
||||||
end
|
end
|
||||||
|
return id
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
fn(changes)
|
fn(changes)
|
||||||
|
@ -650,9 +650,6 @@ TEST("changetracker", function()
|
||||||
|
|
||||||
local e = world:entity()
|
local e = world:entity()
|
||||||
world:set(e, Test, { foo = 11 })
|
world:set(e, Test, { foo = 11 })
|
||||||
for e, test in world:query(Test) do
|
|
||||||
test.foo = test.foo + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
TestTracker.track(function(changes)
|
TestTracker.track(function(changes)
|
||||||
local added = 0
|
local added = 0
|
||||||
|
@ -690,6 +687,7 @@ TEST("changetracker", function()
|
||||||
for e in changes.removed() do
|
for e in changes.removed() do
|
||||||
removed+=1
|
removed+=1
|
||||||
end
|
end
|
||||||
|
|
||||||
CHECK(added == 0)
|
CHECK(added == 0)
|
||||||
CHECK(changed == 1)
|
CHECK(changed == 1)
|
||||||
CHECK(removed == 0)
|
CHECK(removed == 0)
|
||||||
|
|
Loading…
Reference in a new issue