Jump to content

Moving sprites by .velocity behaves differently based on browser focus/browser type?


Recommended Posts

I'm trying to get sprites to move around a maze, and so I do things like "if your x position is > 420, then set velocity.x to -50 and keep moving left, then stop once you get to x = 445".  The problem is, it seems hit or miss on whether they actually do what I tell them to. 


Sometimes they stop at x == 420, and sometimes they don't.  In FireFox, they never do.  In Chrome, they stop only if the game is in focus.  If it's not in focus, they keep walking. 


Shouldn't the game behave the same, in the same browser, regardless of whether the windows containing the game is active or not?  Or is this something that is caused by how I am moving them?

        /***************************        ****   UPDATE ENEMIES  *****        ****************************/        // 'enemies' is a Group of enemy vars.        for (var i = 0; i < enemies.length; i++)        {            if (enemies.getAt(i).x > 420)            {                // move left                enemies.getAt(i).body.velocity.x = -50;                                // Stop once sprite arrives at x == 420                if (enemies.getAt(i).x == 420)                {                    enemies.getAt(i).body.velocity.x = 0;                };            }        }
Link to comment
Share on other sites

That is a pretty precise condition

if (enemies.getAt(i).x == 420)

If you enemy is a fraction over or under, it won't trigger and will probably overshoot the mark the next frame.

You could use:

if (enemies.getAt(i).x <= 420){    enemies.getAt(i).x = 420;    enemies.getAt(i).body.velocity.x = 0;}

Are these enemies walking around the same maze you were working on before?

Can you not have them collide with the maze walls and set a new velocity depending on what side they collide on?



Also, you should look at using group.forEach instead of iterating like that.

Or, if you are planning on killing the enemies, forEachAlive might be better.

Works like this:

enemies.forEachAlive(function(enemy){    //Your code here, but replace 'enemies.getAt(i)' with 'enemy'...}, this/*callback context*/);
Link to comment
Share on other sites



Thanks again for helping me out, I really do appreciate it! 


I was going to use game.physics.moveToXY(), but there doesn't seem to be a way to make it stop once you use it.  I'm pretty sure that I saw somewhere in phaser.js that there wasn't a way.  But if there was a way to stop it, that'd be easiest, because then I could just save the pathing in "steps" (go to this spot.  go to that spot.  etc).


That's a good suggestion with doing a check for "around" the area that I need them to get to, and then putting them there.  I'd have them collide with the walls, but then that looks kind of silly - there's a bit of room round each sprite, and I was hoping to get them to "walk" down the middle of each of the roads that make up the "maze".  I thought about bringing the walls inside the "roads" a bit more (that's what the maze is, technically...roads to the "goal" area in the game), but if I made them any smaller, the player would have a hard time moving.  I imagine it would be frustrating playing a game where the player clips his arm on the corner of a "wall" and can't move because of it, especially when there's a time limit :)


For .forEachAlive(), I have two questions that I hope you can help me with.


  1. Where is forEachAlive() located in the documentation?  I don't see it under Sprite, Physics (Arcade), or Game. 
  2. is there a way to get the index of which "object" you're working with?  Let's say I have 10 enemies still alive, is there a way to do something like this?
            if (enemy.index == 1)            {                console.log('Im Number One!');            };
Link to comment
Share on other sites

1 it's a group property : http://docs.phaser.io/Phaser.Group.html#toc39

2a there are group methods about item indexes : getAt(index), next(), previous()

2b there's also a property cursor : http://docs.phaser.io/Phaser.Group.html#toc11


I haven't read the Group object code so far, but I guess it's not implemented as a simple javascript array but rather as double-linked list

Link to comment
Share on other sites

Oh ok, I didn't realize it was in Group.  I had been using getAt(index) in loops (as Xeke noted above).  My goal is to make this "enemies navigating a maze"  deal simpler, and it doesn't seem to be working out that way.  Xeke mentioned .forEachAlive, which is awesome (and thank you for showing me where it was, because I missed it somehow). 


