[SOLVED] Fixing 'self.app.fire()' ... issue(?)

I have been around this area before, and it seems that there are major differences in how functions are declared in the ‘initialize’ when it comes to scope of ‘this’. PS I do know a tedious workaround, but the .fire approach could be some much easier, and the tutorials are referencing to a conflict-free use of .fire also.
Please read the out-commented ‘//’ meta-code along:

I initially ‘fire’ from a parallel script:


self.app.fire("isClickedTDD", hitEntity.name);

Here is a cut-out of the receiving script:


Mouse2.attributes.add("gettingHE_local", {type: "entity"});

Mouse2.prototype.initialize = function() {
    this.gettingHE_local = this.app.root.findByName("BoxHjInit");

    this.pos = new pc.Vec3();
   
    this.app.mouse.disableContextMenu();

    this.app.mouse.on(pc.EVENT_MOUSEMOVE, this.onMouseMove, this); // This declaration seem to make no conflict with 'this'-scope
    this.app.mouse.on(pc.EVENT_MOUSEDOWN, this.onMouseDown, this); // This declaration seem to make no conflict with 'this'-scope
    
    this.app.on("isClickedTDD", this.isClickedTDD_Event, this); // This declaration seem to make  conflict with 'this'-scope, and I wonder if it somehow is compiled too early?
};

Mouse2.prototype.isClickedTDD_Event = function(gettingHE){
    this.initialize().call(this); // My own debug of trying to manage conflict above.  PS: is the approach of https://www.youtube.com/watch?v=NV9sHLX-jZU&t=569s possible in PlayCanvas-JS? It does work perfectly when working with 'straight/common' JS outside of PlayCanvas.
    
    selfic = this; // does not work as a local presentation of 'this' (selfic: self IsClicked)
    
    console.log("gettingHE IN: "+gettingHE); 
    selfic.gettingHE_local = gettingHE; console.log("gettingHE local: "+selfic.gettingHE_local); 
               var getObj_TagLag1 = this.app.root.findByTag("1");var getObj_TagLag2 = this.app.root.findByTag("2");var getObj_TagLag3 = this.app.root.findByTag("3");
    
    for(var x=0;x<getObj_TagLag1.length;x++) {
                if (getObj_TagLag1[x].name ===gettingHE){this.lag =1;}
            }
        
          for(var k=0;k<getObj_TagLag2.length;k++) {
                if (getObj_TagLag2[k].name ===gettingHE){this.lag =2;}
            }
        
          for(var h=0;h<getObj_TagLag3.length;h++) {
                if (getObj_TagLag3[h].name ===gettingHE){this.lag =3;}
            }
};

Mouse2.prototype.onMouseMove = function (event) {
    
    selfmm = this;    selfmm = this; // works fluent as a local presentation of 'this' (selfmm: self MouseMove) ... works in the start only

console.log("gettingHE self: "+selfmm.gettingHE_local.name); // this breaks down at mouseDown event? {the ".isClickedTDD_Event" properly tried to access an invalid pointer-address above (?). Hence the likely conflict}
    if(selfmm.gettingHE_local.name !== "BoxHjInit"){
        console.log("lpos "+    selfmm.entity.getLocalPosition() +" :entName: "+ selfmm.entity.name +" :entName: "+ selfmm.gettingHE_local.name);

etc...

PPS: Seems not to be working on ‘update’ either (again: when does the different types of functions compile initially? {‘app.on(" …")’ versus ‘app.mouse.on(pc.MOUSEDOWN … etc)’ versus ‘update’ and so on …})

Can you post a project link please?

There’s some oddness in your code (calling initialise every time the event is fired is really odd).

You also seem to be changing the reference of gettingHE_local from an entity to a mouse click event.

In this case ‘Sharing’ is not an option, as the project is a bit classified. But in regards to the ‘.fire’-method I am only using this event-tutorial https://developer.playcanvas.com/en/tutorials/using-events-with-scripts/

If you somehow are able to reproduce the issue in there?
This rewrite of it will for instance fail -> with garantee:


var EventReceiver = pc.createScript('eventReceiver');

EventReceiver.attributes.add("gettingHE_local", {type: "entity"});

// initialize code called once per entity
EventReceiver.prototype.initialize = function() {
this.gettingHE_local = this.app.root.findByName("Box");

    // Listen for the 'changePosition' event so when it is fired, call
    // the function onChangePositionEvent
    this.app.on("changePosition", this.onChangePositionEvent, this);
};

EventReceiver.prototype.onChangePositionEvent = function(x, y, z) {
    this.entity.setPosition(x, y, z);
console.log(this.gettingHE_local.name);
};

Works fine for me: https://playcanvas.com/editor/scene/859312

Not sure why in your code you have an attribute for gettingHE_local and then overwrite the reference with this.gettingHE_local = this.app.root.findByName("Box");

ok, I think I finally get it in regards to ‘.this’ inside the PlayCanvas-version of JS

(PS: if others are to read my troubles in the direction, please be aware that; as PlayCanvas-JS has some obvious simplification-advantages, it is vital that one does not stare blind on rules from traditional JS while learning PC-JS.

The way initiation of variables is quite different between the two versions. Yaustar’s abovementioned “attribute” and “reference” is not the same as a A} “var” and a local-scope B} “this”, in the A} start and B} body of a traditional JS-script.
“Var”>>exchanged-with>>“attribute” as a topscript-initiator is not needed in PlayCanvas-JS, which might lead to conflicts as above and topic-mentioned).

