Miroku_87 Posted August 5, 2014 Share Posted August 5, 2014 Hey guys,I'm trying to learn Phaser by recreating Space Invaders.I'm now developing the player shot colliding with the aliens. My aliens are in a nested group (rows of aliens inside a generic rows group, since in the game every row moves at different times) and my player and the sprites of the shots are external of this groups.In order to make the collide happen I've looked at THIS example and set things like this//I won't write all the inheriting stuff Alien = function(game){ Phaser.Sprite.call(this,game,0,0,'alienimg'); this.physicsBodyType = Phaser.Physics.ARCADE; this.bodyEnabled = true;}AlienRow = function(game){ Phaser.Group.call(this,game); for(var i = 0; i < numAlienPerOneRow; i++) { this.add(new Alien(this.game)) //more } this.bodyEnabled = true;}AlienGroup = function(game){ Phaser.Group.call(this,game); for(var i = 0; i < numRows; i++) { this.add(new AlienRow(this.game)) //more } this.physicsBodyType = Phaser.Physics.ARCADE; this.bodyEnabled = true;}/******** Game.js ***************/ create: function () { console.log('Game create'); this.physics.startSystem(Phaser.Physics.ARCADE); this.alienG = new AlienGroup(this.game,'easy'); this.alienG.x = (this.world.width - this.alienG.width) / 2; this.alienG.y = 10; this.add.existing(this.alienG); this.player = new Player(this.game); this.player.x = this.world.centerX; this.player.y = this.world.height; this.add.existing(this.player); this.controls = this.input.keyboard.createCursorKeys(); }, update: function () { if(this.controls.left.isDown) this.player.x -= 5; else if(this.controls.right.isDown) this.player.x += 5; if(!this.spacebarWasDown && this.input.keyboard.isDown(Phaser.Keyboard.SPACEBAR)) { this.projectile = new Projectile(this.game); this.projectile.x = this.player.x; this.projectile.y = this.player.y - this.player.height; this.add.existing(this.projectile); this.physics.arcade.enable(this.projectile,Phaser.Physics.ARCADE); } if(this.projectile){ this.physics.arcade.collide(this.projectile, this.alienG, this.collisionHandler, null, this); //this.physics.arcade.collide(this.alienG, this.alienG); } this.spacebarWasDown = this.input.keyboard.isDown(Phaser.Keyboard.SPACEBAR); }, collisionHandler: function (what) { console.log(what); }Unfortunately collisionHandler console.log is not showing.Am I missing something?Is the problem the fact that I'm working with nested groups? I hope I've been clear =) Thank you in advance! Link to comment Share on other sites More sharing options...
lewster32 Posted August 6, 2014 Share Posted August 6, 2014 Collide/overlap will not step through groups recursively, so yes, if the collide handler is looking at a group, and the only thing that group contains is other groups, you won't get any collisions. A way around this would be to add all of your aliens to a flat array as you create them, and check your shot against this array instead. This will then work regardless of how they're grouped. Link to comment Share on other sites More sharing options...
Miroku_87 Posted August 6, 2014 Author Share Posted August 6, 2014 Thank you Lewster I will try that as soon as I can and will report you back =) lewster32 1 Link to comment Share on other sites More sharing options...
Miroku_87 Posted August 6, 2014 Author Share Posted August 6, 2014 Hey Lewster I've tried what you suggested and it works!I also forgot to enable the projectile for physics btw Thank you! Link to comment Share on other sites More sharing options...
Miroku_87 Posted August 7, 2014 Author Share Posted August 7, 2014 Hey guys, sorry for spamming but I've been testing the code I wrote with Lewster suggestion and I've found an issue.It happens sometimes that when I press the shoot button I see no projectile go out from my player's cannon and an alien magically dies somewhere in the formation.It's like the 2 elements are in the same spot when the projectile is added to the world but that's not true. It even happens that I see the projectile and that the collision happens with a very distant element. Isn't it that collision doesn't look for the absolute position while working with sprites inserted in nested groups but looks for the relative one? Thank you again for your patience! Link to comment Share on other sites More sharing options...
lewster32 Posted August 7, 2014 Share Posted August 7, 2014 Yes, I believe this is the case Miroku - if you debug the bodies of all of your sprites you should theoretically be able to see where the game thinks they are and make a judgement call based on that. I don't think currently bodies calculate their positions based on the global coordinates of their sprites, though I guess there are arguments for and against that. I guess my solution would be more arrays! Have an array for all of your enemies, then several arrays holding each row, and then loop through the row arrays moving each sprite by the amount you'd normally have moved the groups each update. Link to comment Share on other sites More sharing options...
Miroku_87 Posted August 7, 2014 Author Share Posted August 7, 2014 Would I be crazy to extend the Physics.Arcade object and override the collide/overlap function to use global position? It'd be a real pity stopping to use groups and nested groups =/ Link to comment Share on other sites More sharing options...
lewster32 Posted August 7, 2014 Share Posted August 7, 2014 Hmm actually I'm wrong - it does seem to try and get the world coordinates:this.position.x = (this.sprite.world.x - (this.sprite.anchor.x * this.width)) + this.offset.x;this.position.y = (this.sprite.world.y - (this.sprite.anchor.y * this.height)) + this.offset.y;However, I don't think the world coordinates are being correctly determined, as the code that does that just looks at the parent position:this.world.setTo(this.parent.position.x + this.position.x, this.parent.position.y + this.position.y);When I'm guessing it should really be going through all of the parents to figure this out. Link to comment Share on other sites More sharing options...
Miroku_87 Posted August 7, 2014 Author Share Posted August 7, 2014 I agree, there should be a loop of all the parents. Link to comment Share on other sites More sharing options...
lewster32 Posted August 7, 2014 Share Posted August 7, 2014 I think that code was written with the assumption that groups wouldn't be nested... it probably needs to be updated. Link to comment Share on other sites More sharing options...
Miroku_87 Posted August 7, 2014 Author Share Posted August 7, 2014 who's going to notice it to them on github? You already know the line Link to comment Share on other sites More sharing options...
lewster32 Posted August 7, 2014 Share Posted August 7, 2014 The thing is, pixi has recently had a commit for global/local coordinate conversion, so this will probably be usable in Phaser next release. Miroku_87 1 Link to comment Share on other sites More sharing options...
Miroku_87 Posted August 7, 2014 Author Share Posted August 7, 2014 Cool! Let's hope it will be soon! =D Link to comment Share on other sites More sharing options...
Miroku_87 Posted August 7, 2014 Author Share Posted August 7, 2014 I worked around this by extending Sprite and creating my enemies from this new class.Now it works really better!Haven't tested it enough to say that with 100% of certainty.I will get back to you when I have done it /******* FixedSprite.js ********/FixedSprite = function(game, x, y, key, frame){ Phaser.Sprite.call(this,game, x, y, key, frame);};FixedSprite.prototype = Object.create(Phaser.Sprite.prototype);FixedSprite.prototype.constructor = FixedSprite;FixedSprite.prototype.absoluteX = function(){ var level = this; var absX = level.position.x; while(level.parent != null) { level = level.parent; absX += level.position.x; } return absX;};FixedSprite.prototype.absoluteY = function(){ var level = this; var absY = level.position.y; while(level.parent != null) { level = level.parent; absY += level.position.y; } return absY;};FixedSprite.prototype.preUpdate = function(){ if (this._cache[4] === 1 && this.exists) { this.world.setTo(this.absoluteX(), this.absoluteY()); this.worldTransform.tx = this.world.x; this.worldTransform.ty = this.world.y; this._cache[0] = this.world.x; this._cache[1] = this.world.y; this._cache[2] = this.rotation; if (this.body) { this.body.preUpdate(); } this._cache[4] = 0; return false; } this._cache[0] = this.world.x; this._cache[1] = this.world.y; this._cache[2] = this.rotation; if (!this.exists || !this.parent.exists) { // Reset the renderOrderID this._cache[3] = -1; return false; } if (this.lifespan > 0) { this.lifespan -= this.game.time.elapsed; if (this.lifespan <= 0) { this.kill(); return false; } } // Cache the bounds if we need it if (this.autoCull || this.checkWorldBounds) { this._bounds.copyFrom(this.getBounds()); } if (this.autoCull) { // Won't get rendered but will still get its transform updated this.renderable = this.game.world.camera.screenView.intersects(this._bounds); } if (this.checkWorldBounds) { // The Sprite is already out of the world bounds, so let's check to see if it has come back again if (this._cache[5] === 1 && this.game.world.bounds.intersects(this._bounds)) { this._cache[5] = 0; this.events.onEnterBounds.dispatch(this); } else if (this._cache[5] === 0 && !this.game.world.bounds.intersects(this._bounds)) { // The Sprite WAS in the screen, but has now left. this._cache[5] = 1; this.events.onOutOfBounds.dispatch(this); if (this.outOfBoundsKill) { this.kill(); return false; } } } this.world.setTo(this.game.camera.x + this.worldTransform.tx, this.game.camera.y + this.worldTransform.ty); if (this.visible) { this._cache[3] = this.game.stage.currentRenderOrderID++; } this.animations.update(); if (this.body) { this.body.preUpdate(); } // Update any Children for (var i = 0, len = this.children.length; i < len; i++) { this.children[i].preUpdate(); } return true;};/******* Alien .js ********/Alien = function(game){ FixedSprite.call(this,game,0,0,'alienimg'); this.physicsBodyType = Phaser.Physics.ARCADE; this.bodyEnabled = true;} lewster32 1 Link to comment Share on other sites More sharing options...
lewster32 Posted August 7, 2014 Share Posted August 7, 2014 Nice! Clever! Link to comment Share on other sites More sharing options...
Miroku_87 Posted August 8, 2014 Author Share Posted August 8, 2014 (edited) Ok I managed to do some more testing.Unfortunately I found another strange behaviour. As you'll see in the video I'm linking below, before one row of aliens moves there's a fraction of second in which all of them are in the left top corner and it's not just a debug render problem because if I shoot at that point I actually kill some alien.Maybe it's a preUpdate issue? I just don't know .__. Here the video:https://db.tt/hTLsWHJgAdditional Info: I'm moving the alien rows by using a timer.loop event Edited August 8, 2014 by Miroku_87 Link to comment Share on other sites More sharing options...
Recommended Posts