-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathacomponent.js
More file actions
152 lines (136 loc) · 4.13 KB
/
Copy pathacomponent.js
File metadata and controls
152 lines (136 loc) · 4.13 KB
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
'use strict';
const { AComponentSymbol } = require('./internal/symbols');
/**
* `AComponent` represent data or behaviors on an `Entity`. As an example, it can
* represent a position (x,y), a hitbox or a texture.
*
* The `A` in `AComponent` is for Abstract, it means you can not construct but you
* must inherit it. A non-inherited `AComponent` represent nothing.
*
* So on, you must inherit it, specify your datas and/or behaviours. You can
* set your behaviours in the `update()` function or in public functions. You can
* access the parent entity, and others components.
*
* If your component require others components, you must check their existence
* in the constructor and throw if they are missing. Remember, if you want to
* follow this project design, you must fail-fast. It means you check every error-case
* and throw as soon as possible. Better see sooner than unreproducible undefined behaviors in production.
*
* The `update()` function is automatically called when your entity tree got its function
* `update()` called.
*/
class AComponent
{
/**
* On inheriting `AComponent`, `parent` will be passed to your constructor among
* your own arguments. You must keep `parentEntity` first, then your arguments.
*
* @param {Entity} parent The entity which own this component
*/
constructor(parent)
{
if (new.target === AComponent)
{
throw new Error('AComponent can not be instantiated. You must inherit it.');
}
if (parent.constructor.name !== 'Entity')
{
throw new TypeError('parent must be an instance of Entity');
}
/**
* The entity which own this component
* @type {Entity}
* @private
*/
this._parent = parent;
}
/**
* Emit an event from parent identified as this component.
*
* This function works as a regular EventEmitter. Only differences are:
* - Event will be emitted from the parent entity
* - Event name will be `identity:name` (ex: 'sprite:visible')
*
* So on, it is a shortcut to `this.parent.emit(this.identity + ':' + name, payload)`.
*
* @param {String} name Name of this event.
* @param {*} [payload] Optional payload to pass to the event.
*/
emit(name, payload = null)
{
this.parent.emit(`${this.identity}:${name}`, payload);
}
/**
* @returns {Entity} Owner of this component.
*/
get parent()
{
return this._parent;
}
/**
* Early update of this component. See `Entity` documentation for more information.
* @override
*/
earlyUpdate()
{
}
/**
* Late update of this component. See `Entity` documentation for more information.
* @override
*/
lateUpdate()
{
}
/**
* This function will be called on destruction.
*
* You can do some cleanup if needed.
* @override
*/
destructor()
{
}
/**
* On inheriting AComponent, you must override this function to return the
* component name from your class static function name.
*
* See static function `AComponent.identity`.
*
* @override
* @returns {?String}
*/
get identity()
{
return null;
}
/**
* On inheriting AComponent, you must override this function to return the component name.
*
* The component name will be the easy-access key on your entity. If you set
* `position`, you will be able to access the component using `entity.position`.
*
* It must be unique.
*
* See the instance function `AComponent.identity`.
*
* @override
* @returns {?String}
*/
static get identity()
{
return null;
}
/**
* This field is used as type checking.
*
* You will often pass your inherited class directly as a class - not as an instance.
* This static field return a well-known symbol which will be equality checked to ensure
* inheritance.
* @private
*/
static get _AComponentSymbol()
{
return AComponentSymbol;
}
}
module.exports = AComponent;