Lattice Workshop - Step 1

Add the first system: PositionSystem

Note: to skip to this checkpoint, checkout branch step1 Next step

We already saw a component (Position) and an entity (0) in action. Let's add the first client system: the PositionSystem, rendering a Phaser game object for each entity with a Position component.

Every client system lives in its own file and is then loaded in the main Game.ts file.

The PositionSystem includes a query for all entities with Position component, which updates whenever any of the component values changes (defineUpdateQuery).

We react to value updates of the Position component using defineReactionSystem. The second callback function is run whenever the data returned by the first callback function changes. The updated value of the first callback function is then passed as a parameter to the second callback function.

In the second callback function of the PositionSystem, we transform the tile-based coordinate of each entity into a pixel-based coordinate. We then get a game object from the object pool and place it at the given pixel coordinate.

Since we modified Game.sol (to set the Position component value of entity 0), we need to redeploy our contracts. Simply stop the hardhad node (CTRL+C) and restart it (ENTER if you ran yarn start in the root directory or yarn start if you ran yarn start in the contracts directory).

After restarting our node, we can observe the Position system in action - your local game instace in the Lattice launcher should now include a green square at coordinate (0, 0). The green square is Phaser's default texture if the game object does not have a texture. Let's add some textures in the next step.

Files changed (3) hide show
  1. client/src/Game.ts +2 -2
  2. client/src/systems/PositionSystem.ts +40 -0
  3. contracts/src/Game.sol +1 -0
client/src/Game.ts CHANGED
@@ -2,7 +2,7 @@ import { createWorld } from "@latticexyz/mobx-ecs";
2
2
  import { createMapping, loadEvents, setupContracts, setupMappings } from "../packages/lattice-eth-middleware";
3
3
  import { setupPhaser } from "@latticexyz/phaser-middleware";
4
4
  import { createCoordComponent, decodeCoordComponent } from "./components";
5
- import { createExampleSystem } from "./systems/ExampleSystem";
5
+ import { createPositionSystem } from "./systems/PositionSystem";
6
6
 
7
7
  export async function createGame(contractAddress: string, privateKey: string, chainId: number, personaId: number) {
8
8
  const world = createWorld();
@@ -58,7 +58,7 @@ export async function createGame(contractAddress: string, privateKey: string, ch
58
58
  /*****************************************
59
59
  * Systems
60
60
  *****************************************/
61
- createExampleSystem(context);
61
+ createPositionSystem(context);
62
62
 
63
63
  return context;
64
64
  }
client/src/systems/PositionSystem.ts ADDED
@@ -0,0 +1,40 @@
1
+ import { defineReactionSystem, defineUpdateQuery, getComponentValue, Has } from "@latticexyz/mobx-ecs";
2
+ import { worldCoordToPixel } from "@latticexyz/phaser-middleware";
3
+ import { Context } from "../types";
4
+
5
+ export function createPositionSystem(context: Context) {
6
+ const {
7
+ world,
8
+ components: { Position },
9
+ phaser: { objectPool, map },
10
+ } = context;
11
+
12
+ const query = defineUpdateQuery(world, [Has(Position)]);
13
+
14
+ defineReactionSystem(
15
+ world,
16
+ () => query.get(),
17
+ (entities) => {
18
+ for (const entity of entities) {
19
+ // Get the entity's position from the Position component
20
+ const coord = getComponentValue(Position, entity);
21
+
22
+ // The update query also returns an entity if its value just got removed
23
+ // In this case, remove the game object from the pool.
24
+ if (!coord) {
25
+ objectPool.remove(entity);
26
+ return;
27
+ }
28
+
29
+ // Get the entity's game object from the object pool
30
+ const object = objectPool.get(entity);
31
+
32
+ // Convert the tile coordinate to a pixel coordinate for phaser
33
+ const pixelCoord = worldCoordToPixel(map, coord);
34
+
35
+ // Set the game object's position on the map
36
+ object.setPosition(pixelCoord.x, pixelCoord.y);
37
+ }
38
+ }
39
+ );
40
+ }
contracts/src/Game.sol CHANGED
@@ -33,6 +33,7 @@ contract Game {
33
33
  function registerComponents(Components memory _components, address[] memory _componentList) public onlyContractOwner {
34
34
  c = _components;
35
35
  componentList = _componentList;
36
+ c.position.set(0, Coord(0, 0));
36
37
  }
37
38
 
38
39
  /**