UNPKG

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