Jump to content

Grid game - wrapping sprites around screen with collision support


RickB
 Share

Recommended Posts

I started playing around with Phaser (pretty cool so far!) building a simple puzzle game and I'm curious if there is a built in way to accomplish some game mechanics I have in mind.  The game has a grid based level that allows the player to move their sprite either vertically or horizontally per move.  Some tiles are 'walls' that will block the player tile.  This is all working using the built in tilemapLayer, sprite and collision system.

 

One of the mechanics I have in mind is to allow the player to move off the screen to the right, and reappear on the left side (or vice versa).  I have this working in basic form by listening to the onOutOfBounds Phaser.Signal and adjusting the player tile across the screen accordingly.  This approach has two problems that I'm not sure if there is something built in that I could be using or if I should extend sprite or arcade to handle the situation (or some better way).

 

Issues:

  1. As the player begins to leave the right side of the screen, I would like part of their graphic to appear on the left of the screen and part on the right.  In a way, there should be no "out of bounds".  The problem with using 'onOutOfBounds' is that it only fires when the tile is completely off the screen (which makes sense, but doesn't work for me).
  2. Building on the scenario above, if the player tries to leave the right edge of the screen and there is a wall tile on the left side of the screen, I should prevent them from leaving the right side of the screen.  In the example grid below, the 'P' should not be able to move to the right and wrap around to the left side because there is a wall on the left side.  
[1, 1, 1, 1, 1][1, 0, 0, 0, P][1, 0, 0, 0, 1][0, 0, 0, 0, 0][1, 1, 1, 1, 1]

I'm curious if there is a command to "wrap" the world that would inform the physics system to account for and perform collision with tiles on the other side of the tilemap.  I'm assuming there isn't because I haven't seen one in the docs or the source, but figured I'd ask to make sure.

 

My current thoughts to solve the problems:

  1. Create a player class that contained two player sprites.  As the primary sprite moved off the right side of the screen, coordinate moving the secondary sprite in on the left and then swap the two at some point and reset secondary.
  2. perform the collision check for tiles on the other side of the tilemap manually in an extended sprite class in the update() method or extend the arcade class and override collideSpriteVsTilemapLayer to check the tile on the opposite side of the screen as soon as the sprite leaves the screen.

Any ideas or suggestions are greatly appreciated!

 

Link to comment
Share on other sites

Interesting use-case! There is no way to do this automatically as you've surmised. Personally I would use the two-sprites approach to make it appear on the left/right at the same time. Also you could use getTile on the layer to see if there is a tile on the left-hand side as they walk off the right, and then block them or not. You could do this in the processCallback of collide.

 

Actually thinking about it you could also do it like this: Have 2 layers for your map. So the top layer is the visible one, with all the blocks in, and the 2nd layer is set to visible false, so it doesn't render, but is the one the player collides with. Then you could only draw in the tiles that would cause an actual collision, leaving gaps where they can wrap around.

Link to comment
Share on other sites

Thanks for the suggestions!

 

Good idea to use the processCallback for the additional check.  I'll look into that.  I'm not following the second idea though.  I get the point of using a hidden collision map, however what would I add to it to prevent the player tile from wrapping?

Link to comment
Share on other sites

Makes sense.  Now I'm wondering if I could generate the hidden layer on loading of the level.  It might be as simple as copying all edge tiles to their corresponding opposite side of the map in the extra column / row.  If possible, it would save having to have two tilemaps that are pretty similar.  I like this idea and will try it next.

 

That being said, I started playing around with the getTiles function for the specific scenario of testing if the sprite is allowed to wrap off the right and on to the left. I got it to work, but found something I couldn't seem to make sense of. When the sprite leaves the right of the screen, I call the following function:

// get the tile on the other edge of the screen.  Hard-coded for right to left wrap testingvar tiles = tileMapLayer.getTiles(0, sprite.body.y, sprite.body.width, sprite.body.height, false); 

Because the x, y, height, and width I am passing to the function match a tile in the map exactly, I was surprised to find that there are 4 tiles returned.  It's returning the tile I am expecting to get, the one to its right, bottom and bottom right.  I would have thought only one tile would be returned if the x, y, height, and width doesn't overlap into multiple tiles.

 

I modified the getTiles function so that tw and th get set to 1 when width / height is less than or equal to tileWidth / tileHeight and that made getTiles work as i would have expected, however it broke something in the physics for bottom and right collisions (makes sense given the change I made).  Anyway, I reverted the change.  Is there an overarching reason getTiles works this way?

Link to comment
Share on other sites

Creating a collision map on the fly works really well.

 

Now I just need to figure out how to offset the collision map so it is in line with the regular map.  As it stands now, it's off by one tile because of adding the top and left row / columns.

// Create the collision tilemapvar collisionTilemap = new Phaser.Tilemap(game);collisionTilemap.create("Collision Map", 22, 16); // real tilemap is 20x14      // fill the collision mapcollisionTilemap.paste(1, 1, tilemap.copy(0, 0, 20, 14)); // Copy the whole mapcollisionTilemap.paste(0, 1, tilemap.copy(19, 0, 1, 14)); // move right to leftcollisionTilemap.paste(21, 1, tilemap.copy(0, 0, 1, 14)) // move left to rightcollisionTilemap.paste(1, 0, tilemap.copy(0, 13, 20, 1)); // move bottom to topcollisionTilemap.paste(1, 15, tilemap.copy(0, 0, 20, 1)); // move top to bottom      // Add it to the gamecollisionMapLayer = game.add.tilemapLayer(0, 0, 800, 600, tileset, collisionTilemap, 0);collisionMapLayer.visible = false;  
Link to comment
Share on other sites

  • 2 years later...
 Share

  • Recently Browsing   0 members

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