summaryrefslogtreecommitdiff
path: root/public/js/components/testroom.js
blob: ba5a16aeaef2e0507ef12c313b8fb6d49edeb5d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/* global AFRAME, THREE */
// The world: a plain, brightly lit white room with a small table in the middle,
// for trying things out. The chess board on the table is its own entity
// (chess.js); its reset buttons and resetChess() are passed through here.
(function () {
  const ROOM = { half: 4, height: 3 };              // 8 × 8 m, 3 m tall
  const TABLE = { half: 0.4, height: 0.75, top: 0.04, leg: 0.05 };
  const MARGIN = 0.25;                               // how close your head gets to a wall
  const LEAN = 0.08;                                 // and to the table, so you can reach across it

  AFRAME.registerComponent('testroom', {
    init() {
      this.group = new THREE.Group();
      this.el.setObject3D('mesh', this.group);
      this.seats = [];
      this.spawn = { x: 0, z: 2.5, yaw: 0 };
      this.screen = { x: 0, y: 1.55, z: -3.85, yaw: 0, width: 3 };  // against the far wall
      // Child entities start first, so the board is there already.
      const chess = this.chess();
      this.touchables = chess ? chess.touchables : [];

      const white = new THREE.MeshLambertMaterial({ color: '#ffffff', side: THREE.BackSide });
      const room = new THREE.Mesh(new THREE.BoxGeometry(ROOM.half * 2, ROOM.height, ROOM.half * 2), white);
      room.position.y = ROOM.height / 2;
      this.group.add(room);

      const wood = new THREE.MeshLambertMaterial({ color: '#b08a60' });
      const top = new THREE.Mesh(new THREE.BoxGeometry(TABLE.half * 2, TABLE.top, TABLE.half * 2), wood);
      top.position.y = TABLE.height - TABLE.top / 2;
      this.group.add(top);
      const legHeight = TABLE.height - TABLE.top;
      const legGeometry = new THREE.BoxGeometry(TABLE.leg, legHeight, TABLE.leg);
      const inset = TABLE.half - TABLE.leg;
      for (const [x, z] of [[-1, -1], [1, -1], [-1, 1], [1, 1]]) {
        const leg = new THREE.Mesh(legGeometry, wood);
        leg.position.set(x * inset, legHeight / 2, z * inset);
        this.group.add(leg);
      }
    },

    chess() {
      const el = this.el.querySelector('[chess]');
      return el && el.components.chess;
    },

    resetChess() {
      const chess = this.chess();
      if (chess) chess.resetChess();
    },

    remove() {
      this.group.traverse((o) => {
        if (o.geometry) o.geometry.dispose();
        if (o.material) o.material.dispose();
      });
      this.el.removeObject3D('mesh');
    },

    // Keeps a head position inside the walls and out of the table.
    confine(p) {
      const wall = ROOM.half - MARGIN;
      p.x = Math.min(wall, Math.max(-wall, p.x));
      p.z = Math.min(wall, Math.max(-wall, p.z));
      const t = TABLE.half + LEAN;
      if (Math.abs(p.x) < t && Math.abs(p.z) < t) {
        if (Math.abs(p.x) > Math.abs(p.z)) p.x = Math.sign(p.x) * t;
        else p.z = (Math.sign(p.z) || 1) * t;
      }
      return p;
    },
  });
})();