Programatically adding a script doesn't work like when its done manually

Hello! I am trying to spawn an entity programatically. It is going great until the very last part where I add the Platform Collision Script. If I do these manually in the editor, it all works great but doing it programmatically makes the script not detect collision. Let me know if anyone has any ideas. I know that the script is being added because I’ve console logged and gotten it to fire correctly.

Here is the entity being created:

PlatformManager.prototype.spawnPlatform = function(spriteName) {
    //creates entity, adds sprite, makes pixels correct scale
    var platform = new pc.Entity();
    platform.setLocalScale(1.5,1.5,1.5);
    platform.addComponent('sprite', {
        type: pc.SPRITETYPE_SIMPLE,
        spriteAsset: this.app.assets.find(spriteName)
    });
    
    //depending on which sprite is chosen, changes the vertical and horizontal collision
    //and adds them to the platform's hierarchy
    var verticalCollision = new pc.Entity();
    var lSideCollision = new pc.Entity();
    var rSideCollision = new pc.Entity();

    if(spriteName === "platform1"){
        verticalCollision.setLocalPosition(this.platOneVCollision);
        lSideCollision.setLocalPosition(this.platOneLCollision);
        rSideCollision.setLocalPosition(this.platOneRCollision);
    }
    else if(spriteName === "platform2"){
        verticalCollision.setLocalPosition(this.platTwoVCollision);
        lSideCollision.setLocalPosition(this.platTwoLCollision);
        rSideCollision.setLocalPosition(this.platTwoRCollision);
    }
    else if(spriteName === "platform3"){
        verticalCollision.setLocalPosition(this.platThreeVCollision);
        lSideCollision.setLocalPosition(this.platThreeLCollision);
        rSideCollision.setLocalPosition(this.platThreeRCollision);
    }

    platform.addChild(verticalCollision);
    platform.children[0].addChild(lSideCollision);
    platform.children[0].addChild(rSideCollision);


    //ISSUE HERE!!!
    //adds a script that reads these collisions and fires events based on them
    platform.addComponent('script');
    platform.script.create("platformCollision");
    
    this.entity.addChild(platform);
};

And here is the Platform Collision Script:

var PlatformCollision = pc.createScript('platformCollision');

// initialize code called once per entity
PlatformCollision.prototype.initialize = function() {
    this.isPlayerFalling = true;
    this.LPlayerCollision = this.app.root.findByName("lPlayerCollision").getPosition().x;
    this.RPlayerCollision = this.app.root.findByName("rPlayerCollision").getPosition().x;
    this.verticalPlayerCollision = this.app.root.findByName("verticalPlayerCollision").getPosition().y;

    this.singleFireTimerMax = 1;
    this.singleFireTimer = this.singleFireTimerMax;

    this.app.on('notFalling',function(){
        this.isPlayerFalling = false;
    },this);
    this.app.on('falling',function(){
        this.isPlayerFalling = true;
    },this);
};

// update code called every frame
PlatformCollision.prototype.update = function(dt) {
    this.verticalPlayerCollision = this.app.root.findByName("verticalPlayerCollision").getPosition().y;
    //checks vertical with the child of the platform which is vertical collision
    if(Math.abs(this.verticalPlayerCollision - this.entity.children[0].getPosition().y) < 0.04){
        //checks horizontal with the children of the child of the platform which is horizontal collisions
        this.LPlayerCollision = this.app.root.findByName("lPlayerCollision").getPosition().x;
        this.RPlayerCollision = this.app.root.findByName("rPlayerCollision").getPosition().x;
        var leftPlatCollision = this.entity.children[0].children[0].getPosition().x;
        var rightPlatCollision = this.entity.children[0].children[1].getPosition().x;
        if(((this.LPlayerCollision > leftPlatCollision) && (this.LPlayerCollision < rightPlatCollision)) || 
           ((this.RPlayerCollision > leftPlatCollision) && (this.RPlayerCollision < rightPlatCollision))){
            if(this.isPlayerFalling === true){
                if(this.singleFireTimer >= this.singleFireTimerMax){
                    this.app.fire('normalJump');
                    this.app.fire('notFalling');
                    this.singleFireTimer = 0;
                }
            }
        }
    }
    
    if(this.singleFireTimer < this.singleFireTimerMax){
        this.singleFireTimer += dt;
    }
};

