Jump to content

move player 32 by 32 pixels


Lucas
 Share

Recommended Posts

Actually, I'm making a rpg using phaser (html5) + nodejs (in real time), check out the picture below ... but everything I tried did not work .. because that function (sprite.x) does not work collision layers (tiled map).

 

The only problem is the que collisions are not working with sprite.x ... And yes only with sprite.body.velocity.x

 

(example image of my game)

 

capt06.gif

 

 


I've tested with up to 4 players online, and all corresponded exactly to the movement of the other. I add friends system, negotiate, and now I'm doing a battle system. 

 

It's a simple system, I might even release to download ...

Link to comment
Share on other sites

As per Rich's suggestion, have you tried moving by a fixed amount?

if(game.input.keyboard.isDown(Phaser.Keyboard.RIGHT)) {     sprite.body.x += 32;}

If you set the sprite's anchor to be its middle, this will allow you to move 32 pixels from its position to the center, assuming your map is 32x32 tiles, of the next tile.

sprite.anchor.setTo(0.5, 0.5);
Link to comment
Share on other sites

I would probably use a tween to do the movement, as that seems to be easiest way to move a sprite towards a position and stop the movement at that position.

 

Collision you should be able to check in advance with overlap detection. You can generate a new sprite with the body size same as your characters body, and just make the sprite full transparent. Then just place this transparent sprite where you plan to move your character, before actually moving the character. If the new position of the test sprite fires your overlap callback, the path is blocked, otherwise you are good to tween your character to that place.

 

Possibly not the most efficient implementation, but it should solve the problem.

Link to comment
Share on other sites

 

Show me an example of collision using the function of motion: sprite.body.x += 32;
 
not really find anything to help me, and to my knowledge is not as deep phaser ...

 

 

I was answering your original question about moving only 32 pixels at a time. That is how you do that, by moving an exact, fixed amount each time.

 

You are right that collisions won't work with this method. The problem is that the various physics systems in Phaser work off of velocity. They need to know the amount of movement (velocity or similar calculation) in order to separate the objects upon detecting collision. Moving the sprite's bodies directly does not involve velocity and will not trigger collisions usually.

 

r00's solution reads as if it might work, though. Before each move, testing to see if the sprite.width/height + 32 would trigger an overlap with specific tiles in the tilemap and, if not, calling the animation/tween and making the move.

 

Instead of 'Arcade' physics, you might have success using one of the other two systems as well. P2 uses a different, unit-based movement system, for example. If you didn't use gravity, you could have your players move around the world in something approximating 32 pixels. Maybe even something like the tilemap demo? It would be changing your code for a different physics system, but it might be closer to your total solution than my own first suggestion.

Link to comment
Share on other sites

But how can I get the data to validate whether the next step is a collision or not?

 

Well, if you want to keep the sprite.body.x/y += 32 code, you could use something like this example. Then, combine the checkOverlap with TilemapLayer.getTiles and Tile.intersects or checking its Tile.index. (If your colliding tiles are a separate layer, intersects would work, otherwise testing for its index would be a better fit.)

 

Within the update loop, check for input. For that direction, move a fully transparent sprite 32 pixels in that direction. Run the checkOverlap test. If it passes (returns false), move the actual sprite in that direction 32 pixels. If it fails (returns true), reset the fully transparent sprite to the same position as the real sprite and don't move.

 

I'm not sure how useful this analogy will be, but I think about in terms of navigating a two-dimensional matrix. From wherever you are, if you want to move in a new direction, you need to test the new x and y position of that direction. For 'up', that is y - 1. For 'left', that's x - 1. (Or, in this case, 32 pixels instead of just one unit.)

 

If you don't plan on using the physics system for velocity or other calculations, you could just use overlap-checking functions. One set of checks for the group of player sprites and another for the players against the tilemap.

Link to comment
Share on other sites

  • 7 months later...

Hello,

 

 