For instance, right now I'm testing out a sort of "waypoint" system, so that I don't have to make the enemies change velocity based on location, but rather based on whether they collided with a specific waypoint.  Each waypoint is a 1 pixel transparent square that I stretch to 10 pixels for larger coverage, and then do this:


        waypoints = game.add.group();        for (var i = 0; i < 8; i++)        {            if (i == 0) {                var waypoint = waypoints.create(445,125, 'waypoint');                waypoint.scale.setTo(10,10);                waypoint.body.immovable = true;            }            else if (i == 1) {                var waypoint = waypoints.create(445,275, 'waypoint');                waypoint.scale.setTo(10,10);                waypoint.body.immovable = true;            }            else if (i == 2) {                var waypoint = waypoints.create(445,465, 'waypoint');                waypoint.scale.setTo(10,10);                waypoint.body.immovable = true;            };            // And so on...        };

That places each of the waypoints where I need them on the map.


And then what I wanted to do, was to call a collision check like this...

game.physics.collide(enemies, waypoints, waypointHandler(), null, this);

And then have the waypointHandler() function check which waypoint was "hit", and change the velocity of the enemy that hit it.  Something like this...

    function followWaypoints (enemy, waypoint) {        // Top-right waypoint, move enemy down        // I want to be able to use something like [if waypoint index = 0, then...]        // Because this code below obviously doesn't work (it doesn't know what "waypoint" is, I think).        if (waypoint.x == 445 && waypoint.y == 125) {            enemy.body.velocity.x = 0;            enemy.body.velocity.y = 50;        };        // Right center waypoint, move left        if (waypoint.x == 445 && waypoint.y == 275) {            enemy.body.velocity.x = -50;            enemy.body.velocity.y = 0;        };        // Left center waypoint, move up        if (waypoint.x == 220 && waypoint.y == 275) {            enemy.body.velocity.x = 0;            enemy.body.velocity.y = -50;        };    }

But the problem is, inside the waypointHandler() function itself, I don't know how to check which enemy hit which waypoint.  Whenever I try to pass waypoint.getIndex(), I must be doing it wrong because  putting that into my collision statement just comes back with an error saying Uncaught TypeError: Object [object Object] has no method 'getIndex'


I mean, it looks like .getIndex() requires that we pass it a child, but even when I did this...

        enemies.forEachAlive(function(enemy)        {            console.log('My index is: ' + getIndex(enemy));        });  

It gives me an error saying that getIndex isn't defined, so I'm pretty sure that I'm using it wrong.

Link to comment
Share on other sites

You'll be pleased to know that in 1.1.4 you can set Sprite.body.x/y directly without having to use velocity and still get collision responses, which should solve this issue (although I would still advocate not using such precise value comparisons).


If I can only just get the SAT to tilemap working without jittering so badly I could release the bloody thing!

Link to comment
Share on other sites

naive question :


won't it be better for you to simply use a A-star algorithm to have your sprites moving in your maze ?


here is a phaser plugin : https://github.com/appsbu-de/phaser_plugin_pathfinding



Wow, that's a neat find! 

Looking at the example, I see how it's implemented, but I'm not using tiles or a grid in my game at all.  Honestly, I tried looking at using a tilemap first, but it confused me once it got around to the JSON part.  I even installed Tiled and saved my map as a .JSON file, couldn't get it to work, and was afraid of flooding the forum here with any more questions (see my post history...1 week and I'm all over the place). 

My game, as it stands, is just a background image of the road, grass, the "goal", and the three "lanes" that enemies will spawn out of.  I made "walls" that are 1 pixel in width to block off the road, so that the player and enemies can't walk into the grass, but those were put down at specific coordinates (I suspect that if someon resizes the canvas, my game will no longer work).

So, in short...I'm not knowldgeable enougj (right now) to figure out how to put that in my game. :(

Link to comment
Share on other sites

You'll be pleased to know that in 1.1.4 you can set Sprite.body.x/y directly without having to use velocity and still get collision responses, which should solve this issue (although I would still advocate not using such precise value comparisons).


If I can only just get the SAT to tilemap working without jittering so badly I could release the bloody thing!


Wow, thanks for dropping by!  If I can get this "waypoint" idea to work, or if I can figure out how to add in the addon that Jerome posted about above (which means that I'll actually need to get tilemaps/sets to work in my game, instead of just using a background), I can get away from those silly coordinate checks.  Is there any chance of a moveToXY(x,y) function that actually STOPS at the x,y point that it was moving towards?  That, also, would solve this problem, and it would do so in a very simple manner. ;-)

Link to comment
Share on other sites

getIndex() is a method on Group, so 'enemies.getIndex( enemy )' should return you the index of 'enemy' in the 'enemies' group.


that said, I'm not clear on why you need the index - you already have the object itself. anything you need to do with/to the 'enemy' you can perform directly on that object...


I think your waypoints idea is a good one (it's what I had in mind as I read through your initial posting above). using a*star wouldn't be hard - you don't need to use a tilemap, you can define your own custom grid data structure - but to get it to exhibit the behaviour you describe, with the enemy sprites walking down the "middle" of the path, your grid would get more complicated than a simple "one square for the path" structure, because the sprites would move all the way to the edge of that 'path' square before hitting the edge and changing direction. (you could modify the a* code to do this easily enough, but why bother). unless you plan on creating lots of different levels and/or random levels - in which case you'll want the path-finding to be algorithmic, because hard-coding each levels path-finding logic will get real old, real quick.

Link to comment
Share on other sites

jcs, you said:

"anything you need to do with/to the 'enemy' you can perform directly on that object."

That's the thing, I don't know how to do what I want.  Here's why:

I have a group called "waypoints".

        waypoints = game.add.group();    // There are about 8 waypoints, each with different coordinates.        var waypoint = waypoints.create(445,125, 'waypoint');        waypoint.scale.setTo(10,10);        waypoint.body.immovable = true;

I have a group called "Enemies".

       enemies = game.add.group();        var enemy = enemies.create(790, 0, 'enemy');        enemy.body.allowGravity = true;        enemy.body.collideWorldBounds = false;

What I want to do, is check to see WHICH enemy collides with WHICH waypoint, so that I can change that specific enemy's direction so that it moves towards the next waypoint.  How can I do this? 

This is what I thought would be the right way, by getting the indices of the enemy and waypoint that were collided, and passing those indices to a function...

        game.physics.collide(enemies, waypoints, waypointHandler(enemies.getIndex(enemy), waypoints.getIndex(waypoint)), null, this);

And the function itself would be like this...

    function waypointHandler (enemyIndex, waypointIndex)    {        if (waypointIndex == 1)        {            // Stop moving left, start moving down.            enemies.getAt(enemyIndex).body.velocity.x = 0;            enemies.getAt(enemyIndex).body.velocity.y = 50;        }        else if (waypointIndex == 2)        {            // Stop moving down, start moving left again.            enemies.getAt(enemyIndex).body.velocity.x = -50;            enemies.getAt(enemyIndex).body.velocity.y = 0;        };;       }

But this doesn't work.  If I use it, I get an error that says "enemy is not defined" on the waypointCollision function call...it doesn't know what enemy I'm passing to enemies.getIndex().

        game.physics.collide(enemies, waypoints, waypointHandler(enemies.getIndex(enemy), waypoints.getIndex(waypoint)), null, this);

On top of this, in the waypointCollision() function, I had it send something to the console log just to see if the collision was called...and it turns out that it is colliding ALL THE TIME, as soon as I start the game, even when enemies aren't bumping into the waypoints:

    function waypointHandler (enemyIndex, waypointIndex)    {        console.log('Collision between enemy and waypoint detected!');    }
12:35:49.080 "Collision between enemy #1 and waypoint #1 detected!" index.html:353 


So am I calling on the function the wrong way?  Because I'm pretty sure it's not supposed to go off every milisecond...lol! 

Link to comment
Share on other sites

okay, a couple of things. last first:


- you aren't passing the function 'waypointHandler' to collide. rather, you are calling waypointHandler() and passing the result to collide. this is why it is getting called every frame. just pass the function itself (e.g. just 'waypointHandler'). the callback for collide will be called with the colliding objects as arguments - you can't change what they are going to be.


- as far as needing to identify the waypoint / enemy goes: add an 'id' property to the objects and set it when you create them. it can be a simple index or a name or whatever. just something unique to identify them. then, in your waypointHandler you can check it and take action: 'if( enemy.id === 1 ) { /* do some stuff */ }'. getting the index of an item in a collection may be expensive, depending on how the collection is implemented. it's the kind of thing best avoided where possible. when you need values like this repeatedly (like every frame) it's best to cache them.

Link to comment
Share on other sites

You know, it's funny that you answered that first one...I responded while I was in the car during my lunch break (this site is blocked at work), took a nap, and then went back to work.  I sat down, finished my work project, started fiddling with the game (at least it's programming, and it keeps my mind going when I'd otherwise be drooling at my desk)....and solved my problem.  When I had first read about physics.body.collide, it was here in the forums.  Then I looked in the documentation, but couldn't find it.  And when I found it, I didn't understand what it meant at first.  Thanks for providing the added clarification!


Now, I've got this healthy set of collision checks...

        /***************************        ****  CHECK COLLISION  *****        ***************************/        game.physics.collide(player, walls);        game.physics.collide(player, enemies);        game.physics.collide(enemies, walls);        game.physics.overlap(enemies, waypoints, waypointHandler, null, this);

And some pathing logic like this:


      if (waypoints.getIndex(waypoint) == 0)        {            // Walk down            enemy.body.velocity.x = 0;            enemy.body.velocity.y = 30;            enemy.animations.play('down');
Link to comment
Share on other sites


  • Recently Browsing   0 members

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