@cc-component/cc-core 1.2.9 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,302 @@
1
+ import { ecs } from "./ECS";
2
+ import { ECSMask } from "./ECSMask";
3
+ import { CompCtor, CompType, ECSModel } from "./ECSModel";
4
+
5
+ //#region 辅助方法
6
+
7
+ /**
8
+ * 实体身上组件有增删操作,广播通知对应的观察者
9
+ * @param entity 实体对象
10
+ * @param componentTypeId 组件类型id
11
+ */
12
+ function broadcastCompAddOrRemove(entity: ECSEntity, componentTypeId: number) {
13
+ let events = ECSModel.compAddOrRemove.get(componentTypeId);
14
+ for (let i = events!.length - 1; i >= 0; i--) {
15
+ events![i](entity);
16
+ }
17
+ // 判断是不是删了单例组件
18
+ if (ECSModel.tid2comp.has(componentTypeId)) {
19
+ ECSModel.tid2comp.delete(componentTypeId);
20
+ }
21
+ }
22
+
23
+ /**
24
+ * 创建组件对象
25
+ * @param ctor
26
+ */
27
+ function createComp<T extends ecs.IComp>(ctor: CompCtor<T>): T {
28
+ const cct = ECSModel.compCtors[ctor.tid];
29
+ if (!cct) {
30
+ throw Error(`没有找到该组件的构造函数,检查${ctor.compName}是否为不可构造的组件`);
31
+ }
32
+ let comps = ECSModel.compPools.get(ctor.tid)!;
33
+ let component = comps.pop() || new (cct as CompCtor<T>);
34
+ return component as T;
35
+ }
36
+
37
+ /**
38
+ * 销毁实体
39
+ *
40
+ * 缓存销毁的实体,下次新建实体时会优先从缓存中拿
41
+ * @param entity
42
+ */
43
+ function destroyEntity(entity: ECSEntity) {
44
+ if (ECSModel.eid2Entity.has(entity.eid)) {
45
+ let entitys = ECSModel.entityPool.get(entity.name);
46
+ if (entitys == null) {
47
+ entitys = [];
48
+ ECSModel.entityPool.set(entity.name, entitys);
49
+ }
50
+ entitys.push(entity);
51
+ ECSModel.eid2Entity.delete(entity.eid);
52
+ }
53
+ else {
54
+ console.warn('试图销毁不存在的实体');
55
+ }
56
+ }
57
+
58
+ //#endregion
59
+
60
+ /** ECS实体对象 */
61
+ export class ECSEntity {
62
+ /** 实体唯一标识,不要手动修改 */
63
+ eid: number = -1;
64
+ /** 实体对象名 */
65
+ name: string = "";
66
+ /** 实体是否有效 */
67
+ isValid: boolean = true;
68
+ /** 组件过滤数据 */
69
+ private mask = new ECSMask();
70
+ /** 当前实体身上附加的组件构造函数 */
71
+ private compTid2Ctor: Map<number, CompType<ecs.IComp>> = new Map();
72
+ /** 配合 entity.remove(Comp, false), 记录组件实例上的缓存数据,在添加时恢复原数据 */
73
+ private compTid2Obj: Map<number, ecs.IComp> = new Map();
74
+
75
+ private _parent: ECSEntity | null = null;
76
+ /** 父实体 */
77
+ get parent(): ECSEntity | null {
78
+ return this._parent;
79
+ }
80
+ set parent(value: ECSEntity | null) {
81
+ this._parent = value;
82
+ }
83
+
84
+ /** 子实体 */
85
+ private childs: Map<number, ECSEntity> = null!;
86
+
87
+ /** 获取子实体 */
88
+ getChild<T>(eid: number) {
89
+ return this.childs.get(eid) as T;
90
+ }
91
+
92
+ /**
93
+ * 添加子实体
94
+ * @param entity 被添加的实体对象
95
+ * @returns 子实体的唯一编号, -1表示添加失败
96
+ */
97
+ addChild(entity: ECSEntity): number {
98
+ if (this.childs == null) this.childs = new Map<number, ECSEntity>();
99
+
100
+ if (this.childs.has(entity.eid)) {
101
+ console.warn(`子实体${entity.name}已存在`);
102
+ return -1;
103
+ }
104
+
105
+ entity._parent = this;
106
+ this.childs.set(entity.eid, entity);
107
+ return entity.eid;
108
+ }
109
+
110
+ /**
111
+ * 移除子实体
112
+ * @param entity 被移除的实体对象
113
+ * @param isDestroy 被移除的实体是否释放,默认为释放
114
+ * @returns
115
+ */
116
+ removeChild(entity: ECSEntity, isDestroy = true) {
117
+ if (this.childs == null) return;
118
+
119
+ entity.parent = null;
120
+ this.childs.delete(entity.eid);
121
+ if (isDestroy) entity.destroy();
122
+ }
123
+
124
+ /**
125
+ * 根据组件类动态创建组件,并通知关心的系统。如果实体存在了这个组件,那么会先删除之前的组件然后添加新的
126
+ *
127
+ * 注意:不要直接new Component,new来的Component不会从Component的缓存池拿缓存的数据
128
+ * @param componentTypeId 组件类
129
+ * @param isReAdd true-表示用户指定这个实体可能已经存在了该组件,那么再次add组件的时候会先移除该组件然后再添加一遍。false-表示不重复添加组件
130
+ */
131
+ add<T extends ecs.IComp>(obj: T): ECSEntity;
132
+ add<T extends ecs.IComp>(ctor: CompType<T>, isReAdd?: boolean): T;
133
+ add<T extends ecs.IComp>(ctor: CompType<T> | T, isReAdd: boolean = false): T | ECSEntity {
134
+ if (typeof ctor === 'function') {
135
+ let compTid = ctor.tid;
136
+ if (ctor.tid === -1) {
137
+ throw Error(`【${this.name}】实体【${ctor.compName}】组件未注册`);
138
+ }
139
+ if (this.compTid2Ctor.has(compTid)) { // 判断是否有该组件,如果有则先移除
140
+ if (isReAdd) {
141
+ this.remove(ctor);
142
+ }
143
+ else {
144
+ console.log(`【${this.name}】实体【${ctor.compName}】组件已存在`);
145
+ // @ts-ignore
146
+ return this[ctor.compName] as T;
147
+ }
148
+ }
149
+ this.mask.set(compTid);
150
+
151
+ let comp: T;
152
+ if (this.compTid2Obj.has(compTid)) {
153
+ comp = this.compTid2Obj.get(compTid) as T;
154
+ this.compTid2Obj.delete(compTid);
155
+ }
156
+ else {
157
+ // 创建组件对象
158
+ comp = createComp(ctor) as T;
159
+ }
160
+
161
+ // 将组件对象直接附加到实体对象身上,方便直接获取
162
+ // @ts-ignore
163
+ this[ctor.compName] = comp;
164
+ this.compTid2Ctor.set(compTid, ctor);
165
+ comp.tid = compTid;
166
+ comp.ent = this;
167
+ // 广播实体添加组件的消息
168
+ broadcastCompAddOrRemove(this, compTid);
169
+
170
+ return comp;
171
+ }
172
+ else {
173
+ let tmpCtor = (ctor.constructor as CompCtor<T>);
174
+ let compTid = tmpCtor.tid;
175
+ // console.assert(compTid !== -1 || !compTid, '组件未注册!');
176
+ // console.assert(this.compTid2Ctor.has(compTid), '已存在该组件!');
177
+ if (compTid === -1 || compTid == null) throw Error(`【${this.name}】实体【${tmpCtor.name}】组件未注册`);
178
+ if (this.compTid2Ctor.has(compTid)) throw Error(`【${this.name}】实体【${tmpCtor.name}】组件已经存在`);
179
+
180
+ this.mask.set(compTid);
181
+ //@ts-ignore
182
+ this[tmpCtor.compName] = ctor;
183
+ this.compTid2Ctor.set(compTid, tmpCtor);
184
+ //@ts-ignore
185
+ ctor.tid = compTid;
186
+ //@ts-ignore
187
+ ctor.canRecycle = false;
188
+ //@ts-ignore
189
+ ctor.ent = this;
190
+ broadcastCompAddOrRemove(this, compTid);
191
+
192
+ return this;
193
+ }
194
+ }
195
+
196
+ /**
197
+ * 批量添加组件
198
+ * @param ctors 组件类
199
+ * @returns
200
+ */
201
+ addComponents<T extends ecs.IComp>(...ctors: CompType<T>[]) {
202
+ for (let ctor of ctors) {
203
+ this.add(ctor);
204
+ }
205
+ return this;
206
+ }
207
+
208
+ /**
209
+ * 获取一个组件实例
210
+ * @param ctor 组件类
211
+ */
212
+ get(ctor: number): number;
213
+ get<T extends ecs.IComp>(ctor: CompCtor<T>): T;
214
+ get<T extends ecs.IComp>(ctor: CompCtor<T> | number): T {
215
+ // @ts-ignore
216
+ return this[ctor.compName];
217
+ }
218
+
219
+ /**
220
+ * 组件是否在实体存在内
221
+ * @param ctor 组件类
222
+ */
223
+ has(ctor: CompType<ecs.IComp>): boolean {
224
+ if (typeof ctor == "number") {
225
+ return this.mask.has(ctor);
226
+ }
227
+ else {
228
+ return this.compTid2Ctor.has(ctor.tid);
229
+ }
230
+ }
231
+
232
+ /**
233
+ * 从实体上删除指定组件
234
+ * @param ctor 组件构造函数或者组件Tag
235
+ * @param isRecycle 是否回收该组件对象。对于有些组件上有大量数据,当要描述移除组件但是不想清除组件上的数据是可以
236
+ * 设置该参数为false,这样该组件对象会缓存在实体身上,下次重新添加组件时会将该组件对象添加回来,不会重新从组件缓存
237
+ * 池中拿一个组件来用。
238
+ */
239
+ remove(ctor: CompType<ecs.IComp>, isRecycle: boolean = true) {
240
+ let hasComp = false;
241
+ //@ts-ignore
242
+ let componentTypeId = ctor.tid;
243
+ //@ts-ignore
244
+ let compName = ctor.compName;
245
+ if (this.mask.has(componentTypeId)) {
246
+ hasComp = true;
247
+ //@ts-ignore
248
+ let comp = this[ctor.compName];
249
+ //@ts-ignore
250
+ comp.ent = null;
251
+ if (isRecycle) {
252
+ comp.reset();
253
+
254
+ // 回收组件到指定缓存池中
255
+ if (comp.canRecycle) {
256
+ const compPoolsType = ECSModel.compPools.get(componentTypeId)!;
257
+ compPoolsType.push(comp);
258
+ }
259
+ }
260
+ else {
261
+ this.compTid2Obj.set(componentTypeId, comp); // 用于缓存显示对象组件
262
+ }
263
+ }
264
+
265
+ // 删除实体上的组件逻辑
266
+ if (hasComp) {
267
+ //@ts-ignore
268
+ this[compName] = null;
269
+ this.mask.delete(componentTypeId);
270
+ this.compTid2Ctor.delete(componentTypeId);
271
+ broadcastCompAddOrRemove(this, componentTypeId);
272
+ }
273
+ }
274
+
275
+ /** 销毁实体,实体会被回收到实体缓存池中 */
276
+ destroy() {
277
+ this.isValid = false;
278
+
279
+ // 如果有父模块,则移除父模块上记录的子模块
280
+ if (this._parent) {
281
+ this._parent.removeChild(this, false);
282
+ this._parent = null;
283
+ }
284
+
285
+ // 移除模块上所有子模块
286
+ if (this.childs) {
287
+ this.childs.forEach(e => {
288
+ this.removeChild(e);
289
+ });
290
+ this.childs = null!;
291
+ }
292
+
293
+ // 移除实体上所有组件
294
+ this.compTid2Ctor.forEach(this._remove, this);
295
+ destroyEntity(this);
296
+ this.compTid2Obj.clear();
297
+ }
298
+
299
+ private _remove(comp: CompType<ecs.IComp>) {
300
+ this.remove(comp, true);
301
+ }
302
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "ver": "4.0.24",
3
+ "importer": "typescript",
4
+ "imported": true,
5
+ "uuid": "1fb62582-dcf6-4fbc-b863-a1941fad1109",
6
+ "files": [],
7
+ "subMetas": {},
8
+ "userData": {}
9
+ }
@@ -0,0 +1,83 @@
1
+ /*
2
+ * @Author: dgflash
3
+ * @Date: 2022-09-01 18:00:28
4
+ * @LastEditors: dgflash
5
+ * @LastEditTime: 2022-09-05 14:21:54
6
+ */
7
+ import { ecs } from "./ECS";
8
+ import { ECSEntity } from "./ECSEntity";
9
+
10
+ export class ECSGroup<E extends ECSEntity = ECSEntity> {
11
+ /** 实体筛选规则 */
12
+ private matcher: ecs.IMatcher;
13
+
14
+ private _matchEntities: Map<number, E> = new Map();
15
+
16
+ private _entitiesCache: E[] | null = null;
17
+
18
+ /**
19
+ * 符合规则的实体
20
+ */
21
+ get matchEntities() {
22
+ if (this._entitiesCache === null) {
23
+ this._entitiesCache = Array.from(this._matchEntities.values());
24
+ }
25
+ return this._entitiesCache;
26
+ }
27
+
28
+ /**
29
+ * 当前group中实体的数量
30
+ *
31
+ * 注:不要手动修改这个属性值。
32
+ * 注:其实可以通过this._matchEntities.size获得实体数量,但是需要封装get方法。为了减少一次方法的调用所以才直接创建一个count属性
33
+ */
34
+ count = 0;
35
+
36
+ /** 获取matchEntities中第一个实体 */
37
+ get entity(): E {
38
+ return this.matchEntities[0];
39
+ }
40
+
41
+ private _enteredEntities: Map<number, E> | null = null;
42
+ private _removedEntities: Map<number, E> | null = null;
43
+
44
+ constructor(matcher: ecs.IMatcher) {
45
+ this.matcher = matcher;
46
+ }
47
+
48
+ onComponentAddOrRemove(entity: E) {
49
+ if (this.matcher.isMatch(entity)) { // Group只关心指定组件在实体身上的添加和删除动作。
50
+ this._matchEntities.set(entity.eid, entity);
51
+ this._entitiesCache = null;
52
+ this.count++;
53
+
54
+ if (this._enteredEntities) {
55
+ this._enteredEntities.set(entity.eid, entity);
56
+ this._removedEntities!.delete(entity.eid);
57
+ }
58
+ }
59
+ else if (this._matchEntities.has(entity.eid)) { // 如果Group中有这个实体,但是这个实体已经不满足匹配规则,则从Group中移除该实体
60
+ this._matchEntities.delete(entity.eid);
61
+ this._entitiesCache = null;
62
+ this.count--;
63
+
64
+ if (this._enteredEntities) {
65
+ this._enteredEntities.delete(entity.eid);
66
+ this._removedEntities!.set(entity.eid, entity);
67
+ }
68
+ }
69
+ }
70
+
71
+ watchEntityEnterAndRemove(enteredEntities: Map<number, E>, removedEntities: Map<number, E>) {
72
+ this._enteredEntities = enteredEntities;
73
+ this._removedEntities = removedEntities;
74
+ }
75
+
76
+ clear() {
77
+ this._matchEntities.clear();
78
+ this._entitiesCache = null;
79
+ this.count = 0;
80
+ this._enteredEntities?.clear();
81
+ this._removedEntities?.clear();
82
+ }
83
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "ver": "4.0.24",
3
+ "importer": "typescript",
4
+ "imported": true,
5
+ "uuid": "c21a2de8-f4fe-4534-96a6-70c9a86167ec",
6
+ "files": [],
7
+ "subMetas": {},
8
+ "userData": {}
9
+ }
@@ -0,0 +1,57 @@
1
+ /*
2
+ * @Author: dgflash
3
+ * @Date: 2022-05-12 14:18:44
4
+ * @LastEditors: dgflash
5
+ * @LastEditTime: 2022-05-24 11:09:49
6
+ */
7
+ import { ECSModel } from "./ECSModel";
8
+
9
+ export class ECSMask {
10
+ private mask: Uint32Array;
11
+ private size: number = 0;
12
+
13
+ constructor() {
14
+ let length = Math.ceil(ECSModel.compTid / 31);
15
+ this.mask = new Uint32Array(length);
16
+ this.size = length;
17
+ }
18
+
19
+ set(num: number) {
20
+ // https://stackoverflow.com/questions/34896909/is-it-correct-to-set-bit-31-in-javascript
21
+ // this.mask[((num / 32) >>> 0)] |= ((1 << (num % 32)) >>> 0);
22
+ this.mask[((num / 31) >>> 0)] |= (1 << (num % 31));
23
+ }
24
+
25
+ delete(num: number) {
26
+ this.mask[((num / 31) >>> 0)] &= ~(1 << (num % 31));
27
+ }
28
+
29
+ has(num: number) {
30
+ return !!(this.mask[((num / 31) >>> 0)] & (1 << (num % 31)));
31
+ }
32
+
33
+ or(other: ECSMask) {
34
+ for (let i = 0; i < this.size; i++) {
35
+ // &操作符最大也只能对2^30进行操作,如果对2^31&2^31会得到负数。当然可以(2^31&2^31) >>> 0,这样多了一步右移操作。
36
+ if (this.mask[i] & other.mask[i]) {
37
+ return true;
38
+ }
39
+ }
40
+ return false;
41
+ }
42
+
43
+ and(other: ECSMask) {
44
+ for (let i = 0; i < this.size; i++) {
45
+ if ((this.mask[i] & other.mask[i]) != this.mask[i]) {
46
+ return false;
47
+ }
48
+ }
49
+ return true;
50
+ }
51
+
52
+ clear() {
53
+ for (let i = 0; i < this.size; i++) {
54
+ this.mask[i] = 0;
55
+ }
56
+ }
57
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "ver": "4.0.24",
3
+ "importer": "typescript",
4
+ "imported": true,
5
+ "uuid": "d1869e0f-3dbb-46b3-9229-828fef689057",
6
+ "files": [],
7
+ "subMetas": {},
8
+ "userData": {}
9
+ }
@@ -0,0 +1,215 @@
1
+ import { ecs } from "./ECS";
2
+ import { ECSEntity } from "./ECSEntity";
3
+ import { ECSMask } from "./ECSMask";
4
+ import { CompCtor, CompType, ECSModel } from "./ECSModel";
5
+
6
+ let macherId: number = 1;
7
+
8
+ /**
9
+ * 筛选规则间是“与”的关系
10
+ * 比如:ecs.Macher.allOf(...).excludeOf(...)表达的是allOf && excludeOf,即实体有“这些组件” 并且 “没有这些组件”
11
+ */
12
+ export class ECSMatcher implements ecs.IMatcher {
13
+ protected rules: BaseOf[] = [];
14
+ protected _indices: number[] | null = null;
15
+ public isMatch!: (entity: ECSEntity) => boolean;
16
+ public mid: number = -1;
17
+
18
+ private _key: string | null = null;
19
+ public get key(): string {
20
+ if (!this._key) {
21
+ let s = '';
22
+ for (let i = 0; i < this.rules.length; i++) {
23
+ s += this.rules[i].getKey()
24
+ if (i < this.rules.length - 1) {
25
+ s += ' && '
26
+ }
27
+ }
28
+ this._key = s;
29
+ }
30
+ return this._key;
31
+ }
32
+
33
+ constructor() {
34
+ this.mid = macherId++;
35
+ }
36
+
37
+ /**
38
+ * 匹配器关注的组件索引。在创建Group时,Context根据组件id去给Group关联组件的添加和移除事件。
39
+ */
40
+ get indices() {
41
+ if (this._indices === null) {
42
+ this._indices = [];
43
+ this.rules.forEach((rule) => {
44
+ Array.prototype.push.apply(this._indices, rule.indices);
45
+ });
46
+ }
47
+ return this._indices;
48
+ }
49
+
50
+ /**
51
+ * 组件间是或的关系,表示关注拥有任意一个这些组件的实体。
52
+ * @param args 组件索引
53
+ */
54
+ anyOf(...args: CompType<ecs.IComp>[]): ECSMatcher {
55
+ this.rules.push(new AnyOf(...args));
56
+ this.bindMatchMethod();
57
+ return this;
58
+ }
59
+
60
+ /**
61
+ * 组件间是与的关系,表示关注拥有所有这些组件的实体。
62
+ * @param args 组件索引
63
+ */
64
+ allOf(...args: CompType<ecs.IComp>[]): ECSMatcher {
65
+ this.rules.push(new AllOf(...args));
66
+ this.bindMatchMethod();
67
+ return this;
68
+ }
69
+
70
+ /**
71
+ * 表示关注只拥有这些组件的实体
72
+ *
73
+ * 注意:
74
+ * 不是特殊情况不建议使用onlyOf。因为onlyOf会监听所有组件的添加和删除事件。
75
+ * @param args 组件索引
76
+ */
77
+ onlyOf(...args: CompType<ecs.IComp>[]): ECSMatcher {
78
+ this.rules.push(new AllOf(...args));
79
+ let otherTids: CompType<ecs.IComp>[] = [];
80
+ for (let ctor of ECSModel.compCtors) {
81
+ if (args.indexOf(ctor) < 0) {
82
+ otherTids.push(ctor);
83
+ }
84
+ }
85
+ this.rules.push(new ExcludeOf(...otherTids));
86
+ this.bindMatchMethod();
87
+ return this;
88
+ }
89
+
90
+ /**
91
+ * 不包含指定的任意一个组件
92
+ * @param args
93
+ */
94
+ excludeOf(...args: CompType<ecs.IComp>[]) {
95
+ this.rules.push(new ExcludeOf(...args));
96
+ this.bindMatchMethod();
97
+ return this;
98
+ }
99
+
100
+ private bindMatchMethod() {
101
+ if (this.rules.length === 1) {
102
+ this.isMatch = this.isMatch1;
103
+ }
104
+ else if (this.rules.length === 2) {
105
+ this.isMatch = this.isMatch2;
106
+ }
107
+ else {
108
+ this.isMatch = this.isMatchMore;
109
+ }
110
+ }
111
+
112
+ private isMatch1(entity: ECSEntity): boolean {
113
+ return this.rules[0].isMatch(entity);
114
+ }
115
+
116
+ private isMatch2(entity: ECSEntity): boolean {
117
+ return this.rules[0].isMatch(entity) && this.rules[1].isMatch(entity);
118
+ }
119
+
120
+ private isMatchMore(entity: ECSEntity): boolean {
121
+ for (let rule of this.rules) {
122
+ if (!rule.isMatch(entity)) {
123
+ return false;
124
+ }
125
+ }
126
+ return true;
127
+ }
128
+
129
+ clone(): ECSMatcher {
130
+ let newMatcher = new ECSMatcher();
131
+ newMatcher.mid = macherId++;
132
+ this.rules.forEach(rule => newMatcher.rules.push(rule));
133
+ return newMatcher;
134
+ }
135
+ }
136
+
137
+ abstract class BaseOf {
138
+ indices: number[] = [];
139
+
140
+ protected mask = new ECSMask();
141
+
142
+ constructor(...args: CompType<ecs.IComp>[]) {
143
+ let componentTypeId = -1;
144
+ let len = args.length;
145
+ for (let i = 0; i < len; i++) {
146
+ if (typeof (args[i]) === "number") {
147
+ componentTypeId = args[i] as number;
148
+ }
149
+ else {
150
+ componentTypeId = (args[i] as CompCtor<ecs.IComp>).tid;
151
+ }
152
+ if (componentTypeId == -1) {
153
+ throw Error('存在没有注册的组件!');
154
+ }
155
+ this.mask.set(componentTypeId);
156
+
157
+ if (this.indices.indexOf(componentTypeId) < 0) { // 去重
158
+ this.indices.push(componentTypeId);
159
+ }
160
+ }
161
+ if (len > 1) {
162
+ this.indices.sort((a, b) => { return a - b; }); // 对组件类型id进行排序,这样关注相同组件的系统就能共用同一个group
163
+ }
164
+ }
165
+
166
+ toString(): string {
167
+ return this.indices.join('-'); // 生成group的key
168
+ }
169
+
170
+ abstract getKey(): string;
171
+
172
+ abstract isMatch(entity: ECSEntity): boolean;
173
+ }
174
+
175
+ /**
176
+ * 用于描述包含任意一个这些组件的实体
177
+ */
178
+ class AnyOf extends BaseOf {
179
+ public isMatch(entity: ECSEntity): boolean {
180
+ // @ts-ignore
181
+ return this.mask.or(entity.mask);
182
+ }
183
+
184
+ getKey(): string {
185
+ return 'anyOf:' + this.toString();
186
+ }
187
+ }
188
+
189
+ /**
190
+ * 用于描述包含了“这些”组件的实体,这个实体除了包含这些组件还可以包含其他组件
191
+ */
192
+ class AllOf extends BaseOf {
193
+ public isMatch(entity: ECSEntity): boolean {
194
+ // @ts-ignore
195
+ return this.mask.and(entity.mask);
196
+ }
197
+
198
+ getKey(): string {
199
+ return 'allOf:' + this.toString();
200
+ }
201
+ }
202
+
203
+ /**
204
+ * 不包含指定的任意一个组件
205
+ */
206
+ class ExcludeOf extends BaseOf {
207
+ public getKey(): string {
208
+ return 'excludeOf:' + this.toString();
209
+ }
210
+
211
+ public isMatch(entity: ECSEntity): boolean {
212
+ // @ts-ignore
213
+ return !this.mask.or(entity.mask);
214
+ }
215
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "ver": "4.0.24",
3
+ "importer": "typescript",
4
+ "imported": true,
5
+ "uuid": "37e8aae5-a8f9-4ded-a999-6321c5bc1229",
6
+ "files": [],
7
+ "subMetas": {},
8
+ "userData": {}
9
+ }