I'm currently writing a little roguelike and I was presented with the same problem. Make the player move, but respect collisions. I ended up not using overlap or collision detection from the tilemap, but do the checks myself. It's easier than it sounds.

 

Let's take a look at my map. A lot of the magic happens in the Tilemap; I extended the Phaser.Tilemap with a bunch of extra functionality. For example, in Tiled I have five layers:  Walls (collision layer), Background, Items, Objects, and Creatures

 

RmXWQb9.png

 

The blue knight, the drow and the blue ghost are creatures in the creature layer. They are animated in-game so they can't be a part of the tilemap. You *could* keep swapping tiles out to simulate animation, but eh, that's a lot of work and unflexible. What would happen if you moved a monster? You'd have to pop the tile out, sprite the creature- something you might have wanted to avoid anyway- and then put it back into the tilemap. So I opted to just extract all tiles in the Creature layer and push them into an Array. I do the same with Items, Objects, and Walls. The background can stay a tilemap because it's static and I don't need to do any checking on it (yet).

 

Now that we've popped all of the dynamic tiles off the Tilemap, converted them to Sprites, and placed them in Arrays, we are able to do some logic!

 

Let's say my hero is in Position (0, 0) and wants to move east to (1, 0). First, my game recognizes that my user has pressed the "Move East" button and wants to move a cell.

this.actionMap[settings.move_right] = () => this.tryMoveTo(toTileCoordinates(this.map, { x: this.player.x + 24, y: this.player.y }));

