Jump to content

Scope issue. Really am lost after hours of trying.


kriket
 Share

Recommended Posts

Right, I really need some help here. I have been debugging for couple of hours and still getting nowhere. Code is similar to my last thread cos its the same game, but its a different problem and warrants a clean thread cos I want to grasp this concept as it seems I am struggling with this in Javascript. 

 

 

Check out this game behaviour. http://testing9.site44.com/

 

Basically, cloud is the trigger and when the player collides with it, a function called this.rockTrigger is called. But I am running into scope issues. 

 

 

Controls = click on left side to move left, click in middle to jump, click on right side to move right.

 

 

 

Error = Uncaught TypeError: Cannot read property 'body' of undefined

  create: function() {    this.game.physics.startSystem(Phaser.Physics.P2JS);    this.game.physics.p2.setImpactEvents(true);    this.game.physics.p2.restitution = 0.5;    this.game.physics.p2.gravity.y = 300;    this.stationaryCollisionGroup = this.game.physics.p2.createCollisionGroup();    this.playerCollisionGroup = this.game.physics.p2.createCollisionGroup();    this.triggerCollisionGroup = this.game.physics.p2.createCollisionGroup();    this.rocksCollisionGroup = this.game.physics.p2.createCollisionGroup();        // TRIGGER for rocks    this.trigger = this.game.add.group();    this.trigger.enableBody = true;    this.trigger.physicsBodyType = Phaser.Physics.P2JS;    this.trigger.create(100, 500, 'cloud-platform');          for(var i = 0; i < this.trigger.children.length; i++){            this.trigger.children[i].body.kinematic = true;            this.trigger.children[i].body.setCollisionGroup(this.triggerCollisionGroup);            this.trigger.children[i].body.collides([this.triggerCollisionGroup, this.playerCollisionGroup]);    }    // ROCKS    this.rocks = this.game.add.group();    this.rocks.enableBody = true;    this.rocks.physicsBodyType = Phaser.Physics.P2JS;          this.rocks.create(500, 100, 'rock2');    this.rocks.create(650, 300, 'rock2');    this.rocks.create(400, 300, 'rock2');    for(var i = 0; i < this.rocks.children.length; i++){            this.rocks.children[i].body.kinematic = true;            this.rocks.children[i].body.setCollisionGroup(this.rocksCollisionGroup);            this.rocks.children[i].body.collides([this.rocksCollisionGroup, this.playerCollisionGroup]);    }                //  Platforms that don't move    this.stationary = this.game.add.group();    this.stationary.enableBody = true;    this.stationary.physicsBodyType = Phaser.Physics.P2JS;    var array = [];    for(var i = 0; i < 16; i++){            array[i] = this.stationary.create(150*i, 550, 'platform');            array[i].body.kinematic = true;            array[i].body.setCollisionGroup(this.stationaryCollisionGroup);            array[i].body.collides([this.stationaryCollisionGroup, this.playerCollisionGroup]);            array[i].body.collides([this.stationaryCollisionGroup, this.rocksCollisionGroup, this.killRock, this]);    }    this.player.body.setCollisionGroup(this.playerCollisionGroup);    this.player.body.collides(this.triggerCollisionGroup, this.rockTrigger, this);    this.player.body.collides(this.rocksCollisionGroup, this.gameOver, this);},
 
 

I thought since the "this" context was already passed along here     

this.player.body.collides(this.triggerCollisionGroup, this.rockTrigger, this);

  , I had access to it in the function below.

rockTrigger: function() {        if(this.rocks.countLiving() !== 0) {//          var that = this;            var index = this.rocks.children[Math.floor(Math.random()*this.rocks.children.length-1)];            console.log(index);//          if(this.rocks.children[index].alive) {            if(true) {                this.rocks.children[index].body.kinematic = false;                console.log('awesome');            }                  }    },

I am getting this error

Uncaught TypeError: Cannot read property 'body' of undefined

for the line

                this.rocks.children[index].body.kinematic = false;

and this line too if I uncomment it.

//          if(this.rocks.children[index].alive) {

So clearly I need to grasp a concept that I clearly dont know by heart. Please help. 

Link to comment
Share on other sites

your index variable is set up to be a reference to the actual child instead of the index.

 

change your variable init to this:

var index = Math.floor(Math.random()*this.rocks.children.length-1);

see if that helps.

 

or just go 

index.body.kinematic = false;
Link to comment
Share on other sites

 

your index variable is set up to be a reference to the actual child instead of the index.

 

change your variable init to this:

var index = Math.floor(Math.random()*this.rocks.children.length-1);

see if that helps.

 

or just go 

index.body.kinematic = false;

 

changed it to             

var index = Math.floor(Math.random()*this.rocks.children.length-1);
 

. Check http://testing9.site44.com/  and open console when player collides with cloud. 

 

Still get the error. 

Link to comment
Share on other sites

Thanks hsaka.             

if(index >= 0) {} 

fixed that.

 

But I there's one other thing I need to know. Why isnt the following working? Why isnt the kinematic property being set to false?

Again the following code is running at http://testing9.site44.com/

 

Why arent the rocks falling? (lol, hair pull time)

 

btw Game Controls = click on left side to move left, click in middle to jump, click on right side to move right.

 

 

    rockTrigger: function() {        if(this.rocks.countLiving() !== 0) {          this.game.time.events.add(Phaser.Timer.SECOND * 1, this.rockFall, this);        }    },            rockFall: function() {            var index = Math.floor(Math.random()*this.rocks.children.length-1);            console.log(index);//          if(this.rocks.children[index].alive) {            if(index >= 0) {                this.rocks.children[index].body.kinematic = false;            }    },
Link to comment
Share on other sites

@wayfinder 

 

but the rocks should fall if kinematic was being set to false. There's global p2 gravity being applied in create().

    this.game.physics.p2.gravity.y = 300;

And if I comment out the             

this.trigger.children[i].body.kinematic = true;

in create(), they fall like they would if kinematic was false. So I really dont understand why they arent falling.

 

 

For the server, I did this just now,

 

    rockFall: function() {            var index = Math.round(Math.random() * (this.rocks.children.length - 1));            console.log(index);//            if(this.rocks.children[index].alive) {            if(true) {                this.rocks.children[index].body.kinematic = false;            }    },

 

 

PS - I am up all night and if you ask me to make a code change on the server as well, I will just be two seconds so it can be tested live. But pls help me resolve this. Hair pull time. 

 

https://www.dropbox.com/sh/fvuvfqa2hy9c4ad/AABzx1GHlhRrWpBZEd2fohTna?dl=0

Link to comment
Share on other sites

@wayfinder, basically, I am trying to have this behavior. When player touches the cloud/trigger (even if only once), the rest of the rocks fall under gravity, one-by-one as per the delay (but which rock is falling next in sequence is random), until they touch the floor (green dotted lines/platforms at the bottom), and get kill(). 

 

 

I am thinking about how I would implement this on the current code, think we are nearly there, but its late and I am not as enthusiastic as I usually am. So would appreciate if you can offer some advise as to how I can go about this. Being unfamiliar with p2 has been a headache when implementing this. As you can see, changing code to 

//                this.rocks.children[index].body.kinematic = false;                this.rocks.children[index].body.dynamic = true;
is getting us there but not making the rocks fall under gravity. They are just evaporating into thin air. 
 
 
btw - DANKE! I would even put up a bounty for this behavior, if anyone wants. bountysource.com or something cos appreciate the help I am getting here.
Link to comment
Share on other sites

I'm not sure how much I can help you. The y position of any rock that's set to dynamic is NaN in the next frame. With phaser.min.js it's basically impossible to debug. But perhaps it's a start for you to look into. Double-check everything: what are the rocks colliding with, etc. Step through the physics update, watch the variable and see where it changes to NaN

Link to comment
Share on other sites

I'm not sure how much I can help you. The y position of any rock that's set to dynamic is NaN in the next frame. With phaser.min.js it's basically impossible to debug. But perhaps it's a start for you to look into. Double-check everything: what are the rocks colliding with, etc. Step through the physics update, watch the variable and see where it changes to NaN

 

Yeah, will do that. BTW changed to phaser.js in case you or anyone gets the time to help me down the line. Going through everything. 

Link to comment
Share on other sites

How far did you get in the end? If I test the game, the trigger seems to work : the rocks "move" when on the cloud. However, the "move" is not, I guess, what you expected : rocks kinda dissapear (do they fall extremely fast?)

 

Srry, havent got around to checking it. Will do so tonight and update here. 

Link to comment
Share on other sites

Update (help needed still)

 

http://testing9.site44.com/

Controls = click on left side to move left, click in middle to jump, click on right side to move right.

 

 

In essence, this should be happening.

 

1. player touches the cloud and triggers the 

    rockTrigger: function() {        if(this.rocks.countLiving() !== 0) {          this.game.time.events.add(Phaser.Timer.SECOND * 1, this.rockFall, this);            }    },

which after a delay calls the rockFall function that should have made the rocks fall.  

    rockFall: function() {            var index = Math.round(Math.random() * (this.rocks.children.length - 1));            console.log(index);            if(this.rocks.children[index].alive) {//            if(true) {//                this.rocks.children[index].body.kinematic = false;                this.rocks.children[index].body.dynamic = true;            }    },
 If the rocks did fell as intended, they would've touched the dotted platforms at the bottom. 
            array[i].body.collides([this.stationaryCollisionGroup, this.rocksCollisionGroup, this.killRock, this]);

And killRock function would have killed the rocks. 

    killRock: function() {        this.rocks.children[index].kill();        console.log('awesome');                          // NEVER CALLED. MEANING ROCKS ARE NOT KILLED EITHER    },
BUT, console.log('awesome'); in the killRock() never gets displayed on the console. This is furthermore confirmed by console.log(index); in the rockFall() as that keeps on getting logged in the console everytime we touch cloud (trigger rockTrigger function) even when there are no rocks in view.         if(this.rocks.countLiving() !== 0) {  But obviously they are still alive in the group ad killRock() is never called. 
 
 
This can only mean one thing. Rocks are not falling under physics as intended.                 this.rocks.children[index].body.dynamic = true;  in rockFall()  is just not doing the trick for us I guess.
 
To debug further and find where the heck the rocks are in the world and why did they disappear if they weren't getting kill(), I added a loop to rockTrigger()
 
    rockTrigger: function() {        if(this.rocks.countLiving() !== 0) {        // POSITION OF ROCKS IN WORLD    for(var i = 0; i < this.rocks.children.length; i++){            console.log(this.rocks.children[i]);            console.log(this.rocks.children[i].world);    }                      this.game.time.events.add(Phaser.Timer.SECOND * 1, this.rockFall, this);            }    },

The output is this.

 

prhWq56.png

 

 

 

HeL0oip.png

 

 

 

8Td6vJ6.png

 

 

 

 

 

 

Well, as you can see. Two rocks are at (0,0) position, the other at (400,300) position according to console but clearly not in game as I cant see it at 400,300.

 

Starting position for all rocks was 

    this.rocks.create(500, 100, 'rock2');    this.rocks.create(650, 300, 'rock2');    this.rocks.create(400, 300, 'rock2');

 

 

This is some weird behavior indeed. Really am clueless as to why this is happening. If I had to guess, I think kinematic, dynamic, static is the culprit and something's wrong physics-wise.

Why doesnt changing                 this.rocks.children[index].body.dynamic = true;       to                this.rocks.children[index].body.dynamic = true;

make it fall??

 

Looking into it further but defo need help as running out of ideas and time. 

Full code is same link throughout the thread = https://www.dropbox.com/sh/fvuvfqa2hy9c4ad/AABzx1GHlhRrWpBZEd2fohTna?dl=0

Link to comment
Share on other sites

After you set the body to be dynamic, try and call this:

this.rocks.children[index].body.mass = 1;

p2 automatically sets the mass of any kinematic or static object to Infinity, and when adding gravity mass is a factor so the force might end up being infinitely large if the mass properties aren't updated yet when the body first switches to dynamic, which would explain the NaN value in the y coordinate. I think this may be a Phaser bug actually, I'm raising an issue on github.

Link to comment
Share on other sites

After you set the body to be dynamic, try and call this:

this.rocks.children[index].body.mass = 1;

p2 automatically sets the mass of any kinematic or static object to Infinity, and when adding gravity mass is a factor so the force might end up being infinitely large if the mass properties aren't updated yet when the body first switches to dynamic, which would explain the NaN value in the y coordinate. I think this may be a Phaser bug actually, I'm raising an issue on github.

 

Just very quickly (am a work),

 

 

That seems to make the rocks fall properly. Check  testing9.site44.com

 

Will check thoroughly tonight, but seems that is a bug.

Link to comment
Share on other sites

Well, I am back from work and thank you so much wayfinder. I couldnt have done it without you. Really appreciate it.

 

At least it works with your suggestion, even if it is a bug. 

 

 

 

I do have one simple question and might ask here since you are already familiar with the code:

In create method, I am colliding children of one group with another. 


            this.rocks.children[i].body.collides(this.stationaryCollisionGroup, this.killRock, this);

In the killRock() function, I want to kill the child of the rock group thats calling it. Basically, I want to do something like this


// PSEUDOCODE    killRock: function() {        this.rocks.children[i].kill();  // will obv give error cos not a proper handle    },

How do I get a handle on this child/object this.rocks.children, thats actually calling the killRock function, from within the function and kill() it? 

Link to comment
Share on other sites

yeah, I realise that this is passed as the context.

 

Problem is 

        this.rocks.children[0].kill();

above line works but 

        this.rocks.children[i].kill();
doesnt cos I cant always know what to pass as index and i is obviously not in scope. So how do I kill the child thats calling the callback func.
Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...