And here is a screenshot of the hierarchy that works within the editor :

What is this.platOneVCollision? An entity, position etc?

Hey, it will be more feasible for us if you can provide with the sample project link having the same issue. Looking at the code, the one thing that seems to be an issue is you are setting the entities’ positions before adding them to the hierarchy.
image

Local Position is being set in reference to the position of its parent’s position. Here it doesn’t have any parent so maybe that cause an issue here. Can you first add them to hierarchy and then set their positions and see if that works for you or not.

@yaustar They are entity positions in relation to the platform. Bassically I am setting up some physics logics for jumping on the platforms without using any of the 2D physics to keep it as light as possible. I need to keep track of a few positions based on which sprite is chosen because they are different sizes

@saif I tried that but sadly it did not work. I will set up a sample project

Here is the project: PlayCanvas 3D HTML5 Game Engine

You can use the arrows to move left and right to see that collision behaves properly with the platform on the bottom. The platform that is being spawned above via the platform manager entity is what is giving me issues. Eventually I am hoping that the platform manager will spawn and delete platforms over and over again but before I do that I need the platform collision to work. Let me know if anyone has anymore thoughts on this.

Had a look, the spawnPlatform function is being called before the vectors for the positions are created:

// initialize code called once per entity
PlatformManager.prototype.initialize = function() {
    this.spawnPlatform("platform1");
    
    //vertical, left, right collision points on plats
    this.platOneVCollision = new pc.Vec3(0,0.045,0);
    this.platOneLCollision = new pc.Vec3(-0.22,0,0);
    this.platOneRCollision = new pc.Vec3(0.22,0,0);

    this.platTwoVCollision = new pc.Vec3(0,0.06,0);
    this.platTwoLCollision = new pc.Vec3(-0.12,0,0);
    this.platTwoRCollision = new pc.Vec3(0.12,0,0);
    
    this.platThreeVCollision = new pc.Vec3(0,0.04,0);
    this.platThreeLCollision = new pc.Vec3(-0.18,0,0);
    this.platThreeRCollision = new pc.Vec3(0.18,0,0);

};

This means that the variables like this.platThreeVCollision are undefined when creating the entity.

Move the spawnPlatform function call to the end will fix this:

// initialize code called once per entity
PlatformManager.prototype.initialize = function() {    
    //vertical, left, right collision points on plats
    this.platOneVCollision = new pc.Vec3(0,0.045,0);
    this.platOneLCollision = new pc.Vec3(-0.22,0,0);
    this.platOneRCollision = new pc.Vec3(0.22,0,0);

    this.platTwoVCollision = new pc.Vec3(0,0.06,0);
    this.platTwoLCollision = new pc.Vec3(-0.12,0,0);
    this.platTwoRCollision = new pc.Vec3(0.12,0,0);
    
    this.platThreeVCollision = new pc.Vec3(0,0.04,0);
    this.platThreeLCollision = new pc.Vec3(-0.18,0,0);
    this.platThreeRCollision = new pc.Vec3(0.18,0,0);

    this.spawnPlatform("platform1");
};

Kapture 2021-08-07 at 22.06.07

As a side note, you could use templates instead to create new platforms at runtime rather than creating it all purely via code.

Oh my goodness it was that simple… Thank you for taking a look.

I saw that templates were an option but is that a good idea for this? In the end, there is going to be a platform manager that spawns decently customized platforms (different sprites, booleans to define whether or not the platform will have a trampoline or a spike or nothing, and maybe if the platform will crumble after jumping once). It seemed like it would be easier to just define everything within code to have more control but let me know if you have other thoughts on that.

Without knowing the full details such as how different the items can be, I be tempted with using templates but maybe it’s easier to handle it all via code.

I was thinking you would have the different sized platforms all set up and all you would do via code was position and maybe change the sprite for the look?

It be easier to setup the hierarchy and visual look via a template in the editor and any fine tuning/modifications can be done in code.