Skip to content

Commit

Permalink
Another quick rewrite :-) (#215)
Browse files Browse the repository at this point in the history
  • Loading branch information
hmans committed Oct 27, 2022
1 parent a1f2d79 commit b11083d
Show file tree
Hide file tree
Showing 21 changed files with 617 additions and 772 deletions.
25 changes: 25 additions & 0 deletions .changeset/healthy-dragons-think.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
"@miniplex/core": patch
---

Aaaaah, another rewrite of the core library! `@miniplex/core` kept the same lightweight core, but the `World` is now much more aware of archetypes and what kind of entities they represent. This was done to allow for better introspection and to fix some remaining issues like [#204](https://github.com/hmans/miniplex/issues/204)].

The `WithRequiredKeys` type has been renamed to `WithComponents`.

`world.archetype()` now allows two forms:

```ts
world.archetype("position", "velocity")
world.archetype({ all: ["position", "velocity"] })
```

The second form involves a query object that can also have `any` and `none` keys:

```ts
world.archetype({
all: ["position", "velocity"],
none: ["dead"]
})
```

**Breaking Change:** `bucket.derive()` has been removed. It was cool and fun and cute, but also a little too generic to be useful. Similar to Miniplex 1.0, there is only the _world_ and a series of _archetypes_ now. (But both share the same lightweight `Bucket` base class that can also be used standalone.)
11 changes: 11 additions & 0 deletions .changeset/quiet-bats-fetch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@miniplex/react": patch
---

`<Archetype>` has been changed to match the new query capabilities of the core library's `world.archetype` function. All of these are now valid:

```tsx
<Archetype query="position" />
<Archetype query={["position", "velocity"]} />
<Archetype query={{ all: ["position", "velocity"], none: ["dead"] }} />
```
11 changes: 5 additions & 6 deletions apps/demo/src/entities/Asteroids.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Composable, Modules } from "material-composer-r3f"
import { WithRequiredKeys } from "miniplex"
import { Archetype, WithComponents } from "miniplex"
import { insideCircle, power } from "randomish"
import { useLayoutEffect } from "react"
import { $, Input, InstanceID, Lerp } from "shader-composer"
Expand Down Expand Up @@ -49,11 +49,13 @@ export const Asteroids = () => {
{segmentedAsteroids.entities.map((segment, i) => (
<ECS.Bucket key={i} bucket={segment} as={RenderableEntity} />
))}

{/* <ECS.Bucket bucket={asteroids} as={RenderableEntity} /> */}
</InstancedParticles>
)
}

export type Asteroid = WithRequiredKeys<
export type Asteroid = WithComponents<
Entity,
| "isAsteroid"
| "transform"
Expand All @@ -63,10 +65,7 @@ export type Asteroid = WithRequiredKeys<
| "render"
>

export const isAsteroid = (entity: Entity): entity is Asteroid =>
"isAsteroid" in entity

const asteroids = ECS.world.derive(isAsteroid)
const asteroids = ECS.world.archetype("isAsteroid") as Archetype<Asteroid>

const tmpVec3 = new Vector3()

Expand Down
2 changes: 1 addition & 1 deletion apps/demo/src/entities/Bullets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const Bullets = () => (
<planeGeometry args={[0.15, 0.5]} />
<meshStandardMaterial color={new Color("orange").multiplyScalar(5)} />

<ECS.Archetype components="isBullet" as={RenderableEntity} />
<ECS.Archetype query="isBullet" as={RenderableEntity} />
</InstancedParticles>
)

Expand Down
4 changes: 2 additions & 2 deletions apps/demo/src/entities/RenderableEntity.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { WithRequiredKeys } from "miniplex"
import { WithComponents } from "miniplex"
import { Entity } from "../state"

export const RenderableEntity = ({
entity
}: {
entity: WithRequiredKeys<Entity, "render">
entity: WithComponents<Entity, "render">
}) => <>{entity.render}</>
4 changes: 2 additions & 2 deletions apps/demo/src/systems/physicsSystem.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useFrame } from "@react-three/fiber"
import { WithRequiredKeys } from "miniplex"
import { WithComponents } from "miniplex"
import { MathUtils, Vector3 } from "three"
import { ECS, Entity } from "../state"

type PhysicsEntity = WithRequiredKeys<Entity, "transform" | "physics">
type PhysicsEntity = WithComponents<Entity, "transform" | "physics">

const entities = ECS.world.archetype("transform", "physics")

Expand Down
10 changes: 4 additions & 6 deletions apps/demo/src/systems/playerSystem.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { useFrame } from "@react-three/fiber"
import { WithRequiredKeys } from "miniplex"
import { Archetype, WithComponents } from "miniplex"
import { Vector3 } from "three"
import { spawnBullet } from "../entities/Bullets"
import { ECS, Entity } from "../state"
import { useKeyboard } from "../util/useKeyboard"

const tmpVec3 = new Vector3()

const isPlayer = (
entity: Entity
): entity is WithRequiredKeys<Entity, "transform" | "physics"> =>
!!entity.isPlayer
type Player = WithComponents<Entity, "isPlayer" | "transform" | "physics">

const players = ECS.world.derive(isPlayer)
// const players = ECS.world.archetype(isPlayer)
const players = ECS.world.archetype("isPlayer") as Archetype<Player>

let lastFireTime = 0

Expand Down
33 changes: 33 additions & 0 deletions packages/miniplex-core/src/Archetype.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Bucket } from "./Bucket"
import { IEntity, Query } from "./types"

/**
* A bucket type that stores entities belonging to a specific archetype.
* This archetype is expressed as a `Query` object, stored in the archetype's
* `query` property.
*/
export class Archetype<E extends IEntity> extends Bucket<E> {
constructor(public query: Query<E>) {
super()
}

matchesEntity(entity: E): boolean {
return this.matchesComponents(Object.keys(entity))
}

matchesComponents(components: (keyof E)[]): boolean {
const all =
this.query.all === undefined ||
this.query.all.every((key) => components.includes(key))

const any =
this.query.any === undefined ||
this.query.any.some((key) => components.includes(key))

const none =
this.query.none === undefined ||
this.query.none.every((key) => !components.includes(key))

return all && any && none
}
}

0 comments on commit b11083d

Please sign in to comment.