新增entitylist用于管理实体

This commit is contained in:
yhh
2020-06-08 20:11:58 +08:00
parent 57efc5b0e6
commit a048a8ac29
15 changed files with 936 additions and 38 deletions

View File

@@ -26,6 +26,7 @@ declare abstract class Component {
abstract initialize(): any; abstract initialize(): any;
update(): void; update(): void;
bind(displayRender: egret.DisplayObject): this; bind(displayRender: egret.DisplayObject): this;
registerComponent(): void;
} }
declare class Entity { declare class Entity {
name: string; name: string;
@@ -34,6 +35,7 @@ declare class Entity {
readonly components: Component[]; readonly components: Component[];
private _updateOrder; private _updateOrder;
private _enabled; private _enabled;
componentBits: BitSet;
enabled: boolean; enabled: boolean;
setEnabled(isEnabled: boolean): this; setEnabled(isEnabled: boolean): this;
constructor(name: string); constructor(name: string);
@@ -47,7 +49,7 @@ declare class Entity {
} }
declare class Scene extends egret.DisplayObjectContainer { declare class Scene extends egret.DisplayObjectContainer {
camera: Camera; camera: Camera;
entities: Entity[]; readonly entities: EntityList;
private _projectionMatrix; private _projectionMatrix;
private _transformMatrix; private _transformMatrix;
private _matrixTransformMatrix; private _matrixTransformMatrix;
@@ -55,7 +57,7 @@ declare class Scene extends egret.DisplayObjectContainer {
constructor(displayObject: egret.DisplayObject); constructor(displayObject: egret.DisplayObject);
createEntity(name: string): Entity; createEntity(name: string): Entity;
addEntity(entity: Entity): Entity; addEntity(entity: Entity): Entity;
destoryAllEntities(): void; destroyAllEntities(): void;
findEntity(name: string): Entity; findEntity(name: string): Entity;
addEntityProcessor(processor: EntitySystem): EntitySystem; addEntityProcessor(processor: EntitySystem): EntitySystem;
removeEntityProcessor(processor: EntitySystem): void; removeEntityProcessor(processor: EntitySystem): void;
@@ -139,6 +141,11 @@ declare class EntitySystem {
scene: Scene; scene: Scene;
constructor(matcher?: Matcher); constructor(matcher?: Matcher);
initialize(): void; initialize(): void;
onChanged(entity: Entity): void;
add(entity: Entity): void;
onAdded(entity: Entity): void;
remove(entity: Entity): void;
onRemoved(entity: Entity): void;
update(): void; update(): void;
lateUpdate(): void; lateUpdate(): void;
protected begin(): void; protected begin(): void;
@@ -153,8 +160,48 @@ declare abstract class EntityProcessingSystem extends EntitySystem {
protected process(entities: Entity[]): void; protected process(entities: Entity[]): void;
protected lateProcess(entities: Entity[]): void; protected lateProcess(entities: Entity[]): void;
} }
declare class BitSet {
private static LONG_MASK;
private _bits;
constructor(nbits?: number);
and(bs: BitSet): void;
andNot(bs: BitSet): void;
cardinality(): number;
clear(pos?: number): void;
private ensure;
get(pos: number): boolean;
intersects(set: BitSet): boolean;
isEmpty(): boolean;
nextSetBit(from: number): number;
set(pos: number): void;
}
declare class ComponentTypeManager {
private static _componentTypesMask;
static add(type: any): void;
static getIndexFor(type: any): number;
}
declare class EntityList {
scene: Scene;
private _entitiesToRemove;
private _entitiesToAdded;
private _tempEntityList;
private _entities;
constructor(scene: Scene);
readonly count: number;
readonly buffer: Entity[];
add(entity: Entity): void;
remove(entity: Entity): void;
findEntity(name: string): Entity;
update(): void;
removeAllEntities(): void;
updateLists(): void;
}
declare class Matcher { declare class Matcher {
protected allSet: BitSet;
protected exclusionSet: BitSet;
protected oneSet: BitSet;
static empty(): Matcher; static empty(): Matcher;
IsIntersted(e: Entity): boolean;
} }
declare class MathHelper { declare class MathHelper {
static toDegrees(radians: number): number; static toDegrees(radians: number): number;

View File

@@ -264,6 +264,11 @@ var Component = (function () {
this.displayRender = displayRender; this.displayRender = displayRender;
return this; return this;
}; };
Component.prototype.registerComponent = function () {
var _this = this;
this.entity.componentBits.set(ComponentTypeManager.getIndexFor(this));
this.entity.scene.entityProcessors.forEach(function (processor) { return processor.onChanged(_this.entity); });
};
return Component; return Component;
}()); }());
var Entity = (function () { var Entity = (function () {
@@ -273,6 +278,7 @@ var Entity = (function () {
this.name = name; this.name = name;
this.transform = new Transform(this); this.transform = new Transform(this);
this.components = []; this.components = [];
this.componentBits = new BitSet();
} }
Object.defineProperty(Entity.prototype, "enabled", { Object.defineProperty(Entity.prototype, "enabled", {
get: function () { get: function () {
@@ -310,7 +316,8 @@ var Entity = (function () {
}; };
Entity.prototype.attachToScene = function (newScene) { Entity.prototype.attachToScene = function (newScene) {
this.scene = newScene; this.scene = newScene;
newScene.entities.push(this); newScene.entities.add(this);
this.components.forEach(function (component) { return component.registerComponent(); });
for (var i = 0; i < this.transform.childCount; i++) { for (var i = 0; i < this.transform.childCount; i++) {
this.transform.getChild(i).entity.attachToScene(newScene); this.transform.getChild(i).entity.attachToScene(newScene);
} }
@@ -342,10 +349,10 @@ var Scene = (function (_super) {
__extends(Scene, _super); __extends(Scene, _super);
function Scene(displayObject) { function Scene(displayObject) {
var _this = _super.call(this) || this; var _this = _super.call(this) || this;
_this.entities = [];
displayObject.stage.addChild(_this); displayObject.stage.addChild(_this);
_this._projectionMatrix = new Matrix2D(0, 0, 0, 0, 0, 0); _this._projectionMatrix = new Matrix2D(0, 0, 0, 0, 0, 0);
_this.entityProcessors = []; _this.entityProcessors = [];
_this.entities = new EntityList(_this);
_this.addEventListener(egret.Event.ACTIVATE, _this.onActive, _this); _this.addEventListener(egret.Event.ACTIVATE, _this.onActive, _this);
_this.addEventListener(egret.Event.DEACTIVATE, _this.onDeactive, _this); _this.addEventListener(egret.Event.DEACTIVATE, _this.onDeactive, _this);
_this.addEventListener(egret.Event.ENTER_FRAME, _this.update, _this); _this.addEventListener(egret.Event.ENTER_FRAME, _this.update, _this);
@@ -357,15 +364,19 @@ var Scene = (function (_super) {
return this.addEntity(entity); return this.addEntity(entity);
}; };
Scene.prototype.addEntity = function (entity) { Scene.prototype.addEntity = function (entity) {
this.entities.push(entity); this.entities.add(entity);
entity.scene = this; entity.scene = this;
for (var i = 0; i < entity.transform.childCount; i++)
this.addEntity(entity.transform.getChild(i).entity);
return entity; return entity;
}; };
Scene.prototype.destoryAllEntities = function () { Scene.prototype.destroyAllEntities = function () {
this.entities.forEach(function (entity) { return entity.destory(); }); for (var i = 0; i < this.entities.count; i++) {
this.entities.buffer[i].destory();
}
}; };
Scene.prototype.findEntity = function (name) { Scene.prototype.findEntity = function (name) {
return this.entities.firstOrDefault(function (entity) { return entity.name == name; }); return this.entities.findEntity(name);
}; };
Scene.prototype.addEntityProcessor = function (processor) { Scene.prototype.addEntityProcessor = function (processor) {
processor.scene = this; processor.scene = this;
@@ -391,8 +402,9 @@ var Scene = (function (_super) {
Scene.prototype.onDeactive = function () { Scene.prototype.onDeactive = function () {
}; };
Scene.prototype.update = function () { Scene.prototype.update = function () {
this.entities.updateLists();
this.entityProcessors.forEach(function (processor) { return processor.update(); }); this.entityProcessors.forEach(function (processor) { return processor.update(); });
this.entities.forEach(function (entity) { return entity.update(); }); this.entities.update();
this.entityProcessors.forEach(function (processor) { return processor.lateUpdate(); }); this.entityProcessors.forEach(function (processor) { return processor.lateUpdate(); });
}; };
Scene.prototype.prepRenderState = function () { Scene.prototype.prepRenderState = function () {
@@ -406,8 +418,7 @@ var Scene = (function (_super) {
this.removeEventListener(egret.Event.ACTIVATE, this.onActive, this); this.removeEventListener(egret.Event.ACTIVATE, this.onActive, this);
this.camera.destory(); this.camera.destory();
this.camera = null; this.camera = null;
this.entities.forEach(function (entity) { return entity.destory(); }); this.entities.removeAllEntities();
this.entities.length = 0;
}; };
return Scene; return Scene;
}(egret.DisplayObjectContainer)); }(egret.DisplayObjectContainer));
@@ -599,7 +610,7 @@ var Camera = (function (_super) {
}; };
Camera.prototype.update = function () { Camera.prototype.update = function () {
var _this = this; var _this = this;
SceneManager.getActiveScene().entities.forEach(function (entity) { return entity.components.forEach(function (component) { SceneManager.getActiveScene().entities.buffer.forEach(function (entity) { return entity.components.forEach(function (component) {
if (component.displayRender) { if (component.displayRender) {
var has = _this.entity.scene.$children.indexOf(component.displayRender); var has = _this.entity.scene.$children.indexOf(component.displayRender);
if (has == -1) { if (has == -1) {
@@ -644,6 +655,26 @@ var EntitySystem = (function () {
}); });
EntitySystem.prototype.initialize = function () { EntitySystem.prototype.initialize = function () {
}; };
EntitySystem.prototype.onChanged = function (entity) {
var contains = this._entities.contains(entity);
var interest = this._matcher.IsIntersted(entity);
if (interest && !contains)
this.add(entity);
else if (!interest && contains)
this.remove(entity);
};
EntitySystem.prototype.add = function (entity) {
this._entities.push(entity);
this.onAdded(entity);
};
EntitySystem.prototype.onAdded = function (entity) {
};
EntitySystem.prototype.remove = function (entity) {
this._entities.remove(entity);
this.onRemoved(entity);
};
EntitySystem.prototype.onRemoved = function (entity) {
};
EntitySystem.prototype.update = function () { EntitySystem.prototype.update = function () {
this.begin(); this.begin();
this.process(this._entities); this.process(this._entities);
@@ -679,12 +710,231 @@ var EntityProcessingSystem = (function (_super) {
}; };
return EntityProcessingSystem; return EntityProcessingSystem;
}(EntitySystem)); }(EntitySystem));
var BitSet = (function () {
function BitSet(nbits) {
if (nbits === void 0) { nbits = 64; }
var length = nbits >> 6;
if ((nbits & BitSet.LONG_MASK) != 0)
length++;
this._bits = new Array(length);
}
BitSet.prototype.and = function (bs) {
var max = Math.min(this._bits.length, bs._bits.length);
var i;
for (var i_1 = 0; i_1 < max; ++i_1)
this._bits[i_1] &= bs._bits[i_1];
while (i < this._bits.length)
this._bits[i++] = 0;
};
BitSet.prototype.andNot = function (bs) {
var i = Math.min(this._bits.length, bs._bits.length);
while (--i >= 0)
this._bits[i] &= ~bs._bits[i];
};
BitSet.prototype.cardinality = function () {
var card = 0;
for (var i = this._bits.length - 1; i >= 0; i--) {
var a = this._bits[i];
if (a == 0)
continue;
if (a == -1) {
card += 64;
continue;
}
a = ((a >> 1) & 0x5555555555555555) + (a & 0x5555555555555555);
a = ((a >> 2) & 0x3333333333333333) + (a & 0x3333333333333333);
var b = ((a >> 32) + a);
b = ((b >> 4) & 0x0f0f0f0f) + (b & 0x0f0f0f0f);
b = ((b >> 8) & 0x00ff00ff) + (b & 0x00ff00ff);
card += ((b >> 16) & 0x0000ffff) + (b & 0x0000ffff);
}
return card;
};
BitSet.prototype.clear = function (pos) {
if (pos != undefined) {
var offset = pos >> 6;
this.ensure(offset);
this._bits[offset] &= ~(1 << pos);
}
else {
for (var i = 0; i < this._bits.length; i++)
this._bits[i] = 0;
}
};
BitSet.prototype.ensure = function (lastElt) {
if (lastElt >= this._bits.length) {
var nd = new Number[lastElt + 1];
nd = this._bits.copyWithin(0, 0, this._bits.length);
this._bits = nd;
}
};
BitSet.prototype.get = function (pos) {
var offset = pos >> 6;
if (offset >= this._bits.length)
return false;
return (this._bits[offset] & (1 << pos)) != 0;
};
BitSet.prototype.intersects = function (set) {
var i = Math.min(this._bits.length, set._bits.length);
while (--i >= 0) {
if ((this._bits[i] & set._bits[i]) != 0)
return true;
}
return false;
};
BitSet.prototype.isEmpty = function () {
for (var i = this._bits.length - 1; i >= 0; i--) {
if (this._bits[i] != 0)
return false;
}
return true;
};
BitSet.prototype.nextSetBit = function (from) {
var offset = from >> 6;
var mask = 1 << from;
while (offset < this._bits.length) {
var h = this._bits[offset];
do {
if ((h & mask) != 0)
return from;
mask <<= 1;
from++;
} while (mask != 0);
mask = 1;
offset++;
}
return -1;
};
BitSet.prototype.set = function (pos) {
var offset = pos >> 6;
this.ensure(offset);
this._bits[offset] |= 1 << pos;
};
BitSet.LONG_MASK = 0x3f;
return BitSet;
}());
var ComponentTypeManager = (function () {
function ComponentTypeManager() {
}
ComponentTypeManager.add = function (type) {
if (!this._componentTypesMask.has(type))
this._componentTypesMask[type] = this._componentTypesMask.size;
};
ComponentTypeManager.getIndexFor = function (type) {
var v = -1;
if (!this._componentTypesMask.has(type)) {
this.add(type);
v = this._componentTypesMask.get(type);
}
return v;
};
ComponentTypeManager._componentTypesMask = new Map();
return ComponentTypeManager;
}());
var EntityList = (function () {
function EntityList(scene) {
this._entitiesToRemove = [];
this._entitiesToAdded = [];
this._tempEntityList = [];
this._entities = [];
this.scene = scene;
}
Object.defineProperty(EntityList.prototype, "count", {
get: function () {
return this._entities.length;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EntityList.prototype, "buffer", {
get: function () {
return this._entities;
},
enumerable: true,
configurable: true
});
EntityList.prototype.add = function (entity) {
this._entitiesToAdded.push(entity);
};
EntityList.prototype.remove = function (entity) {
if (this._entitiesToAdded.contains(entity)) {
this._entitiesToAdded.remove(entity);
return;
}
if (!this._entitiesToRemove.contains(entity))
this._entitiesToRemove.push(entity);
};
EntityList.prototype.findEntity = function (name) {
for (var i = 0; i < this._entities.length; i++) {
if (this._entities[i].name == name)
return this._entities[i];
}
return this._entitiesToAdded.firstOrDefault(function (entity) { return entity.name == name; });
};
EntityList.prototype.update = function () {
for (var i = 0; i < this._entities.length; i++) {
var entity = this._entities[i];
if (entity.enabled)
entity.update();
}
};
EntityList.prototype.removeAllEntities = function () {
this._entitiesToAdded.length = 0;
this.updateLists();
for (var i = 0; i < this._entities.length; i++) {
this._entities[i].scene = null;
}
this._entities.length = 0;
};
EntityList.prototype.updateLists = function () {
var _this = this;
if (this._entitiesToRemove.length > 0) {
var temp = this._entitiesToRemove;
this._entitiesToRemove = this._tempEntityList;
this._tempEntityList = temp;
this._tempEntityList.forEach(function (entity) {
_this._entities.remove(entity);
entity.scene = null;
_this.scene.entityProcessors.forEach(function (processor) { return processor.remove(entity); });
});
this._tempEntityList.length = 0;
}
if (this._entitiesToAdded.length > 0) {
var temp = this._entitiesToAdded;
this._entitiesToAdded = this._tempEntityList;
this._tempEntityList = temp;
this._tempEntityList.forEach(function (entity) {
_this._entities.push(entity);
entity.scene = _this.scene;
_this.scene.entityProcessors.forEach(function (processor) { return processor.onChanged(entity); });
});
this._tempEntityList.length = 0;
}
};
return EntityList;
}());
var Matcher = (function () { var Matcher = (function () {
function Matcher() { function Matcher() {
this.allSet = new BitSet();
this.exclusionSet = new BitSet();
this.oneSet = new BitSet();
} }
Matcher.empty = function () { Matcher.empty = function () {
return new Matcher(); return new Matcher();
}; };
Matcher.prototype.IsIntersted = function (e) {
if (!this.allSet.isEmpty()) {
for (var i = this.allSet.nextSetBit(0); i >= 0; i = this.allSet.nextSetBit(i + 1)) {
if (!e.componentBits.get(i))
return false;
}
}
if (!this.exclusionSet.isEmpty() && this.exclusionSet.intersects(e.componentBits))
return false;
if (!this.oneSet.isEmpty() && !this.oneSet.intersects(e.componentBits))
return false;
return true;
};
return Matcher; return Matcher;
}()); }());
var MathHelper = (function () { var MathHelper = (function () {

File diff suppressed because one or more lines are too long

View File

@@ -26,6 +26,7 @@ declare abstract class Component {
abstract initialize(): any; abstract initialize(): any;
update(): void; update(): void;
bind(displayRender: egret.DisplayObject): this; bind(displayRender: egret.DisplayObject): this;
registerComponent(): void;
} }
declare class Entity { declare class Entity {
name: string; name: string;
@@ -34,6 +35,7 @@ declare class Entity {
readonly components: Component[]; readonly components: Component[];
private _updateOrder; private _updateOrder;
private _enabled; private _enabled;
componentBits: BitSet;
enabled: boolean; enabled: boolean;
setEnabled(isEnabled: boolean): this; setEnabled(isEnabled: boolean): this;
constructor(name: string); constructor(name: string);
@@ -47,7 +49,7 @@ declare class Entity {
} }
declare class Scene extends egret.DisplayObjectContainer { declare class Scene extends egret.DisplayObjectContainer {
camera: Camera; camera: Camera;
entities: Entity[]; readonly entities: EntityList;
private _projectionMatrix; private _projectionMatrix;
private _transformMatrix; private _transformMatrix;
private _matrixTransformMatrix; private _matrixTransformMatrix;
@@ -55,7 +57,7 @@ declare class Scene extends egret.DisplayObjectContainer {
constructor(displayObject: egret.DisplayObject); constructor(displayObject: egret.DisplayObject);
createEntity(name: string): Entity; createEntity(name: string): Entity;
addEntity(entity: Entity): Entity; addEntity(entity: Entity): Entity;
destoryAllEntities(): void; destroyAllEntities(): void;
findEntity(name: string): Entity; findEntity(name: string): Entity;
addEntityProcessor(processor: EntitySystem): EntitySystem; addEntityProcessor(processor: EntitySystem): EntitySystem;
removeEntityProcessor(processor: EntitySystem): void; removeEntityProcessor(processor: EntitySystem): void;
@@ -139,6 +141,11 @@ declare class EntitySystem {
scene: Scene; scene: Scene;
constructor(matcher?: Matcher); constructor(matcher?: Matcher);
initialize(): void; initialize(): void;
onChanged(entity: Entity): void;
add(entity: Entity): void;
onAdded(entity: Entity): void;
remove(entity: Entity): void;
onRemoved(entity: Entity): void;
update(): void; update(): void;
lateUpdate(): void; lateUpdate(): void;
protected begin(): void; protected begin(): void;
@@ -153,8 +160,48 @@ declare abstract class EntityProcessingSystem extends EntitySystem {
protected process(entities: Entity[]): void; protected process(entities: Entity[]): void;
protected lateProcess(entities: Entity[]): void; protected lateProcess(entities: Entity[]): void;
} }
declare class BitSet {
private static LONG_MASK;
private _bits;
constructor(nbits?: number);
and(bs: BitSet): void;
andNot(bs: BitSet): void;
cardinality(): number;
clear(pos?: number): void;
private ensure;
get(pos: number): boolean;
intersects(set: BitSet): boolean;
isEmpty(): boolean;
nextSetBit(from: number): number;
set(pos: number): void;
}
declare class ComponentTypeManager {
private static _componentTypesMask;
static add(type: any): void;
static getIndexFor(type: any): number;
}
declare class EntityList {
scene: Scene;
private _entitiesToRemove;
private _entitiesToAdded;
private _tempEntityList;
private _entities;
constructor(scene: Scene);
readonly count: number;
readonly buffer: Entity[];
add(entity: Entity): void;
remove(entity: Entity): void;
findEntity(name: string): Entity;
update(): void;
removeAllEntities(): void;
updateLists(): void;
}
declare class Matcher { declare class Matcher {
protected allSet: BitSet;
protected exclusionSet: BitSet;
protected oneSet: BitSet;
static empty(): Matcher; static empty(): Matcher;
IsIntersted(e: Entity): boolean;
} }
declare class MathHelper { declare class MathHelper {
static toDegrees(radians: number): number; static toDegrees(radians: number): number;

View File

@@ -264,6 +264,11 @@ var Component = (function () {
this.displayRender = displayRender; this.displayRender = displayRender;
return this; return this;
}; };
Component.prototype.registerComponent = function () {
var _this = this;
this.entity.componentBits.set(ComponentTypeManager.getIndexFor(this));
this.entity.scene.entityProcessors.forEach(function (processor) { return processor.onChanged(_this.entity); });
};
return Component; return Component;
}()); }());
var Entity = (function () { var Entity = (function () {
@@ -273,6 +278,7 @@ var Entity = (function () {
this.name = name; this.name = name;
this.transform = new Transform(this); this.transform = new Transform(this);
this.components = []; this.components = [];
this.componentBits = new BitSet();
} }
Object.defineProperty(Entity.prototype, "enabled", { Object.defineProperty(Entity.prototype, "enabled", {
get: function () { get: function () {
@@ -310,7 +316,8 @@ var Entity = (function () {
}; };
Entity.prototype.attachToScene = function (newScene) { Entity.prototype.attachToScene = function (newScene) {
this.scene = newScene; this.scene = newScene;
newScene.entities.push(this); newScene.entities.add(this);
this.components.forEach(function (component) { return component.registerComponent(); });
for (var i = 0; i < this.transform.childCount; i++) { for (var i = 0; i < this.transform.childCount; i++) {
this.transform.getChild(i).entity.attachToScene(newScene); this.transform.getChild(i).entity.attachToScene(newScene);
} }
@@ -342,10 +349,10 @@ var Scene = (function (_super) {
__extends(Scene, _super); __extends(Scene, _super);
function Scene(displayObject) { function Scene(displayObject) {
var _this = _super.call(this) || this; var _this = _super.call(this) || this;
_this.entities = [];
displayObject.stage.addChild(_this); displayObject.stage.addChild(_this);
_this._projectionMatrix = new Matrix2D(0, 0, 0, 0, 0, 0); _this._projectionMatrix = new Matrix2D(0, 0, 0, 0, 0, 0);
_this.entityProcessors = []; _this.entityProcessors = [];
_this.entities = new EntityList(_this);
_this.addEventListener(egret.Event.ACTIVATE, _this.onActive, _this); _this.addEventListener(egret.Event.ACTIVATE, _this.onActive, _this);
_this.addEventListener(egret.Event.DEACTIVATE, _this.onDeactive, _this); _this.addEventListener(egret.Event.DEACTIVATE, _this.onDeactive, _this);
_this.addEventListener(egret.Event.ENTER_FRAME, _this.update, _this); _this.addEventListener(egret.Event.ENTER_FRAME, _this.update, _this);
@@ -357,15 +364,19 @@ var Scene = (function (_super) {
return this.addEntity(entity); return this.addEntity(entity);
}; };
Scene.prototype.addEntity = function (entity) { Scene.prototype.addEntity = function (entity) {
this.entities.push(entity); this.entities.add(entity);
entity.scene = this; entity.scene = this;
for (var i = 0; i < entity.transform.childCount; i++)
this.addEntity(entity.transform.getChild(i).entity);
return entity; return entity;
}; };
Scene.prototype.destoryAllEntities = function () { Scene.prototype.destroyAllEntities = function () {
this.entities.forEach(function (entity) { return entity.destory(); }); for (var i = 0; i < this.entities.count; i++) {
this.entities.buffer[i].destory();
}
}; };
Scene.prototype.findEntity = function (name) { Scene.prototype.findEntity = function (name) {
return this.entities.firstOrDefault(function (entity) { return entity.name == name; }); return this.entities.findEntity(name);
}; };
Scene.prototype.addEntityProcessor = function (processor) { Scene.prototype.addEntityProcessor = function (processor) {
processor.scene = this; processor.scene = this;
@@ -391,8 +402,9 @@ var Scene = (function (_super) {
Scene.prototype.onDeactive = function () { Scene.prototype.onDeactive = function () {
}; };
Scene.prototype.update = function () { Scene.prototype.update = function () {
this.entities.updateLists();
this.entityProcessors.forEach(function (processor) { return processor.update(); }); this.entityProcessors.forEach(function (processor) { return processor.update(); });
this.entities.forEach(function (entity) { return entity.update(); }); this.entities.update();
this.entityProcessors.forEach(function (processor) { return processor.lateUpdate(); }); this.entityProcessors.forEach(function (processor) { return processor.lateUpdate(); });
}; };
Scene.prototype.prepRenderState = function () { Scene.prototype.prepRenderState = function () {
@@ -406,8 +418,7 @@ var Scene = (function (_super) {
this.removeEventListener(egret.Event.ACTIVATE, this.onActive, this); this.removeEventListener(egret.Event.ACTIVATE, this.onActive, this);
this.camera.destory(); this.camera.destory();
this.camera = null; this.camera = null;
this.entities.forEach(function (entity) { return entity.destory(); }); this.entities.removeAllEntities();
this.entities.length = 0;
}; };
return Scene; return Scene;
}(egret.DisplayObjectContainer)); }(egret.DisplayObjectContainer));
@@ -599,7 +610,7 @@ var Camera = (function (_super) {
}; };
Camera.prototype.update = function () { Camera.prototype.update = function () {
var _this = this; var _this = this;
SceneManager.getActiveScene().entities.forEach(function (entity) { return entity.components.forEach(function (component) { SceneManager.getActiveScene().entities.buffer.forEach(function (entity) { return entity.components.forEach(function (component) {
if (component.displayRender) { if (component.displayRender) {
var has = _this.entity.scene.$children.indexOf(component.displayRender); var has = _this.entity.scene.$children.indexOf(component.displayRender);
if (has == -1) { if (has == -1) {
@@ -644,6 +655,26 @@ var EntitySystem = (function () {
}); });
EntitySystem.prototype.initialize = function () { EntitySystem.prototype.initialize = function () {
}; };
EntitySystem.prototype.onChanged = function (entity) {
var contains = this._entities.contains(entity);
var interest = this._matcher.IsIntersted(entity);
if (interest && !contains)
this.add(entity);
else if (!interest && contains)
this.remove(entity);
};
EntitySystem.prototype.add = function (entity) {
this._entities.push(entity);
this.onAdded(entity);
};
EntitySystem.prototype.onAdded = function (entity) {
};
EntitySystem.prototype.remove = function (entity) {
this._entities.remove(entity);
this.onRemoved(entity);
};
EntitySystem.prototype.onRemoved = function (entity) {
};
EntitySystem.prototype.update = function () { EntitySystem.prototype.update = function () {
this.begin(); this.begin();
this.process(this._entities); this.process(this._entities);
@@ -679,12 +710,231 @@ var EntityProcessingSystem = (function (_super) {
}; };
return EntityProcessingSystem; return EntityProcessingSystem;
}(EntitySystem)); }(EntitySystem));
var BitSet = (function () {
function BitSet(nbits) {
if (nbits === void 0) { nbits = 64; }
var length = nbits >> 6;
if ((nbits & BitSet.LONG_MASK) != 0)
length++;
this._bits = new Array(length);
}
BitSet.prototype.and = function (bs) {
var max = Math.min(this._bits.length, bs._bits.length);
var i;
for (var i_1 = 0; i_1 < max; ++i_1)
this._bits[i_1] &= bs._bits[i_1];
while (i < this._bits.length)
this._bits[i++] = 0;
};
BitSet.prototype.andNot = function (bs) {
var i = Math.min(this._bits.length, bs._bits.length);
while (--i >= 0)
this._bits[i] &= ~bs._bits[i];
};
BitSet.prototype.cardinality = function () {
var card = 0;
for (var i = this._bits.length - 1; i >= 0; i--) {
var a = this._bits[i];
if (a == 0)
continue;
if (a == -1) {
card += 64;
continue;
}
a = ((a >> 1) & 0x5555555555555555) + (a & 0x5555555555555555);
a = ((a >> 2) & 0x3333333333333333) + (a & 0x3333333333333333);
var b = ((a >> 32) + a);
b = ((b >> 4) & 0x0f0f0f0f) + (b & 0x0f0f0f0f);
b = ((b >> 8) & 0x00ff00ff) + (b & 0x00ff00ff);
card += ((b >> 16) & 0x0000ffff) + (b & 0x0000ffff);
}
return card;
};
BitSet.prototype.clear = function (pos) {
if (pos != undefined) {
var offset = pos >> 6;
this.ensure(offset);
this._bits[offset] &= ~(1 << pos);
}
else {
for (var i = 0; i < this._bits.length; i++)
this._bits[i] = 0;
}
};
BitSet.prototype.ensure = function (lastElt) {
if (lastElt >= this._bits.length) {
var nd = new Number[lastElt + 1];
nd = this._bits.copyWithin(0, 0, this._bits.length);
this._bits = nd;
}
};
BitSet.prototype.get = function (pos) {
var offset = pos >> 6;
if (offset >= this._bits.length)
return false;
return (this._bits[offset] & (1 << pos)) != 0;
};
BitSet.prototype.intersects = function (set) {
var i = Math.min(this._bits.length, set._bits.length);
while (--i >= 0) {
if ((this._bits[i] & set._bits[i]) != 0)
return true;
}
return false;
};
BitSet.prototype.isEmpty = function () {
for (var i = this._bits.length - 1; i >= 0; i--) {
if (this._bits[i] != 0)
return false;
}
return true;
};
BitSet.prototype.nextSetBit = function (from) {
var offset = from >> 6;
var mask = 1 << from;
while (offset < this._bits.length) {
var h = this._bits[offset];
do {
if ((h & mask) != 0)
return from;
mask <<= 1;
from++;
} while (mask != 0);
mask = 1;
offset++;
}
return -1;
};
BitSet.prototype.set = function (pos) {
var offset = pos >> 6;
this.ensure(offset);
this._bits[offset] |= 1 << pos;
};
BitSet.LONG_MASK = 0x3f;
return BitSet;
}());
var ComponentTypeManager = (function () {
function ComponentTypeManager() {
}
ComponentTypeManager.add = function (type) {
if (!this._componentTypesMask.has(type))
this._componentTypesMask[type] = this._componentTypesMask.size;
};
ComponentTypeManager.getIndexFor = function (type) {
var v = -1;
if (!this._componentTypesMask.has(type)) {
this.add(type);
v = this._componentTypesMask.get(type);
}
return v;
};
ComponentTypeManager._componentTypesMask = new Map();
return ComponentTypeManager;
}());
var EntityList = (function () {
function EntityList(scene) {
this._entitiesToRemove = [];
this._entitiesToAdded = [];
this._tempEntityList = [];
this._entities = [];
this.scene = scene;
}
Object.defineProperty(EntityList.prototype, "count", {
get: function () {
return this._entities.length;
},
enumerable: true,
configurable: true
});
Object.defineProperty(EntityList.prototype, "buffer", {
get: function () {
return this._entities;
},
enumerable: true,
configurable: true
});
EntityList.prototype.add = function (entity) {
this._entitiesToAdded.push(entity);
};
EntityList.prototype.remove = function (entity) {
if (this._entitiesToAdded.contains(entity)) {
this._entitiesToAdded.remove(entity);
return;
}
if (!this._entitiesToRemove.contains(entity))
this._entitiesToRemove.push(entity);
};
EntityList.prototype.findEntity = function (name) {
for (var i = 0; i < this._entities.length; i++) {
if (this._entities[i].name == name)
return this._entities[i];
}
return this._entitiesToAdded.firstOrDefault(function (entity) { return entity.name == name; });
};
EntityList.prototype.update = function () {
for (var i = 0; i < this._entities.length; i++) {
var entity = this._entities[i];
if (entity.enabled)
entity.update();
}
};
EntityList.prototype.removeAllEntities = function () {
this._entitiesToAdded.length = 0;
this.updateLists();
for (var i = 0; i < this._entities.length; i++) {
this._entities[i].scene = null;
}
this._entities.length = 0;
};
EntityList.prototype.updateLists = function () {
var _this = this;
if (this._entitiesToRemove.length > 0) {
var temp = this._entitiesToRemove;
this._entitiesToRemove = this._tempEntityList;
this._tempEntityList = temp;
this._tempEntityList.forEach(function (entity) {
_this._entities.remove(entity);
entity.scene = null;
_this.scene.entityProcessors.forEach(function (processor) { return processor.remove(entity); });
});
this._tempEntityList.length = 0;
}
if (this._entitiesToAdded.length > 0) {
var temp = this._entitiesToAdded;
this._entitiesToAdded = this._tempEntityList;
this._tempEntityList = temp;
this._tempEntityList.forEach(function (entity) {
_this._entities.push(entity);
entity.scene = _this.scene;
_this.scene.entityProcessors.forEach(function (processor) { return processor.onChanged(entity); });
});
this._tempEntityList.length = 0;
}
};
return EntityList;
}());
var Matcher = (function () { var Matcher = (function () {
function Matcher() { function Matcher() {
this.allSet = new BitSet();
this.exclusionSet = new BitSet();
this.oneSet = new BitSet();
} }
Matcher.empty = function () { Matcher.empty = function () {
return new Matcher(); return new Matcher();
}; };
Matcher.prototype.IsIntersted = function (e) {
if (!this.allSet.isEmpty()) {
for (var i = this.allSet.nextSetBit(0); i >= 0; i = this.allSet.nextSetBit(i + 1)) {
if (!e.componentBits.get(i))
return false;
}
}
if (!this.exclusionSet.isEmpty() && this.exclusionSet.intersects(e.componentBits))
return false;
if (!this.oneSet.isEmpty() && !this.oneSet.intersects(e.componentBits))
return false;
return true;
};
return Matcher; return Matcher;
}()); }());
var MathHelper = (function () { var MathHelper = (function () {

File diff suppressed because one or more lines are too long

View File

@@ -30,4 +30,10 @@ abstract class Component {
return this; return this;
} }
/** 内部使用 运行时不应该调用 */
public registerComponent(){
this.entity.componentBits.set(ComponentTypeManager.getIndexFor(this));
this.entity.scene.entityProcessors.forEach(processor => processor.onChanged(this.entity));
}
} }

View File

@@ -20,7 +20,7 @@ class Camera extends Component {
} }
public update(){ public update(){
SceneManager.getActiveScene().entities.forEach(entity => entity.components.forEach(component => { SceneManager.getActiveScene().entities.buffer.forEach(entity => entity.components.forEach(component => {
if (component.displayRender){ if (component.displayRender){
let has = this.entity.scene.$children.indexOf(component.displayRender) let has = this.entity.scene.$children.indexOf(component.displayRender)
if (has == -1){ if (has == -1){

View File

@@ -9,6 +9,8 @@ class Entity {
private _updateOrder: number = 0; private _updateOrder: number = 0;
private _enabled: boolean = true; private _enabled: boolean = true;
public componentBits: BitSet;
public get enabled(){ public get enabled(){
return this._enabled; return this._enabled;
} }
@@ -29,6 +31,7 @@ class Entity {
this.name = name; this.name = name;
this.transform = new Transform(this); this.transform = new Transform(this);
this.components = []; this.components = [];
this.componentBits = new BitSet();
} }
public get updateOrder(){ public get updateOrder(){
@@ -52,7 +55,8 @@ class Entity {
public attachToScene(newScene: Scene){ public attachToScene(newScene: Scene){
this.scene = newScene; this.scene = newScene;
newScene.entities.push(this); newScene.entities.add(this);
this.components.forEach(component => component.registerComponent());
for (let i = 0; i < this.transform.childCount; i ++){ for (let i = 0; i < this.transform.childCount; i ++){
this.transform.getChild(i).entity.attachToScene(newScene); this.transform.getChild(i).entity.attachToScene(newScene);

View File

@@ -1,7 +1,7 @@
/** 场景 */ /** 场景 */
class Scene extends egret.DisplayObjectContainer { class Scene extends egret.DisplayObjectContainer {
public camera: Camera; public camera: Camera;
public entities: Entity[] = []; public readonly entities: EntityList;
private _projectionMatrix: Matrix2D; private _projectionMatrix: Matrix2D;
private _transformMatrix: Matrix2D; private _transformMatrix: Matrix2D;
@@ -14,6 +14,7 @@ class Scene extends egret.DisplayObjectContainer {
displayObject.stage.addChild(this); displayObject.stage.addChild(this);
this._projectionMatrix = new Matrix2D(0, 0, 0, 0, 0, 0); this._projectionMatrix = new Matrix2D(0, 0, 0, 0, 0, 0);
this.entityProcessors = []; this.entityProcessors = [];
this.entities = new EntityList(this);
this.addEventListener(egret.Event.ACTIVATE, this.onActive, this); this.addEventListener(egret.Event.ACTIVATE, this.onActive, this);
this.addEventListener(egret.Event.DEACTIVATE, this.onDeactive, this); this.addEventListener(egret.Event.DEACTIVATE, this.onDeactive, this);
@@ -27,18 +28,23 @@ class Scene extends egret.DisplayObjectContainer {
} }
public addEntity(entity: Entity){ public addEntity(entity: Entity){
this.entities.push(entity); this.entities.add(entity);
entity.scene = this; entity.scene = this;
for (let i = 0; i < entity.transform.childCount; i ++)
this.addEntity(entity.transform.getChild(i).entity);
return entity; return entity;
} }
public destoryAllEntities(){ public destroyAllEntities(){
this.entities.forEach(entity => entity.destory()); for (let i = 0; i < this.entities.count; i ++){
this.entities.buffer[i].destory();
}
} }
public findEntity(name: string): Entity{ public findEntity(name: string): Entity{
return this.entities.firstOrDefault(entity => entity.name == name); return this.entities.findEntity(name);
} }
/** /**
@@ -74,7 +80,7 @@ class Scene extends egret.DisplayObjectContainer {
/** 场景激活 */ /** 场景激活 */
public onActive(){ public onActive(){
} }
/** 场景失去焦点 */ /** 场景失去焦点 */
@@ -83,8 +89,10 @@ class Scene extends egret.DisplayObjectContainer {
} }
public update(){ public update(){
this.entities.updateLists();
this.entityProcessors.forEach(processor => processor.update()); this.entityProcessors.forEach(processor => processor.update());
this.entities.forEach(entity => entity.update()); this.entities.update();
this.entityProcessors.forEach(processor => processor.lateUpdate()); this.entityProcessors.forEach(processor => processor.lateUpdate());
} }
@@ -103,7 +111,6 @@ class Scene extends egret.DisplayObjectContainer {
this.camera.destory(); this.camera.destory();
this.camera = null; this.camera = null;
this.entities.forEach(entity => entity.destory()); this.entities.removeAllEntities();
this.entities.length = 0;
} }
} }

View File

@@ -21,7 +21,34 @@ class EntitySystem {
} }
public initialize(){ public initialize(){
}
public onChanged(entity: Entity){
let contains = this._entities.contains(entity);
let interest = this._matcher.IsIntersted(entity);
if (interest && !contains)
this.add(entity);
else if(!interest && contains)
this.remove(entity);
}
public add(entity: Entity){
this._entities.push(entity);
this.onAdded(entity);
}
public onAdded(entity: Entity){
}
public remove(entity: Entity){
this._entities.remove(entity);
this.onRemoved(entity);
}
public onRemoved(entity: Entity){
} }
public update(){ public update(){

View File

@@ -0,0 +1,129 @@
/**
* 这个类可以从两方面来考虑。你可以把它看成一个位向量或者一组非负整数。这个名字有点误导人。
*
* 它是由一个位向量实现的,但同样可以把它看成是一个非负整数的集合;集合中的每个整数由对应索引处的集合位表示。该结构的大小由集合中的最大整数决定。
*/
class BitSet{
private static LONG_MASK: number = 0x3f;
private _bits: number[];
constructor(nbits: number = 64){
let length = nbits >> 6;
if ((nbits & BitSet.LONG_MASK) != 0)
length ++;
this._bits = new Array(length);
}
public and(bs: BitSet){
let max = Math.min(this._bits.length, bs._bits.length);
let i;
for (let i = 0; i < max; ++i)
this._bits[i] &= bs._bits[i];
while (i < this._bits.length)
this._bits[i ++] = 0;
}
public andNot(bs: BitSet){
let i = Math.min(this._bits.length, bs._bits.length);
while(--i >= 0)
this._bits[i] &= ~bs._bits[i];
}
public cardinality(): number{
let card = 0;
for (let i = this._bits.length - 1; i >= 0; i --){
let a = this._bits[i];
if (a == 0)
continue;
if (a == -1){
card += 64;
continue;
}
a = ((a >> 1) & 0x5555555555555555) + (a & 0x5555555555555555);
a = ((a >> 2) & 0x3333333333333333) + (a & 0x3333333333333333);
let b = ((a >> 32) + a);
b = ((b >> 4) & 0x0f0f0f0f) + (b & 0x0f0f0f0f);
b = ((b >> 8) & 0x00ff00ff) + (b & 0x00ff00ff);
card += ((b >> 16) & 0x0000ffff) + (b & 0x0000ffff);
}
return card;
}
public clear(pos?: number){
if (pos != undefined){
let offset = pos >> 6;
this.ensure(offset);
this._bits[offset] &= ~(1 << pos);
}else{
for (let i = 0; i < this._bits.length; i ++)
this._bits[i] = 0;
}
}
private ensure(lastElt: number){
if (lastElt >= this._bits.length){
let nd = new Number[lastElt + 1];
nd = this._bits.copyWithin(0, 0, this._bits.length);
this._bits = nd;
}
}
public get(pos: number): boolean{
let offset = pos >> 6;
if (offset >= this._bits.length)
return false;
return (this._bits[offset] & (1 << pos)) != 0;
}
public intersects(set: BitSet){
let i = Math.min(this._bits.length, set._bits.length);
while (--i >= 0){
if ((this._bits[i] & set._bits[i]) != 0)
return true;
}
return false;
}
public isEmpty(): boolean{
for (let i = this._bits.length - 1; i >= 0; i --){
if (this._bits[i] != 0)
return false;
}
return true;
}
public nextSetBit(from: number){
let offset = from >> 6;
let mask = 1 << from;
while (offset < this._bits.length){
let h = this._bits[offset];
do {
if ((h & mask) != 0)
return from;
mask <<= 1;
from ++;
} while (mask != 0);
mask = 1;
offset ++;
}
return -1;
}
public set(pos: number){
let offset = pos >> 6;
this.ensure(offset);
this._bits[offset] |= 1 << pos;
}
}

View File

@@ -0,0 +1,18 @@
class ComponentTypeManager{
private static _componentTypesMask: Map<any, number> = new Map<any, number>();
public static add(type){
if (!this._componentTypesMask.has(type))
this._componentTypesMask[type] = this._componentTypesMask.size;
}
public static getIndexFor(type){
let v = -1;
if (!this._componentTypesMask.has(type)){
this.add(type);
v = this._componentTypesMask.get(type);
}
return v;
}
}

View File

@@ -0,0 +1,92 @@
class EntityList{
public scene: Scene;
private _entitiesToRemove: Entity[] = [];
private _entitiesToAdded: Entity[] = [];
private _tempEntityList: Entity[] = [];
private _entities: Entity[] = [];
constructor(scene: Scene){
this.scene = scene;
}
public get count(){
return this._entities.length;
}
public get buffer(){
return this._entities;
}
public add(entity: Entity){
this._entitiesToAdded.push(entity);
}
public remove(entity: Entity){
if (this._entitiesToAdded.contains(entity)){
this._entitiesToAdded.remove(entity);
return;
}
if (!this._entitiesToRemove.contains(entity))
this._entitiesToRemove.push(entity);
}
public findEntity(name: string){
for (let i = 0; i < this._entities.length; i ++){
if (this._entities[i].name == name)
return this._entities[i];
}
return this._entitiesToAdded.firstOrDefault(entity => entity.name == name);
}
public update(){
for (let i = 0; i < this._entities.length; i++){
let entity = this._entities[i];
if (entity.enabled)
entity.update();
}
}
public removeAllEntities(){
this._entitiesToAdded.length = 0;
this.updateLists();
for (let i = 0; i < this._entities.length; i ++){
this._entities[i].scene = null;
}
this._entities.length = 0;
}
public updateLists(){
if (this._entitiesToRemove.length > 0){
let temp = this._entitiesToRemove;
this._entitiesToRemove = this._tempEntityList;
this._tempEntityList = temp;
this._tempEntityList.forEach(entity => {
this._entities.remove(entity);
entity.scene = null;
this.scene.entityProcessors.forEach(processor => processor.remove(entity));
});
this._tempEntityList.length = 0;
}
if (this._entitiesToAdded.length > 0){
let temp = this._entitiesToAdded;
this._entitiesToAdded = this._tempEntityList;
this._tempEntityList = temp;
this._tempEntityList.forEach(entity => {
this._entities.push(entity);
entity.scene = this.scene;
this.scene.entityProcessors.forEach(processor => processor.onChanged(entity));
});
this._tempEntityList.length = 0;
}
}
}

View File

@@ -1,5 +1,26 @@
class Matcher{ class Matcher{
protected allSet = new BitSet();
protected exclusionSet = new BitSet();
protected oneSet = new BitSet();
public static empty(){ public static empty(){
return new Matcher(); return new Matcher();
} }
public IsIntersted(e: Entity){
if (!this.allSet.isEmpty()){
for (let i = this.allSet.nextSetBit(0); i >= 0; i = this.allSet.nextSetBit(i + 1)){
if (!e.componentBits.get(i))
return false;
}
}
if (!this.exclusionSet.isEmpty() && this.exclusionSet.intersects(e.componentBits))
return false;
if (!this.oneSet.isEmpty() && !this.oneSet.intersects(e.componentBits))
return false;
return true;
}
} }