Phaser programming skills and phaser programming skills
February 6, 2015
Welcome!
After discussing the platform jump game mechanism for several weeks in a row, we should take a break. Therefore, this week's tutorial will be based on the features that we often talk about on the Forum: Grid movement, or a more specific point: how to be like Pacman (Note: Eating beans or genie on a red-white machine) in this way, move in the grid.
The code we discussed this week allows players to elegantly move in tile maps and turn in small spaces. We will also build the core code of the Pacman game.
Obtain source code
Here I will only highlight the most important part of the code. So please first browse the code. If you have any questions about the code, you can go to the Forum to ask.
Run/edit the automotive game code to jsbin or codepen)
Run/edit the Pacman code to jsbin or codepen)
Clone the Phaser programming skills code to git repo.
Infrastructure Construction
We need a gamer Genie and a tile map. A tile map contains the layout of a level. Here we draw a simple level in Tiled (Translator's note: Tiled official website http://www.mapeditor.org:
This software exports a JSON file and imports it into the game together with tileset. In the create method, all objects are generated:
this.map = this.add.tilemap('map');this.map.addTilesetImage('tiles', 'tiles');this.layer = this.map.createLayer('Tile Layer 1');this.map.setCollision(20, true, this.layer);this.car = this.add.sprite(48, 48, 'car');this.car.anchor.set(0.5);this.physics.arcade.enable(this.car);this.cursors = this.input.keyboard.createCursorKeys();this.move(Phaser.DOWN);
We have created maps and layers. The collision is set to tile 20 (dark-gray brick ). The car is placed in the upper left corner of the map and moved down from the very beginning ..
In the update function, we detect the collision with the tile map:
this.physics.arcade.collide(this.car, this.layer);
Current Problem
Moving in a player's map is a game challenge that needs to be addressed. Although this seems simple on the surface, it actually requires the player to have a basic understanding of the surrounding conditions.
The player uses the up and down arrow keys to control the movement. When the button is pressed, the player starts to move in the corresponding direction until it hits the wall or presses other arrow keys to another direction.
In the above section, the car is approaching a crossroads. If the user does not press any key, it will continue to move down. However, if you right-click the gap to the right of the wall, the car will open to the right.
You are surrounded.
So how does a car know whether it can turn or when it should turn? To figure this out, we created four temporary tiles around the car.
In the update function, we will use the built-in features in the Phaser Tilemap class, which can be used to scan special tiles:
this.marker.x = this.math.snapToFloor(Math.floor(this.car.x), 32) / 32;this.marker.y = this.math.snapToFloor(Math.floor(this.car.y), 32) / 32;var i = this.layer.index;var x = this.marker.x;var y = this.marker.y;this.directions[Phaser.LEFT] = this.map.getTileLeft(i, x, y);this.directions[Phaser.RIGHT] = this.map.getTileRight(i, x, y);this.directions[Phaser.UP] = this.map.getTileAbove(i, x, y);this.directions[Phaser.DOWN] = this.map.getTileBelow(i, x, y);
Tilemap.getTileLeft
Similar functions are used to implement the functions we mentioned above: return the tile on the left of the given coordinate (if not found, the rangenull
).
Because these functions are based on tile coordinates rather than pixels, we need to first find the exact location in the map of our car. We call the x and y values of a car.Math.floor
Function, and then usePhaser.Math.snapToFloor
Convert to grid coordinates. In this step, you will get the exact tile where the car is located. We store the results inmarker
Variable.
Four surrounding tiles are stored indirections
Array. When the rendering debugging switch is enabled, we can see that the car knows about its surroundings:
Green tiles indicate that cars can move safely. Red indicates an obstacle, and white indicates the current direction of movement.
Place a turning icon
Determining whether a car can turn is the first thing to solve. The second solution is to tell it when to turn, because we want it to turn when it quickly reaches the right position of the map. Otherwise, it will hit the wall and stop moving forward.
AvailablecheckDirection
Function.
This function requires a parameter: the direction of the car to turn. This is a constant in the Phaser direction, for examplePhaser.LEFT
OrPhaser.DOWN
.
The first thing this function does is to determine whether the following conditions are met:
The direction of the car is the direction to turn
No tiles in that direction
The tile in that direction is not a "security tile" (for example, a wall)
If any of the above conditions is not met, a steering flag will be set next. This flag is stored inturnPoint
, This IsPhaser.Point
Object, saving the coordinates of the point where we want the car to change its direction.
if (this.current === this.opposites[turnTo]){ this.move(turnTo);}else{ this.turning = turnTo; this.turnPoint.x = (this.marker.x * this.gridsize) + (this.gridsize / 2); this.turnPoint.y = (this.marker.y * this.gridsize) + (this.gridsize / 2);}
The ideal turning point is the center of the square that the car is currently driving. You can see a yellow dot in the figure:
Warm and Fuzzy Inside
When the car. x and car. y match the turning point value, the car will turn to a new direction. If the car moves at a pixel speed per frame, that's okay. However, if we want to apply acceleration effects or other methods to change the speed of a car, there will be problems. Because the x/y coordinates of a car will only be close to the turning point rather than exactly equal.
To solve this problem, we usePhaser.Math.fuzzyEqual
This function. It accepts two values and a threshold value. It will compare two values if they are within the threshold range and they are considered equal:
this.math.fuzzyEqual(a, b, threshold)
This is meeting our needs. For a speed of 150, our threshold can be set to 3. This value is sufficient to ensure that the car does not skip the turning point. Inupdate
In the function, we will check whether the car has reached the turning point.
When the car arrives, we will reset its coordinates, reset the coordinates of the car's rigid body, and then turn to the new direction:
this.car.x = this.turnPoint.x;this.car.y = this.turnPoint.y;this.car.body.reset(this.turnPoint.x, this.turnPoint.y);this.move(this.turning);this.turning = Phaser.NONE;
By adding the last part of the code above, you can now freely drive on the map, turn at the corner, and hit the wall at will.
Enter Pacman
Let's use the above working mechanism to clone a Pacman. The first build is the same: a player Genie and a tile map. The difference is that our Pacman genie is dynamic:
Animation is handled by Phaser Animation Manager:
this.pacman.animations.add('munch', [0, 1, 2, 1], 20, true);this.pacman.play('munch');
Howevermove
In the function, we need to turn its face to a new direction:
this.pacman.scale.x = 1;this.pacman.angle = 0;if (direction === Phaser.LEFT){ this.pacman.scale.x = -1;}else if (direction === Phaser.UP){ this.pacman.angle = 270;}else if (direction === Phaser.DOWN){ this.pacman.angle = 90;}
We reset its horizontal scaling and angle, and then adjust it based on its direction. Its face is right by default, so we can adjust it throughscale.x
To make it left. To make it face up or down, you need to rotate it.
Another important part is that Pacman is actually larger than the mesh, so we need to adjust its rigid body to the mesh size:
this.pacman.body.setSize(16, 16, 0, 0);
This sentence sets a 16x16-sized rigid body at the center of the genie (32x32 size), which perfectly adapts to the 16x16 size grid.
Beans
Pacman needs some beans to eat. Bean has been painted to the tile map using tile 7. So we will use the Phaser feature to convert all the 7 tiles into genie.
this.dots = this.add.physicsGroup();this.map.createFromTiles(7, this.safetile, 'dot', this.layer, this.dots);this.dots.setAll('x', 6, false, false, 1);this.dots.setAll('y', 6, false, false, 1);
First, retrieve the bean tile, replace it with a blank tile (Security tile), and thendots
Add a genie to the group.setAll
The function is used to adjust the position of the bean Genie and add 6 pixel offsets because they only have 4x4 sizes, which puts them in the center of the tile.
The collision detection between Pacman and beans isupdate
Function:
this.physics.arcade.overlap(this.pacman, this.dots, this.eatDot, null, this);
If they overlap, call:
eatDot: function (pacman, dot) { dot.kill(); if (this.dots.total === 0) { this.dots.callAll('revive'); }},
Beans are destroyed. If the number of beans in the group changes to zero, we need to regenerate the beans. So you can eat the beans again!
We hope you can see that we only use a small amount of code, and now we have implemented the most basic eat bean game.
Star Bug
Based on the code above, we use these concepts to further evolve the game. Add more levels, flying enemies, and a large number of collections. The final result is the Star Bug game:
This game will appear in our upcoming Phaser Book of Games Book.