Hey, I was wondering if there is any way that I could test if an entity is currently inside of a trigger volume. I tried having it test for enter and leave but if multiple entities are in it and one leaves it would trigger the leave function. Here’s my code.
var Button = pc.createScript('button');
Button.attributes.add("materials", {type: "asset", assetType: "material", array: true, title: "Materials"});
Button.attributes.add("contained", {type: "number", title: "Entities in Volume",default: 0,min: 0, step: 1});
var amountIn = 0;
// initialize code called once per entity
Button.prototype.initialize = function() {
var i = 0;
var renders = this.entity.findComponents('render');
var meshInstances = renders[i].meshInstances;
var mesh = meshInstances[i];
this.materialIndex = 0;
var material = this.materials[this.materialIndex];
mesh.material = material.resource;
this.entity.collision.on('triggerenter', function (result) {
if (result != null) {
if (result.name == "Player" || result.name == "Other") {
this.contained += 1;
}
}
});
this.entity.collision.on('triggerleave', function (result) {
if (result != null) {
if (result.name == "Player" || result.name == "Other") {
this.contained -= 1;
}
}
});
};
// update code called every frame
Button.prototype.update = function(dt) {
var i = 0;
var renders = this.entity.findComponents('render');
var meshInstances = renders[i].meshInstances;
var mesh = meshInstances[i];
var material = this.materials[this.materialIndex];
var material2 = this.materials[1];
if (this.contained > 0) {
mesh.material = material2.resource;
} else if (this.contained < 1) {
this.contained = 0;
mesh.material = material.resource;
}
};
// swap method called for script hot-reloading
// inherit your script state here
// Button.prototype.swap = function(old) { };
// to learn more about script anatomy, please read:
// https://developer.playcanvas.com/en/user-manual/scripting/
Hi @Cryptonaph,
Yes you got it right as a way to approach that, since triggers provide only on enter and on leave events.
What you can do is instead of listening for those events on the trigger entity, start listening for those events on the entity that enters/leaves the trigger.
Check the documentation here, on the top you will see what events each entity depending on its type, it can subscribe on:
https://developer.playcanvas.com/api/pc.CollisionComponent.html
1 Like
Wait, couldn’t I do something like this since it would be attached to that entity and not the script since I have multiple buttons?
Button.attributes.add("contains", {type: "entity", array: true, title: "Held Entities"});
...
Button.prototype.update = function(dt) {
if (this.contains) {
//Change color/activate
}
}
In the … portion it would be the code in initialize that tests for entries, and when it gets enters or leaves it pushes/splices the values into or out of the array. I say “Would this work?” because this.contains.push(result); and this.contains.splice(index,1); return these errors:
Uncaught TypeError: Cannot read properties of undefined (reading 'push')
Uncaught TypeError: Cannot read properties of undefined (reading 'indexOf')
How can I format this to not see it as undefined? Do I have to set the array length first?
Would you be able to post an example project? It probably be easier to see and help as there are a few scripts here.
Yeah, I’m just going to publish my project that this is in and send it here. I got it fixed, but now there is the error that you will find if you stand on both buttons and then get off of one. It’s a bit easier to see if you do it yourself than explain it.
I am not sure how to fix that, so if you could provide some insight that would be awesome.
The issue is here:
Button.prototype.initialize = function() {
var textholder = this.entity.findByName("count");
newArray = new Array(this.contains);
newArray.splice(0,1);
You’ve created the variable newArray as a global variable, not one that is scoped to the object so both buttons are using the same array.
Change it to this and it should be fine (untested):
var Button = pc.createScript('button');
Button.attributes.add("materials", {type: "asset", assetType: "material", array: true, title: "Materials"});
Button.attributes.add("contains", {type: "entity", array: true, title: "Held Entities", size: 0});
Button.attributes.add("textbox", {type: "entity", title: "Text Box"});
Button.attributes.add("buttonMesh", {type: "entity", title: "Button Mesh"});
var newArray = null;
// initialize code called once per entity
Button.prototype.initialize = function() {
var textholder = this.entity.findByName("count");
this.newArray = new Array(this.contains);
this.newArray.splice(0,1);
var i = 0;
var renders = this.buttonMesh.findComponents('render');
var meshInstances = renders[i].meshInstances;
var mesh = meshInstances[i];
this.materialIndex = 0;
var material = this.materials[this.materialIndex];
var material2 = this.materials[1];
mesh.material = material.resource;
this.entity.collision.on('triggerenter', function (result) {
if (result != null) {
if (result.name == "Player" || result.name == "Other") {
//this.script.amountIn += 1;
console.log("Entered");
this.newArray.push(result);
mesh.material = material2.resource;
textholder.element.text = "Contains: " + this.newArray.length.toString() + " entities";
}
}
}, this);
this.entity.collision.on('triggerleave', function (result) {
if (result != null) {
if (result.name == "Player" || result.name == "Other") {
//this.script.amountIn -= 1;
console.log("Exited");
var index = this.newArray.indexOf(result);
this.newArray.splice(index,1);
if (this.newArray.length <= 0) {
this.newArray.length = 0;
mesh.material = material.resource;
}
textholder.element.text = "Contains: " + this.newArray.length.toString() + " entities";
}
}
}, this);
};
Cannot read properties of null (reading “length”), oof.
You will need to fix up the rest of the script to use the this.newArray
instead of newArray
@yaustar That worked, when I joined my test version, because it uses the same server as the published version, there were just two random people in there, so that was funny.