The last version of box2d.ts on github, with bad performance.
I pull & build the last version of box2d.ts and run my performance test again. the fps is from 60fps to 30FPS
the version https://github.com/flyover/box2d.ts/commit/f8d1af84ab6d09f970877aea117efa5f7f1c79af is still fast.
Is b2List the criminal ?
BTW , I hope you could use linked-list again , because the native Box2d use it. And it's fast.
With original box2d.ts ( linked-list version) , I could do this:
for (var b = world.m_bodyList; b; b = b.m_next) {
// ...
}
for fetch bodies. It is as same as box2d .
And I found the iterator (Symbol.iterator) is also very slow in js.
I'll try to implement a b2LinkedList & b2LinkedListNode . Then I will create a PR.
Thanks for the feedback. I'm already working on a linked-list version of b2List. I suppose the overhead for the "downlevelIteration" option is causing the slowdown. In any case, it's much easier now to swap out list implementations.
OK. this is my linked list , I hope it could give some help :
export class b2LinkedListNode {
public m_next: b2LinkedListNode = null;
public m_prev: b2LinkedListNode = null;
}
export class b2LinkedList<T extends b2LinkedListNode>{
public readonly head: b2LinkedListNode = new b2LinkedListNode();
public readonly tail: b2LinkedListNode = new b2LinkedListNode();
public size: number = 0;
public clear(): void {
this.head.m_next = this.tail;
this.tail.m_prev = this.head;
this.head.m_prev = this.tail.m_next = null;
this.size = 0;
}
public add(value: b2LinkedListNode): void {
value.m_prev = this.tail.m_prev;
value.m_next = this.tail;
value.m_prev.m_next = this.tail.m_prev = value;
this.size++;
}
public delete(value: b2LinkedListNode): void {
value.m_prev.m_next = value.m_next;
value.m_next.m_prev = value.m_prev;
value.m_next = value.m_prev = null;
this.size--;
}
public forEach(fn: (node: T, index: number, thisArg: any) => any): boolean {
let index = -1;
let node = this.head;
while ((node = node.m_next) !== this.tail) {
index++;
// if `fn()` returns `true` , `forEach` will stop, and return `true`
const _break = fn(node as T, index, this);
if (_break === true) {
return true;
}
}
return false;
}
}
. .
the use-case : ( b2Body & b2Joint are extends b2LinkedListNode )
public ShouldCollideConnected(other: b2Body): boolean {
// Does a joint prevent collision?
let _break: boolean = false;
_break = this.m_jointList.forEach((joint) => {
if (joint.GetOtherBody(this) === other) {
if (!joint.m_collideConnected) {
return true;
}
}
return false;
});
return _break ? false : true;
}
Thanks for the code sample. I reverted all the container changes until I can test them more completely.
@flyover I found forEach is also with bad performance.
for (var b = world.m_bodyList.m_first; b; b = b.m_next) {
}
is better.
@flyover, have you tried something like Map or Set for storage purposes? I think it will iterate much faster than the current approach. Also, they both don't require iteration for delete operations. There are also weak versions of them. WeakMap and WeakSet. They keep a weak reference to objects you put inside them. When you delete all the references to those objects from everywhere else they get garbage collected.
Changing to Map and Set and iterating using for..in is what caused the slowdown. At that time, leaving it as a linked-list was faster. I still have this change archived and can merge it back if it ever runs faster.