kriket Posted August 12, 2015 Share Posted August 12, 2015 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 errorUncaught TypeError: Cannot read property 'body' of undefinedfor 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. Full project, so u can test in brackets = https://www.dropbox.com/sh/fvuvfqa2hy9c4ad/AABzx1GHlhRrWpBZEd2fohTna?dl=0 Link to comment Share on other sites More sharing options...
wayfinder Posted August 12, 2015 Share Posted August 12, 2015 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 More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 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 More sharing options...
Hsaka Posted August 12, 2015 Share Posted August 12, 2015 index will be -1 at some point (you can debug your code as it's running using the chrome dev tools and you'll see it happen). Just check that index has a valid value before using it. Link to comment Share on other sites More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 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 More sharing options...
wayfinder Posted August 12, 2015 Share Posted August 12, 2015 better way to fix the selector:var index = Math.round(Math.random() * (this.rocks.children.length - 1));that will select from all rocks properly, without the need for later checks. and kinematic is being set to false here: Link to comment Share on other sites More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 @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 More sharing options...
wayfinder Posted August 12, 2015 Share Posted August 12, 2015 you want them to be dynamic (as they are if you don't init them with anything). if you set kinematic to false, they will be static. so just instead of kinematic = false, do dynamic = true Link to comment Share on other sites More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 @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 More sharing options...
wayfinder Posted August 12, 2015 Share Posted August 12, 2015 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 More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 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 More sharing options...
Skeptron Posted August 13, 2015 Share Posted August 13, 2015 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?) Link to comment Share on other sites More sharing options...
kriket Posted August 13, 2015 Author Share Posted August 13, 2015 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 More sharing options...
kriket Posted August 13, 2015 Author Share Posted August 13, 2015 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. 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 More sharing options...
EulaConstellar Posted August 14, 2015 Share Posted August 14, 2015 This might be a silly question and you probably have done this already but did you define this.game?var GameState = function (game) { this.game = game;} Link to comment Share on other sites More sharing options...
wayfinder Posted August 14, 2015 Share Posted August 14, 2015 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. kriket 1 Link to comment Share on other sites More sharing options...
kriket Posted August 14, 2015 Author Share Posted August 14, 2015 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 More sharing options...
kriket Posted August 14, 2015 Author Share Posted August 14, 2015 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 More sharing options...
wayfinder Posted August 14, 2015 Share Posted August 14, 2015 the callback receives it as an argument. Link to comment Share on other sites More sharing options...
kriket Posted August 14, 2015 Author Share Posted August 14, 2015 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 More sharing options...
wayfinder Posted August 14, 2015 Share Posted August 14, 2015 no the callback literally receives the objects that collided as arguments. like this.rocks.children[i].body.collides(this.stationaryCollisionGroup, this.killRock, this);killRock: function(a, b, c, d) { console.log(a, b, c, d) },try it out kriket 1 Link to comment Share on other sites More sharing options...
Recommended Posts