新增hashSet

This commit is contained in:
yhh
2020-11-27 11:07:43 +08:00
parent 6113fd9986
commit bac1ce5b7a
11 changed files with 697 additions and 122 deletions

View File

@@ -8,7 +8,7 @@ module es {
}
}
export class Entity {
export class Entity implements IEqualityComparable {
public static _idGenerator: number = 0;
public static entityComparer: IComparer<Entity> = new EntityComparer();
/**
@@ -399,6 +399,14 @@ module es {
return compare;
}
public equals(other: Entity): boolean {
return this.compareTo(other) == 0;
}
public getHashCode(): number {
return this.id;
}
public toString(): string {
return `[Entity: name: ${this.name}, tag: ${this.tag}, enabled: ${this.enabled}, depth: ${this.updateOrder}]`;
}

View File

@@ -8,11 +8,11 @@ module es {
/**
* 本帧添加的实体列表。用于对实体进行分组,以便我们可以同时处理它们
*/
public _entitiesToAdded: Set<Entity> = new Set<Entity>();
public _entitiesToAdded: HashSet<Entity> = new HashSet<Entity>();
/**
* 本帧被标记为删除的实体列表。用于对实体进行分组,以便我们可以同时处理它们
*/
public _entitiesToRemove: Set<Entity> = new Set<Entity>();
public _entitiesToRemove: HashSet<Entity> = new HashSet<Entity>();
/**
* 标志,用于确定我们是否需要在这一帧中对实体进行排序
*/
@@ -56,18 +56,18 @@ module es {
* @param entity
*/
public remove(entity: Entity) {
if (!this._entitiesToRemove.has(entity)) {
if (!this._entitiesToRemove.contains(entity)) {
console.warn(`您正在尝试删除已经删除的实体(${entity.name})`);
return;
}
// 防止在同一帧中添加或删除实体
if (this._entitiesToAdded.has(entity)) {
this._entitiesToAdded.delete(entity);
if (this._entitiesToAdded.contains(entity)) {
this._entitiesToAdded.remove(entity);
return;
}
if (!this._entitiesToRemove.has(entity))
if (!this._entitiesToRemove.contains(entity))
this._entitiesToRemove.add(entity);
}
@@ -98,7 +98,7 @@ module es {
* @param entity
*/
public contains(entity: Entity): boolean {
return this._entities.contains(entity) || this._entitiesToAdded.has(entity);
return this._entities.contains(entity) || this._entitiesToAdded.contains(entity);
}
public getTagList(tag: number) {
@@ -128,15 +128,15 @@ module es {
public update() {
for (let i = 0; i < this._entities.length; i++) {
let entity = this._entities[i];
let entity = this._entities.buffer[i];
if (entity.enabled && (entity.updateInterval == 1 || Time.frameCount % entity.updateInterval == 0))
entity.update();
}
}
public updateLists() {
if (this._entitiesToRemove.size > 0) {
for (let i = 0; i< this._entitiesToRemove.size; i ++) {
if (this._entitiesToRemove.getCount() > 0) {
for (let i = 0; i< this._entitiesToRemove.getCount(); i ++) {
let entity = this._entitiesToRemove[i];
// 处理标签列表
this.removeFromTagList(entity);
@@ -153,9 +153,9 @@ module es {
this._entitiesToRemove.clear();
}
if (this._entitiesToAdded.size > 0) {
for (let i = 0; i < this._entitiesToAdded.size; i ++) {
let entity = this._entitiesToAdded[i];
if (this._entitiesToAdded.getCount() > 0) {
for (let i = 0; i < this._entitiesToAdded.getCount(); i ++) {
let entity = this._entitiesToAdded.toArray()[i];
this._entities.add(entity);
entity.scene = this.scene;
@@ -165,8 +165,8 @@ module es {
this.scene.entityProcessors.onEntityAdded(entity);
}
for (let i = 0; i < this._entitiesToAdded.size; i ++)
this._entitiesToAdded[i].onAddedToScene();
for (let i = 0; i < this._entitiesToAdded.getCount(); i ++)
this._entitiesToAdded.toArray()[i].onAddedToScene();
this._entitiesToAdded.clear();
this._isEntityListUnsorted = true;
@@ -179,8 +179,7 @@ module es {
// 根据需要对标签列表进行排序
if (this._unsortedTags.size == 0) {
for (let i = 0; i < this._unsortedTags.size; i ++)
this._entityDict.get(this._unsortedTags[i]).sort();
this._unsortedTags.forEach(value => this._entityDict.get(value).sort((a, b) => a.compareTo(b)));
this._unsortedTags.clear();
}
@@ -196,9 +195,10 @@ module es {
return this._entities[i];
}
for (let i = 0; i < this._entitiesToAdded.size; i ++){
if (this._entitiesToAdded[i].name == name)
return this._entitiesToAdded[i];
for (let i = 0; i < this._entitiesToAdded.getCount(); i ++){
let entity = this._entitiesToAdded.toArray()[i];
if (entity.name == name)
return entity;
}
return null;
@@ -232,10 +232,10 @@ module es {
list.push(this._entities[i] as T);
}
for (let i = 0; i < this._entitiesToAdded.size; i ++){
let entity = this._entitiesToAdded[i];
if (entity instanceof type) {
list.push(entity);
for (let i = 0; i < this._entitiesToAdded.getCount(); i ++){
let entity = this._entitiesToAdded.toArray()[i];
if (TypeUtils.getType(entity) instanceof type) {
list.push(entity as T);
}
}
@@ -255,8 +255,8 @@ module es {
}
}
for (let i = 0; i < this._entitiesToAdded.size; i++) {
let entity: Entity = this._entitiesToAdded[i];
for (let i = 0; i < this._entitiesToAdded.getCount(); i++) {
let entity: Entity = this._entitiesToAdded.toArray()[i];
if (entity.enabled) {
let comp = entity.getComponent<T>(type);
if (comp)
@@ -279,8 +279,8 @@ module es {
this._entities[i].getComponents(type, comps);
}
for (let i = 0; i < this._entitiesToAdded.size; i++) {
let entity = this._entitiesToAdded[i];
for (let i = 0; i < this._entitiesToAdded.getCount(); i++) {
let entity = this._entitiesToAdded.toArray()[i];
if (entity.enabled)
entity.getComponents(type, comps);
}

View File

@@ -5,9 +5,9 @@ module es {
export class ColliderTriggerHelper {
private _entity: Entity;
/** 存储当前帧中发生的所有活动交点对 */
private _activeTriggerIntersections: Set<Pair<Collider>> = new Set();
private _activeTriggerIntersections: HashSet<Pair<Collider>> = new HashSet<Pair<Collider>>();
/** 存储前一帧的交点对,这样我们就可以在移动这一帧后检测到退出 */
private _previousTriggerIntersections: Set<Pair<Collider>> = new Set();
private _previousTriggerIntersections: HashSet<Pair<Collider>> = new HashSet<Pair<Collider>>();
private _tempTriggerList: ITriggerListener[] = [];
constructor(entity: Entity) {
@@ -36,8 +36,8 @@ module es {
let pair = new Pair<Collider>(collider, neighbor);
// 如果我们的某一个集合中已经有了这个对子(前一个或当前的触发交叉点),就不要调用输入事件了
let shouldReportTriggerEvent = !this._activeTriggerIntersections.has(pair) &&
!this._previousTriggerIntersections.has(pair);
let shouldReportTriggerEvent = !this._activeTriggerIntersections.contains(pair) &&
!this._previousTriggerIntersections.contains(pair);
if (shouldReportTriggerEvent)
this.notifyTriggerListeners(pair, true);
@@ -54,39 +54,21 @@ module es {
private checkForExitedColliders() {
// 删除所有与此帧交互的触发器,留下我们退出的触发器
this.excepthWith(this._previousTriggerIntersections, this._activeTriggerIntersections);
this._previousTriggerIntersections.exceptWith(this._activeTriggerIntersections.toArray());
for (let i = 0; i < this._previousTriggerIntersections.size; i++) {
for (let i = 0; i < this._previousTriggerIntersections.getCount(); i++) {
this.notifyTriggerListeners(this._previousTriggerIntersections[i], false)
}
this._previousTriggerIntersections.clear();
// 添加所有当前激活的触发器
this.unionWith(this._previousTriggerIntersections, this._activeTriggerIntersections);
this._previousTriggerIntersections.unionWith(this._activeTriggerIntersections.toArray());
// 清空活动集,为下一帧做准备
this._activeTriggerIntersections.clear();
}
private excepthWith(previous: Set<Pair<Collider>>, active: Set<Pair<Collider>>){
for (let i = 0; i < previous.size; i ++){
let previousDATA: Pair<Collider> = previous[i];
for (let j = 0; j < active.size; j ++){
let activeDATA: Pair<Collider> = active[j];
if (activeDATA.equals(previousDATA))
previous.delete(previousDATA);
}
}
}
private unionWith(previous: Set<Pair<Collider>>, active: Set<Pair<Collider>>) {
for (let i = 0; i < this._activeTriggerIntersections.size; i ++) {
if (!this._previousTriggerIntersections.has(this._activeTriggerIntersections[i]))
this._previousTriggerIntersections.add(this._activeTriggerIntersections[i]);
}
}
private notifyTriggerListeners(collisionPair: Pair<Collider>, isEntering: boolean) {
TriggerListenerHelper.getITriggerListener(collisionPair.first.entity, this._tempTriggerList);
for (let i = 0; i < this._tempTriggerList.length; i++) {

View File

@@ -1,17 +1,61 @@
module es {
export class EqualityComparer<T> implements IEqualityComparer {
public static default<T>(){
export class EqualityComparer<T> implements IEqualityComparer<T> {
public static default<T>() {
return new EqualityComparer<T>();
}
protected constructor(){ }
protected constructor() { }
public equals(x: T, y: T): boolean{
if (typeof x["equals"] == 'function'){
public equals(x: T, y: T): boolean {
if (typeof x["equals"] == 'function') {
return x["equals"](y);
} else {
return x === y;
}
}
public getHashCode(o: T): number {
if (typeof o == 'number') {
return this._getHashCodeForNumber(o);
}
if (typeof o == 'string') {
return this._getHashCodeForString(o);
}
let hashCode = 385229220;
this.forOwn(o, (value) => {
if (typeof value == 'number') {
hashCode += this._getHashCodeForNumber(value);
} else if (typeof value == 'string') {
hashCode += this._getHashCodeForString(value);
} else if (typeof value == 'object') {
this.forOwn(value, () => {
hashCode += this.getHashCode(value);
});
}
});
return hashCode;
}
private _getHashCodeForNumber(n: number): number {
return n;
}
private _getHashCodeForString(s: string): number {
let hashCode = 385229220;
for (let i = 0; i < s.length; i++) {
hashCode = (hashCode * -1521134295) ^ s.charCodeAt(i);
}
return hashCode;
}
private forOwn(object, iteratee){
object = Object(object);
Object.keys(object).forEach((key) => iteratee(object[key], key, object));
}
}
}

View File

@@ -0,0 +1,17 @@
module es {
/**
* 对象声明自己的平等方法和Hashcode的生成
*/
export interface IEqualityComparable {
/**
* 确定另一个对象是否等于这个实例
* @param other
*/
equals(other: any): boolean;
/**
* 生成对象的哈希码
*/
getHashCode(): number;
}
}

View File

@@ -1,5 +1,19 @@
module es {
export interface IEqualityComparer {
equals(x: any, y: any): boolean;
/**
* 为确定对象的哈希码和两个项目是否相等提供接口
*/
export interface IEqualityComparer<T> {
/**
* 判断两个对象是否相等
* @param x
* @param y
*/
equals(x: T, y: T): boolean;
/**
* 生成对象的哈希码
* @param value
*/
getHashCode(value: T): number;
}
}

View File

@@ -2,7 +2,7 @@ module es {
/**
* 用于管理一对对象的简单DTO
*/
export class Pair<T> implements IEquatable<Pair<T>> {
export class Pair<T> implements IEqualityComparable {
public first: T;
public second: T;
@@ -19,5 +19,10 @@ module es {
// 这两种方法在功能上应该是等价的
return this.first == other.first && this.second == other.second;
}
public getHashCode(): number {
return EqualityComparer.default<T>().getHashCode(this.first) * 37 +
EqualityComparer.default<T>().getHashCode(this.second);
}
}
}

204
source/src/Utils/Set.ts Normal file
View File

@@ -0,0 +1,204 @@
module es {
export interface ISet<T> {
add(item: T): boolean
remove(item: T): boolean
contains(item: T): boolean
getCount(): number
clear(): void
toArray(): Array<T>
/**
* 从当前集合中删除指定集合中的所有元素
* @param other
*/
exceptWith(other: Array<T>): void
/**
* 修改当前Set对象使其只包含该对象和指定数组中的元素
* @param other
*/
intersectWith(other: Array<T>): void
/**
* 修改当前的集合对象,使其包含所有存在于自身、指定集合中的元素,或者两者都包含
* @param other
*/
unionWith(other: Array<T>): void
isSubsetOf(other: Array<T>): boolean
isSupersetOf(other: Array<T>): boolean
overlaps(other: Array<T>): boolean
setEquals(other: Array<T>): boolean
}
interface IBucketsWithCount<T> {
Buckets: Array<Array<T>>
Count: number
}
abstract class Set<T> implements ISet<T> {
protected buckets: T[][];
protected count: number;
constructor(source?: Array<T>) {
this.clear();
if (source)
source.forEach(value => {
this.add(value);
});
}
abstract getHashCode(item: T): number;
abstract areEqual(value1: T, value2: T): boolean;
add(item: T) {
let hashCode = this.getHashCode(item);
let bucket = this.buckets[hashCode];
if (bucket === undefined) {
let newBucket = new Array<T>();
newBucket.push(item);
this.buckets[hashCode] = newBucket;
this.count = this.count + 1;
return true;
}
if (bucket.some((value) => this.areEqual(value,item)))
return false;
bucket.push(item);
this.count = this.count + 1;
return true;
};
remove(item: T) {
let hashCode = this.getHashCode(item);
let bucket = this.buckets[hashCode];
if (bucket === undefined) {
return false;
}
let result = false;
let newBucket = new Array<T>();
bucket.forEach((value) => {
if (!this.areEqual(value, item))
newBucket.push(item);
else
result = true;
});
this.buckets[hashCode] = newBucket;
if (result)
this.count = this.count - 1;
return result;
}
contains(item: T) {
return this.bucketsContains(this.buckets, item)
};
getCount() {
return this.count;
}
clear() {
this.buckets = new Array<Array<T>>();
this.count = 0;
}
toArray() {
let result = new Array<T>()
this.buckets.forEach(value => {
value.forEach(inner => {
result.push(inner);
});
});
return result;
}
/**
* 从当前集合中删除指定集合中的所有元素
* @param other
*/
exceptWith(other: Array<T>) {
if (other) {
other.forEach(value => {
this.remove(value);
})
}
}
/**
* 修改当前Set对象使其只包含该对象和指定数组中的元素
* @param other
*/
intersectWith(other: Array<T>) {
if (other) {
let otherBuckets = this.buildInternalBuckets(other);
this.toArray().forEach(value => {
if (!this.bucketsContains(otherBuckets.Buckets, value))
this.remove(value);
});
}
else {
this.clear();
}
}
unionWith(other: Array<T>) {
other.forEach(value => {
this.add(value);
});
}
isSubsetOf(other: Array<T>) {
let otherBuckets = this.buildInternalBuckets(other);
return this.toArray().every(value => this.bucketsContains(otherBuckets.Buckets, value));
}
isSupersetOf(other: Array<T>) {
return other.every(value => this.contains(value));
}
overlaps(other: Array<T>) {
return other.some(value => this.contains(value));
}
setEquals(other: Array<T>) {
let otherBuckets = this.buildInternalBuckets(other);
if (otherBuckets.Count !== this.count)
return false
return other.every(value => this.contains(value));
}
private buildInternalBuckets(source: Array<T>): IBucketsWithCount<T> {
let internalBuckets = new Array<Array<T>>();
let internalCount = 0;
source.forEach(item=> {
let hashCode = this.getHashCode(item);
let bucket = internalBuckets[hashCode];
if (bucket === undefined) {
let newBucket = new Array<T>();
newBucket.push(item);
internalBuckets[hashCode] = newBucket;
internalCount = internalCount + 1;
}
else if (!bucket.some((value) => this.areEqual(value, item))) {
bucket.push(item);
internalCount = internalCount + 1;
}
});
return { Buckets: internalBuckets, Count: internalCount };
}
private bucketsContains(internalBuckets: Array<Array<T>>, item: T) {
let hashCode = this.getHashCode(item);
let bucket = internalBuckets[hashCode];
if (bucket === undefined) {
return false;
}
return bucket.some((value) => this.areEqual(value, item));
}
}
export class HashSet<T extends IEqualityComparable> extends Set<T> {
constructor(source?: Array<T>) {
super(source)
}
getHashCode(item: T) {
return item.getHashCode();
}
areEqual(value1: T, value2: T) {
return value1.equals(value2);
}
}
}