GotConfused
GotConfused

Reputation: 31

How to remove Box3 in ThreeJS?

I'm using Box3 to detect intersections so player could collect coins. I'd like the coin to be removed after detecting that it's intersecting with player but for some reason, I can't remove its (coin's) Box3.

I've read the documentation and deduced that Box3 is connected to the item's geometry, but removing the geometry and removing the item from the scene doesn't seem to remove Box3; it just stays in place, still interacting with player.

My code fiddle: https://jsfiddle.net/ImLost/g3mu1fqe/2/

Code:

        function main() {
            const canvas = document.querySelector('#canva');
            const renderer = new THREE.WebGLRenderer({ canvas });
            renderer.setSize(window.innerWidth, window.innerHeight);

            /* Camera */
            const fov = 40;
            const aspect = window.innerWidth / window.innerHeight;
            const near = 0.1;
            const far = 1000;
            const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
           
            camera.position.set(0, 65, -45);
            camera.up.set(0, 0, 1);
            camera.lookAt(0, 0, 0);

            const scene = new THREE.Scene();

            /* Lights */
            const mainLight = new THREE.DirectionalLight(0xffffff, .85);
            mainLight.position.set(0, 20, 0);
            scene.add(mainLight);
            mainLight.castShadow = true;
            mainLight.shadow.mapSize.width = 2048;
            mainLight.shadow.mapSize.height = 2048;

  
            /* Board */
            const boardGeometry = new THREE.PlaneGeometry(50, 50);
            const boardMaterial = new THREE.MeshToonMaterial({ color: 0xEEEEEE, side: THREE.DoubleSide });
            const board = new THREE.Mesh(boardGeometry, boardMaterial);
            board.rotation.x = Math.PI / 2; //The board must be placed flat on the x axis
            scene.add(board);

            /* Player */
            const playerBox = new THREE.Box3() // Used to determine collisions

            const playerGeometry = new THREE.BoxGeometry(1, 1, 1.5);
            const playerMaterial = new THREE.MeshToonMaterial({ color: 0xAAAAAA });
            const player = new THREE.Mesh(playerGeometry, playerMaterial);

            player.geometry.computeBoundingBox(playerBox);
            scene.add(player);

            /* Box helper */
            const playerHelper = new THREE.Box3Helper(playerBox, 0xffff00);
            scene.add(playerHelper);


            /* Coin */
            const smallCollectibleRadius = .4
            const bigCollectibleRadius = .6

            const coinBox = new THREE.Box3();

            const coinGeometry = new THREE.SphereGeometry(smallCollectibleRadius, 100, 100);
            const coinMaterial = new THREE.MeshToonMaterial({ color: 0xffff00, emissive: 0xffff00 });
            const coin = new THREE.Mesh(coinGeometry, coinMaterial);
            coin.position.set(0, 0, 3)
            scene.add(coin);

            coin.geometry.computeBoundingBox(coinBox);

            const coinHelper = new THREE.Box3Helper(coinBox, 0xffff00);
            scene.add(coinHelper);

            function checkCollision(box) {
                var collision = playerBox.intersectsBox(box);
                if (collision == true) {
                    return true
                }
            }

            document.addEventListener("keypress", function (event) {
                if (checkCollision(coinBox)) {
                    console.log("Yummy coin!")
                    coinGeometry.dispose()
                    coin.geometry.dispose()
                    scene.remove(coin)
                }
            });

            function render(time) {
                time *= 0.001;
                const speed = 0.0005
                const rotSpeed = 0.00005
                const dir = new THREE.Vector3();

                playerBox.copy(player.geometry.boundingBox).applyMatrix4(player.matrixWorld);
                coinBox.copy(coin.geometry.boundingBox).applyMatrix4(coin.matrixWorld);

                document.addEventListener("keypress", function (event) {
                    if (event.keyCode == 119) {
                        player.getWorldDirection(dir);
                        player.position.addScaledVector(dir, speed);
                    }
                    if (event.keyCode == 115) {
                        player.getWorldDirection(dir);
                        player.position.addScaledVector(dir, -speed);
                    }

                    if (event.keyCode == 97) {
                        player.rotation.y += rotSpeed
                    }

                    if (event.keyCode == 100) {
                        player.rotation.y -= rotSpeed
                    }
                });

                renderer.render(scene, camera);

                requestAnimationFrame(render);
            }

            requestAnimationFrame(render);
        }

        main();

Upvotes: 1

Views: 793

Answers (1)

TheJim01
TheJim01

Reputation: 8886

coinGeometry.dispose()
coin.geometry.dispose()
scene.remove(coin)

The code above does not invalidate your coin object, nor its .geometry property--it simply discards the buffer and attribute data from memory. Other properties, like boundingBox still exist. Otherwise, you would be getting errors when you copy the bounding box into coinBox after the coin has been "consumed."

Now, you can invalidate the whole coin by setting it to null:

scene.remove(coin)
coin = null

However, JavaScript is garbage-collected, and you may still be able to access the object before it is actually removed from the heap. I would recommend a simple logical workaround:

scene.remove(coin)
coin.userData.consumed = true
coin = null

Then in your renderer and key event listener, add checks for the new property:

document.addEventListener("keypress", function (event) {
  if (coin !== null && !('consumed' in coin.userData) && checkCollision(coinBox)) {
playerBox.copy(player.geometry.boundingBox).applyMatrix4(player.matrixWorld);
if( coin !== null && !('consumed' in coin.userData) ){
  coinBox.copy(coin.geometry.boundingBox).applyMatrix4(coin.matrixWorld);
}

Upvotes: 2

Related Questions