How to use entity's find() function

Most of ETA’s map editor/builder script is complete. The only thing to do now is to add a delete functionality.

See, ETA’s Builder works by spawning a cyan “ghost” tile, moving it with the arrow keys, q, & e, and rotating with middle and right mouse buttons. That all works fine, and the tiles behave exactly the same as the ones made in the Editor. The only problem is that function to delete tiles (by overlapping the ghost tile and then pressing the delete key) doesn’t seem to work.

Currently, I am trying to make it work by using entity’s find() function, and using it to return a tile that shares the same position and rotation as the ghost tile, if such a tile does exist. if it does exist, that tile (not the ghost tile) is then deleted (builder.js, lines 81-95). However, I get an uncaught TypeError when I try it: “Cannot read property ‘type’ of undefined.” Clearly, I seem to misunderstood how Entity’s find() function works. I would be very thankful to anyone who could help me understand how to make the find() function work in this context.

Here is my script: https://playcanvas.com/editor/code/600366?tabs=18801293

EDIT: Here’s the script for my passiveDelete() function:

// script to delete passive tile at same position as ghost when delete is pressed
Builder.prototype.passiveDelete = function() {
    var ghost       = this.app.root.findByName("Ghost");
    var tileToDelete = this.app.root.find(function(node) {
        return node.model.type === "box" && node.getLocalPosition() === ghost.getLocalPosition() && node.getLocalRotation() === ghost.getLocalRotation() !== -1;  // return any box models (tiles) that have the same position as the ghos tile.
    });
    // if there is a tile that has the same position as ghost
    if (tileToDelete)
        // ghost.getLocalPosition() === this.app.root.findByName("Passive_Tile").getLocalPosition() 
    {
        // delete that specific tiles (don't delete tokens, ghost, or UI elements)
        tileToDelete.destroy();
    }
    
};

You usage of the find function is correct so you have understood the documentation :slight_smile: The function you are passing has some issues though.

var tileToDelete = this.app.root.find(function(node) {
        return node.model.type === "box" && node.getLocalPosition() === ghost.getLocalPosition() && node.getLocalRotation() === ghost.getLocalRotation() !== -1;  // return any box models (tiles) that have the same position as the ghos tile.
    });

Not all child entities have a model component so when the search function tries to access node.model.type, model might be null. You will have to do do a check to see if model exists.

The second issue (that you haven’t run into yet) is that comparing floats is not recommended due to way they are stored in memory. There is always a degree of floating point inaccuracy in comparisons and the recommended way is to see if the difference between the two values is very small.

Lastly, find() returns an array of nodes, not a singular node.

This makes the code (untested)

var tilesToDelete = this.app.root.find(function(node) {
    var result = false;
    
    if (node.model && node.model.type === "box") { 
    	var distance = new pc.Vec3();
    	distance.sub2(node.getPosition(), ghost.getPosition());
    	if (distance.length() < 0.001) {
    		var nr = node.getRotation();
    		var gr = ghost.getRotation();
    		var rotationDiff = new pc.Vec4();
    		rotationDiff.sub2(nr.x - gr.x, nr.y - gr.y, nr.z - gr.z, nr.w - gr.w);
    		if (rotation.Diff.length()  < 0.001) {
    			result = true;
    		}    		
    	}
    }
    
    
    return result;
});

All that said, as an alternative to using find(), I recommend adding a tag to all the tiles nodes/entities and using findByTag which is less expensive then find() since it doesn’t have to loop through every child object.

Once you have all the tile entities, you can loop through them to check if the ghost tile is occupying the tile.

To make it even better, when you place the ghost token on the tile, you can give that information to the ghost token script on which tile it is on. This way, as long as you have a reference to the ghost token, you can immediately access the tile entity from it rather than going through the expensive process of checking many entities and the position/rotation comparison.

1 Like

How do I do this?

Again, thank you very much for helping me out. I really appreciate it.