PPS: My so called “tedious workaround” was accessing an entity with a var-holding script, which still is needed in cases with re-usage of a script that tries to cope with a entity-local script version of a ‘.this’-object. These ‘.this’-objects will all be handled as a global object being ‘boxed’ at (for instance: ‘true, false, false, true etc’ as opposed to ‘true’ only within the “tedious workaround”).

Can you provide an example project of your workaround? Maybe there’s something there that I could help with once I see the implementation?

Ok, but this is what I have time for right now :slight_smile:
{you or others can try it out - will be glad if it can be fixed at lower library tier, as the workaround really is needed at setup below to avoid the ‘scope flooding’ I am referencing to}

Sorry, I don’t understand that diagram. If you later get time for a project that showcases the problem, that would be great.

Edit: Going back to your original code, this line confused me:

    selfic = this; // does not work as a local presentation of 'this' (selfic: self IsClicked)

As selfic is a global variable and not a local one so it doesn’t get scoped in the function.

yes, sure … I know you have a ton of experience with PS-JS, so chances should be good in case I find time to make an understandable copy of the classified setup.

Anyways if you want to nerd some more with it, I think you should read from the top post (‘selfic’ is inspired by the approach from the Indian guy on the youtube-video … ‘re-usage’ of the exact same script on multiple entities should also be a large large hint for both you and coders who should fall upon this topic in the future :-)) )

The topic did turn [SOLVED] with ‘this.’-usage within ‘initialize’ only

I’m really am not quite sure what you are trying to achieve.

Having multiple instances of the scripts on different objects using local attributes works fine with each instance of the script referencing to a different entity in the scene. https://playcanvas.com/editor/scene/859312:

Used a local variable to reference the ‘this’ pointer which seems to be what you were trying to do?

EventReceiver.prototype.onChangePositionEvent = function(x, y, z) {
    this.entity.setPosition(x, y, z);
    var something = this;
    console.log(something.targetEntity.name);
    console.log(this.targetEntity.name);
};

Looking at the example in the video you linked, he is using a local variable, not a global one (let that = this (note the use of let) which is blocked scope. In your case, you are attempting to use the same global variable in each instance of the script:

The video host is also using it to handle a scenario that isn’t present in the code in the first post (declaring a new function object while in the scope of another function object).

Edit: An example would really help alongside what you are expecting to be outputted/happen.

Looking at the original code in the first post:

Mouse2.attributes.add("gettingHE_local", {type: "entity"});

This adds gettingHE_local to this instance of the script and can be set in the editor to reference an entity. At this point, we have this.gettingHE_local referencing an entity.

Then the initialize function gets called and this line is odd:

    this.gettingHE_local = this.app.root.findByName("BoxHjInit");

The value set to this.gettingHE_local by the attribute within the editor is now overridden by this line where it is now set to the entity named BoxHjInit.

Later in the callback function

    selfic = this; // does not work as a local presentation of 'this' (selfic: self IsClicked)
    
    console.log("gettingHE IN: "+gettingHE); 
    selfic.gettingHE_local = gettingHE;

The global variable selfic is referencing the current instance of this script and then this.gettingHE_local / selfic.gettingHE_local which was referencing an entity object assigned from the initialise function is then assigned a reference to the string object gettingHE

This is what really confuses me as there are a number of anomalies in the original code and can’t work out the reason why it was done this way.

For reference, you can see how the .on and .fire are implemented if you want to look under the hood:


Line 162 shows how the callback is fired using the object that is passed with the .on function to register a handler:

1 Like

Are you trying to fire an event to a specific instance of a script rather than all instances of the script?

Looking at the original code again and trying to get a rough idea on what you are trying to achieve, is this what you were looking to try to do (click on the cones)?

https://playcanvas.com/editor/scene/863033

2 Likes

Great, I think both I and others will get an extra experience of ‘chrystalization’ if they go into depth with the whole lots of post within the topic.

Of your last posts I find this subtopic relevant to reply:
“The video host is also using it to handle a scenario that isn’t present in the code in the first post (declaring a new function object while in the scope of another function object).”

Firstly, I wasn’t aware of the great ‘Initialize’-optimization effect early on. Secondly, I was trying to draw a parallel to out-of-scope ‘.this’ between function limits in the video, and my problem of out-of-scope ‘.this’ within passing/reading between scripts in a ‘.fire’-setup :slight_smile: … [think this will be my last post, thx again @Yaustar]

PPS final: the “BoxHjInit” is a desperate method from years back Unity + my early PC-days, where I use a physical box-entity to create a gathering point (and/or for a variable in different scripts -> to all outside readers -> see past that, please)