koota 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -17
- package/dist/{chunk-VKZPO7LA.js → chunk-GWGL3UX4.js} +1084 -911
- package/dist/index.cjs +879 -703
- package/dist/index.d.cts +25 -29
- package/dist/index.d.ts +25 -29
- package/dist/index.js +11 -5
- package/dist/react.cjs +689 -795
- package/dist/react.d.cts +6 -2
- package/dist/react.d.ts +6 -2
- package/dist/react.js +110 -22
- package/dist/{world-qDo1l6Ai.d.cts → types-ROPlWITM.d.cts} +171 -114
- package/dist/{world-qDo1l6Ai.d.ts → types-ROPlWITM.d.ts} +171 -114
- package/package.json +2 -2
- package/react/index.cjs +689 -795
- package/react/index.d.cts +6 -2
- package/react/index.d.ts +6 -2
- package/react/index.js +110 -22
package/README.md
CHANGED
|
@@ -72,11 +72,7 @@ createRoot(document.getElementById('root')!).render(
|
|
|
72
72
|
function RocketRenderer() {
|
|
73
73
|
// Reactively update whenever the query updates with new entities
|
|
74
74
|
const rockets = useQuery(Position, Velocity)
|
|
75
|
-
return (
|
|
76
|
-
<>
|
|
77
|
-
{rockets.map((entity) => <RocketView key={entity} entity={entity} />)}
|
|
78
|
-
</>
|
|
79
|
-
)
|
|
75
|
+
return rockets.map((entity) => <RocketView key={entity} entity={entity} />)
|
|
80
76
|
}
|
|
81
77
|
|
|
82
78
|
function RocketView({ entity }) {
|
|
@@ -84,7 +80,7 @@ function RocketView({ entity }) {
|
|
|
84
80
|
const position = useTrait(entity, Position)
|
|
85
81
|
return (
|
|
86
82
|
<div style={{ position: 'absolute', left: position.x ?? 0, top: position.y ?? 0 }}>
|
|
87
|
-
|
|
83
|
+
🚀
|
|
88
84
|
</div>
|
|
89
85
|
)
|
|
90
86
|
}
|
|
@@ -95,10 +91,10 @@ function RocketView({ entity }) {
|
|
|
95
91
|
Use actions to safely modify Koota from inside of React in either effects or events.
|
|
96
92
|
|
|
97
93
|
```js
|
|
98
|
-
import {
|
|
94
|
+
import { defineActions } from 'koota'
|
|
99
95
|
import { useActions } from 'koota/react'
|
|
100
96
|
|
|
101
|
-
const actions =
|
|
97
|
+
const actions = defineActions((world) => ({
|
|
102
98
|
spawnShip: (position) => world.spawn(Position(position), Velocity),
|
|
103
99
|
destroyAllShips: () => {
|
|
104
100
|
world.query(Position, Velocity).forEach((entity) => {
|
|
@@ -286,6 +282,29 @@ const parent = world.spawn()
|
|
|
286
282
|
const changedChildren = world.query(Changed(ChildOf), ChildOf(parent))
|
|
287
283
|
```
|
|
288
284
|
|
|
285
|
+
#### Relation events
|
|
286
|
+
|
|
287
|
+
Relations emit events per **relation pair**. This makes it easy to know exactly which target was involved.
|
|
288
|
+
|
|
289
|
+
- `onAdd(Relation, (entity, target) => {})` triggers when `entity.add(Relation(target))` is called.
|
|
290
|
+
- `onRemove(Relation, (entity, target) => {})` triggers when `entity.remove(Relation(target))` is called.
|
|
291
|
+
- `onChange(Relation, (entity, target) => {})` triggers when relation **store data** is updated with `entity.set(Relation(target), data)` (only for relations created with a `store`).
|
|
292
|
+
|
|
293
|
+
```js
|
|
294
|
+
const ChildOf = relation({ store: { priority: 0 } })
|
|
295
|
+
|
|
296
|
+
const unsubAdd = world.onAdd(ChildOf, (entity, target) => {})
|
|
297
|
+
const unsubRemove = world.onRemove(ChildOf, (entity, target) => {})
|
|
298
|
+
const unsubChange = world.onChange(ChildOf, (entity, target) => {})
|
|
299
|
+
|
|
300
|
+
const parent = world.spawn()
|
|
301
|
+
const child = world.spawn()
|
|
302
|
+
|
|
303
|
+
child.add(ChildOf(parent)) // onAdd(child, parent)
|
|
304
|
+
child.set(ChildOf(parent), { priority: 1 }) // onChange(child, parent)
|
|
305
|
+
child.remove(ChildOf(parent)) // onRemove(child, parent)
|
|
306
|
+
```
|
|
307
|
+
|
|
289
308
|
### Query modifiers
|
|
290
309
|
|
|
291
310
|
Modifiers are used to filter query results enabling powerful patterns. All modifiers can be mixed together.
|
|
@@ -394,9 +413,14 @@ entity.set(Position, { x: 10, y: 20 })
|
|
|
394
413
|
entity.remove(Position)
|
|
395
414
|
```
|
|
396
415
|
|
|
416
|
+
When subscribing to relations, callbacks receive `(entity, target)` so you know which relation pair changed. Relation `onChange` events are triggered by `entity.set(Relation(target), data)` and only on relations with data via the store prop.
|
|
417
|
+
|
|
397
418
|
```js
|
|
398
|
-
|
|
399
|
-
|
|
419
|
+
const Likes = relation()
|
|
420
|
+
|
|
421
|
+
const unsub = world.onAdd(Likes, (entity, target) => {
|
|
422
|
+
console.log(`Entity ${entity} likes ${target}`)
|
|
423
|
+
})
|
|
400
424
|
```
|
|
401
425
|
|
|
402
426
|
### Change detection with `updateEach`
|
|
@@ -808,7 +832,7 @@ const positions = getStore(world, Position)
|
|
|
808
832
|
|
|
809
833
|
A Koota query is a lot like a database query. Parameters define how to find entities and efficiently process them in batches. Queries are the primary way to update and transform your app state, similar to how you'd use SQL to filter and modify database records.
|
|
810
834
|
|
|
811
|
-
####
|
|
835
|
+
#### Defining queries
|
|
812
836
|
|
|
813
837
|
Inline queries are great for readability and are optimized to be as fast as possible, but there is still some small overhead in hashing the query each time it is called.
|
|
814
838
|
|
|
@@ -820,13 +844,13 @@ function updateMovement(world) {
|
|
|
820
844
|
}
|
|
821
845
|
```
|
|
822
846
|
|
|
823
|
-
While this is not likely to be a bottleneck in your code compared to the actual update function, if you want to save these CPU cycles you can cache the query ahead of time and use the returned
|
|
847
|
+
While this is not likely to be a bottleneck in your code compared to the actual update function, if you want to save these CPU cycles you can cache the query ahead of time and use the returned ref. This will have the additional effect of creating the internal query immediately on all worlds, otherwise it will get created the first time it is run.
|
|
824
848
|
|
|
825
849
|
```js
|
|
826
850
|
// The internal query is created immediately before it is invoked
|
|
827
|
-
const movementQuery =
|
|
851
|
+
const movementQuery = defineQuery(Position, Velocity)
|
|
828
852
|
|
|
829
|
-
//
|
|
853
|
+
// The query ref is used for fast array-based lookup
|
|
830
854
|
function updateMovement(world) {
|
|
831
855
|
world.query(movementQuery).updateEach(([pos, vel]) => {})
|
|
832
856
|
}
|
|
@@ -834,7 +858,7 @@ function updateMovement(world) {
|
|
|
834
858
|
|
|
835
859
|
#### Query all entities
|
|
836
860
|
|
|
837
|
-
To get all queryable entities you simply query with no parameters.
|
|
861
|
+
To get all queryable entities you simply query the world with no parameters.
|
|
838
862
|
|
|
839
863
|
```js
|
|
840
864
|
const allEntities = world.query()
|
|
@@ -1014,13 +1038,51 @@ useTraitEffect(world, GameState, (state) => {
|
|
|
1014
1038
|
})
|
|
1015
1039
|
```
|
|
1016
1040
|
|
|
1041
|
+
### `useTarget`
|
|
1042
|
+
|
|
1043
|
+
Observes an entity, or world, for a relation and reactively returns the first target entity. Returns `undefined` if no target exists.
|
|
1044
|
+
|
|
1045
|
+
```js
|
|
1046
|
+
const ChildOf = relation()
|
|
1047
|
+
|
|
1048
|
+
function ParentDisplay({ entity }) {
|
|
1049
|
+
// Returns the first target of the ChildOf relation
|
|
1050
|
+
const parent = useTarget(entity, ChildOf)
|
|
1051
|
+
|
|
1052
|
+
if (!parent) return <div>No parent</div>
|
|
1053
|
+
|
|
1054
|
+
return <div>Parent: {parent.id()}</div>
|
|
1055
|
+
}
|
|
1056
|
+
```
|
|
1057
|
+
|
|
1058
|
+
### `useTargets`
|
|
1059
|
+
|
|
1060
|
+
Observes an entity, or world, for a relation and reactively returns all target entities as an array. Returns an empty array if no targets exist.
|
|
1061
|
+
|
|
1062
|
+
```js
|
|
1063
|
+
const Contains = relation()
|
|
1064
|
+
|
|
1065
|
+
function InventoryDisplay({ entity }) {
|
|
1066
|
+
// Returns all targets of the Contains relation
|
|
1067
|
+
const items = useTargets(entity, Contains)
|
|
1068
|
+
|
|
1069
|
+
return (
|
|
1070
|
+
<ul>
|
|
1071
|
+
{items.map((item) => (
|
|
1072
|
+
<li key={item.id()}>Item {item.id()}</li>
|
|
1073
|
+
))}
|
|
1074
|
+
</ul>
|
|
1075
|
+
)
|
|
1076
|
+
}
|
|
1077
|
+
```
|
|
1078
|
+
|
|
1017
1079
|
### `useActions`
|
|
1018
1080
|
|
|
1019
|
-
Returns actions bound to the world that is context. Use actions created by `
|
|
1081
|
+
Returns actions bound to the world that is in context. Use actions created by `defineActions`.
|
|
1020
1082
|
|
|
1021
1083
|
```js
|
|
1022
1084
|
// Create actions
|
|
1023
|
-
const actions =
|
|
1085
|
+
const actions = defineActions((world) => ({
|
|
1024
1086
|
spawnPlayer: () => world.spawn(IsPlayer).
|
|
1025
1087
|
destroyAllPlayers: () => {
|
|
1026
1088
|
world.query(IsPlayer).forEach((player) => {
|