Lattice Workshop - Step 2.2

Systems for texture and appearance

Next step

After setting up the contract and client components for texture and appearance, let's add the systems to actually render the sprites.

Just as with the PositionSystem, we'll create a new file for the AppearanceSystem and the TextureSystem.

The TextureSystem queries for entities with the Texture component (= "texture entities") and loads them into the Phaser cache. It then updates the Phaser texture of all entities with Appearance component pointing to this texture entity.

The AppearanceSystem queries for entities with Appearance component and sets the Phaser texture of the entity's game object to the value stored in the corresponding texture entity's Texture component.

Files changed (3) hide show
  1. client/src/Game.ts +4 -0
  2. client/src/systems/AppearanceSystem.ts +26 -0
  3. client/src/systems/TextureSystem.ts +40 -0
client/src/Game.ts CHANGED
@@ -10,6 +10,8 @@ import {
10
10
  decodeUintComponent,
11
11
  } from "./components";
12
12
  import { createPositionSystem } from "./systems/PositionSystem";
13
+ import { createTextureSystem } from "./systems/TextureSystem";
14
+ import { createAppearanceSystem } from "./systems/AppearanceSystem";
13
15
 
14
16
  export async function createGame(contractAddress: string, privateKey: string, chainId: number, personaId: number) {
15
17
  const world = createWorld();
@@ -72,6 +74,8 @@ export async function createGame(contractAddress: string, privateKey: string, ch
72
74
  * Systems
73
75
  *****************************************/
74
76
  createPositionSystem(context);
77
+ createTextureSystem(context);
78
+ createAppearanceSystem(context);
75
79
 
76
80
  return context;
77
81
  }
client/src/systems/AppearanceSystem.ts ADDED
@@ -0,0 +1,26 @@
1
+ import { defineAutorunSystem, defineUpdateQuery, getComponentValue, Has, hasComponent } from "@latticexyz/mobx-ecs";
2
+ import { Context } from "../types";
3
+
4
+ export function createAppearanceSystem(context: Context) {
5
+ const {
6
+ world,
7
+ components: { Appearance, Texture },
8
+ phaser: { objectPool },
9
+ } = context;
10
+
11
+ const appearances = defineUpdateQuery(world, [Has(Appearance)]);
12
+
13
+ defineAutorunSystem(world, () => {
14
+ const entities = appearances.get();
15
+ for (const entity of entities) {
16
+ const appearance = getComponentValue(Appearance, entity);
17
+ if (!appearance) {
18
+ objectPool.remove(entity);
19
+ return;
20
+ }
21
+
22
+ const object = objectPool.get(entity);
23
+ if (hasComponent(Texture, appearance.value)) object.setTexture(String(appearance.value));
24
+ }
25
+ });
26
+ }
client/src/systems/TextureSystem.ts ADDED
@@ -0,0 +1,40 @@
1
+ import {
2
+ defineAutorunSystem,
3
+ defineQuery,
4
+ defineUpdateQuery,
5
+ getComponentValue,
6
+ Has,
7
+ HasValue,
8
+ } from "@latticexyz/mobx-ecs";
9
+ import { load } from "@latticexyz/phaser-middleware";
10
+ import { Context } from "../types";
11
+
12
+ export function createTextureSystem(context: Context) {
13
+ const {
14
+ world,
15
+ components: { Texture, Appearance },
16
+ phaser: { scene, objectPool },
17
+ } = context;
18
+
19
+ const query = defineUpdateQuery(world, [Has(Texture)]);
20
+
21
+ defineAutorunSystem(world, async () => {
22
+ const entities = query.get();
23
+ for (const textureEntity of entities) {
24
+ const texture = getComponentValue(Texture, textureEntity);
25
+ if (!texture) return;
26
+
27
+ // Load the texture into the Phaser cache, use the entity id as key
28
+ await load(scene, (loader) =>
29
+ loader.spritesheet(String(textureEntity), texture.value, { frameWidth: 16, frameHeight: 16 })
30
+ );
31
+
32
+ // Update entities with this texture
33
+ const entities = defineQuery([HasValue(Appearance, { value: textureEntity })]).get();
34
+ for (const entity of entities) {
35
+ // Since we used the entity id as key when loading, we can refer to it when setting the phaser texture
36
+ objectPool.get(entity).setTexture(String(textureEntity));
37
+ }
38
+ }
39
+ });
40
+ }