MCPcopy Index your code
hub / github.com/melonjs/melonJS / removeChildNow

Method removeChildNow

packages/melonjs/src/renderable/container.js:791–867  ·  view source on GitHub ↗

* Removes (and optionally destroys) a child from the container. * (removal is immediate and unconditional) * Never use keepalive=true with objects from pool. Doing so will create a memory leak. * @param {Renderable|Entity|Sprite|Collectable|Trigger|Draggable|DropTarget|NineSlic

(child, keepalive)

Source from the content-addressed store, hash-verified

789 * @param {boolean} [keepalive=False] - True to prevent calling child.destroy()
790 */
791 removeChildNow(child, keepalive) {
792 if (this.hasChild(child) && this.getChildIndex(child) >= 0) {
793 if (typeof child.onDeactivateEvent === "function") {
794 child.onDeactivateEvent();
795 }
796
797 const root = this.getRootAncestor();
798
799 // Evict the child (and any descendants if it's a container)
800 // from the broadphase quadtree. The broadphase is rebuilt
801 // each `world.update()`, but pointer events and narrow-phase
802 // queries can fire between the deferred `removeChildNow` and
803 // the next rebuild — a stale reference there would return a
804 // destroyed renderable and crash any caller that read its
805 // `pos` (e.g. `_sortReverseZ`).
806 if (root?.broadphase) {
807 if (typeof child.addChild === "function") {
808 root.broadphase.removeContainer(child);
809 }
810 root.broadphase.remove(child);
811 }
812
813 // Remove the body first to avoid a condition where a body can
814 // be detached from its parent before it's removed from the
815 // game world. `child.body` may be a melonJS `Body` (legacy /
816 // builtin adapter) or an adapter-specific handle (e.g.
817 // `Matter.Body` under the matter adapter); either way the
818 // adapter knows how to clean it up by renderable identity.
819 if (child.body) {
820 /** @type {{ adapter?: { removeBody?: (r: object) => void } }} */
821 const world = root;
822 if (world?.adapter?.removeBody) {
823 world.adapter.removeBody(child);
824 } else if (child.body instanceof Body) {
825 // Container detached from the world tree — fall back to
826 // the legacy `world.removeBody(body)` path if available.
827 // This only handles a legacy `Body`; an adapter-specific
828 // handle reaching this branch silently leaks (warn so it
829 // surfaces in development).
830 root?.removeBody?.(child.body);
831 } else {
832 console.warn(
833 "melonJS: removeChildNow could not clean up an adapter-specific body — the container is not attached to a world with an adapter. The body remains in the physics engine.",
834 );
835 }
836 }
837
838 if (!keepalive) {
839 // attempt at recycling the object
840 if (pool.push(child, false) === false) {
841 // else just destroy it
842 if (typeof child.destroy === "function") {
843 child.destroy();
844 }
845 }
846 }
847
848 // Don't cache the child index; another element might have been removed

Callers 15

resetMethod · 0.95
parity.spec.tsFile · 0.80
deferredRemoveFunction · 0.80
addChildMethod · 0.80
addChildAtMethod · 0.80
imagelayer.spec.jsFile · 0.80
lights.spec.jsFile · 0.80
freshAlignmentStateFunction · 0.80
freshLitStateFunction · 0.80

Calls 11

hasChildMethod · 0.95
getChildIndexMethod · 0.95
getRootAncestorMethod · 0.95
getChildrenMethod · 0.95
updateBoundsMethod · 0.95
removeContainerMethod · 0.65
removeMethod · 0.65
removeBodyMethod · 0.65
destroyMethod · 0.65
onDeactivateEventMethod · 0.45
pushMethod · 0.45

Tested by 3

freshAlignmentStateFunction · 0.64
freshLitStateFunction · 0.64
drawPassFunction · 0.64