-
Notifications
You must be signed in to change notification settings - Fork 0
/
health.js
96 lines (82 loc) · 2.52 KB
/
health.js
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// @ts-check
import { assumeDefined } from './lib/assert.js';
import { makeViewModel } from './view-model.js';
import { makeMacroViewModel } from './macro-view-model.js';
import { makeElementWatcher } from './element-watcher.js';
import { makeBoxTileMap } from './tile-map-box.js';
import { makeRotatingElementController } from './rotator.js';
const svgNS = 'http://www.w3.org/2000/svg';
/**
* @param {Object} args
* @param {number} args.tileSizePx
* @param {number} args.healthTileType
* @param {(tile: number, type: number) => Element} args.createElement
* @param {(tile: number) => void} [args.collectElement]
*/
export function writeHealthBar({
tileSizePx,
healthTileType,
createElement,
collectElement,
}) {
const element = document.createElementNS(svgNS, 'svg');
element.setAttributeNS(null, 'viewBox', `0 0 5 1`);
element.setAttributeNS(null, 'height', `${(1 * tileSizePx) / 2}`);
element.setAttributeNS(null, 'width', `${(5 * tileSizePx) / 2}`);
element.setAttributeNS(null, 'class', 'healthBar');
const rotatingElementController = makeRotatingElementController(element, -1);
const watcher = makeElementWatcher(
element,
null,
createElement,
collectElement,
);
const viewModel = makeViewModel();
const tileMap = makeBoxTileMap({ x: 5, y: 1 });
viewModel.watchEntities(tileMap, watcher);
const macroViewModel = makeMacroViewModel(viewModel, { name: 'healthBar' });
let health = 0;
let next = 0;
/** @type {Array<number>} */
const entities = [];
/** @param {number} newHealth */
const set = newHealth => {
while (health < newHealth) {
const entity = next;
entities.push(entity);
macroViewModel.put(entity, health, healthTileType);
macroViewModel.enter(entity);
next += 1;
health += 1;
}
while (newHealth < health) {
const entity = assumeDefined(entities.pop());
macroViewModel.exit(entity);
health -= 1;
}
};
const { show, hide } = rotatingElementController;
const tick = () => {
macroViewModel.tick();
rotatingElementController.tick();
};
const tock = () => {
macroViewModel.tock();
rotatingElementController.tock();
};
/** @type {import('./progress.js').AnimateFn} */
const animate = progress => {
macroViewModel.animate(progress);
rotatingElementController.animate(progress);
};
const controller = {
set,
animate,
tick,
tock,
hide,
show,
};
return { element, controller };
}
/** @typedef {ReturnType<writeHealthBar>['controller']} HealthController */