Removing an object in Three.js using scene.getObjectByName() method

When developing my game, I encountered a challenge. I'm loading 4 different buildings and creating 15 clones of each within a for loop. These clones are then added to an array called masterBuildingArray, which I iterate through using a forEach loop. The buildings are loaded using the .MTL and .OBJ loaders.

Since the buildings are meant for a city environment, I implemented a randomization algorithm to shuffle the order of the buildings in the array. I then used if statements to arrange every 10 buildings into 3 rows on either side of a central road.

The Challenge I'm Facing

I need the ability to remove specific objects from the array, especially landmark buildings that should be placed in certain positions. For instance, I know the building closest to the camera on the right side has a position of approximately (550, -75, 800). Although the X and Z positions have slight variations.

The code snippet is included at the end of this question

Possible Solutions

To address this issue, I inserted an index counter into my forEach loop and assigned it to each building as userData to facilitate access. My approach was to use a conditional statement within the forEach loop as follows:

if (highriseBuilding.userData.index == 31) {
    initialBuildingName = highriseBuilding.name;
    highriseBuilding.name = highriseBuilding.name + "_toBeRemoved";
}

By appending "_toBeRemoved" to the building name in the desired position, my objective was to remove that object from the scene.

I attempted to remove it using the following code snippet:

scene.remove(scene.getObjectByName(initialBuildingName + "_toBeRemoved"));

However, this approach proved ineffective regardless of where I placed it (inside the initial forEach loop, in a separate loop that iterated over the masterBuildingArray after the initial loop, etc.).

See the code below:

Sample code for loading a building:

function createHighrise4() {

var onProgress = function ( xhr ) {
    if ( xhr.lengthComputable ) {
        var percentComplete = xhr.loaded / xhr.total * 100;
        console.log( Math.round(percentComplete, 2) + '% downloaded' );
    }
};

var onError = function ( xhr ) { };
THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader(loadingManager) );
var mtlLoader = new THREE.MTLLoader(loadingManager);
mtlLoader.setPath( '/objects/highrise4_white_curved/' );

mtlLoader.load( 'highrise4_white_curved.mtl', function( materials ) {

    materials.preload();

    var objLoader = new THREE.OBJLoader(loadingManager);

    objLoader.setMaterials( materials );
    objLoader.setPath( '/objects/highrise4_white_curved/' );

    objLoader.load( 'highrise4_white_curved.obj', function ( highrise4_white_curved ) {

        highrise4_white_curved.scale.set(10,10,10);

        highrise4_white_curved.traverse( function ( child ) {
                if ( child instanceof THREE.Mesh ) {
                    child.receiveShadow = true;
                    child.castShadow = true;
                }
            } );

        for (let i = 0; i < 15; i++) {

            clonedHighrise4 = highrise4_white_curved.clone();
            clonedHighrise4.name = "highrise4_white_curved";
            masterBuildingArray.push(clonedHighrise4);

        }

    }, onProgress, onError );

});

}

Building placement logic + attempted solution:

function loopThroughBuildingArray() {

randomShuffle(masterBuildingArray);

masterBuildingArray.forEach(function(highriseBuilding, i){

    let building_randomYScale = Math.floor(Math.random() * (15 - 10) + 10);
    highriseBuilding.userData.index = i;

    if (i < 10) {
        rowLeft1.push(highriseBuilding);
        highriseBuilding.position.z = Math.floor(Math.random() * (950 - 850) + 850);
        highriseBuilding.position.x = incrementLeft1;
        incrementLeft1 -= Math.floor(Math.random() * (800 - 550) + 550);
    }
    if (i >= 10 && i < 20) {
        rowLeft2.push(highriseBuilding);
        highriseBuilding.position.z = Math.floor(Math.random() * (50 - -50) + -50);
        highriseBuilding.position.x = incrementLeft2;
        incrementLeft2 -= Math.floor(Math.random() * (800 - 550) + 550);
    }
    if (i >= 20 && i < 30) {
        rowLeft3.push(highriseBuilding);
        highriseBuilding.position.z = Math.floor(Math.random() * (-950 - -850) + -850);
        highriseBuilding.position.x = incrementLeft3;
        incrementLeft3 -= Math.floor(Math.random() * (800 - 550) + 550);
    }
    if (i >= 30 && i < 40) {
        rowRight1.push(highriseBuilding);
        highriseBuilding.position.z = Math.floor(Math.random() * (950 - 850) + 850);
        highriseBuilding.position.x = incrementRight1;
        incrementRight1 += Math.floor(Math.random() * (800 - 550) + 550);
    }
    if (i >= 40 && i < 50) {
        rowRight2.push(highriseBuilding);
        highriseBuilding.position.z = Math.floor(Math.random() * (50 - -50) + -50);
        highriseBuilding.position.x = incrementRight2;
        incrementRight2 += Math.floor(Math.random() * (800 - 550) + 550);
    }
    if (i >= 50 && i < 60) {
        rowRight3.push(highriseBuilding);
        highriseBuilding.position.z = Math.floor(Math.random() * (-950 - -850) + -850);
        highriseBuilding.position.x = incrementRight3;
        incrementRight3 += Math.floor(Math.random() * (800 - 550) + 550);
    }
    // 31 is building in position: right side, bottom left corner (closest to camera & road on right side)

    if (highriseBuilding.userData.index == 31) {
        initialBuildingName = highriseBuilding.name;
        highriseBuilding.name = highriseBuilding.name + "_toBeRemoved";

    }

    highriseBuilding.scale.y = building_randomYScale;
    highriseBuilding.position.y = -75;
//        highriseBuilding.position.y = (highriseBuildingBoundingBox.max.y * highriseBuilding.scale.y) / 2;


    cityScape.add(highriseBuilding);

});

cityScape.position.z = -9300;
cityScape.scale.set(0.5, 0.5, 0.5);
scene.add(cityScape);
scene.remove(scene.getObjectByName(initialBuildingName + "_toBeRemoved"));
}

I would greatly appreciate any insights or assistance with this seemingly simple issue that has me stumped!

Answer №1

By default, the name of any three objects is an empty string. When using scene.getObjectByName, it will return the first object with the specified name. Therefore, using

scene.remove(scene.getObjectByName(initialBuildingName + "_toBeRemoved"));
will always target the first object added, as they all share the same name "_toBeRemoved". To avoid this, assign unique names to each building.

I hope this explanation is helpful.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it necessary to use `top` or `parent` when utilizing local scripts in an iFrame?

Is it possible to eliminate the use of top or parent in iFrame localized scripts, as the title suggests? Upon examining the screenshot below, I encounter a "not defined" error unless I include top or parent as a prefix to my function call. test(); does n ...

Utilize a drop-down selector in JavaScript to search and refine the results

Looking for a way to enhance your product search form? Consider adding an option to select a specific shop from the dropdown menu. This will allow users to search for products within a particular store if desired. <form action="#" method="get"> &l ...

Shared items found in a pair of entities

