perf: collision hashes
This commit is contained in:
parent
ebc4ebd957
commit
3a37cf4938
|
@ -17,7 +17,7 @@ export default class Colliders extends System {
|
|||
if (!checked.has(entity)) {
|
||||
checked.set(entity, new Set());
|
||||
}
|
||||
const within = this.ecs.system('MaintainColliderHash').within(entity.Collider.aabb);
|
||||
const within = this.ecs.system('MaintainColliderHash').collisions(entity);
|
||||
for (const other of within) {
|
||||
if (entity === other || !other.Collider) {
|
||||
continue;
|
||||
|
|
|
@ -3,12 +3,103 @@ import SpatialHash from '@/util/spatial-hash.js';
|
|||
|
||||
export default class MaintainColliderHash extends System {
|
||||
|
||||
hash;
|
||||
AreaSize;
|
||||
|
||||
groups = new Map();
|
||||
|
||||
collisions(entity) {
|
||||
const collisions = new Set();
|
||||
const {aabb, bodies} = entity.Collider;
|
||||
for (let {bits, group, mask} of bodies) {
|
||||
const bitsList = [];
|
||||
const maskList = [];
|
||||
let bit = 0;
|
||||
while (bits > 0) {
|
||||
if (bits & 1) {
|
||||
bitsList.push(bit);
|
||||
}
|
||||
bit += 1;
|
||||
bits >>= 1;
|
||||
}
|
||||
if (mask !== 4294967295) {
|
||||
bit = 0;
|
||||
while (mask > 0) {
|
||||
if (mask & 1) {
|
||||
maskList.push(bit);
|
||||
}
|
||||
bit += 1;
|
||||
mask >>= 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
maskList.push(-1);
|
||||
}
|
||||
for (const [key, hashes] of this.groups) {
|
||||
if (group === key && group < 0) {
|
||||
continue;
|
||||
}
|
||||
if (group === key && group > 0) {
|
||||
const within = hashes.group.within(aabb);
|
||||
for (const other of within) {
|
||||
if (other !== entity.id) {
|
||||
collisions.add(this.ecs.get(other));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (key !== group || 0 === key) {
|
||||
if (maskList.length > 0) {
|
||||
if (-1 === maskList[0]) {
|
||||
for (const [, hash] of hashes.bits) {
|
||||
const within = hash.within(aabb);
|
||||
for (const other of within) {
|
||||
if (other !== entity.id) {
|
||||
collisions.add(this.ecs.get(other));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const mask of maskList) {
|
||||
if (!hashes.bits.get(mask)) {
|
||||
continue;
|
||||
}
|
||||
const within = hashes.bits.get(mask).within(aabb);
|
||||
for (const other of within) {
|
||||
if (other !== entity.id) {
|
||||
collisions.add(this.ecs.get(other));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const bits of bitsList) {
|
||||
if (!hashes.mask.get(bits)) {
|
||||
continue;
|
||||
}
|
||||
const within = hashes.mask.get(bits).within(aabb);
|
||||
for (const other of within) {
|
||||
if (other !== entity.id) {
|
||||
collisions.add(this.ecs.get(other));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return collisions;
|
||||
}
|
||||
|
||||
deindex(entities) {
|
||||
super.deindex(entities);
|
||||
for (const id of entities) {
|
||||
this.hash.remove(id);
|
||||
for (const [, hashes] of this.groups) {
|
||||
for (const id of entities) {
|
||||
hashes.group.remove(id);
|
||||
for (const map of [hashes.bits, hashes.mask]) {
|
||||
for (const [, hash] of map) {
|
||||
hash.remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,22 +113,61 @@ export default class MaintainColliderHash extends System {
|
|||
for (const id of entities) {
|
||||
if (1 === id) {
|
||||
const {AreaSize} = this.ecs.get(1);
|
||||
if (AreaSize) {
|
||||
this.hash = new SpatialHash(AreaSize);
|
||||
}
|
||||
this.AreaSize = AreaSize;
|
||||
this.groups.clear();
|
||||
}
|
||||
}
|
||||
super.reindex(entities);
|
||||
for (const id of entities) {
|
||||
this.updateHash(this.ecs.get(id));
|
||||
this.updateHashes(this.ecs.get(id));
|
||||
}
|
||||
}
|
||||
|
||||
updateHash(entity) {
|
||||
if (!entity.Collider || !this.hash) {
|
||||
updateHashes(entity) {
|
||||
if (!entity.Collider || !this.AreaSize) {
|
||||
return;
|
||||
}
|
||||
this.hash.update(entity.Collider.aabb, entity.id);
|
||||
const {bodies} = entity.Collider;
|
||||
for (let {bits, group, mask} of bodies) {
|
||||
if (!this.groups.has(group)) {
|
||||
this.groups.set(group, {
|
||||
bits: new Map(),
|
||||
group: new SpatialHash(this.AreaSize),
|
||||
mask: new Map(),
|
||||
});
|
||||
}
|
||||
this.groups.get(group).group.update(entity.Collider.aabb, entity.id);
|
||||
let bit = 0;
|
||||
while (bits > 0) {
|
||||
if (bits & 1) {
|
||||
if (!this.groups.get(group).bits.has(bit)) {
|
||||
this.groups.get(group).bits.set(bit, new SpatialHash(this.AreaSize));
|
||||
}
|
||||
this.groups.get(group).bits.get(bit).update(entity.Collider.aabb, entity.id);
|
||||
}
|
||||
bit += 1;
|
||||
bits >>= 1;
|
||||
}
|
||||
if (mask !== 4294967295) {
|
||||
bit = 0;
|
||||
while (mask > 0) {
|
||||
if (mask & 1) {
|
||||
if (!this.groups.get(group).mask.has(bit)) {
|
||||
this.groups.get(group).mask.set(bit, new SpatialHash(this.AreaSize));
|
||||
}
|
||||
this.groups.get(group).mask.get(bit).update(entity.Collider.aabb, entity.id);
|
||||
}
|
||||
bit += 1;
|
||||
mask >>= 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!this.groups.get(group).mask.has(-1)) {
|
||||
this.groups.get(group).mask.set(-1, new SpatialHash(this.AreaSize));
|
||||
}
|
||||
this.groups.get(group).mask.get(-1).update(entity.Collider.aabb, entity.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tick() {
|
||||
|
@ -48,14 +178,14 @@ export default class MaintainColliderHash extends System {
|
|||
entity.Collider.updateAabbs();
|
||||
}
|
||||
for (const entity of this.ecs.changed(['Position'])) {
|
||||
this.updateHash(entity);
|
||||
this.updateHashes(entity);
|
||||
}
|
||||
}
|
||||
|
||||
within(query) {
|
||||
const within = new Set();
|
||||
if (this.hash) {
|
||||
for (const id of this.hash.within(query)) {
|
||||
for (const [, hashes] of this.groups) {
|
||||
for (const id of hashes.group.within(query)) {
|
||||
within.add(this.ecs.get(id));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user