Search code examples
javascriptthree.jssceneterrainplane

removing a plane when another one is added threejs


My goal is to have a button which switches between terrain-generating functions and removes the previous terrain.

Currently, the buttons work but the plane's stack on top of eachother. Here is a photo of the problem (https://i.sstatic.net/UYvlG.png)

Two functions creating a lava-type terrain, and the other a cobblestone terrain. I have put them both into their own functions


  function lavaGround() {
    const planeLava = new THREE.Mesh(
      new THREE.PlaneGeometry(200, 200, 512, 512),
      new THREE.MeshStandardMaterial({
        //irrelevant code
      })
    );
    scene.add(planeLava);
  }

  function cobbleGround() {
    const planeCobble = new THREE.Mesh(
      new THREE.PlaneGeometry(200, 200, 512, 512),
      new THREE.MeshStandardMaterial({
      //irrelevant code
      })
    );
    scene.add(planeCobble);

two buttons which successfully add the new terrain to the scene.

  let cobbleButton = document.getElementById("cobblestone");
  cobbleButton.addEventListener("click", cobbleGround);

  let lavaButton = document.getElementById("lava");
  lavaButton.addEventListener("click", lavaGround);

Then to remove the other terrain, I tried using scene.remove to remove the other grounds but this did not work.

  let lavaButton = document.getElementById("lava");
      lavaButton.addEventListener("click", lavaGround);
      if (lavaGround) {
        scene.remove(planeCobble);
      }
let cobbleButton = document.getElementById("cobblestone");
    cobbleButton.addEventListener("click", cobbleGround);
    if (cobbleButton) {
      scene.remove(planeLava);
    }

I also tried creating one big terrain function but still did not work. Any ideas would be appreciated thanks !


Solution

  • depending on your code structure:

    • you can add an object and assign it to the created mesh (or a list and add new created meshs to this list), so that you can trace which object is created when removing them:
        let createdTerrain;
    
        function lavaGround() {
        const planeLava = new THREE.Mesh(
          new THREE.PlaneGeometry(200, 200, 512, 512),
          new THREE.MeshStandardMaterial({
            //irrelevant code
          })
         );
          // see if a terain exists, and remove it from the scene
          if(createdTerrain != null) scene.remove(createdTerrain)
          scene.add(planeLava);
          // store the created terain
          createdTerrain = planeLava
        }
    
        function cobbleGround() {
          const planeCobble = new THREE.Mesh(
          new THREE.PlaneGeometry(200, 200, 512, 512),
          new THREE.MeshStandardMaterial({
          //irrelevant code
          })
          );
            if(createdTerrain != null) scene.remove(createdTerrain)        
            scene.add(planeCobble);
            // store the created terain
            createdTerrain = planeCobble 
         }
    

    If these terrains are the same shape everytime they are created, you can store the two terrains so that the can be reused instead of creating new terrains everytime you call the method, ex:

        let planeLava;
        let planeCobble;
    
        function lavaGround() {
        if(planeLava != null) 
        {
           if(planeCobble != null) scene.remove(planeCobble)
           scene.add(planeLava)
        }
        else{
           const plane_Lava = new THREE.Mesh(
             new THREE.PlaneGeometry(200, 200, 512, 512),
             new THREE.MeshStandardMaterial({
              //irrelevant code
            })
          );
          // see if a previous terain exists, and remove it from the scene
          if(planeCobble != null) scene.remove(planeCobble)
          scene.add(planeLava);
          // store the created terain
          planeLava = plane_Lava
          }
        }
    

    Of course this can be furthure modified/optimized hope this helps