UNPKG

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