UNPKG

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