Writing games can be both challenging and rewarding.
Starting game development is an overwhelming endeavor. There are many game engines, all of which do different things well. Even after choosing an engine, you must learn new concepts, design patterns, user experience, game design...the list goes on.
To help you dive into game development, I’m going to demonstrate the process I used to build my simple game, Uniball.
Choosing the Engine
In order to initialize Phaser and get a canvas up and running, I created a new game object. This is very simple in Phaser. All that needs to be done is to call “Phaser.Game” and pass in an object that contains configuration options. Things such as width, height, background color game type, etc. The pen below demonstrates making a game canvas that is 400x400 pixels.
The next step is to pass an object that contains a state to Phaser. State is, as the name implies, the state of the game. If you’ve worked with React you will be familiar with the concept. The three functions I’ll work with are “preload,” “create,” and “update.” These functions get called automatically by Phaser when appropriate.
- Preload – Good for loading assets such as images and fonts
- Create – This is where game objects are created
- Update – This function gets called every frame
After creating these three functions, they are passed to the state property of the Phaser game object.
Game Rules & Design
The objective of Uniball is to collect balls that match the color of your “player” ball. There are three colors - red, yellow and blue, as well as a “wild” ball that changes its color every second. If you touch a ball that doesn’t match the color as your “player,” it’s game over.
When you collect a “wild” your color will change to the color the wild was when you collected the ball. Once you collect a wild, a new one will be generated so you can never run out of color changes. Collecting all the balls results in winning the game.
As for the behavior of the balls, there is a set limit to how many can be on the screen at any given time. I set that number to 5 of each color, plus one player and one wild – 17 total. The “enemy” balls have random velocities and starting positions so all of them will have variance in both speed and direction of travel.
Setting Up Configuration Variables
Since I came up with the design ahead of time, I can foresee a few variables that needed to be created. Things like the game canvas height and width, player speed, ball radius, colors, etc. Putting all of this information at the top helps you digest what is going in the game logic, while also giving you a way to easily re-configure the game.
The next step was creating the image assets for Uniball. I was striving for minimalistic simplicity, so I created two images: one for the player and the other for the colored balls.
The “enemies” are colored spheres with a radius of 10 pixels each. Since my “wild” ball will change colors based on the ones I created, it only makes sense to recycle the image and use it for the wild as well. Knowing that the wild will animate means I’ll need to use a sprite sheet.
A sprite sheet is an image that contains multiple images. Since there are three colors, I just need to multiply the width x3 to get the width of the canvas in Photoshop, which ends up being 10x30.
I needed the player to be differentiated amongst the other balls in the game, while also being able to change colors. My solution was to create a small white ball that had an outline of the current color, almost like a crosshair. Since I only used three colors, I had to follow the same principle as my enemies, by tripling the width of the canvas. I also wanted to make this sphere just a little bit bigger as well, so I chose 15x45 for the size.
Importing the Assets into Phaser
Phaser provides multiple ways to add an asset into the game. Since both of my images are sprite sheets, I was required to use the sprite sheet loader. Phaser expects several parameters to be passed.
• Key – What you want to call this asset, to reference it later
- Path – Where is the image located
- Height – The height in pixels
- Width – The width in pixels
- Frames – How many frames are in the sprite sheet. In my case, it’s 3.
Adding Groups & Instantiating Balls
Groups are a way to manage multiple game objects in Phaser conveniently. I created four groups to manage all the balls in the game, one for each color and wild. By creating groups, I could also enable physics on each layer allowing each ball to behave in a physics environment. That is, allowed me to add velocity (speed) to each ball.
In order to add a ball to the scene, I needed a few helper functions that assist the creation process.
- Generate a random vector point – used to set the initial x, y coordinate of the ball
- Generate a random velocity – used to set the speed of the ball
- A function to create a ball
The random vector point and velocity functions are essentially just random number generators. The difference being the minimum and maximum values they can generate. For vectors, we don’t want the balls to place half way off the canvas, so it is beneficial to add or subtract the ball radius in our calculation to ensure this doesn’t happen.
The random velocity is a bit simpler. We supply the minimum and maximum velocity to the calculation which will return a number within those bounds.
The ball creation function accepts a single parameter, group ID. This allows the function to assign the ball to a group (red, yellow, blue, wild). Along with this assignment, this was a good place to set values such as the random velocity.
If a wild is being created, there is an additional step of creating the animation that plays the cycling colors on the ball. This will show one color per second, as well as sets a constant velocity of 25 as I wanted to make sure the wilds were somewhat predictable.
You’ll see that the canvas is finally coming to life! There are only a few more components that need to be addressed before the game is mostly complete. Collision checking and player controls.
Since there is only one player, creating this ball is simpler as the code doesn’t really need to be re-usable. I just needed to create a new ball sprite and assign it to the player variable. Then the ball is turned into a physics object and an animation is added. This animation will be used to change the color of the ball when it collides with a wild by changing the “frame” to equal the frame of the wild's animation. This logic is extracted into its own function, so that it can be passed to a collider listener in the next section.
Collision checking is put simply, a method of checking if two game objects overlap each other. Since the player ball should collide with all other balls, there needs to be at least four collider detection listeners in place, one for each color group. For each of these listeners, I pass a function as a callback that will do the actual discerning of which group is being collided with. If the color doesn’t match the players current color the game ends.
Changing Player Code
Changing the player color is simple. A callback function is passed to the collision handler between a player and a wild. Then I assigned the players color animation frame to be equal to that of the wild's animation frame, resulting in a new color.
Lastly, what game would be fun if you aren’t able to control anything? This is where the player movement comes in. Since this game only involves moving the player and not performing actions such as shooting a projectile or jumping, all I needed to do is bind controls to the arrow keys (up, down, left, right).
When the left or right keys are pressed, I can move the player left or right by adding or subtracting from the x axis. Similarly, I could move up or down by adding or subtracting from the y axis.
We have a working game! The only bad thing is if you manage to collect all the balls, you’ll notice nothing happens. I leave this as a challenge to you. Implement a way check if the player has successfully collected all the balls and show something to the player that they won. Let us know what ending you curate!