This function currently returns the difference between two objects, but I need to modify it so that it returns the common objects instead. Any assistance on how to achieve this would be greatly appreciated. Array example: var array1 = [ { "Name": " ...

Obtain the data of the highlighted row in a telerik grid directly from the client side

I am attempting to retrieve the value of a GridBoundColumn with DataField="id" using JavaScript on the client side. When the user clicks on the image button within a row, I need to extract the id for that specific row and then invoke a web method by passin ...

Despite having unique ids, two file input forms are displayed in the same div in the image preview

Running into a minor issue once again. It may not be the most eloquent query, but I'm genuinely stuck and in need of some assistance. I am attempting to showcase image previews of selected files in a file input form. I have a jQuery script that reads ...

Struggling to get the angular application to function properly within the meteor templates

Having trouble integrating an Angular app into Meteor templates Below is my index.html code snippet: <body> </body> <template name="myIndex"> <section ng-app="myApp" ng-controller="AppController as app"> <div ng-in ...

Maintain scroll position during ajax request

I am working on a single-page website that contains numerous containers. Each container's content is loaded dynamically via ajax, so they may not all be populated at the same time. These containers have variable heights set to auto. The website uti ...

Is the typeahead feature acting unusual - could this be a glitch?

My input field uses typeahead functionality like this: <input type="text" id="unit" name="unit" class="form-control form-input" ng-model="item.unit" autocomplete="off" typeahead-min-length="0" uib-typeahead="unit a ...

Whenever I create the code using javascript, padding seems to always show up

I have a basic stacked row layout that displays an upper box and lower box without any padding. <span id="route" class="small"> <div class="row" style="border-style:solid;"> <div class="col-md-12 col-12"> <p>UpperBox</p& ...

What is the process of linking a response to the correct request in a callback function?

While reading "The Node Beginner Book" by Manuel Kiesling, I stumbled upon the following code snippet located under a request handler. I'm curious about how the correct response object will be referenced when handling multiple concurrent requests: v ...

What causes the error message "ng-model is undefined"?

Within my form, there are three angular-ui-bootstrap typehead elements <form> <div class="form-group"> <label for="fieldname" class="col-md-3 control-label">Name</label> <div class="col-md-6"> <input type="text ...

Is the unit-converts npm package compatible with the website https://unpkg.com?

Having issues importing the npm package 'convert-units' using unpkg, I attempted the following method: <script src="unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="02616d6c746770762f776c6b767142302c31 ...

Extract the label from Chip component within the onClick() event in material-ui

-- Using Material-UI with React and Redux -- Within my material-ui table, there are <TableRow> elements each containing multiple <TableCell> components with <Chip> elements. These <Chip> components display text via their label prop ...

Is there potentially a memory leak in this code? If there is, what steps can be taken to eliminate it?

Recently I inherited a project from my senior colleagues that focused on seamless page reloading using AJAX. The code is filled with numerous functions like this one: function iCreateProblems() { //some random code document.getElement ...

My JavaScript code runs perfectly fine on JSFiddle, but for some reason, it's not functioning correctly on

I need a solution where a new button is generated every time the post button is clicked, and each of these buttons should have its own counter. This works successfully in JSFiddle, but unfortunately doesn't work when I try to implement it elsewhere. ...

Is there a specific jest matcher available for comparing Array<Objects>?

I'm currently testing the equality of two arrays of objects and have found that the toEqual matcher in Jest only works for arrays of strings. Is there another matcher available in Jest that can handle this condition? Please refrain from marking this a ...

Error message "npm install is causing a warning due to an outdated lockfile"

npm 8.1.2 | node 16.13.1 Upon running npm install, I encountered the error message below. It seems to be related to version compatibility issues, even though I tried installing npm version 7.19.1, the same error persists. Any suggestions on why this is ha ...

When multiple checkboxes are selected, corresponding form fields should dynamically appear based on the checkboxes selected. I attempted to achieve this functionality using the select option method

Require checkboxes instead of a selection option and have multiple checkbox options. Depending on the checked checkboxes, different form fields should appear. A submit button is needed. I have included some CSS code, but a more detailed CSS code is requir ...

Enhance your Vue.js application by dynamically adding a class when a computed value

Just delving into the world of vue.js and I have a simple query. I've been following a tutorial but now I'd like to add my own touch to it :-P Whenever there is a change in my rank, I would like to include a CSS class for animating the label. Ho ...

The functionality of three.js Raycaster appears to be dependent on the initial key frame of animation in every instance

In my current project, raycasting selection works perfectly fine for static meshes. However, when it comes to animated meshes, the ray selection seems to ignore the movement of the mesh and only recognizes the original position of the mesh. The issue aris ...