ekstrakt Posted July 16, 2014 Share Posted July 16, 2014 Hi all, I have a bit of weird behaviour in my code, while trying to optimize it. Setup:A level with a tilemap layer, with enemies and bombs.The enemies extend the Phaser.Sprite class.Arcade physics.Gravity is on.When a bomb explodes, it applies force to the enemies, pushing them away (both horizontally and vertically). The issue:When I use States update() function to check for collision, it works fine, the enemies are launched in the air (depending on proximity)://pseudo codeGameState.prototype.update = function(){ Phaser.Physics.Arcade.collide(enemiesGroup, layer);}Having a look at Phaser's source code, I want to optimize my code, and skip unnecesary object type checks. Because I know the object types of the stuff I want to check collision on, I use Sprite.update() function to check for collision.//pseudo codeEnemy.prototype.update = function(){ Phaser.Physics.Arcade.collideSpriteVsTilemapLayer(this, layer);}With this, the enemies are pushed only horizontally, which is the issue. In short, from the source code (physics/arcade/World.js, line 371), Phaser.Physics.Arcade.collide(object1, object2) checks the passed objects types and calls the coresponding function, in this case Phaser.Physics.Arcade.collideSpriteVsTilemapLayer(object1, object2). By order of internal Phaser's calling of functions, State.update() gets called first, then Sprite.update(), but I think the call order shouldn't have any effect. The reasons behind the optimization:I might have quite a lot of enemies at any given time (150-200), so I want the code to run without checking every enemy for the object type.Also, from OOP point of view, it's better to have the enemy itself check for collision, instead of the state. So, any idea on how can I have this optimization, or why is there a difference? Link to comment Share on other sites More sharing options...
InsaneHero Posted July 17, 2014 Share Posted July 17, 2014 Just a wild guess, but could it be something to do with gravity effects? So either your objects could be sinking into platforms from gravity so the vertical forces can't push them out... or maybe the gravity is being added in such a way to erase the vertical explosion force.I can't think of any other reason why the horizontal forces would continue to work but the vertical ones would vanish. When working in a framework, order of operations will often sneak up and bite you in the ass. Unfortunately you need to know *everything* the framework does in order to know whether changing the order is safe or not. Generally I just try it and only worry about the details when something breaks Link to comment Share on other sites More sharing options...
ekstrakt Posted July 17, 2014 Author Share Posted July 17, 2014 It has nothing to do with how the gravity or velocity is added. The enemies are affected by the world gravity, and when a bomb explodes, their vertical velocity is changed (enemy.body.velocity.y += calculatedNumber). The only difference is the place where I check for collision (State or Sprite). As for the call order, I can't change it, since it's internal part of Phaser. Link to comment Share on other sites More sharing options...
codevinsky Posted July 17, 2014 Share Posted July 17, 2014 The reasons behind the optimization:I might have quite a lot of enemies at any given time (150-200), so I want the code to run without checking every enemy for the object type.Also, from OOP point of view, it's better to have the enemy itself check for collision, instead of the state. So, starting off, I'm going to assume you aren't using groups. That's a huge mistake, especially for things like this. Secondly, instead of calling the base phaser classes, you have access to all the things you need inside of the game object. I don't know if what you've done has exposed a bug or not, but try doing this first:create: function() { this.enemies = this.game.add.group(); // add 10 enemies for(var i = 0; i < 10; i++) { this.enemies.add(new Enemy(this.game, x, y, key, frame)); } // we now have 10 enemies... let's assume you have a tilemapLayer setup properly this.layer = { ... pseudocode for tilemap layer ... }},update: function() { this.game.physics.arcade.collide(this.enemies, this.layer);},Using the built in arcade physics collide method takes care of figuring out what type of collisions need to take place and using a group means that you can tell the physics system to only collide the objects in that group. Link to comment Share on other sites More sharing options...
rich Posted July 17, 2014 Share Posted July 17, 2014 I believe the issue is the way you're calling the physics methods. You can certainly skip the generic 'collide' method, to avoid the type check, but you are treating it as if it's a Static method, but it isn't. It needs access to local properties in order to do the collision (forceX being one such property). Without access to those it will just do a horizontal check every time, because it can't see the value of forceX. Pretty sure all you need do is change the way you're calling it, so you use a local reference to the game from within the Sprite. (this.game.physics would work as Sprite always has a reference to the game itself) lewster32 1 Link to comment Share on other sites More sharing options...
ekstrakt Posted July 17, 2014 Author Share Posted July 17, 2014 I believe the issue is the way you're calling the physics methods. You can certainly skip the generic 'collide' method, to avoid the type check, but you are treating it as if it's a Static method, but it isn't. It needs access to local properties in order to do the collision (forceX being one such property). Without access to those it will just do a horizontal check every time, because it can't see the value of forceX. Pretty sure all you need do is change the way you're calling it, so you use a local reference to the game from within the Sprite. (this.game.physics would work as Sprite always has a reference to the game itself) The code I wrote in the original post is pseudo code, for easier explanation of the methods used. I'm calling the physics methods using the game object itself. This is the actual code:Enemy.prototype.update = function(){ this.game.physics.arcade.collideSpriteVsTilemapLayer(this, this.game.globals.layer); ....VSStateMainGame.prototype.update = function(){ this.game.physics.arcade.collide(this.game.enemies, this.game.globals.layer); ....}(I'm hijacking the game object (adding my globals object to it), to pass variables around)) Link to comment Share on other sites More sharing options...
rich Posted July 17, 2014 Share Posted July 17, 2014 Shove a trace or a debugger call into the separate function then and be sure it is actually calling separateY. Link to comment Share on other sites More sharing options...
ekstrakt Posted July 18, 2014 Author Share Posted July 18, 2014 From debugging, they both call the same collision method (Phaser.Physics.Arcade#separateTile), and it has nothing to do with the collision. So, it comes to my original assumption about the origin of the issue: the order of calling of State.update(), Sprite.preUpdate() and Sprite.update() methods. This order interferes with how and when the Sprites velocity is calculated, meaning the calculation lags behind the rendering. To explain:Because State.update() gets executed first, it calculates the new velocity values. Then Sprite.preUpdate() gets executed and it sets the Sprites newVelocity property (Phaser.Physics.Arcade.Body#newVelocity) to the correct value. Then comes the Sprite.update() and the rendering. In what I'm trying to accomplish, the collision gets checked in Sprite.update(), so it's after Sprite.preUpdate() and the engine renders the Sprite with the old velocity values. A way to get around this issue would be to somehow get the collision check to run before Sprite.preUpdate(), but still within the same class.I was thinking of overloading the Sprite.preUpdate() method, making it check for collision, and then run the original preUpdate() method, like this:Enemy.prototype._oldPreUpdate = Enemy.prototype.preUpdate;Enemy.prototype.preUpdate = function(){ this.game.physics.arcade.collideSpriteVsTilemapLayer(this, this.game.globals.layer); return this._oldPreUpdate();} but it doesn't work. So, any suggestions? Link to comment Share on other sites More sharing options...
Recommended Posts