Now, there might be a wall, a monster, an interactable object, an item on the ground, or nothing there. This is what my logic looks like for when the player tries to move:

        private tryMoveTo(destination: TileCoordinates) {            // Darn, a wall  Can't move, so just return/optionally show a message            if (this.map.wallAt(destination))                return;            // Is there a creature in the way? If so, attack it.            if (this.map.creatureAt(destination)) {                this.attack(this.player, this.map.creatureAt(destination));            // Is there an interactable object in the way? If so, activate it.            } else if (this.map.objectAt(destination)) {                this.activate(this.player, this.map.objectAt(destination));            // There's nothing blocking our way  Let's go!            } else {                // But wait! Is there an item? If so, pick it up as we move.                if (this.map.itemAt(destination))                    this.pickUp(this.player, this.map.itemAt(destination));                this.move(this.player, destination);            }        }

All that's left to do is move my character. I call my UX Component, the GameView, to tween the player in order to simulate movement.

        move(entity: Phaser.Sprite, to: WorldCoordinates) {            var tween = this.game.add.tween(entity).to(to, 300, Phaser.Easing.Linear.None);            this.registerTweenDeletion(tween);            this.tweensToPlay.push(tween);        }

So far so good, but what happens in the Tilemap? Since I'm programming a pure roguelike, there is a very clear structuring of what can go on a tile. It allows me to test step-wise what is in a given tile. The ordering of first checking for walls, then creatures, objects, and items is no mistake. This enables me to have very specific checks for every type of object in the game:

        wallAt(at: TileCoordinates) {            return this.tileExists(at, this.WallsLayer);        }        itemAt(at: TileCoordinates) {            return _.find(this.items, (item: Phaser.Sprite) => _.isEqual(toTileCoordinates(this, item), at));        }        objectAt(at: TileCoordinates) {            return _.find(this.activatableObjects, (object: Phaser.Sprite) => _.isEqual(toTileCoordinates(this, object), at));        }        creatureAt(at: TileCoordinates) {            return _.find(this.creatures, (creature: Phaser.Sprite) => _.isEqual(toTileCoordinates(this, creature), at));        }

So much for the explanation. Perhaps some FAQ-style questions:

 

1. Why an Array, not a Group?

 

Groups are awful awful awful in my opinion. I found it difficult to search through a group as there is a lack of iterating functions. Of course there is forEach and iterate, but eeeeh. I found it a pain to use for my use-case.

 

2. Is this performant?

 

I think so. Array are naturally fast and for most small tilemaps there will only be a few dozen items/objects in them at any given time. I haven't done any real performance tests, so your mileage may vary. I'm also not planning on supporting mobile devices, so eh.

 

3. Source Code?

 

Because of the tileset, I opted to keep the repository private. That sucks, because I'd like to release my game to the public once I'm reasonably convinced that this system works. I will have convinced myself once the game works and is shipped :P Until then, I hope to whip a blog post or two describing in detail how I made this system work. To that end, I'd appreciate anybody calling me out if this design is just not feasible.

Link to comment
Share on other sites

  • 9 months later...

I have the same probleme so i tried the folowing this code work for x movement only because it's what i need you can add code for y movement. Hope that will help you

// the following code is in the update functionif (this.moving === false) {            if (cursors.right.justPressed(1000 / 60))            {                this.finalX = this.player.body.x + 32;                this.speed = +300;                this.moving = true;            }            else if (cursors.left.justPressed(1000 / 60))            {                this.finalX = this.player.body.x - 32;                this.speed = -300;                this.moving = true;            }        }        if (this.moving === true) {            if (this.speed > 0) {                if (this.player.body.x < this.finalX) {                    this.player.body.velocity.x = this.speed;                } else if (this.player.body.x >= this.finalX) {                    this.player.body.x = this.finalX;                    this.moving = false;                    this.player.body.velocity.x = 0;                }            } else if (this.speed < 0) {                if (this.player.body.x > this.finalX) {                    this.player.body.velocity.x = this.speed;                } else if (this.player.body.x <= this.finalX) {                    this.player.body.x = this.finalX;                    this.moving = false;                    this.player.body.velocity.x = 0;                }            }        }
Link to comment
Share on other sites

Why not use velocity normally and then stop the player (set velocity to 0) if(player.body.x % 32 == 0)? (or player.body.y, of course) You would still use velocity and have collisions enabled.

 

For continuous movement, you could add a check on keyboard keys to the 'if'.

Link to comment
Share on other sites

  • 6 months later...

Hi,

I had the same problem recently, attempting to make a Pacman where the character stops moving when you stop pressing the arrow keys. I needed continuous movement to make in fluid (if you keep pressing, it should move smoothly until you stop), but still limit it to the 32*32 grid of my game. And of course,with collisions (ideally using built-in arcade collisions). I did something along the line of Skeptron's answer, here is the code :
 

Game.inStopRange = function(coord,correction){
    // correction because it'll take one frame for the velocity to drop to 0, during which pacman will move by speed/fps
    return ((Game.pacman[coord]+correction)%32 == 0 || (Game.pacman[coord]-correction)%32 == 0);
};

Game.update = function(){
    game.physics.arcade.collide(Game.pacman, Game.layer); // Collision with tiles
    var speed = 120;
    var correction = Math.floor(speed/game.time.fps);
    if(Game.cursors.left.isDown)
    {
        Game.pacman.body.velocity.x = -speed;
        Game.pacman.animations.play('left');
    }
    else if(Game.cursors.right.isDown)
    {
        Game.pacman.body.velocity.x = speed;
        Game.pacman.animations.play('right');
    }else if(Game.inStopRange('x',correction)){
        Game.pacman.body.velocity.x = 0;
    }

    ...
};

(I only put the code for the x movements, obviously it's the same logic for y).

The idea is that the velocity should be maintained until Pacman is in a cell of the grid. However, if you just use if(sprite.x%32 == 0){velocity.x= 0;}, it doesn't work because it seems that the velocity is maintained for one frame before getting to 0 and your character ends up 2 pixels too far (speed/fps pixels too far, precisely). Hence my 'correction' variable, which is based on how many pixels Pacman will move in one frame, and anticipate whether it will be in a grid cell at that time. I hope it's understandable.

In summary, continuous grid-locked movement using velocity and arcade collision detection.

Now, it seems to work fine for me, but I don't know if relying like that on the FPS doesn't make the solution a bit brittle? Any feedback is appreciated because although it works, it doesn't feel elegant somehow.
 

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

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