Lattice Workshop - Step 2.1

Components for texture and appearance

Next step

Let's add some textures! We want to be able to create new entities with new textures later without touching the code, so let's store the texture urls on chain.

To store the texture URls, we'll add a Texture component. We could naively assign this component to all entities with texture and use the respective component values to render the texture. But this solution would lead to a lot of duplicated strings stored on chain. A better option is to store each texture only once by adding it to a "texture entity". We'll then refer to the ID of this texture entity in the Appearance component and only have to store one uint256 per entity.

The contracts/functions to add components of types UintComponent and StringComponent are already provided to us by the Starterkit code. All we need to do is initialize them in the contracts, client and lattice.config.ts to add them to the deployment.

First add the components to the contracts, then run yarn build in the contracts folder to rebuild the ABI and generate Typescript types using Typechain. Next, add the components to the client and add a new mapping to sync the contract state with the client state.

You can confirm the mapping was successful if you receive the event logs in the developer console of your local game instance after restarting your node. In the next step we'll add client systems to render the textures.

Files changed (3) hide show
  1. client/src/Game.ts +14 -1
  2. contracts/lattice.config.ts +2 -1
  3. contracts/src/Game.sol +12 -2
client/src/Game.ts CHANGED
@@ -1,7 +1,14 @@
1
1
  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
- import { createCoordComponent, decodeCoordComponent } from "./components";
4
+ import {
5
+ createCoordComponent,
6
+ createStringComponent,
7
+ createUintComponent,
8
+ decodeCoordComponent,
9
+ decodeStringComponent,
10
+ decodeUintComponent,
11
+ } from "./components";
5
12
  import { createPositionSystem } from "./systems/PositionSystem";
6
13
 
7
14
  export async function createGame(contractAddress: string, privateKey: string, chainId: number, personaId: number) {
@@ -24,9 +31,13 @@ export async function createGame(contractAddress: string, privateKey: string, ch
24
31
  * Component definitions
25
32
  *****************************************/
26
33
  const Position = createCoordComponent(world, "Position");
34
+ const Texture = createStringComponent(world, "Texture");
35
+ const Appearance = createUintComponent(world, "Appearance");
27
36
 
28
37
  const components = {
29
38
  Position,
39
+ Texture,
40
+ Appearance,
30
41
  };
31
42
 
32
43
  /*****************************************
@@ -34,6 +45,8 @@ export async function createGame(contractAddress: string, privateKey: string, ch
34
45
  *****************************************/
35
46
  setupMappings(world, contracts.World, {
36
47
  ...createMapping(componentAddresses.position, Position, decodeCoordComponent),
48
+ ...createMapping(componentAddresses.texture, Texture, decodeStringComponent),
49
+ ...createMapping(componentAddresses.appearance, Appearance, decodeUintComponent),
37
50
  });
38
51
  await loadEvents(provider, contracts.World);
39
52
 
contracts/lattice.config.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export const componentConfig = {
2
2
  position: 'CoordComponent',
3
- num: 'UintComponent',
3
+ texture: 'StringComponent',
4
+ appearance: 'UintComponent',
4
5
  };
contracts/src/Game.sol CHANGED
@@ -6,10 +6,15 @@ import { World } from 'lattice-ecs/World.sol';
6
6
  import { Component } from 'lattice-ecs/Component.sol';
7
7
  import { CoordComponent, Coord } from './components/CoordComponent.sol';
8
8
  import { UintComponent } from './components/UintComponent.sol';
9
+ import { StringComponent } from './components/StringComponent.sol';
9
10
 
10
11
  struct Components {
11
12
  CoordComponent position;
12
- UintComponent num;
13
+ StringComponent texture;
14
+ UintComponent appearance;
15
+ }
16
+ enum Texture {
17
+ Imp
13
18
  }
14
19
 
15
20
  contract Game {
@@ -33,7 +38,12 @@ contract Game {
33
38
  function registerComponents(Components memory _components, address[] memory _componentList) public onlyContractOwner {
34
39
  c = _components;
35
40
  componentList = _componentList;
36
- c.position.set(0, Coord(0, 0));
41
+ c.position.set(1, Coord(0, 0));
42
+
43
+ string memory imp = 'https://imagedelivery.net/kiVB3FlOmd8gwoTJWblSOA/ef4adf50-0e0d-4959-9917-439de7ed9500/public';
44
+ c.texture.set(uint256(Texture.Imp), imp);
45
+
46
+ c.appearance.set(1, uint256(Texture.Imp));
37
47
  }
38
48
 
39
49
  /**