kriket Posted August 12, 2015 Share Posted August 12, 2015 So I have a group of sprites/obstacles that are placed at the top of the world to start with. Once player enters/overlaps a trigger zone, a trigger function is called which makes the obstacles fall. But the obstacles fall randomly and there's a 2 second delay before another random obstacle falls. I got as far as grabbing a random child.alive, but how can I keep going through the obstacleGroup until all alive children have been dealt with. Randomly, of course. I know there's a forEach method with every group, but dont know how I can implement in this situation. obstacleTrigger: function() { Phaser.Math.getRandom(this.obstacleGroup.children.filter(function(child) { if(child.alive) { /* wait 2 seconds before falling */ if(this.nextShot > this.time.now){return;} // too early /* make shot */ child.body.kinematic = false; /* (every child is immovable to start with (using p2 physics, kinematic = true), and make kinematic = false drops its under global gravity of p2, and once it overlaps floor, I call child.kill() in other function) */ this.nextShot = this.time.now + 2000; // wait at least 2 seconds (2000ms) to next shot } })); }, Link to comment Share on other sites More sharing options...
drhayes Posted August 12, 2015 Share Posted August 12, 2015 Caveat: I have absolutely no experience using p2 whatsoever. Why not make this an emitter, instead? Emitters have all the code for timing and killing and you could customize it further with a custom particle class. Emitters have a maximum number of particles that they emit, as well. Would that work? Link to comment Share on other sites More sharing options...
Skeptron Posted August 12, 2015 Share Posted August 12, 2015 Couldn't you do use the "countLiving" property? Like : obstacleTrigger: function() { while(this.obstacleGroup.countLiving !== 0){ Phaser.Math.getRandom(this.obstacleGroup.children.filter(function(child) { .... } }, Link to comment Share on other sites More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 Caveat: I have absolutely no experience using p2 whatsoever. Why not make this an emitter, instead? Emitters have all the code for timing and killing and you could customize it further with a custom particle class. Emitters have a maximum number of particles that they emit, as well. Would that work? Emitter would be my last resort mate since I wait to avoid activating different systems throughout the game. Targetting mobile, and dont think emmiter's are quite what I am after. But innovative suggestion nonetheless Couldn't you do use the "countLiving" property? Like : obstacleTrigger: function() { while(this.obstacleGroup.countLiving !== 0){ Phaser.Math.getRandom(this.obstacleGroup.children.filter(function(child) { .... } }, I think this could work. I ran into a issue in my code below. Console is giving me "Uncaught TypeError: Cannot read property 'now' of undefined" for this line if(this.nextShot > this.time.now) {Full code block: while(this.obstacleGroup.countLiving !== 0){ Phaser.Math.getRandom(this.obstacleGroup.children.filter(function(child) { if(child.alive) {// wait 1-3 seconds before falling if(this.nextShot > this.time.now) { return; } // too early /* make shot */ child.body.kinematic = false; this.nextShot = this.time.now + 1000; // wait at least 1 second (1000ms) to next shot } })); } Link to comment Share on other sites More sharing options...
tips4design Posted August 12, 2015 Share Posted August 12, 2015 Try this.game.time.now Link to comment Share on other sites More sharing options...
AzraelTycka Posted August 12, 2015 Share Posted August 12, 2015 Hello, phaser docs say that getRandom is deprecated so I'm not sure if I would use it because with future phaser versions there might not be this function at all. Btw you can always go with simple reference.var array = [0, 1, 2, 3, 4]; // positions in your group of living bodiesfor (var i = 0; i < array.length; i++ ) { var index = array[getRandomIntInRange(0 to 4)]; functionDoSomethingWithYourGroup(yourGroup[index]); array.splice(index, 1);}Or if you don't want to use timed events for all your bodies you can go instead of for loop with simple function and call it every time your 2 seconds are finished. kriket 1 Link to comment Share on other sites More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 Try this.game.time.now didnt work mate. The problem is related to anonymous function. Anyway, better at javascript than me, can help me resolve this pls? Reading up more on anonymous functions and how to provide context to them. I had read up on this ages ago. Link to comment Share on other sites More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 Hello, phaser docs say that getRandom is deprecated so I'm not sure if I would use it because with future phaser versions there might not be this function at all. Btw you can always go with simple reference.var array = [0, 1, 2, 3, 4]; // positions in your group of living bodiesfor (var i = 0; i < array.length; i++ ) { var index = array[getRandomIntInRange(0 to 4)]; functionDoSomethingWithYourGroup(yourGroup[index]); array.splice(index, 1);}Or if you don't want to use timed events for all your bodies you can go instead of for loop with simple function and call it every time your 2 seconds are finished. thanks for letting me know thats deprecated now. I am trying out your way instead. Will post results asap. Link to comment Share on other sites More sharing options...
Skeptron Posted August 12, 2015 Share Posted August 12, 2015 Can you try, before the block of code, to write : var that = this; And then use that.timer.now instead of this.timer.now ? I think this isn't reachable anymore in your block, because of scope limitations kriket 1 Link to comment Share on other sites More sharing options...
drhayes Posted August 12, 2015 Share Posted August 12, 2015 Use "var that = this;" or bind the function by doing something like this:filter(function(blah) { // Code goes here.}.bind(this)) kriket 1 Link to comment Share on other sites More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 Thanks a lot guys. Just getting the final code block ready using what @AzraelTycka suggested above since getRandom method is deprecated. But now I know how to bind and sort the scope out of anonymous functions properly. Many thanks. Will update soon on the code. Link to comment Share on other sites More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 Hello, phaser docs say that getRandom is deprecated so I'm not sure if I would use it because with future phaser versions there might not be this function at all. Btw you can always go with simple reference.var array = [0, 1, 2, 3, 4]; // positions in your group of living bodiesfor (var i = 0; i < array.length; i++ ) { var index = array[getRandomIntInRange(0 to 4)]; functionDoSomethingWithYourGroup(yourGroup[index]); array.splice(index, 1);}Or if you don't want to use timed events for all your bodies you can go instead of for loop with simple function and call it every time your 2 seconds are finished. I am getting an error message. rockTrigger: function() { var array = [0, 1, 2, 3, 4]; // positions in your group of living bodies while(this.rocks.countLiving !== 0){ for (var i = 0; i < array.length; i++ ) { var index = array[getRandomIntInRange(0, 4)]; } this.game.time.events.add(Phaser.Timer.SECOND * 2, this.rockFall(this.rocks[index]), this); array.splice(index, 1); } }, rockFall: function(child) { child.body.kinematic = false; },PS - I have learnt so much today. It feels awesome! Many thanks to such an amazing community. Link to comment Share on other sites More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 Sorry, I thought I didnt have to implement this getRandomIntInRange function myself? Thought it was built in? Let me try again with a randomising function. Link to comment Share on other sites More sharing options...
Skeptron Posted August 12, 2015 Share Posted August 12, 2015 Try this : var item = items[Math.floor(Math.random()*items.length)]; SO link : http://stackoverflow.com/questions/5915096/get-random-item-from-javascript-array (if you haven't already found it ) kriket 1 Link to comment Share on other sites More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 Thanks Skeptron. var index = this.game.rnd.integerInRange(0, 4); also does the trick. Anyway, onto something very important and strange. Check this out = http://testing9.site44.com/ Clicking on right, moves player right. Clicking on left of the screen, moves player left, clicking in middle = jump. But notice, how when you collide with what was supposed to be the trigger (first rock), the player just stops responding. No errors in console. Ziltch. Code here - https://www.dropbox.com/sh/fvuvfqa2hy9c4ad/AABzx1GHlhRrWpBZEd2fohTna?dl=0Try running it in Brackets pls. Getting images loaded onto jsbin is something I have to learn and I am short on time atm so pls bare with me. Did I say, I am only playing with JS now Although, game.js is short, the code that concerns us is: create: function() { this.game.physics.p2.setImpactEvents(true); this.game.physics.p2.restitution = 0.5; this.game.physics.p2.gravity.y = 300; this.playerCollisionGroup = this.game.physics.p2.createCollisionGroup(); this.triggerCollisionGroup = this.game.physics.p2.createCollisionGroup(); this.rocksCollisionGroup = this.game.physics.p2.createCollisionGroup(); // TRIGGER for rocks fall this.trigger = this.game.add.group(); this.trigger.enableBody = true; this.trigger.physicsBodyType = Phaser.Physics.P2JS; this.trigger.create(200, 500, 'rock1'); 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]); } this.player.body.setCollisionGroup(this.playerCollisionGroup); this.player.body.collides(this.triggerCollisionGroup, this.rockTrigger, this); this.player.body.collides(this.rocksCollisionGroup, this.gameOver, this); }, rockTrigger: function() { var array = [0, 1, 2, 3, 4]; // positions in your group of living bodies while(this.rocks.countLiving !== 0){ for (var i = 0; i < array.length; i++ ) { var index = this.game.rnd.integerInRange(0, 4); } this.game.time.events.add(Phaser.Timer.SECOND * 2, this.rockFall(this.rocks[index]), this); array.splice(index, 1); } }, rockFall: function(child) {// child.body.kinematic = false; }, Link to comment Share on other sites More sharing options...
Skeptron Posted August 12, 2015 Share Posted August 12, 2015 I'm really not familiar with P2JS and your way of creating groups and collisions, but what I found is that if you look at the Debug plugin (GG for using it, btw), you'll find that Rock1 is not in the same group as the other Rocks. That would explain that this very particular rock has a different behaviour (the crash). EDIT : ok now I see you're just creating one child for this group. Why iterate over its length then? For future changes? Link to comment Share on other sites More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 I'm really not familiar with P2JS and your way of creating groups and collisions, but what I found is that if you look at the Debug plugin (GG for using it, btw), you'll find that Rock1 is not in the same group as the other Rocks. That would explain that this very particular rock has a different behaviour (the crash). Yeah, as you can see from the code, trigger rock group is separate from the rocks that fall. TBH I would use another image for trigger but its was just a quick hack with the same rock image. The reason for separate group for trigger and other rocks is obviously cos on overlap, different functions will be called depending on what collided with what. I have to group everything cos player is grouped and when all the assets in my game are grouped, I dodnt think I will run into any glitches that arise from sprite VS group collisions. All I do is from the official tuts and examples. I am still learning p2 physics myself. Link to comment Share on other sites More sharing options...
Skeptron Posted August 12, 2015 Share Posted August 12, 2015 Ok I think I found an issue : countLiving() is a method, not a property. Add the parenthesis. And when it crashes like that, put breakpoints so that you can debug until crash point. kriket 1 Link to comment Share on other sites More sharing options...
Skeptron Posted August 12, 2015 Share Posted August 12, 2015 And careful, the brackets of your for loop are poorly placed:for (var i = 0; i < array.length; i++ ) { var index = this.game.rnd.integerInRange(0, 4); } this.game.time.events.add(Phaser.Timer.SECOND * 2, this.rockFall(this.rocks[index]), this); array.splice(index, 1);Rock creation should be within the loop, just as array.splice kriket 1 Link to comment Share on other sites More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 Ok I think I found an issue : countLiving() is a method, not a property. Add the parenthesis. And when it crashes like that, put breakpoints so that you can debug until crash point. skeptron, I changed it to while(this.rocks.countLiving() !== 0){but still same issue. Player just freezes, no movement when clicking, and no errors. Link to comment Share on other sites More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 And careful, the brackets of your for loop are poorly placed:for (var i = 0; i < array.length; i++ ) { var index = this.game.rnd.integerInRange(0, 4); } this.game.time.events.add(Phaser.Timer.SECOND * 2, this.rockFall(this.rocks[index]), this); array.splice(index, 1);Rock creation should be within the loop, just as array.splice Rock creation? Where am I creating them? Can u pls elaborate? Srry, I know I have been a pain, but if I solve this, today would be legendary in terms of knowledge gained about phaser and JS. Link to comment Share on other sites More sharing options...
AzraelTycka Posted August 12, 2015 Share Posted August 12, 2015 Well, didin't think it needs to be pointed out. I used overally descriptive names for function calls to make sure that you cna understand what is that function supposed to do but you still need to make them on your own, that wasn't important in my suggestion after all ;-). kriket 1 Link to comment Share on other sites More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 Well, didin't think it needs to be pointed out. I used overally descriptive names for function calls to make sure that you cna understand what is that function supposed to do but you still need to make them on your own, that wasn't important in my suggestion after all ;-).lol, yes. APIs and libraries all over the web nowadays, didnt think it was pseudocode. Helped a lot still. thx Link to comment Share on other sites More sharing options...
kriket Posted August 12, 2015 Author Share Posted August 12, 2015 And careful, the brackets of your for loop are poorly placed:for (var i = 0; i < array.length; i++ ) { var index = this.game.rnd.integerInRange(0, 4); } this.game.time.events.add(Phaser.Timer.SECOND * 2, this.rockFall(this.rocks[index]), this); array.splice(index, 1);Rock creation should be within the loop, just as array.splice you're right skeptron . Let me fix that and see if it works.PS - I also think I have an infinite loop running. Let me debug and return if I still cant fix it. Am grateful for all the support. Link to comment Share on other sites More sharing options...
AzraelTycka Posted August 12, 2015 Share Posted August 12, 2015 btw that random integer in range 0 to 4 was for that specific array which had length 5 [0, 1, 2, 3, 4], so if you are pointing to some larger array don't forget to adjust the numbers, in generall you can go with rndIntInRange(0, array.length - 1); as long as your array which you are pointing to is continuos (all alive bodies in the original array are as this: var orgArr = [b0, b1, b2, b3, b4]; and so on - where bX is an object for example, then you are referencig to this with your var array = [0, 1, 2, 3, 4]; in case orgArr has more elements you need to extend your array as well - it's very simple to do it with one loop, no need to type it by hand. If your array isn't continuous but is more like this: var orgArr = [b0, b1, dead, b3, dead, b5]; then probably easisest is to sort orgArr to [b0, b1, b3, b5, dead, dead] and change rndIntInRange(0, array.length - 1); to rndIntInRange(0, orgArr.countTotalLivingBodies - 1); Link to comment Share on other sites More sharing options...
Recommended Posts