UNPKG

8.62 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
5Object.defineProperty(exports, "__esModule", {
6 value: true
7});
8exports.ComponentManager = exports.Component = void 0;
9
10var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
11
12var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
13
14var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
15
16var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
17
18var _Entity = require("./Entity");
19
20var Component = function Component(data) {//
21
22 (0, _classCallCheck2.default)(this, Component);
23};
24/**
25 * 管理某一类 Component,尽可能做到 AoS 而非 SoA
26 * @see https://wickedengine.net/2019/09/29/entity-component-system/
27 * @see https://github.com/turanszkij/WickedEngine/blob/master/WickedEngine/wiECS.h
28 */
29// tslint:disable-next-line:max-classes-per-file
30
31
32exports.Component = Component;
33
34var ComponentManager = /*#__PURE__*/function () {
35 /**
36 * 不在 Entity 中维护拥有的 Component 列表,反之亦然
37 */
38 function ComponentManager(clazz) {
39 (0, _classCallCheck2.default)(this, ComponentManager);
40 this.clazz = void 0;
41 this.components = [];
42 this.entities = [];
43 this.lookup = {};
44 this.clazz = clazz;
45 }
46
47 (0, _createClass2.default)(ComponentManager, [{
48 key: "clear",
49 value: function clear() {
50 this.components = [];
51 this.entities = [];
52 this.lookup = {};
53 }
54 }, {
55 key: "contains",
56 value: function contains(entity) {
57 return this.lookup[entity] > -1;
58 }
59 }, {
60 key: "create",
61 value: function create(entity, data) {
62 this.lookup[entity] = this.components.length;
63 var component = new this.clazz(data || {});
64 this.components.push(component);
65 this.entities.push(entity);
66 return component;
67 }
68 }, {
69 key: "remove",
70 value: function remove(entity) {
71 var componentIndex = this.lookup[entity];
72
73 if (componentIndex > -1) {
74 if (componentIndex < this.components.length - 1) {
75 // 将待删除元素和最后一个元素交换
76 // C++ 中有 std::move 这样的操作,避免数据的拷贝
77 // @see https://github.com/turanszkij/WickedEngine/blob/master/WickedEngine/wiECS.h#L169
78 this.components[componentIndex] = this.components[this.components.length - 1];
79 this.entities[componentIndex] = this.entities[this.entities.length - 1];
80 this.lookup[this.entities[componentIndex]] = componentIndex;
81 }
82 } // 待删除元素已经移动到了最后一个
83
84
85 this.components.pop();
86 this.entities.pop();
87 delete this.lookup[entity];
88 }
89 }, {
90 key: "removeKeepSorted",
91 value: function removeKeepSorted(entity) {
92 var componentIndex = this.lookup[entity];
93
94 if (componentIndex > -1) {
95 var entity2 = this.entities[componentIndex];
96
97 if (componentIndex < this.components.length - 1) {
98 // Move every component left by one that is after this element:
99 for (var _i = componentIndex + 1; _i < this.components.length; ++_i) {
100 this.components[_i - 1] = this.components[_i];
101 } // Move every entity left by one that is after this element and update lut:
102
103
104 for (var _i2 = componentIndex + 1; _i2 < this.entities.length; ++_i2) {
105 this.entities[_i2 - 1] = this.entities[_i2];
106 this.lookup[this.entities[_i2 - 1]] = _i2 - 1;
107 }
108 }
109
110 this.components.pop();
111 this.entities.pop();
112 delete this.lookup[entity2];
113 }
114 }
115 }, {
116 key: "moveItem",
117 value: function moveItem(srcIndex, destIndex) {
118 if (srcIndex === destIndex) {
119 return;
120 } // Save the moved component and entity:
121
122
123 var srcComponent = this.components[srcIndex];
124 var srcEntity = this.entities[srcIndex]; // Every other entity-component that's in the way gets moved by one and lut is kept updated:
125
126 var direction = srcIndex < destIndex ? 1 : -1;
127
128 for (var _i3 = srcIndex; _i3 !== destIndex; _i3 += direction) {
129 var next = _i3 + direction;
130 this.components[_i3] = this.components[next];
131 this.entities[_i3] = this.entities[next];
132 this.lookup[this.entities[_i3]] = _i3;
133 } // Saved entity-component moved to the required position:
134
135
136 this.components[destIndex] = srcComponent;
137 this.entities[destIndex] = srcEntity;
138 this.lookup[srcEntity] = destIndex;
139 }
140 }, {
141 key: "getEntity",
142 value: function getEntity(index) {
143 return this.entities[index];
144 }
145 /**
146 * 由于缺少类似 C++ 的重载操作符,没法通过 [下标] 直接访问。因此只能增加该方法用于遍历。
147 */
148
149 }, {
150 key: "getComponent",
151 value: function getComponent(index) {
152 return this.components[index];
153 }
154 }, {
155 key: "getComponentByEntity",
156 value: function getComponentByEntity(entity) {
157 var componentIndex = this.lookup[entity];
158
159 if (componentIndex > -1) {
160 return this.components[componentIndex];
161 }
162
163 return null;
164 }
165 }, {
166 key: "getCount",
167 value: function getCount() {
168 return this.components.length;
169 }
170 }, {
171 key: "getEntityByComponentIndex",
172 value: function getEntityByComponentIndex(componentIdx) {
173 for (var _i4 = 0, _Object$keys = Object.keys(this.lookup); _i4 < _Object$keys.length; _i4++) {
174 var _entity = _Object$keys[_i4];
175 var entityInNum = Number(_entity);
176
177 if (this.lookup[entityInNum] === componentIdx) {
178 return entityInNum;
179 }
180 }
181
182 return _Entity.EMPTY;
183 }
184 }, {
185 key: "find",
186 value: function find(callback) {
187 for (var _i5 = 0; _i5 < this.getCount(); _i5++) {
188 var _component = this.getComponent(_i5);
189
190 if (callback(_component, _i5)) {
191 return _component;
192 }
193 }
194
195 return null;
196 }
197 }, {
198 key: "findIndex",
199 value: function findIndex(callback) {
200 for (var _i6 = 0; _i6 < this.getCount(); _i6++) {
201 var _component2 = this.getComponent(_i6);
202
203 if (callback(_component2, _i6)) {
204 return _i6;
205 }
206 }
207
208 return -1;
209 }
210 }, {
211 key: "forEach",
212 value: function forEach(callback) {
213 for (var _i7 = 0, _Object$keys2 = Object.keys(this.lookup); _i7 < _Object$keys2.length; _i7++) {
214 var _entity2 = _Object$keys2[_i7];
215 var entityInNum = Number(_entity2);
216 var componentIndex = this.lookup[entityInNum];
217 callback(entityInNum, this.getComponent(componentIndex));
218 }
219 }
220 }, {
221 key: "forEachAsync",
222 value: function () {
223 var _forEachAsync = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(callback) {
224 var _i8, _Object$keys3, _entity3, entityInNum, componentIndex;
225
226 return _regenerator.default.wrap(function _callee$(_context) {
227 while (1) {
228 switch (_context.prev = _context.next) {
229 case 0:
230 _i8 = 0, _Object$keys3 = Object.keys(this.lookup);
231
232 case 1:
233 if (!(_i8 < _Object$keys3.length)) {
234 _context.next = 10;
235 break;
236 }
237
238 _entity3 = _Object$keys3[_i8];
239 entityInNum = Number(_entity3);
240 componentIndex = this.lookup[entityInNum];
241 _context.next = 7;
242 return callback(entityInNum, this.getComponent(componentIndex));
243
244 case 7:
245 _i8++;
246 _context.next = 1;
247 break;
248
249 case 10:
250 case "end":
251 return _context.stop();
252 }
253 }
254 }, _callee, this);
255 }));
256
257 function forEachAsync(_x) {
258 return _forEachAsync.apply(this, arguments);
259 }
260
261 return forEachAsync;
262 }()
263 }, {
264 key: "map",
265 value: function map(callback) {
266 var result = [];
267
268 for (var _i9 = 0, _Object$keys4 = Object.keys(this.lookup); _i9 < _Object$keys4.length; _i9++) {
269 var _entity4 = _Object$keys4[_i9];
270 var entityInNum = Number(_entity4);
271 var componentIndex = this.lookup[entityInNum];
272 result.push(callback(entityInNum, this.getComponent(componentIndex)));
273 }
274
275 return result;
276 }
277 }]);
278 return ComponentManager;
279}();
280
281exports.ComponentManager = ComponentManager;
282//# sourceMappingURL=ComponentManager.js.map
\No newline at end of file