Hey, I’m trying to change materials on a model and keep getting this error:
Cannot read property ‘model’ of undefined
here is my code, anyone got any ideas?
pc.script.attribute("materials", "asset", [], {type: "material"});
pc.script.create('colourChange', function (app) {
// Creates a new ColourChange instance
var ColourChange = function (entity) {
this.entity = entity;
Ent = this.entity;
};
var colourState = 0;
ColourChange.prototype = {
// Called once after all resources are loaded and before the first update
initialize: function () {
this.originalMaterial = app.assets.get(this.materials[0]);
this.redMaterial = app.context.assets.get(this.materials[1]);
this.greenMaterial = app.context.assets.get(this.materials[2]);
this.blueMaterial = app.context.assets.get(this.materials[3]);
window.addEventListener('message', function (e){
// always validate origin
if (e.origin !== 'http://flight.sim720.co.uk/test/Main_Test_Page.html') {
var msg = JSON.parse(e.data);
console.log(msg.Recieved, 'colourChange listening');
colourState = (msg.Recieved);
if (colourState < 10)
return ColourChange;
else if (colourState > 10)
colour();
}
});
function colour(){
if (colourState == 100){
this.entity.model.model.meshInstances[1].material = this.originalMaterial;
console.log('working');
}
else if (colourState == 101){
this.entity.model.model.meshInstances[1].material = this.redMaterial;
console.log('working');
}
else if (colourState == 102){
this.entity.model.model.meshInstances[1].material = this.greenMaterial;
console.log('working');
}
else if (colourState == 103){
this.entity.model.model.meshInstances[1].material = this.blueMaterial;
console.log('working');
}
}}};
return ColourChange;
});
my post message is working and from the buttons im clicking im either getting a 100, 101, 102 or 103 and the colourChange listening console.log is posting.
I have attached the script to the .json model pieces in the editor and refreshed the script attributes and attached the materials. into the 0,1,2,3 array slots.
I just stepped through this in the debugger in Chrome. You have a problem with your this.
Because you are calling the function colour() which isn’t a member of the ColourChange class, the value of this is not what you expect.
I’ve re-written that class to use a member function to change color. You’ll see that I am storing this in a variable so that it can be used in the postMessage callback. I’ve made your colour function a method on the class.
pc.script.attribute('materials', 'asset', [], { type: 'material'});
pc.script.create('colourChange', function (app){
// Creates a new ColourChange instance
var ColourChange = function (entity) {
this.entity = entity;
};
var colourState = 0;
ColourChange.prototype = {
// Called once after all resources are loaded and before the first update
initialize: function () {
this.originalMaterial = this.materials[0].resource;
this.redMaterial = this.materials[1].resource;
this.greenMaterial = this.materials[2].resource;
this.blueMaterial = this.materials[3].resource;
var self = this;
window.addEventListener('message', function (e) {
// always validate origin
if (e.origin !== 'http://flight.sim720.co.uk/test/Main_Test_Page.html') {
var msg = JSON.parse(e.data);
console.log(msg.Recieved, 'colourChange listening');
colourState = (msg.Recieved);
if (colourState < 10) {
// what does this do???
return ColourChange;
} else if (colourState > 10)
self._changeColour(colourState);
}
});
},
_changeColour: function (colourState) {
if (colourState == 100){
this.entity.model.model.meshInstances[0].material = this.originalMaterial;
console.log('working standard');
}
else if (colourState == 101){
this.entity.model.model.meshInstances[0].material = this.redMaterial;
console.log('working red');
}
else if (colourState == 102){
this.entity.model.model.meshInstances[0].material = this.greenMaterial;
console.log('working green');
}
else if (colourState == 103){
this.entity.model.model.meshInstances[0].material = this.blueMaterial;
console.log('working blue');
}
}
};
return ColourChange;
});
I haven’t tested it but it should work.
Also, I’ve highlighted a bit where you are returning the class type from the event callback. Not sure why you are doing that?
Thanks for the update, You’ll have to excuse me but I’ve only been studying coding for approximately 3 weeks so I am unsure on exactly what you have done. I can see the change but its kind of boggled me and inside the editor the syntax is wrong. The part that has confused me is the self.changeColour(colourState) (I understand that self stands for this as I see where you have declared that at the top and I also understand that colourState is my own variable but what is the changeColour? in addition you are starting a function unlike my eyes have seen before so If you have the time to explain it would be really appreciated but I understand you are a busy guy!
I am returning colourchange on line 33 as I am sending a message to multiple scripts and if the number sent is equal to or below 10 then I don’t want this particular script to run. With this being the case is that the correct way to stop this script?
Sorry, I was missing a } in the postMessage callback. I’ve updated the code snippet so it shouldn’t have errors now.
The this property is one of the trickiest parts of Javascript to understand as a new user, so no surprises that you’re confused.
This MDN article explains it though it’s a bit technical. Basically if you do:
obj.myFunction() - inside myFunction: this === obj
if you do:
myFunction() - inside myFunction: this === window or this === null (depending on whether you are using use strict or not. Either way, you probably didn’t want to use this here.
Things get tricky when you start using functions as callbacks, because they are not called “on the object”. For example in your case:
You can also save a value of this into a local variable, like self. And use self instead of this in your functions. This takes advance of the javascript feature “closures”. I prefer this method as there is a slight performance benefit over bind().
Thanks for your comprehensive reply and I’m about to sit down and try and go through that article however as you mentioned it does look very technical hehe!
I have tried your code and as before I get no errors but I still don’t have a material change. I’m stumped as to whether its the code or editor side.
This is how each piece of model that I want the material to change on is set up: