Many games use physics engines to drive the way things move and react. Using a physics engine can add immersion, eye candy, and, best of all, emergent gameplay, but can also, if used incorrectly, lead to unrealistic results or game-breaking problems. In this post, I'll explain how to identify and fix common problems seen in games of today.
We will examine and solve these problems as seen in Unity, focusing on the built-in 3D physics engine Nvidia PhysX, but the core principles can be applied to any other platform and physics engine.
Demo
This demo shows most mistakes mentioned in this article in both a incorrect or broken state, and in a fixed state:
Normal Scale
This is a simple scene with a ball that hits into a stack of barrels. The alternate version Incorrect Scale (10x) shows how the scene changes at 10x scale (see the scale markings on the floor of the demo). Notice how it appears to be in slow-motion, but this effect is simply caused by the scale of the scene.
Character Controller
This shows a simple side-scroller game working as intended. The "bad" alternative; Rigidbody & Character Controller Together shows the same game, but with a Rigidbody component attached to the character. Notice how the Rigidbody breaks the behavior of the Character Controller.
Objects With Bounciness
Barrels are shot from the side of the scene and are hurled into the air. As they come crashing down, they bounce off the ground and move in simple but majestic ways. The broken version shows the same scene without bounciness, and it looks so much more boring in comparison.
Not Directly Modifying a Rigidbody's Transform
In this scenario, a heavy ball is pushed up a ramp using Rigidbody.AddForce(). In the second scenario, instead of using Rigidbody.AddForce() to move the ball up the ramp, Transform.position is used. The result of using Transform.position is that the ball rolls back down, due to the fact that the rigidbody isn't properly taking into account the rigidbody's velocity change, but then the position modification causes the ball to jitter up and down the ramp.
Common Mistakes
Incorrect Scale
In most games, players would assume that the scale of the world is relatable to Earth's scale. They would expect, for example, an enemy falling from a watch tower to fall at the same rate you would perceive on Earth. If the enemy falls too slowly or too quickly, it can detract from the immersion—particularly if the enemy is human-sized!
Nvidia PhysX in Unity is set up to use one unit per meter. You can use this trait to check whether the scale of your objects are correct by simply adding in a Unity primitive cube. The primitive cube is exactly one cubic meter. If you notice, for example, that a oil barrel in your scene is 2x bigger than the the cube, that means your oil barrel is two meters tall (6.56 feet)!
Fixing the scale is as easy as scaling every object in the scene. Just select all the objects in your scene and use the Scale tool to make them bigger or smaller. If you notice your objects are moving too quickly, make the objects larger. If you notice the opposite—that the objects move too slowly—you should scale the objects down.
You can scale your objects with more precision by grouping them into one null object, and scaling that one object. For example, setting the scale of the parent object to 1.2 on each axis will increase the size of every object within the object by 20%. You can also scale the objects in increments using the scale tool by holding down Ctrl-LMB (Windows) or Cmd-LMB (OS X).
Using a Rigidbody and a Character Controller Together
I've seen this happen a few times, and it actually makes sense how often this occurs. The developer assumes that a Character Controller is necessary to control their avatar, but they want the avatar to be affected by gravity and other objects in the environment.
The problem is that a Character Controller is designed for more classical controls, like those typically found in a platformer or first person shooter. A Rigidbody is simply a non-deformable object that is affected by gravity and other physical forces (such as other objects colliding with it). These are two very separate components, with different intended uses.
Choose only a Character Controller when you want to complete control over how the player moves. On the other hand, if you want your character to be driven by the physics engine, use a Rigidbody. In adding a Rigidbody to a character, you will probably want to constrain rotation so that the player doesn't topple over.
Directly Modifying a Rigidbody's Transform
Unlike a Character Controller, it's not good practice to set the position or rotation of a rigidbody, or scale a rigidbody object constantly (for player control and such). Instead, you should use the AddForce() and AddTorque() methods found in the Rigidbody class. It is okay to directly set the position and rotation of a Rigidbody if, for example, you're spawning in the object for the first time, or resetting the scene. In that situation it will be fine, as long as the Rigidbody is not intersecting other objects.
This matters because, when a rigidbody is moved to an exact position or rotational state, it could pass through an object. The physics engine then has to correct this issue, and most of the time the physics engine does not run at the same time Unity's Update() message does. The end result is jittery behaviour whenever there's an intersection, and it's possible that the rigidbody may pass through objects entirely.
Another bad side effect that can occur when, say, moving a rigidbody along an axis for player movement is that internally the rigidbody is simulated and then it applies it's position. Updating the position then moves the rigidbody without taking into account the velocity change and such. If the rigidbody is rolling back down a slope, it will be moving the rigidbody backwards while your position altering code is moving the rigidbody back up the slope.
Objects Rolling Forever
Let's say you're developing a golf game. There is a problem with how the golf ball does not stop rolling, and somehow manages to continue rolling on forever as long as there isn't any kind of hole or ditch in its path. The reason why this happens is because in real life, the ball would be slowed down by the grass it runs over (among other things), since it has to push the tiny grass blades down, the grass essentially is like a constant ramp. This is called rolling resistance. Unity cannot simulate this behaviour accurately, so instead artificial stopping forces must be used.
In Unity the best force to use to stop an object from rolling forever is "angular drag". Changing the angular drag on the golf ball is the way to fix this issue. The exact value really depends on the behaviour you're looking for, however you may notice that a value of 1.0 angular drag may not even be enough in some cases.
Objects Without Bounciness
Almost every object in the world bounces after an impact. Unity's internal, default physics material has no bounce at all. Meaning every object will not bounce unless your override the default physics material or apply a physics material to the objects in your scene with a bounciness value higher than 0.
One of the best ways on fixing this issue is by creating a creating your own default physics material and assigning it in the Physics Manager found by clicking Edit > Project Settings > Physics.
Rigidbodies Partially Sinking Into Geometry
Most physics engines have some kind of parameter dictating how much two objects can be interpenetrating or intersecting until they are pushed away from one another. This parameter is called Min Penetration For Penalty in Unity. By default this value is 0.01 (meters), meaning that, by default, objects can be intersecting up to 1 centimeter (almost 0.4 inches) before being pushed apart.
You should set Min Penetration For Penalty to a value where it is barely noticeable that objects are intersecting. Setting the value to something tiny, such as 0.0001, may result in jittery rigidbodies.
How to Prevent Mistakes
Writing Code for Rigidbodies (for Programmers)
If you aren't a programmer, you don't have to worry about the following scenario. When writing code that moves, rotates, or scales rigidbodies, it is important to keep this in the FixedUpdate loop. Writing this code in the Update loop will potentially lead to unstable results, since the Update function may be called at 1000 Hz, while the physics engine and the FixedUpdate function are each called at 50 Hz by default.
You can change the frequency on physics steps by changing the parameter Fixed Timestep, found in Edit > Project Settings > Time. The value determines how much time is waited, in seconds, between each physics update or step. You can work out the frequency in Hertz by dividing 1 by the value (for instance, a 0.01 second wait means 1 / 0.01 = 100 Hz). The more frequent the steps, the more accurate and stable the simulation will be. However, setting the frequency higher than the CPU can handle will result in a very unstable simulation. Try to keep the Fixed Update frequency between 30 Hz and 100 Hz.
While working on a destructible brick wall, I ran into an issue caused by Instantiating bricks after a chunk of the wall had been destroyed. I fixed this issue by placing the problematic code into a Coroutine, and placing the following line before Destroying the object:
In waiting for a frame, it would guarantee that the logic was synced up in Update time, rather than FixedUpdate time. This seems to mean that the Destroy function is executed in sync with the Update loop.
Bonus Unity Tip: Don't Use The Standard Assets Physics Materials!
The Physics Materials package, which comes as part of the Unity Standard Assets, is actually almost completely useless. There are five physics materials contained in the package, and all of them are unrealistic in some way.
Each material has identical static and dynamic friction. In the real world, objects that are standing still have slightly more friction then when they are moving. The Rubber material's coefficient of friction is 1.0, which is not similar to any rubber found in the real world. And if that doesn't sound silly enough, every material has 0 "bounciness" (excluding the "Bouncy" material). This all means that the materials not even a close representation of their real life counterpart.
It is best to create your own physics materials when necessary. There are a lot of websites around that share physical properties of materials—the important ones being dynamic friction, static friction, and restitution or bounciness.
Conclusion
Very few physics related problems are actually that difficult to fix. If there is any kind of physics-related bug that seems difficult to track down, try slowing downtime to see what's going on. If you notice that the issue starts around a certain line of code, you can use Debug.Break to pause the editor and inspect what's going on. Feel free to comment here if you have any questions or need help.
In this series, we're focusing on the bone-based 2D animation tools provided by the Unity engine. The main idea is to present and teach the fundamentals of 2D animation in order for you to apply it to your own games. In this tutorial, we'll use Unity's excellent Mecanim tool to blend animations, and we'll add some simple scripting to demonstrate the final result.
Before we start the tutorial, we would like to thank Chenguang (DragonBonesTeam) for providing us with the game art used to produce this tutorial series.
Where We Left Off
In the previous tutorials, we set up the project, assembled a 2D dragon character, and created three different animations. If you haven't completed the previous tutorials yet, we strongly recommend you do so before continuing.
Final Preview
This demo shows the animated dragon we're aiming for—hit Space to make it jump:
Mecanim
At this point, you have your dragon completely assembled with three defined animations. However, there's no connection between them. So, our initial goal is to connect the different animation clips and blend them together. For this, Unity provides an awesome tool called Mecanim that does exactly what you need.
Mecanim is a powerful and flexible animation system. Since it's integrated with Unity itself, there is no need for third party software. You can easily animate anything, from sprites to blend shapes or even lights. Mecanim allows you to create state machines and blend trees to control your character.
But, before we go any further, let's talk a little bit about blending animations and state machines so you'll have a better understanding of what we are about to do.
What is a State Machine?
In Unity, you can blend two or more similar motions—for example, you may want to blend running and walking animations depending on the character's current speed. Basically, you have two different ways to blend animations in Unity. In some situations you may want to use Transitions; in others you will need to use Blend Trees:
Transitions are used for transitioning smoothly between animations. This usually works well if the transition is quick.
Blend Trees allow multiple animations to be blended smoothly, while incorporating parts of them in variable amounts. These amounts are controlled by numerical parameters. To give a practical example, imagine that we have a shooter game; you may want the character to fire and run at the same time. Blend trees allow you to blend the two animations together, letting the character run and shoot at the same time, without needing to create a third animation for that specific mixture of actions.
A state machine stores the state of an entity at a given time, and can react to an input to change the state of that entity, or to cause an action or output. For more information, see Finite-State Machines: Theory and Implementation.
In Unity, you use state machines to control the state of the game's characters. For example, one state for a character could be Walk, and another could be Jump. The character can change from the Walk state to the Jump state based on input from the player (probably hitting the Jump button).
Here you can see an example of a (more complex) state machine from the Unity documentation. Each box represents a state, and the arrows represent possible transitions between them:
We're going to create a state machine with our existing animations, and then use transitions to blend them together.
Building Our State Machine
If you check the Animations folder where you have been saving your .anim files, you will find a Dragon.controller file. This is the mecanim file associated with the character that Unity automatically generated when you saved your first animation.
Double-click on the Dragon.controller file, and Unity will open a Animator view tab next to your Scene and Game tabs.
As you can see, Unity already added the three animations to the file. Since the animations are already in place, there is no need to add them, but, if you wanted to add an extra animation to the controller, all you'd need to do is drag the .anim file to the Animator view. In the same way, if you want to remove an existing animation from the controller, you should just select on the Animator view and press Delete. Feel free to try this for yourself.
We have four different boxes in the Animator:
Any State
Idle
Jump
Fall
Any State is the default state that the mecanim creates, and you will not use it. You can drag it to any corner of the Animator window and leave it there.
The other three boxes refer to the three animations that we created. As you may notice, Idle is colored with orange, while the other two are grey. That's because Idle is the root animation; it's the animation that the character is going to play by default. If you press the play button on your editor and test it, you will see that the character does this Idle animation. In this particular case, that's exactly the behavior we want; however, if you wanted, say, the Fall animation to be the root animation, all you'd have to do is right-click it select Set As Default.
As you can see, the Fall animation is now orange and the Idle is grey.
Since you want Idle to be the root animation, just repeat the process to make it orange again.
It is now time to connect the animations. Right-click Idle and select Make Transition.
This will create a small arrow that starts from Idle. Click on the Jump animation to make the arrow connect the two animations.
If you select the arrow you just created, you will see that new properties show up in the Inspector tab.
As you can see, you have a time-line, and the animations Idle and Jump. There is a blue band over the animations that starts on Idle but then changes to Jump. Also, there is a period in time during which the two animations overlap.
Since the Preview area is empty, even if you click on the play button over the preview, you can't see what is happening.
To preview the transition that you are working on, just select the Dragon game object from the Hierarchy tab and drag it to the Preview area. Now you can see the character in the preview and, if you press play, you can see the transition between the two animations.
In the Inspector, the area where the blue band changes from Idle to Jump is our transition:
You can edit the transitions by dragging the two blue arrows on the timeline that limit the transition area. By changing their position, you can make the transition quicker or softer.
The next thing you need to do is define when you want this transition to happen. To do that, create a new parameter by clicking on the + sign in the Parameters list.
Next, select the Float option and call it VerticalMovement:
Now, go back to the Inspector, and under Conditions the variable VerticalMovement will show up. Select it.
You've just defined the condition to determine when to change the state in the state machine: if the value of VerticalMovement is greater than 0, then the character will start the Jump animation.
We also want a transition between the Jump animation and the Fall animation:
The maximum value that VerticalMovement is going to reach is 1, so, for the transition between Jump and Fall, we can activate it when that value is less than 0.5.
Now we need to make the character return to the Idle animation after the fall. Since Idle should be playing when the character is on the floor, you should create a transition between Fall and Idle.
To finish, you have to make sure it activates when the character is on the ground. You can do that be setting the transition parameter of VerticalMovement to less than0.1—that basically means that the VerticalMovement is 0, meaning that the character is on the ground.
We now need to make sure that we don't see any Idle animations while the character is in the air between the Jump and Fall animations. To do that, create a new parameter, this time a Bool.
Call it OnGround.
Select the transition between Jump and Fall. You want this transition to happen when the character is still in the air, right? So go to the Inspector, click the +, and add a new parameter to the transition. Basically, you want this to happen when the value of OnGround is false.
Next, on the transition from Fall to Idle, add the parameter OnGround and set the value to true:
Our work with Mecanim is done. Now it's time to move to scripting.
Scripting Animations
In your asset directory, create a new folder called Scripts. Next, create a new C# script called CharacterMove.cs. Note that the script you are about to create is a very simple one, which the main goal is to show how you can change the animations of the character by code.
The best practice is to use Unity's physics when you want to create robust games. However, for the sake of simplicity and understanding, we'll just create a small simulation.
Create four variables in the script: one to reference the Animator component, another for the speed of the fall, a third one for the amount of vertical movement, and a flag to check whether the character is on the ground.
public class CharacterMove : MonoBehaviour {
// Variables
public Animator anim; // Refrerence to the animator
private float fallSpeed; // The speed the character falls
private float verticalMovement; // The amount of vertical movement
private bool onGround; // Flag to check whether the character is on the ground
In the Start() method, you need to make sure that the speed is set to 0.03 (or whichever other value you feel suits your animations) and that the character is grounded.
void Start () {
// The character starts on the ground
onGround = true;
// Set the fall speed
fallSpeed = 0.03f;
}
Now, on the Update() method, there are several things you need to check. First, you need to detect when the Space Bar is pressed, to make the character jump. When it's pressed, set the vertical movement to 1 and the onGround flag to false.
void Update () {
// If the space bar is pressed and the character is on the ground
if (Input.GetKeyDown(KeyCode.Space) == true && onGround == true)
{
verticalMovement = 1f;
onGround = false;
}
}
What happens when the Space Bar is not being pressed? Well, you need to check if the character is in the air and its vertical movement is greater than 0; if so, you need to reduce the vertical movement by subtracting the fall speed.
void Update () {
// If the space bar is pressed and the character is on the ground
if (Input.GetKeyDown(KeyCode.Space) == true && onGround == true)
{
verticalMovement = 1f;
onGround = false;
}
else
{
// Check if the character is in the air and the vertical movement greater than 0
if(onGround == false && verticalMovement > 0)
{
// Reduce vertical movement
verticalMovement -= fallSpeed;
}
}
}
As you'll recall, once verticalMovement drops below 0.5, the Fall animation will start playing.
However, we don't want to subtract fallSpeed from verticalMovement forever, since the character will land at some point. If the vertical movement value is equal to or less than 0, we'll say that means the character has hit the ground.
void Update () {
// If the space bar is pressed and the character is on the ground if (Input.GetKeyDown(KeyCode.Space) == true && onGround == true) {
verticalMovement = 1f;
onGround = false;
}
else
{
// Check if the character is in the air and the vertical movement greater than 0
if(onGround == false && verticalMovement > 0)
{
// Reduce vertical movement
verticalMovement -= fallSpeed
// If the vertical movement is less or equal to 0, the character is on the floor
if (verticalMovement < 0)
{
verticalMovement = 0;
onGround = true;
}
}
}
}
To end the Update() method, you need to pass the values of verticalMovement and onGround to the Animator component:
void Update () {
// If the space bar is pressed and the character is on the ground
if (Input.GetKeyDown(KeyCode.Space) == true && onGround == true)
{
verticalMovement = 1f;
onGround = false;
}
else
{
// Check if the character is in the air and the vertical movement greater than 0
if(onGround == false && verticalMovement > 0)
{
// Reduce vertical movement
verticalMovement -= fallSpeed;
// If the vertical movement is less or equal to 0, the character is on the floor
if (verticalMovement < 0)
{
verticalMovement = 0;
onGround = true;
}
}
}
// Update the animator variables
anim.SetFloat("VerticalMovement", verticalMovement);
anim.SetBool("OnGround", onGround);
}
The script is finished. Now you have to add it to the Dragon game object and add the reference to the Animator component. To do this, once you add the script, drag the Animator to the proper field on the script.
If you press play and test it, the animations should be changing like they're supposed to. The dragon starts on Idle, but once you press the Space Bar it will Jump and then start playing the Fall animation before returning to Idle.
External Tools and Technologies
Although in this tutorial series we've only used the default tools that come with Unity, there are a lot of great 2D tools on the Unity Asset Store that can help you make this process even easier and faster. Two good examples are Smooth Moves and Puppet 2D, each of which can help you to define the characters, the hierarchy and the animations in an intuitive and easy way.
Plug-ins like these offer some extras, like the ability to add 2D "bones", making the whole animation process easier and the deformations more realistic. If your idea is to use 2D animations with several degrees of detail, we strongly recommend you to check out those plugins.
Conclusion
This concludes our tutorial series about how to create a bone-based 2D animation with Unity. We've covered a lot of ground in this short series, and you should now know enough to get started with your 2D animations. If you have any questions or comments, as always, feel free to drop us a line in the comments.
References
Dragon sprite sheet: used with permission from Chenguang from DragonBonesTeam
In this tutorial, I'll help you make your first HTML5 game that is controlled by a Leap Motion Controller, using the Kiwi.js engine. (In case you haven't heard of it, Kiwi.js is a relatively new game engine that targets HTML5, WebGL, and JavaScript.)
After hearing about the Leap Motion Controller, I knew I had to get my hands on one. It's a computer hardware sensor device that supports hand and finger motions as input, requiring no hand contact or touching.
I saw this as
a new frontier to gaming not yet fully explored. How could I pass up on an opportunity this exciting? After my controller arrived, and I'd spent the next few days playing with all of the apps on the Airspace store, I decided
that I wanted to take it further and make my own games with it.
Getting Ready
To follow this tutorial, you will need a text
editor and a browser. I use Sublime Text 2, and I prefer Google Chrome for
its extensive developer tools, but the workflow will be pretty much the same
with whichever text editor and browser you choose.
Once you have downloaded the blueprint, you should be able to navigate to the plugin folder located inside it. Once there, you will need to extract the Leap Motion Controller plugin
to the plugins folder.
Loading Assets Into the Game
In the Getting Started blueprint, you will notice that inside the states folder, located inside the src folder, there are three JavaScript files. These contain the main states that we will need to run this particular Kiwi.js game.
A State in Kiwi.js is the main class that we use when wanting to create a game. States are used to keep different sections of a game separated; a single game may be composed of many different States. This means we can only ever have a single State active at a given time.
The blueprint has separated the Kiwi.js game into three states for us: the Loading State, the Intro State, and the Play State.
Inside the Loading State, we need to load
our assets into the game. Since we are making a basic game to start off with will will not be loading many assets. The game we will make will simply give visual feedback on the position of your hand and fingers, represented by dots.
For this example, we'll use the two assets
below. (Don’t worry, these graphics aren't meant to be pretty!)
The green dot will be used to show the
position of your hand in the game, and the red dot will be used to show the position of each finger, so I have named them hand.png and finger.png, respectively. Save them under these names in the img folder inside the assets folder.
To load these assets into the game, you will have to add them to the game’s cache
via the preload() method of LoadingState, which is found in the States folder, in the file named loading.js, like so:
Second, we need
to make sure that the Game object knows we are using the Leap Controller
plugin.
The Game object is the engine of a Kiwi.js game; it handles the initialization of all the various individual game managers. To let the Game know we want it to use the Leap Motion Controller plugin, we need to edit its game options. This can be done by adding a line of code inside the game.js file that is located inside the src folder:
var gameOptions = {
renderer: Kiwi.RENDERER_WEBGL,
plugins:['LeapMotion'], //Add this line of code
width: 800,
height: 600
}
Now we are ready to create our controller object, by calling
the following line inside the init() method of the Play State, which you can find inside the states folder inside the play.js file. You will notice that the state does not yet have a init() method, so you will have to add this. For convenience, we'll call the Leap Controller object control:
GettingStarted.Play.init = function () {
this.control = Kiwi.Plugins.LEAPController.createController();
}
Next, we'll create sprites that we can use to show
the position of our hand and fingers in the game—one "hand" sprite and five "finger" sprites, specifically. To do this, simply create aKiwi.GameObject.Sprite and add it to the state; the best place to do this is in the create method of the state.
In this snippet, we create the sprites and add them to the stage, then store them in the fingers array:
GettingStarted.Play.create = function () {
this.hand = new Kiwi.GameObjects.Sprite(this, this.textures['hand'], 0, 0);
this.addChild(this.hand);
this.fingers = [];
for (var i = 0; i <= 5; i++) {
var temp = new Kiwi.GameObjects.Sprite(this, this.textures['finger'], 0, 0);
this.addChild(temp);
this.fingers.push(temp);
};
}
Using the Leap Motion Controller Object
Once the game has preloaded its assets and been created, the Play State update loop will start running. This is where all of the fun stuff you create
will happen!
In this case, we're going to move the sprites we just created to the positions of their corresponding hand and fingers, as detected by the Leap
Motion Controller. This can be done easily by accessing various properties of the Leap Controller object:
hands[0].posX and hands[0].posY will give you the x- and y-coordinates, in the vertical plane parallel to the Leap Motion Controller, of the first hand that the controller detects.
hands[0].pointables[n].tipX and hands[0].pointables[n].tipY will give you the x- and y-coordinates, in the same space, of the tip of the nth finger on that hand.
In the following snippet, you will see that I have centered the position of the hand and
fingers by moving the x-position over by half of the stage width, reversing
the y-position, and adding the height of the stage to the y-position:
Check out the example below to see what we have made!
With the example above you will be able to start to see how fast and accurate the Leap Motion Controller is with Kiwi.js. Also, with the Leap Motion Controller's tracking capabilities, you can quickly see how you are able to manage multiple interactions with just one hand.
Below is a list or values that the Leap Motion Controller plugin currently tracks for Kiwi.js:
Active Fingers: This indicates how many fingers the controller can detect. It can be found via the pointables.active property.
Active Hands: This indicates the current number of hands that the controller can detect.
It can be found with the hands.active property.
The current hand's x-, y-, and z-coordinates, relative to the controller. This can be done by accessing the posX, posY, and posZ values
of the hand object, as we've seen.
The orientation of the hand: the roll, the pitch, and the yaw. These are taken from the normal vector of the palm of the hand—that is, the vector that points outward from the surface of your palm.
This is also time to look the range at which the Leap Motion controller can track your hand. You will notice that the controller does have limitations to it's tracking range, as represented by the image below.
So you are probably thinking, "What happens when my hand leaves this range?" Well, the Leap Controller instantly notices that your hand is no longer visible and sets the active property of the hand to false. It also saves all of the data of the last known position of your hand until your hand becomes visible again.
Going One Step Further
So far we have only made a basic demo, which may be cool to experiment with, but isn't exactly fun. Next, let's make an actual game like the one shown below:
Loading
Assets
In this game, we
will animate some sprites. I have created a "FlappyNyan" sprite sheet that I will
use for the this tutorial, along with some colored blocks which will be used for the color
trail that FlappyNyan leaves behind. You are welcome to use these assets. Just grab them from the tutorial's GitHub repo.
Creating Classes
Instead of using the standard SpriteGameObject, we will want
to create a new class that extends Sprite. The purpose of this
class is to assist in creating the color trail of the cat. If you wanted to
further your game, you could implement arcade physics into the class, allowing for simple collision detection, and giving access to properties such
as velocity and acceleration.
To create a class you will need to create a separate JS file
in the entities folder; call it Nyan.js. You will
also need to include this script in your index.html file, in the same way as the plugin scripts:
Next, we want to create the FlappyNyan’s trail. To do this, we will continuously spawn boxes that will look like what FlappyNyan always leaves
behind: a glorious rainbow of colour.
For this, I have created another class, called MovingBox. This class simply creates a box of
a certain color, moves left until it is off the screen, and then removes itself from the game:
Remember to include the MovingBox class in the index.html page.
Using Classes
Now you might be wondering how to use these boxes—let's tackle that next. These boxes that will be following FlappyNyan will represent the number of active fingers (that is, fingers that the Leap Motion Controller can see).
Since we want the boxes to follow the FlappyNyan object, we will
create a method to spawn these boxes inside the FlappyNyan class.
To do this, all you need to do is add this method to theFlappyNyan class:
Now that we have set up the two classes we need, all we need
to do now is create a FlappyNyan object in the Create() method of the Play State, and add
a Kiwi.Group to store the boxes in, then add these to the stage.
this.streamerGroup = new Kiwi.Group(this);
this.addChild(this.streamerGroup);
this.flappyNyan = new flappyNyan(this, 100, 100);
this.addChild(this.flappyNyan);
Once this is done we want to update its position, just as we have done for the hand object in the previous game.
Fixed-function pipelines have no more business on our video cards. Here's what you need to know about them—and how to make the switch away from them, if you still haven't done so yet.
In The Beginning: The Rise of Graphics Hardware
Once upon a time, when game development (or coding anything that has to do with real-time graphics, really) was limited to writing to a relatively small matrix of color intensities (the frame buffer) and sending it to hardware, you could do anything you wanted with it. You could draw to the image one, ten, or a hundred times. You could pass over the frame buffer again to do some neat FX. In short, whatever your processor was capable of doing, you could do it to the image that gets sent to the monitor. This allowed you to do some really great and creative stuff, but people never (or seldom) used it to that extent. But why?
The answer: because it was slow. A 640×480px image (a common resolution at that time) contains 307,200 pixels. And the CPUs were so much slower then, that you couldn't really do much in the short time given to you to draw that frame. After all, if you want to keep drawing at 30FPS, you've got only around 30ms to update your game logic and render to the screen, and that has to include the overhead of intercommunication with the hardware. It wasn't much.
Then came along the cool GPUs with rendering pipelines. You, the developer, would take care of updating the game logic and sending your textures and triangles to the GPU, and it would do the heavy-lifting and number crunching on them. Those were fixed-function rendering pipelines (FFPs): meaning that you couldn't configure the functions they performed. You could tell them "make the fog dark gray" or "don't do the lighting for me!" and you could configure a lot of the other parameters, but the functions themselves remained.
The hardware was wired and narrowly specialized so that it performed some standard operations on your data. And because it was wired that way, it was so much faster than doing them on your processor. But one downside was that you were paying a lot for that speed: you were paying in flexibility. But if you ever wanted to draw anything complex, the CPU simply wasn't fast enough, and submitting your vertices to the GPU was the only choice.
The Demands for Better Realism
The graphics world was still changing rapidly. Just like all creative and talented people, game developers love challenges, and one of the challenges for them was (and will remain!), for a long time, to render ever-better looking, realistic images.
The fixed-function pipeline provided some nice features, such as multiple blending modes, per-vertex Gouraud shading, fog effects, stencil buffers (for shadow volumes) and such, so the developers used what they could. Soon, there were some really impressive effects going on, all by virtue of real-life phenomena simulated using a few cheap tricks (well, cheap by today's standards).
This was all going very well, but it was still limited by the amount of functions the fixed pipeline could do. After all, the real world has so many different materials, and for simulating them, the only variation they were allowed to perform was changing some blend modes, adding some more textures, or tweaking the light reflection colors.
Then it happened: the first programmable GPUs came along. They did not come overnight, of course, and they were bound to arrive some day, but this still created excitement. These GPUs had what was called a programmable rendering pipeline: you could now write programs, called shaders, in a limited assembly language, and have them execute for each vertex or fragment, on the video card. This was a big leap forward, and it was just getting better.
Soon the assembly languages increased in complexity and expressiveness, and high-level languages for GPU programming emerged, such as HLSL, GLSL, and later Cg. Today we have geometry shaders which can even stream out new vertices, or shaders which dynamically control tessellation and tessellated triangles, and inside them we can sample an awful lot of textures, dynamically branch and do all sorts of crazy math on the input values.
When you give developers these advantages, they go wild; soon they were writing shaders for all sorts of stuff: parallax mapping, custom lighting models, refraction, you name it. Later, even completely custom lighting systems emerged, such as deferred shading and light pre-pass, and you could see complex post-processing effects such as screen space ambient occlusion and horizon based ambient occlusion. Some were even "abusing" shaders to do repetitive, math-heavy tasks, like statistical processing or breaking string hashes. (This was before general-purpose computing on GPUs got mainstream support.)
In short, computer graphics exploded with the introduction of shaders, and with good reason: the ability to program what exactly happened to vertices, fragments, textures, and so on, and to do it fast, provided nearly endless possibilities.
The Complete Switch
Soon, fixed function pipelines were obsolete, at least for game developers. After all, why bother with such walled gardens when you can program precisely what happens to your data? They stayed in use for a lot longer in some applications where realism was not an issue, such as for CAD. But by and large, they were getting ignored.
OpenGL ES 2.0, released in 2007, deprecated or removed its fixed-function pipeline in favor of a programmable one. OpenGL 3.2, back in 2009, finally removed all notion of fixed-function vertex and fragment processing (however, it remains available for legacy use via a compatibility profile). It's clear that it makes very little sense today to work with the limited pipeline when you've got powerful GPUs capable of doing awesome things at your disposal.
Because these APIs force you to use shaders (and this includes DirectX, which, while not explicitly removing the functionality, includes tools to help migrate from the old approach, and has virtually no new documentation regarding the FFP), they are difficult to get right for a beginner. If you're only starting as a 3D programming rookie, it's a lot easier just to tell the API your matrices, lighting parameters, and whatnot, and have it do it all for you.
But in the long run, it will benefit you much more if you learn to write programs that precisely describe the process. You will intricately understand what's going on under the hood, comprehend some very important concepts the FFP does not require you to, and be able to tweak your materials very easily to do something complex the fixed-function can never do for you (and it's useful for debugging, too!).
I've mentioned OpenGL ES, and let me build up on that in more detail. As gaming on mobile becomes more and more popular, it makes sense to create virtual worlds ever-increasing in complexity. Most of the fixed-function calls were removed in ES 2.0 (which, naturally, means they're absent from subsequent versions as well). This essentially means that, in order to use any of the features after ES 1.1, you need to use shaders.
ES 2.0 is supported by iPhones since 3GS, iPads since the first release, and iPod Touch devices of generation 3 and higher. Qualcomm Snapdragon, a chip widely used in Android phone production, also supports OpenGL ES 2.0. That is very wide support, because ES 2.0 is not exactly "new": it is over 7 years old now. To get the most out of these architectures, you need to let go of the fixed-function pipeline.
I assume most of you have done that long, long ago, but it's not that hard for me to imagine some 2D graphics engines or legacy games that still use fixed-function (because there's no need for more). This is all fine, but using it for new projects, or training programmers in them, seems like a waste of time. This is amplified by the fact that a lot of tutorials you can find on the Internet are grossly outdated and will teach you how to use the FFP from the beginning—and before you even realize what's going on, you'll be deep in there.
My first brush with 3D graphics was an ancient DirectX 7 tutorial written in Visual Basic. At that time, using the fixed-function pipeline generally made sense, because hardware was not advanced enough to achieve the same functionality with shaders at the same rate. But today, we see graphics APIs starting to drop or severely deprecate support for it, and it really becomes only an artifact of the past. It is a good and useful artifact which makes us nostalgic, but we should be staying away from it. It's old and no longer used.
Conclusion
If you are into serious game development, sticking to the fixed-function pipeline is a relic of bygone days. If you're thinking of getting into 3D graphics, my advice (and the advice of many, many developers out there) is to simply avoid it.
If you see passing of lighting positions to the graphics API (not as a shader parameter), or API function calls such as glFogv, run like the wind and don't look back. There's a brave new world of programmable GPUs out there, and it's been around for a long time. Anything else probably just wastes your time.
Even if you're just into 2D graphics, it's still a wise idea not to rely on the FFP anymore. (Of course, that's as long as you are okay with not supporting some ancient hardware.) Shaders can provide you with some great, lightning-fast effects. Image blurring, sharpening, warp grids, vector rendering, and large-scale particle or physics simulation can all be done on the GPU, and they can all benefit both 2D and 3D games.
So, again, my advice, even if you're not explicitly going to learn about 3D game development, is to learn to write shaders. They are fun to work with, and I guarantee you're going to spend many amusing hours perfecting a cool shader effect: a dynamic butty skybox, car paint or parallel-split shadow mapping, or whatever your heart desires. At least that's happened to me: once you're used to working with the fixed pipeline because of some limitation (as I was forced to, back in the day, in order to get acceptable performance on my 5200FX), programming the GPU is a blast, and heaps of fun.
I hope I have explained to those for whom it was unclear, how 3D graphics used to work long ago and how it works now, and I hope I have convinced the few of you who were on the verge of following NeHe or Swiftless tutorials to do otherwise and go look at something more modern. As always, I might have made some mistakes, so feel free to point them out in the comments. Until next time!
Puzzle games often take place on a grid containing tiles that have behaviors and properties, and react to rules and inputs. In this series I'll show you how to build a simple, basic version of the classic game Minesweeper, which is the perfect example to start from for creating your own puzzle games.
Whether you're making a children's memory game or a complex strategy title, implementing the basic building blocks of Minesweeper are a great place to start. In the first part of this three-part tutorial series, we'll build a playing field you can then use to create your own version of the game.
You'll need Unity for this, and a basic understanding of it. (Check out Build Arkanoid With Unity if you're new at it.) The source code can be downloaded, but is not necessary to complete this tutorial.
The Rules of Minesweeper
Minesweeper is a puzzle game in which you have to locate all the mines in a field. The field size varies by difficulty, and can range from 9x9 tiles (easy) to 16x30 tiles (hard), or any custom dimensions.
By clicking on a tile you "uncover" it. If it is a mine, you lose; if it is empty and at least one mine is in one of the bordering tiles, a number appears, showing the number of mines in the neighboring tiles. If there are no mines in the adjacent tiles, all adjacent tiles are uncovered too.
A tile can marked by right-clicking on it, thereby putting a flag on it. Once all tiles with mines have been correctly marked, the game is won.
Try it out here:
Elements We'll Need
From the rules above, we can extrapolate the different elements that our simple version of minesweeper will need. These are
A grid of tiles
Tiles that can contain a mine
Tiles that can be interacted with via mouse clicks
Tiles that take neighboring tiles into account when reacting to mouse clicks
Building a Basic Tile
Create a new Unity project. Create a Cube and name it Tile. Drag it over to the project folder to turn it into a prefab. We'll use this non-functional tile to build the playing field, and then later add functionality to it.
Building the Grid Generator
Create a new empty object and name it Grid, and turn it into a prefab as well. This will be the generator of the game field and all tiles within it.
Create a new JS file, name it Grid as well, and add it to the Grid object.
Add the following lines to the Grid script, so that we can begin creating a field:
public var tilePrefab: Tile;
public var numberOfTiles: int = 10;
public var distanceBetweenTiles: float = 1.0;
function Start()
{
CreateTiles();
}
function CreateTiles()
{
}
Then, drag the Tile prefab onto the Tile Prefab slot of the Grid object. It should look like this:
The numberOfTiles variable will allow you to set the number of tiles to be created. DistanceBetweenTiles defines the distance between them, so that we can adjust the spacing to our liking.
Right now, the grid generator doesn't do anything. In order to have it create several tiles, add this code the CreateTiles() function:
If you run the current scene, it should create a line of our tiles, like this:
The function creates copies of the tile prefab—as many as we specified—and places them in a row, a distance of distanceBetweenTiles apart. Try out some different values to find a good spacing.
But for Minesweeper we'll need a grid, not a line. In order to accomplish that, add this variable at the beginning of the Grid code:
public var tilesPerRow: int = 4;
...and adapt the CreateTiles() function to look like this:
If you run it, you should end up with several lines of tiles:
If you set the tilesPerRow variable correctly (like 24 tiles in 6 rows), the generator should create a nice rectangular playing field. If your programming skills are advanced enough, you can try to figure out how to further automate the process. (The version of Minesweeper we're building will also work with irregularly-shaped fields.)
Turning the Tiles Into Mines
Now that we can create a basic, custom Minesweeper field, we can work on adding actual mines to it.
Create a new JS file, name it Tile, and add it to the Tile prefab. Then, add the following variable to it:
public var isMined: boolean = false;
This will tell us whether the tile has a mine in it.
Assigning mines is a bit trickier. We'll do this from the Grid generator.
First, three arrays to hold our tiles to the Grid code:
static var tilesAll: Tile[];
static var tilesMined: Array;
static var tilesUnmined: Array;
We also need to initialize them. Put the following lines at the beginning of the CreateTiles() function:
tilesAll = new Tile[numberOfTiles];
tilesMined = new Array();
tilesUnmined = new Array();
Then, change the instantiate command in the CreateTiles() function to look like this:
Here is what happens: When a new tile is created in the CreateTiles-function, it is added to the tilesAll-array. All of the tiles in there are then copied into the tilesUnmined-array. From this array we randomly chose one tile to add a mine to. We add a mine to by setting the isMined-variable to true, remove it from the tilesUnmined-array and add it to the tilesMined-array (which we'll use later). In the end we have randomly placed the specified amount of mines on the playing field.
Right now, a mined tile is not visibly different from an unmined tile. The goal of the game is to figure that out, after all!
In this build you can test out how it is supposed to work. For demonstration purposes, mined tiles show up as red.
And voilá: you now have a Minesweeper field with a custom size!
Making the Tiles More Visually Interesting
Right now, the tiles are standard Unity cubes. Let's turn them into actual tiles.
In the source files, you'll find a 3D file called puzzleObjects.fbx. Copy it into your asset folder, so it we can use it in our game. Make sure the file is imported with its size set to 1, so that it fits with the settings we've been using so far.
The import settings of the file should look like this:
Then, go the settings of the tile prefab, and swap out the cube mesh for the tileImproved mesh.
While we're here, press Reset on the Box Collider component of the tile. This will make the collider fit closely around the tile again.
Finally, give the tile a new material, so it doesn't have the standard white look.
Remember to apply all the changes to the tile-prefab as well, so that new
ones get created when we start a new game. If you try it out, the game
should create the grid using these new tiles instead of the old cubes.
Adding a Number Display to the Tiles
We need a way to display a number in
order for a tile to show us how many mines are adjacent to it. A simple way
to accomplish this is by using a 3D Text, which comes with Unity.
Create one by clicking GameObject > Create Other > 3D Text, and add it to the tile. It should look like this:
Let's improve that. Rotate the text so it faces upwards. Set the string it currently displays to 0, so that we know what size the text will be. Also adapt the Font Size and Text Size, so that it doesn't look blurry.
Great!
Now we need to be able to access the 3D text in code. Add the following
variable to the Tile code:
public var displayText: TextMesh;
Drag the 3D text onto the open slot, so that we can access it via code later on.
Remember to apply everything to the tile prefab, and try it out. The new and imporved tiles should now be created.
Conclusion
We have created a functional basis for out puzzle game, but can't actually play it yet. We'll add that functionality in the second part of this series.
Puzzle games often take place on a grid containing tiles that have behaviors and properties, and react to rules and inputs. In this series I'll show you how to build a simple, basic version of the classic game Minesweeper, which is the perfect example to start from for creating your own puzzle games.
Whether you're making a children's memory game or a complex strategy title, implementing the basic building blocks of Minesweeper are a great place to start. In the first part of this three-part tutorial series, we'll build a playing field you can then use to create your own version of the game.
You'll need Unity for this, and a basic understanding of it. (Check out Build Arkanoid With Unity if you're new at it.) The source code can be downloaded, but is not necessary to complete this tutorial.
The Rules of Minesweeper
Minesweeper is a puzzle game in which you have to locate all the mines in a field. The field size varies by difficulty, and can range from 9x9 tiles (easy) to 16x30 tiles (hard), or any custom dimensions.
By clicking on a tile you "uncover" it. If it is a mine, you lose; if it is empty and at least one mine is in one of the bordering tiles, a number appears, showing the number of mines in the neighboring tiles. If there are no mines in the adjacent tiles, all adjacent tiles are uncovered too.
A tile can marked by right-clicking on it, thereby putting a flag on it. Once all tiles with mines have been correctly marked, the game is won.
Try it out here:
Elements We'll Need
From the rules above, we can extrapolate the different elements that our simple version of minesweeper will need. These are
A grid of tiles
Tiles that can contain a mine
Tiles that can be interacted with via mouse clicks
Tiles that take neighboring tiles into account when reacting to mouse clicks
Building a Basic Tile
Create a new Unity project. Create a Cube and name it Tile. Drag it over to the project folder to turn it into a prefab. We'll use this non-functional tile to build the playing field, and then later add functionality to it.
Building the Grid Generator
Create a new empty object and name it Grid, and turn it into a prefab as well. This will be the generator of the game field and all tiles within it.
Create a new JS file, name it Grid as well, and add it to the Grid object.
Add the following lines to the Grid script, so that we can begin creating a field:
public var tilePrefab: GameObject;
public var numberOfTiles: int = 10;
public var distanceBetweenTiles: float = 1.0;
function Start()
{
CreateTiles();
}
function CreateTiles()
{
}
Then, drag the Tile prefab onto the Tile Prefab slot of the Grid object. It should look like this:
The numberOfTiles variable will allow you to set the number of tiles to be created. DistanceBetweenTiles defines the distance between them, so that we can adjust the spacing to our liking.
Right now, the grid generator doesn't do anything. In order to have it create several tiles, add this code the CreateTiles() function:
If you run the current scene, it should create a line of our tiles, like this:
The function creates copies of the tile prefab—as many as we specified—and places them in a row, a distance of distanceBetweenTiles apart. Try out some different values to find a good spacing.
But for Minesweeper we'll need a grid, not a line. In order to accomplish that, add this variable at the beginning of the Grid code:
public var tilesPerRow: int = 4;
...and adapt the CreateTiles() function to look like this:
If you run it, you should end up with several lines of tiles:
If you set the tilesPerRow variable correctly (like 24 tiles in 6 rows), the generator should create a nice rectangular playing field. If your programming skills are advanced enough, you can try to figure out how to further automate the process. (The version of Minesweeper we're building will also work with irregularly-shaped fields.)
Turning the Tiles Into Mines
Now that we can create a basic, custom Minesweeper field, we can work on adding actual mines to it.
Create a new JS file, name it Tile, and add it to the Tile prefab. Then, add the following variable to it:
public var isMined: boolean = false;
This will tell us whether the tile has a mine in it.
Next, we have to put the actual mines into the grid. For that, change the GameObject type of the Tile prefab to the new Tile class we just created.
Change the tilePrefab variable so it looks like this:
public var tilePrefab: Tile;
And then assign the Tile object again to that variable. Now it can automatically access the variables we put in there from the start.
Assigning mines is a bit trickier. We'll do this from the Grid generator.
First, three arrays to hold our tiles to the Grid code:
static var tilesAll: Tile[];
static var tilesMined: Array;
static var tilesUnmined: Array;
We also need to initialize them. Put the following lines at the beginning of the CreateTiles() function:
tilesAll = new Tile[numberOfTiles];
tilesMined = new Array();
tilesUnmined = new Array();
Then, change the instantiate command in the CreateTiles() function to look like this:
Here is what happens: When a new tile is created in the CreateTiles-function, it is added to the tilesAll-array. All of the tiles in there are then copied into the tilesUnmined-array. From this array we randomly chose one tile to add a mine to. We add a mine to by setting the isMined-variable to true, remove it from the tilesUnmined-array and add it to the tilesMined-array (which we'll use later). In the end we have randomly placed the specified amount of mines on the playing field.
Right now, a mined tile is not visibly different from an unmined tile. The goal of the game is to figure that out, after all!
In this build you can test out how it is supposed to work. For demonstration purposes, mined tiles show up as red.
And voilá: you now have a Minesweeper field with a custom size!
Making the Tiles More Visually Interesting
Right now, the tiles are standard Unity cubes. Let's turn them into actual tiles.
In the source files, you'll find a 3D file called puzzleObjects.fbx. Copy it into your asset folder, so it we can use it in our game. Make sure the file is imported with its size set to 1, so that it fits with the settings we've been using so far.
The import settings of the file should look like this:
Then, go the settings of the tile prefab, and swap out the cube mesh for the tileImproved mesh.
While we're here, press Reset on the Box Collider component of the tile. This will make the collider fit closely around the tile again.
Finally, give the tile a new material, so it doesn't have the standard white look.
Remember to apply all the changes to the tile-prefab as well, so that new
ones get created when we start a new game. If you try it out, the game
should create the grid using these new tiles instead of the old cubes.
Adding a Number Display to the Tiles
We need a way to display a number in
order for a tile to show us how many mines are adjacent to it. A simple way
to accomplish this is by using a 3D Text, which comes with Unity.
Create one by clicking GameObject > Create Other > 3D Text, and add it to the tile. It should look like this:
Let's improve that. Rotate the text so it faces upwards. Set the string it currently displays to 0, so that we know what size the text will be. Also adapt the Font Size and Text Size, so that it doesn't look blurry.
Great!
Now we need to be able to access the 3D text in code. Add the following
variable to the Tile code:
public var displayText: TextMesh;
Drag the 3D text onto the open slot, so that we can access it via code later on.
Remember to apply everything to the tile prefab, and try it out. The new and imporved tiles should now be created.
Conclusion
We have created a functional basis for out puzzle game, but can't actually play it yet. We'll add that functionality in the second part of this series.
Parallax scrolling is a simple and effective way to create
the illusion of depth in a 2D game. Whether you’re developing a vertical
shooter or a horizontal side scrolling platformer, parallax scrolling is a
tried and true staple of gaming that will greatly increase the immersion and
graphical impact of your project.
In this tutorial, I'll cover the fundamentals of parallax scrolling, along with
several methods of implementation, in such a way that you'll be able to confidently and successfully introduce parallax scrolling
into your skill set, regardless of your current skill level.
Demo
Try the demo below to see scenes that use horizontal, vertical, both, and no parallax scrolling. Click the demo to activate it, then use the number keys to switch scenes and the arrow keys to move the spaceship (for the appropriate scenes).
What is Parallax
Scrolling?
Parallax is defined as the apparent displacement of an
observed object due to a change in the position of the observer. With 2D
parallax scrolling, the observer’s position only changes along the x- and y-axes. Only an object’s speed and location will change with the position
of the observer, as scaling the object would require a change along the z-axis.
Takashi Nishiyama’s Moon Patrol is widely credited as the
first game to feature 2D parallax scrolling, but the technique existed in
traditional animation as early as 1933. Using a multiplane camera, animators
were able to create a non-stereoscopic 3D effect that created the illusion of
depth by allowing different art assets to move at different speeds in relation
to the perceived distance from the camera lens. This is how parallax scrolling
is achieved in modern video games, but instead of a multiplane camera, scenes
are assembled with multiple layers and a single game camera or view.
By dividing the background and foreground elements of a game
into different layers, it is possible to control the speed and position of
these elements based on their layers. The observer, in this case, is the player, and the
game camera stays focused on a particular point or object, while the background
and foreground layers move accordingly.
This focal point moves at ‘normal’
speed, or the speed defined by gameplay. Background objects move slower than the
focal point while foreground objects move faster than the focal point. This
results in an illusion of depth that makes a 2D scene feel more immersive.
Example 1: Horizontal Parallax Scrolling
In our first example, we have a very simple scene of a
street at night that features horizontal scrolling with no interactive
elements. The various background layers move at pre-determined speeds along the x-axis. For now, let’s focus on the basics of parallax scrolling without worrying
about any player movement or shifting views.
First, let’s break down the individual elements and
attributes of our scene. The game window is 600x300px, and our art assets each have
a width of at least 600px. By using background elements that are larger than the
game window, we can prevent the entire asset from being visible at any given
time. Since the layers are tiled, this will help to prevent too much obvious
repetition as the same asset scrolls indefinitely.
Our scene is composed of four layers. In this
example, the number of the layer defines the order in which the asset is drawn
to the screen as well as its movement speed. If this were a side-scrolling
platformer, then our player object would exist on top of Layer 3. This layer
would be the focal point of the observer, and would also dictate the speed of
the background and foreground layers.
Layer 2 moves more slowly than Layer 3, and Layer 1 moves more slowly than Layer 2. Layer 4 exists as the foreground layer,
so it moves more quickly than the focal point on Layer 3.
There are several ways you can implement this kind of
parallax scrolling technique. In this example, the layers move at
pre-determined speeds without referencing one another. If you plan on having
multiple scenes with varying quantities of background and foreground layers,
then it would be best to define layer speeds by reading the current speed of
the focal point layer. For instance, if the focal point is Layer 3 and is
moving at a speed of 5, then each successive background layer would move at a
speed less than 5. Any foreground layers would move at a speed greater than 5.
While parallax scrolling is most often used with horizontal backgrounds, it can also be used in vertical scenes, as in this space shooter example. There may be more efficient ways to create a star field, but parallax scrolling gets the job done.
The most important thing to take away from this vertical example is that parallax scrolling works in all four directions along the x-and y-axes. (We will see just how important this is in our third and final example.)
This scene features four background layers: a static black background and three collections of stars at different sizes. The static background does not move, and each successive layer of stars grows larger and moves faster, with the final layer of stars ultimately determining the vertical speed of the focal point, the player’s spaceship. This type of parallax scrolling allows us to simulate the depth of space while also simulating forward movement. The player’s ship never actually moves up the screen, but you still get a sensation of fast-paced space traveling.
Example 3: Horizontal and Vertical Parallax Scrolling While Following an Object
Now that we have a better understanding of what parallax scrolling is about, we can begin to construct a scene in which both horizontal and vertical scrolling are implemented, along with a game view that tracks the movement of a player controlled object.
In the demo at the top of the tutorial, this scene is split into two examples. The first version shows what the scene is like without any parallax scrolling. The second version features full vertical and horizontal parallax scrolling, and it really illustrates how parallax scrolling can add a great deal of immersion and depth to what was originally a very flat and lifeless scene.
The most important aspect of this example is player movement and the game view. Because our background is no longer locked into a pre-determined speed or screen position, we have to calculate each layer’s speed and position in relation to the view window as the player moves around.
The origin of our view window is in the upper left corner at (X,Y). Each background layer asset’s origin is in the upper left corner of the sprite at (0,0). By finding the current x- and y-coordinates of the view window in relation to the game world, we can perform a calculation to determine where a background layer’s origin should be placed in the scene. This position changes as the view window moves around based on this calculation.
By using different values in the calculation of each layer, we are able to move each layer at different speeds, depending on how fast the player is moving.
The code to draw the layer that lies directly behind our player object is in the following format: draw_background_tiled_horizontal(layer, x, y) where draw_background_tiled_horizontal() is a simple function to draw a tiled asset at a specific location, and bg_ex_3_2 is our layer asset.
The X value of the layer in this case is defined by the X value of the current view divided by a value of 2.5, creating a horizontal movement that moves slightly slower than the movement of the view itself.
Similarly, the Y value of the layer is defined by the Y value of the current view divided by 10. The Y value of the layer is then increased by 300 to position it correctly in relation to the game world. Without this extra addition of 300, the asset would appear near the top of the game world instead of near the bottom where we want it to be.
These values will obviously differ in your project, but the important thing to remember is that the speed of the layer’s movement will increase as the division number increases, but only up to a certain point. By using division, the layer can only move at the same speed or slower than the speed of the player.
The two layers behind this layer move more slowly, so the division numbers are smaller:
To make a layer that moves faster than the focal point, such as a foreground layer, a slight change needs to be made. There is no foreground layer in this example, and the focal point layer is actually only visible at the bottom of the screen. The player is able to fly up and above the focal point, which is the ground, so the ship itself becomes the focal point. We refer to the ground as the focal point in this example because the ground is the only layer that moves at the same perceived speed as the spaceship. This is where we get our true sense of speed in the scene.
The ground layer moves more quickly than the view itself, so the code to draw this layer is slightly different than the other background layers:
With layers that move more quickly than the view, we take the negative X and Y values of the current view and multiply them by some value. There is no division involved in calculating the speed of foreground layers. In this example, the ground layer moves at a horizontal speed that is one and a half times faster than the speed of the view window. No multiplication is performed on the vertical speed of the layer, so it moves at the same speed as the view. An additional value of 700 is added to the layer’s Y value to place it in the desired location near the bottom of the game world.
Conclusion
Parallax scrolling is a simple but very effective way to add the illusion of depth to a 2D game. I hope the examples in the demo have proven how effective it can be, and I hope the tutorial itself has proven how simple it is to implement!
In this extra-long tutorial, I'll break down the source for Monster Wants Candy, a multi-platform game my colleague and I built with Phaser, the HTML5 game engine. In this way, you'll gain a practical introduction to the engine, and will learn concepts you can use to build your own HTML5 mobile and browser games.
Introduction
If you want to create HTML5 games, it's good to choose a framework or engine. You could, of course, do it in plain JavaScript, but using a framework greatly speeds up development, and takes care of the things that are not so exciting but that have to be done.
Phaser is a hot new HTML5 game development framework with a dedicated community, so if you haven't heard about it yet you should definitely give it a try!
Phaser is a framework for building both desktop and mobile HTML5 games. It was created by Photon Storm. The framework is written in pure JavaScript, but also contains TypeScript definition files, in case you're into that.
Phaser code is heavily based on the Flash gamedev platform Flixel, so Flash developers can feel right at home. Under the hood, it uses the Pixi.js engine to take care of rendering everything on screen using Canvas, or WebGL if possible.
It's quite new, but growing rapidly fast with the help of the active community at HTML5GameDevs forums. There are already many tutorials and articles available, and you can also check the official documentation, and a large collection of examples that can be very helpful during development. It is open sourced and freely available on GitHub, so you can dive directly into the source code and learn from it.
The latest stable build of Phaser, at the time of writing, is version 2.0.7.
What is Monster Wants Candy?
When I start working on a game, I think about the core idea first and try to quickly set up a working prototype. In this case study, we start with a fairly simple demo of a game called Monster Wants Candy.
Instead of working from a prototype, I will show you the structure of the project first, so you can understand the whole idea. We will then go through the chronological steps of our game: from loading the assets to creating the main menu and the actual game loop. You can check out the Monster Wants Candy demo right now to see what we'll be working on together.
The story of Monster Wants Candy is simple: an evil king has kidnapped your love and you have to collect enough candy to get her back. The gameplay is also simple: the sweets are falling down and you can tap them to eat them. The more points you gain from eating the candy, the better. If you miss any and they fall off the screen, you'll lose a life and the game will be over.
As you can see, it is a very simple game, but the structure is complete. You'll find that the most important use of the framework is for tasks like loading images, rendering sprites, and detecting user activity. It also makes for a good starting point from which you can copy the code, start fiddling with it, and build your own game.
Project Setup and Structure
You can read this handy article from the framework author himself about how to get started with Phaser, or you can copy the phaser.min.js file from the GitHub repo into your project directory and start working from scratch. You don't need an IDE—you can simply launch the index.html file in your browser and instantly see the changes you made in the source code.
Our project folder contains the index.html file which includes the HTML5 structure and all the necessary JavaScript files. There are two subfolders: img, which stores all of our graphic assets, and src, which stores the source code of the game.
Here's how the folder structure looks:
In the src folder, you'll find the JavaScript files—this is where the magic happens. In this tutorial, I will describe the purpose and the contents of every file in that folder.
You can see the source for each file in the GitHub repo for this tutorial.
Index.html
Let's start with the index.html file. It looks like a basic HTML5 website, but instead of adding the text and lots of HTML elements, we initialize the Phaser framework, which will render everything to a Canvas element.
<!DOCTYPE html><html><head><meta charset="utf-8" /><title>Monster Wants Candy demo</title><style> body { margin: 0; background: #B4D9E7; } </style><script src="src/phaser.min.js"></script><script src="src/Boot.js"></script><script src="src/Preloader.js"></script><script src="src/MainMenu.js"></script><script src="src/Game.js"></script></head><body><script>
(function() {
var game = new Phaser.Game(640, 960, Phaser.AUTO, 'game');
game.state.add('Boot', Candy.Boot);
game.state.add('Preloader', Candy.Preloader);
game.state.add('MainMenu', Candy.MainMenu);
game.state.add('Game', Candy.Game);
game.state.start('Boot');
})();</script></body></html>
We define the usual structure of the HTML document with the doctype and some information in the <head>: charset encoding, title of the page, and CSS style. Usually, we would reference the external CSS file where we put all the styling, but we don't need it here—as I mentioned earlier, everything will be rendered on a Canvas element, so we won't have any HTML elements to style.
The last thing to do is to include all of our JavaScript files: from the phaser.min.js file with the source code of the Phaser framework, to all of our own files containing the game's code. It is good to minify the number of requests in the browser by combining all the JavaScript files into one, so that your game loads faster, but for the purpose of this tutorial we will simply load them separately.
Let's move to the contents of the <body> tag, where we initialize the framework and start our game. The code is inside a self-invoking function; the first line looks like this:
var game = new Phaser.Game(640, 960, Phaser.AUTO, 'game');
This code will initialize Phaser with some defaults:
640 is the game's Canvas width in pixels and 960 is the game's height.
Phaser.AUTO informs the framework how we want our game to be rendered to the Canvas. There are three options: CANVAS, WEBGL and AUTO. The first runs our game in the 2D context of the Canvas; the second uses WebGL to render it where possible (mostly desktop right now, but the mobile support is getting better); and the third leaves this decision to the framework, which will check whether WebGL is supported and decide whether the game can be rendered in this context—if it can't, then the 2D Canvas rendering will be used.
The framework initialization will be assigned to the single object called game, which we will use when referencing the Phaser instance.
The next lines are all about adding states to our game:
game.state.add('Boot', Candy.Boot);
'Boot' is a state name and Candy.Boot is an object (defined in the next steps) that will be executed when we start that state. We're adding states for Boot (configuration), Preloader (loading assets), MainMenu (you guessed it; the main menu of our game) and Game (the main loop of the game). The last line, game.state.start('Boot'), starts the Boot state, so that the proper function from the Candy.Boot object will be executed.
As you can see, there's one main JavaScript game object created, with many others assigned within for special purposes. In our game we have Boot, Preloader, MainMenu, and Game objects which will be our game states, and we define them by using their prototypes. There are a few special function names inside those objects reserved for the framework itself (preload(), create(), update(), and render()), but we can also define our own (startGame(), spawnCandy(), managePause()). If you're not sure you understand all of this, then don't worry—I'll explain everything using the code examples later.
The Game
Let's forget about the Boot, Preloader and MainMenu states for now. They will be described in detail later; all you have to know at the moment is that the Boot state will take care of the basic config of the game, Preloader will load all the graphic assets, and MainMenu will show you the screen where you'll be able to start the game.
Let's focus on the game itself and see how the code of the Gamestate looks. Before we go through the whole Game.js code, though, let's talk about the concept of the game itself and the most important parts of the logic from a developer's point of view.
Portrait mode
The game is played in portrait mode, meaning that the player holds their mobile vertically to play it.
In this mode, the screen's height is greater than its width—as opposed to the landscape mode, where the screen's width is greater than its height. There are types of games that work better in portrait mode (like Monster Wants Candy), types that work better in landscape mode (including platformer games like Craigen), and even some types that work in both modes, although it's usually a lot harder to code such games.
Game.js
Before we go through the source code of the game.js file, let's talk about its structure. There is a world created for us, and there is a player character inside whose job it is to grab the candy.
Game world: The world behind the monster is static. There's an image of the Candyland in the background, we can see the monster in the foreground, and there's also a user interface.
Player character: This demo is intentionally very simple and basic, so the little monster is doing nothing besides waiting for the candy. The main task for the player is to collect the candy.
Candy: The core mechanic of the game is to catch as much candy as possible. The candies are spawned at the top edge of the screen, and the player must tap (or click) them as they're falling down. If any candy falls off the bottom of the screen, it's removed, and the player character receives damage. We don't have a lives system implemented, so after that the game instantly ends and the appropriate message is displayed.
Okay, let's look at the code structure of our Game.js file now:
Here, we're setting up all the variables that we will be using later in the code.
By defining this._name, we're restricting the use of the variables to the Candy.Game scope, which means they can't be used in other states—we don't need them there, so why expose them?
By defining Candy._name, we're allowing the use of those variables in other states and objects, so, for example, Candy._score can be increased from the Candy.item.clickCandy() function.
The objects are initialized to null, and the variables we need for calculations are initialized with zeros.
We can move on to the contents of Candy.Game.prototype:
At the beginning of the create() function, we set up the ARCADE physics system—there are a few available in Phaser, but this is the simplest one. After that, we add vertical gravity to the game. Then we add three images: the background, the floor on which the monster is standing, and the score UI's background. The fourth item we add is the Pause button, Note that we're using the Candy.GAME_WIDTHand Candy.GAME_HEIGHT variables, which are defined in Candy.Preloader() but are available throughout the whole game code.
Then we create a monster, the player's avatar. It's a sprite with frames—a spritesheet. To have it look like he's standing and breathing calmly, we can animate him.
The animations.add() function creates an animation from the available frames, and the function takes four parameters:
the name of the animation (so we can reference it later)
the table with all the frames we want to use (we can use only some of them if we want)
a framerate
a flag to specify whether to loop the animation and play it indefinitely.
If we want to start our animation, we have to use the animations.play() function with the name specified.
We then set the spawnCandyTimer to 0 (getting ready to count up) and the health of the monster to 10.
Styling the Text
The next two lines let us show some text on the screen. The this.add.text() function takes four parameters: left and top absolute positions on the screen, the actual text string and the config object. We can format the text accordingly using the CSS-like syntax in that config object.
In this case, the font is Arial, it's 40 pixels tall, the color is yellow, there's a stroke defined (with color and thickness), and the text is center-aligned.
After that, we define candyGroup and spawn the first candy.
We change the state of this.game.paused to true every time the pause button is clicked, show the appropriate prompt to the player, and set up an event listener for the player's click or tap on the screen. When that click or tap is detected, we remove the text and set this.game.paused to false.
The paused variable in the game object is special in Phaser, because it stops any animations or calculations in the game, so everything is frozen until we unpause the game by setting it to false.
The Update Loop
The update() function name is one of the reserved words in Phaser. When you write a function with that name, it will be executed on every frame of the game. You can manage calculations inside it based on various conditions.
Every tick in the game world, we add the time elapsed since the previous tick to the spawnCandyTimer variable to keep track of it. The if statement checks whether or not it's time to reset the timer and spawn new candy onto the game world—we do this every second (that is, every time we notice that the spawnCandyTimer has passed 1000 milliseconds). Then, we iterate through the candy group with all the candy object inside (we could have more than one on screen) using a forEach, and add a fixed amount (stored in the candy object's rotateMe value) to the candy's angle variable, so that they each rotate at this fixed speed while falling. The last thing we do is check if the health has dropped to 0—if so, then we show the game over screen and pause the game.
Managing the Candy Events
To separate the candy logic from the main Game, we use an object called item that contains the functions we will use: spawnCandy(), clickCandy() and removeCandy(). We keep some of the variables related to candy in the Game object for easier use, while others are defined only in the item functions for better maintainability.
a randomized x-coordinate to drop the candy from (between zero and the width of the Canvas)
the y-coordinate to drop the candy from, based on its height (which we determine later on based on the type of candy)
a randomized candy type (we have five different images to use)
We then add a single candy as a sprite, with its starting position and image as defined above. The last thing we do in this block is set a new animation frame that will be used when the candy spawns.
Next, we enable the body of the candy for the physics engine, so that it can fall naturally from the top of the screen when the gravity is set. Then, we enable the input on the candy to be clicked or tapped, and set the event listener for that action.
To be sure that the candy will fire an event when it leaves the screen boundaries we set checkWorldBounds to true. events.onOutOfBounds() is a function that will be called when our candy exits the screen; we make it call removeCandy() in turn. Setting the anchor to our candy in the exact middle lets us rotate it around its axis, so that it will spin naturally. We set the rotateMe variable here so we can use it in the update() loop to rotate the candy; we choose a value between -2 and +2. The last line adds our newly created candy to the candy group, so that we can loop through them all.
The removeCandy() function is fired if the candy disappears below the screen without being clicked. The candy object is removed, and the player loses 10 points of health. (He had 10 at the beginning, so missing even one piece of falling candy ends the game.)
Prototypes and Game States
We've learned about the game mechanics, the core idea, and how the gameplay looks. Now it's time to see the other parts of the code: scaling the screen, loading the assets, managing button presses, and so on.
We already know about the game states, so let's see exactly how they look, one after the other:
Boot.js
Boot.js is the JavaScript file where we will define our main game object—let's call it Candy (but you can name it whatever you want). Here's the source code of the Boot.js file:
As you can see, we're starting with var Candy = {} which creates a global object for our game. Everything will be stored inside, so we won't bloat the global namespace.
The code Candy.Boot = function(game){} creates a new function called Boot() (used in index.html) which receives the game object as a parameter (also created by the framework in index.html).
The code Candy.Boot.prototype = {} is a way to define the contents of Candy.Boot using prototypes:
There are a few reserved names for functions in Phaser, as I mentioned before; preload() and create() are two of them. preload() is used to load any assets and create() is called exactly once (after preload()), so you can put the code that will be used as a setup for the object there, such as for defining variables or adding sprites.
Our Boot object contains these two functions, so they can be referenced by using Candy.Boot.preload() and Candy.Boot.create(), respectively. As you can see in the full source code of the Boot.js file, the preload() function loads a preloader image into the framework:
The first parameter in this.load.image() is the name we give to the loading bar image, and the second is the path to the image file in our project structure.
But why are we loading an image in the Boot.js file, when Preload.js is supposed to do it for us anyway? Well, we need an image of a loading bar to show the status of all the other images being loaded in the Preload.js file, so it has to be loaded earlier, before everything else.
Scaling Options
The create() function contains a few Phaser-specific settings for input and scaling:
The first line, which sets input.maxPointers to 1, defines that we won't use multi-touch, as we don't need it in our game.
The scale.scaleMode setting controls the scaling of our game. The available options are: EXACT_FIT, NO_SCALE and SHOW_ALL; you can enumerate through them and use the values of 0, 1, or 2, respectively. The first option will scale the game to all the available space (100% width and height, no ratio preserved); the second will disable scaling completely; and the third will make sure that the game fits in the given dimensions, but everything will be shown on the screen without hiding any fragments (and the ratio will be preserved).
Setting scale.pageAlignHorizontally and scale.pageAlignVertically to true will align our game both horizontally and vertically, so there will be the same amount of free space on the left and right side of the Canvas element; the same goes for top and bottom.
The last line, state.start('Preloader'), executes the next state—in this case, the Preloader state.
Preloader.js
The Boot.js file we just went through has a simple, one-line preload() function and lots of code in the create() function, but Preloader.js looks totally different: we have lots of images to load, and the create() function will just be used to move to another state when all the assets are loaded.
It starts similarly to the previous Boot.js file; we define the Preloader object and add definitions for two functions (preload() and create()) to its prototype. Inside the Prototype object we define two variables: Candy.GAME_WIDTH and Candy.GAME_HEIGHT; these set the default width and height of the game screen, which will be used elsewhere in the code.
The first three lines in the preload() function are responsible for setting the background color of the stage (to #B4D9E7, light blue), showing the sprite in the game, and defining it as a default one for the special function called setPreloadSprite() that will indicate the progress of the loading assets.
As you can see, we pass three values: the absolute left position of the image (the center on screen is achieved by subtracting the width of the image from the width of the stage and halving the result), the absolute top position of the image (calculated similarly), and the name of the image (which we loaded in the Boot.js file already).
Loading spritesheets
The next few lines are all about using load.image() (which you've seen already) to load all of the graphic assets into the game.
This function, load.spritesheet(), rather than loading a single image, takes care of a full collection of images inside one file—a spritesheet. Two extra parameters are needed for telling the function the size of a single image in the sprite.
In this case, we have five different types of candy inside one candy.png file. The whole image is 410x98px, but the single item is set to 82x98px, which is entered in the load.spritesheet() function. The player spritesheet is loaded in a similar manner.
The second function, create(), starts the next state of our game, which is MainMenu. This means that the main menu of the game will be shown just after all the images from the preload() function have been loaded.
MainMenu.js
This file is where we will render some game-related images, and where the user will click on the Start button to launch the game loop and play the game.
The structure looks similar to the previous JavaScript files. The prototype of the MainMenu object doesn't have a preload() function, because we don't need it—all the images have been loaded in the Preload.js file already.
There are two functions defined in the prototype: create() (again) and startGame(). As I mentioned before, the name of the first one is specific to Phaser, while the second one is our own.
This function takes care of one thing only—launching the game loop—but it's not launched automatically or after the assets are loaded. We will assign it to a button and wait for a user input.
The create() method has three add.sprite() Phaser functions that we are familiar with already: they add images to the visible stage by positioning them absolutely. Our main menu will contain the background, the little monster in the corner, and the title of the game.
Buttons
There's also an object we've already used in Game state, a button:
This button looks like it is more complicated than over methods we've seen so far. We pass eight different arguments to create it: left position, top position, name of the image (or sprite), the function to execute after the button is clicked, the context in which this function is executed, and indices of the images in the button's spritesheet.
This is how the button spritesheet looks, with the states labelled:
It's very similar to the candy.png spritesheet we used before, except arranged vertically.
It's important to remember that the last three digits passed to the function—1, 0, 2—are the different states of the button: over (hover), out (normal), and down (touch/click) respectively. We have normal, hover and click states in the button.png spritesheet, respectively, so we change the order in the add.button() function from 0, 1, 2 to 1, 0, 2 to reflect that.
That's it! You now know the basics of Phaser game framework; congratulations!
The Finished Game
The demo game used in the article has evolved into a full, finished game that you can play here. As you can see, there are lives, achievements, high scores, and other interesting features implemented, but most of them are based on the knowledge you've already learned by following this tutorial.
You can also read the short "making of" blog post to learn about the origins of the game itself, the story behind it, and some fun facts.
Resources
Building HTML5 games for mobile devices has exploded in the last few months. The technology is getting better and better, and there are tools and services popping out almost every single day—it's the best time to dive in to the market.
Frameworks like Phaser gives you the ability to create games that run flawlessly on a variety of different devices. Thanks to HTML5, you can target not just mobile and desktop browsers, but also different operating systems and native platforms.
This was a long journey through every line of code of the Monster Wants Candy demo, but I hope it will help you learn Phaser, and that in the near future you will create awesome games using the framework.
The source code used in the article is also freely available on GitHub, so you can fork it or just download it and do whatever you want. Feel free to modify it and create your own games on top of it, and be sure to visit the Phaser forums if you need anything during the development.
We continue building our grid-based puzzle-game by connecting the tiles to each other, making them light up with the mouse cursor, and adding the ability to place flags.
In the last part of this tutorial, we created a field of tiles which form the basis for our puzzle game. In this part, we'll make it playable. This tutorial follows on directly from the last part, so read that before starting this.
Lighting Tiles Up on Mouseover
When the mouse is over a tile, we want it to light up. This is a cool feature which gives even simple actions (such as moving your mouse pointer) instantaneous feedback.
We use the OnMouseOver() function to accomplish this. It gets called automatically whenever the mouse cursor moves over the object the code is attached to. Add these variables to the Tile script:
public var materialIdle: Material;
public var materialLightup: Material;
Then assign your basic tile material to the materialIdle slot. We also need a lightup material, which should have the same color, but uses a different shader. While the basic material can have a diffuse shader...
...the lightup material could have a specular shader. Many games use an additional rim shader for that effect too. Those don't come with Unity, but if you can figure out how to get one, you can use that instead!
Don't forget to actually assign the materials to the Material slots on the tile prefab, so that they can be used.
Then add this OnMouseOver() function to the Tile script
function OnMouseOver()
{
renderer.material = materialLightup;
}
Try it out! When you move the mouse cursor over the tiles, they should change their appearance.
What you might have noticed is that the tiles change their appearance once the mouse is over them, but doesn't actually change back. For that, we need to use the OnMouseExit() function:
function OnMouseExit()
{
renderer.material = materialIdle;
}
And voilá; we now have tiles that light up and make the game much more interesting.
Assigning IDs to Tiles
In order to have the tiles communicate with each other (to find out how many mines are nearby), each tile needs to know its neighboring tiles. One way to accomplish that is using IDs, which each tile will be assigned.
Start by adapting the Tile code to include an ID variable. Also, add a variable to hold the number of tiles per row, which we'll use in this computation:
public var ID: int;
public var tilesPerRow: int;
Then modify the instantiate command in the Grid code to look like the following snippet. (The new line assigns IDs to the tiles as they are being created.)
The first tile will get the ID 0, the next one will be assigned the ID 1, and so on. You can check them by clicking the tiles during runtime, and seeing what number they have been assigned.
Getting Neighboring Tiles
Now we want each tile to know about its neighboring tiles. When we execute an action on a tile (such as uncovering it), we need to take the neighboring tiles into account.
In our case, this means counting the mines that are adjacent to the tile we just uncovered, and possibly uncovering other tiles as well—but we'll get to that later.
This can also be used to, say, check whether three or more tiles are next to each other in a Match-3 game.
Start by adding these variables to the Tile script:
public var tileUpper: Tile;
public var tileLower: Tile;
public var tileLeft: Tile;
public var tileRight: Tile;
public var tileUpperRight: Tile;
public var tileUpperLeft: Tile;
public var tileLowerRight: Tile;
public var tileLowerLeft: Tile;
These will hold all the neighboring tiles. They are public so that we can check during runtime that they have actually been assigned correctly.
Since now every Tile has an ID, the number of tiles that appear in a column, and access to the static array that has all tiles saved in the Grid class, we can calculate the positions of the neighboring tiles after they have been created.
With the IDs and the number of tiles per row, we can calculate which tiles are nearby. Suppose the tile doing the calculations has the ID 3, and that there are five tiles per row. The tile above it will have the ID 8 (the selected tile's ID plus the number of tiles per row); the tile to the right will have the ID 6 (the selected tile's ID plus one), and so on.
Unfortunately, this isn't enough. The code correctly checks the numbers, but when it asks the allTiles array to return the tiles, it can request index numbers that are out of range, producing a long list of errors.
In order to fix this, we need to check that the index we request from the array is actually valid. The most efficient way to do this is with a new inBounds() function. Add it to the Tile:
Now we need to check that each possible neighboring tile is within the bounds of the array that holds all the tiles, before we actually try to get it from the array:
That code block checks all the possibilities. It also checks whether a tile is at the edge of the field. A tile on the right-hand edge of the grid, after all, does not actually have any tiles to its right.
Try it out! Check a few tiles and see whether you've retrieved all the neighboring tiles correctly. It should look like this:
As the tile in this screenshot is a tile on the right edge of the field, it has no neighbors to the right, upper right, or lower right. The variables without assigned tiles are correctly empty, and a test reveals that the remaining ones to have been assigned correctly too.
Finally, once we've made sure that this works, we add all neighboring tiles into an array, so that we can access them all at once later. We need to declare this array at the beginning:
public var adjacentTiles: Array = new Array();
You can then adapt each line of the algorithm we created above to enter each neighboring tile in that array, or add this block afterwards:
After all tiles have
been created, all mines have been assigned, and each tile has retrieved its
neighbors, we then need to check whether each of these neighboring tiles is mined or not.
The Grid code already assigns the specified number of mines to randomly chosen tiles. Now we only need each tile to check its neighbors. Add this code at the beginning of the Tile script, so that we have a place to store the amount of mines:
public var adjacentMines: int = 0;
To count them, we run through the array into which we previously added all neighboring
tiles, and check each entry in turn to see if it is mined. If so, we increase the value of adjacentMines by 1.
function CountMines()
{
adjacentMines = 0;
for each(var currentTile: Tile in adjacentTiles)
if(currentTile.isMined)
adjacentMines += 1;
displayText.text = adjacentMines.ToString();
if(adjacentMines <= 0)
displayText.text = "";
}
This function also sets the text element of the tile to display the number of mines nearby. If there are no mines, it displays nothing (rather than 0).
Tracking the State of Each Mine
Let's add a state to each tile. This way, we can keep track of which state it is currently in—idle, uncovered, or flagged. Depending on which state the tile is in, it will react differently. Add it now, as we'll use it in a moment.
public var state: String = "idle";
Adding Flags
We want to be able to mark tiles as flagged. A flagged tile has a tiny little flag on top of it. If we right-click the flag it will disappear again. If all mined tiles have been flagged, and no incorrectly flagged tiles remain, the game is won.
Start by creating a flag object, and add it to the tile (you'll find a flag mesh in the source files).
We also need a variable to access the flag. Add this code:
public var displayFlag: GameObject;
Remember to drag the flag that is part of the tile onto the displayFlag slot.
Also, add this to the start() function of the tile:
This will disable the flag and text at the beginning. Later, we can then activate a flag, making it visible again, effectively putting it there. Alternatively, if we uncover a tile, we make the text visible again.
Placing and Removing Flags
We'll write a function that handles both placing and removing flags:
function SetFlag()
{
if(state == "idle")
{
state = "flagged";
displayFlag.renderer.enabled = true;
}
else if(state == "flagged")
{
state = "idle";
displayFlag.renderer.enabled = false;
}
}
Once you've added that, also add the code to handle a click event. To do this, adapt the OnMouseOver() function we already have to check for a mouse click:
function OnMouseOver()
{
if(state == "idle")
{
renderer.material = materialLightup;
if (Input.GetMouseButtonDown(1))
SetFlag();
}
else if(state == "flagged")
{
renderer.material = materialLightup;
if (Input.GetMouseButtonDown(1))
SetFlag();
}
}
This will recognize a right-click (button 1) and activate the SetFlag() function. It will then either activate or deactivate the flag on the current tile. Try it out!
Conclusion
We've extended our puzzle game with several vital features, made it visually more interesting, and have given the player the ability to affect the playing field.
Next time, we'll add uncovering of tiles, make a simple interface, and turn this into a proper game.
In this article, we'll examine the use of physics to simulate projectile effects in games like Angry Birds. We'll look at the basics of using 2D physics in game world space, such as creating bodies and applying impulses and forces.
Physics Engines
Why use a physics engine? What does it actually do?
A physics engine helps us do two very important things for our game:
Detect collisions between our in-game objects.
Simulate the forces and resulting motion of our objects from those collisions..
Collision detection: Games wouldn't much much fun if your character fell through the floor before you could jump, or if, when you hit an enemy with your foot, you fell right through. Collision detection using a physics engine allows for very precise contact listening, and allow interactions between objects to be simulated using forces.
Force simulation:After a collision, what should happen? Game logic could be called, you could bounce, the other game object could bounce, or you could simply move no further. This is all handled behind the scenes, using the calculated forces of the engine. But forces aren't limited to contact; other forces, such as gravity and impulses, can occur, without objects actually touching. Forces affect in-game actions and the movement of objects, characters, and even the world-space itself.
We'll look at how physics engines work shortly, but first lets look at what engines you may want to use, and why you may decide to use them, based on your particular needs.
Choosing Your Engine
When you first start to think about using physics in your game, you will need to decide how you want to approach the problem, and what your game will require in terms of simulation. You have two options for using physics:
Use an existing physics engine.
Create a custom physics simulation
Using an Existing Physics Engine
Several excellent options exist for predefined and ready-to-use physics engines. One of the most popular choices for 2D games is Box2D; it's a native C++ written engine, but has wrappers, ports, and extensions that allow it to be used in nearly any 2D platform. Another popular choice is Chipmunk 2D, which is used in several mainstream game engines, like Cocos2D.
Creating a Custom Engine
In some games, using a predefined engine isn't necessarily the optimal choice. Using a physics engine can cause some unnecessary overhead when its full function isn't required. In cases like simple platformers or brick-breaker type games—where you don't need pixel-perfect collision detection or some of the other capabilities of an engine—it may unnecessarily use up resources that could be better spent elsewhere.
Building your own engine can give you more flexibility over the final product, but it can also make things more complicated if you are dealing with more than a few instances of characters and objects.
The Game Loop
Before discussing the properties and details of a physics simulation, let's look at how it is called within the loop of your game scene.
The typical game loop will run through the following for each frame, in order:
Input
Update/Game Logic
Simulate Game Physics
Render Screen/Scene
This means that calculating the resulting physics is the last task performed in the loop before the screen is updated. This makes sense, as the point of the simulation is to react to what has happened within the game's world-space.
Note that this image shows that physics are simulated during every frame of your game loop. This can result in some large overhead if your simulation gets overly large or complicated. For this reason, it is best to keep game management and calls to the simulation and its listeners limited.
Fixed Rate vs. Frame Dependent Physics
It makes sense now to discuss two different methods of polling the physics simulation: fixed vs. frame dependent rates. Consider the (void)update: method consistent within most game loops. This loop is called once per frame of the game scene. If your "simulate physics" method is called from (void)update:, your game world physics is going to depend on your frame-rate, and this can lead to some choppy and unrealistic simulations. In iOS, this effect is mitigated by the use of the usesPreciseCollisionDetection Boolean property, but what about in other engines?
This code is designed to compensate for issues with the delta value for time. Consider a situation where you were playing the game on your phone and got a call: it would help your game for you to reset your delta back to the expected 1/60 (for a 60 fps game).
This is actually the first step into a discussion on decoupling the physics simulation from the time-step of the (void)update: method. While a modified time interval would certainly aid in a more stable physics simulation call, it doesn't correct for all situations. To do this, we would need to actually remove the physics simulation call from the game rendering loop, and create a fixed cycle within which it could run. For instance; if your game is meant to run at 60 fps, you set the physics to simulate 60 times per second. This decoupling removes any concerns of rendering issues causing choppy feedback in your physics simulation.
In short, be conscientious in your implementation of physics. If you find yourself using an engine in an environment where you are taxing system resources, consider a fixed step physics simulation to maintain fairness and fidelity.
From Sprite to Physics Body
A sprite is an image rendered to the screen of your game. A sprite has no properties by default within a physics simulation. You can "fake" some of the behaviours of a physical world by using properties of a sprite such as a bounding box and an intersection call, but then you have to write all of the resulting logic yourself. Wouldn't it be better if the game could handle all of this for us?
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
if (CGRectIntersectsRect(sprite1.frame, sprite2.frame)) {
//do something
}
}
Body Shapes
Physics bodies are "simple" shapes that define the rough size and shape of your sprite, or perhaps define an active area of your sprite. Consider the following:
A physics body is not predefined by the image of your sprite, and is typically invisible within the game. You create the shape dynamically, often by calling a method to either draw the shape that will make up the body, or by using a program to help you draw out and define the body. You then attach the body to the sprite, and gain access to the simulated effects and properties assigned to that body.
You can have multiple physics bodies tied to a single sprite. Take, as an example, a sprite of a hero carrying a sword. It would make sense to create one body for the hero character, and another one for the sword he carries. This would allow you to create game logic based on collisions between different bodies.
In pseudocode, the logic would look something like this:
//physics logic
-(void)physicsCollisionDidOccur{
switch (collision bitmask) {
case (Player||Sword): //do nothing;
break;
case (Player||Enemy): //ouch!!;
break;
case (Sword||Enemy): //do damage!!;
break;
default: //do nothing;
break;
}
Relating the Physics Body to the Sprite
Consider the situation of a of a space game, where you have a hero ship and an enemy ship:
You would likely want to make the physics body of the player a little smaller than the base sprite image for two reasons:
Enhanced Visual Collision: When a player collides with an object in your game, by creating this smaller physics body, the sprite images will overlap temporarily at the point of contact, which looks good visually. (Further to this point: when drawing z-values, keep your player's character at the front of the scene hierarchy.)
User-Perceived Fairness: To try to make your game feel "fair" to the player, keep the collide-able body limited to the bulk of the object, and away from extraneous protrusions like the back fin of the image above. This way, there won't be any "cheap hits" to annoy the players of your game. Conversely, you usually want the enemy physics body to be at least the size of the base image; if we give our space hero a laser to shoot his enemy, a slightly-too-large enemy body makes it more reasonable for our player to obtain a hit. Also consider this same approach for tiles in a platformer or puzzle game that requires your player to jump from platform to platform. Players are used to a little "grace" in these types of games; extending the physics body a tad will help keep your game reasonably "fair".
Typical 2D Engine Constraints
There are two main types of physics bodies:
Edge-based bodies
Volume-based bodies
An edge-based body is a static, immovable line that creates a boundary for other bodies to collide with. It has a negative space within it that has no effect on any bodies. A great application of this would be to create a boundary around your screen to contain any bodies within.
A volume-based body has volume and mass, and can be either dynamic or static. Because these bodies have mass, objects bounce off them and they can be affected by force contacts. Volume based bodies can be any of four main shapes:
Circle
Rectangle
Chain
Complex Polygon
There are some constraints to using bodies within your typical 2D physics engine. Here are the two main limitations:
Convex Physics Bodies
If a shape is convex, it means that no interior angle is less than 180 degrees.
To be clear, it can be possible to run physics simulations on concave shapes, but the processing cost is so high that it is simply not realistic for 2D, especially when running on a handheld or less powerful device. Concave-like shapes can be constructed by linking together two convex shapes using something called a Static Joint. Joints are another great feature available with 2D engines, but are outside of the scope of this discussion.
Rigid Physics Bodies
When a ball hits a wall, in the "real" world something like this will occur:
Your character's sprite can undergo this type of transformation, but its physics body cannot. You can control certain properties of the body to affect its "bounciness", but it cannot actually have a mutable shape. This is known as a Rigid Body, meaning that the body itself cannot be deformed or squished.
Properties of a Physics Body
Let's have a quick look at what some of the some of the most useful properties available on a typical physics body are:
Restitution is a measure of how "bouncy" an object is. More formally, it's the measure of how much energy an object retains after it collides with another object.
Density is the measure of how "heavy" an object is. It is used as a relative quality—for instance, a rock would be more dense than a ball, so when the ball hits the rock, it will be affected more heavily.
Friction is the measure of how "slippery" an object is. This is used when one object is sliding along another, and determines how long will it take for it to stop.
If a body is dynamic, then forces imposed upon it by the world and other objects will have an effect; if it is a static body, then they will not.
Rotation is typically a Boolean variable that can be set on a physics body. In certain cases you may want to limit a body and not allow it to rotate, but you want forces to still be applied to that object.
Most engines have more properties available than this, but for the purposes of this discussion, these will be sufficient to get started.
Motion and Momentum
In a simulated physics world, bodies are moved by the application of forces and impulses.
Forces: General forces typically affect bodies more gradually than impulses They are a constant force that is applied over a unit time (like gravity or an engine).
Impulses (Impulse Forces): Impulses are immediately-applied adjustments to a body's momentum. Impulses are usually applied to a simulation based on user input.
What Next?
Now that you understand the theory, the best way to cement your understanding of projectile physics engines is to build one yourself. Next, I'll break down the code for a simple physics-based game that I've written, so you can see exactly how it works!
In What's in a Projectile Physics Engine, we covered the theory and essential elements of physics engines that can be used to simulate projectile effects in games like Angry Birds. Now, we'll cement that knowledge with a real example. In this tutorial, I'll break down the code for a simple physics-based game that I've written, so you can see exactly how it works.
For those interested, the example code provided throughout this tutorial uses the Sprite Kit API provided for native iOS games. This API uses an Objective-C wrapped Box2D as the physics simulation engine, but the concepts and their application can be used in any 2D physics engine or world.
Building a Game World
Here is the sample game in action:
The overall concept of the game takes the following form:
A structure of platforms with physics bodies are added to the level, building a tower.
One or more objective objects are placed within the tower, each with a physics body assigned to it.
A firing mechanism shoots a projectile body with an momentary impulse; when the projectile's body collides with the platforms' bodies, the simulation takes over and computes the results for us.
If a projectile or a platform touches the objective, it fades from the scene, and the player wins! This collision is detected using the physics bodies, so that the simulation maintains its realism at the point of collision.
Our first use of physics will be to create an edge loop body around our screen's frame. The following is added to an initializer or -(void)loadLevel method:
//create an edge-loop physics body for the screen, basically creating a "bounds"
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
This will keep all of our objects within the frame, so that gravity won't pull our whole game off the screen!
Adding Objects
Let's look at adding some physics-enabled sprites to our scene. First, we will look at the code for adding three types of platforms. We will use square, rectangular, and triangular platforms to work with in this simulation.
-(void)createPlatformStructures:(NSArray*)platforms {
for (NSDictionary *platform in platforms) {
//Grab Info From Dictionay and prepare variables
int type = [platform[@"platformType"] intValue];
CGPoint position = CGPointFromString(platform[@"platformPosition"]);
SKSpriteNode *platSprite;
platSprite.zPosition = 10;
//Logic to populate level based on the platform type
if (type == 1) {
//Square
platSprite = [SKSpriteNode spriteNodeWithImageNamed:@"SquarePlatform"]; //create sprite
platSprite.position = position; //position sprite
platSprite.name = @"Square";
CGRect physicsBodyRect = platSprite.frame; //build a rectangle variable based on size
platSprite.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:physicsBodyRect.size]; //build physics body
platSprite.physicsBody.categoryBitMask = otherMask; //assign a category mask to the physics body
platSprite.physicsBody.contactTestBitMask = objectiveMask; //create a contact test mask for physics body contact callbacks
platSprite.physicsBody.usesPreciseCollisionDetection = YES;
} else if (type == 2) {
//Rectangle
platSprite = [SKSpriteNode spriteNodeWithImageNamed:@"RectanglePlatform"]; //create sprite
platSprite.position = position; //position sprite
platSprite.name = @"Rectangle";
CGRect physicsBodyRect = platSprite.frame; //build a rectangle variable based on size
platSprite.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:physicsBodyRect.size]; //build physics body
platSprite.physicsBody.categoryBitMask = otherMask; //assign a category mask to the physics body
platSprite.physicsBody.contactTestBitMask = objectiveMask; //create a contact test mask for physics body contact callbacks
platSprite.physicsBody.usesPreciseCollisionDetection = YES;
} else if (type == 3) {
//Triangle
platSprite = [SKSpriteNode spriteNodeWithImageNamed:@"TrianglePlatform"]; //create sprite
platSprite.position = position; //position sprite
platSprite.name = @"Triangle";
//Create a mutable path in the shape of a triangle, using the sprite bounds as a guideline
CGMutablePathRef physicsPath = CGPathCreateMutable();
CGPathMoveToPoint(physicsPath, nil, -platSprite.size.width/2, -platSprite.size.height/2);
CGPathAddLineToPoint(physicsPath, nil, platSprite.size.width/2, -platSprite.size.height/2);
CGPathAddLineToPoint(physicsPath, nil, 0, platSprite.size.height/2);
CGPathAddLineToPoint(physicsPath, nil, -platSprite.size.width/2, -platSprite.size.height/2);
platSprite.physicsBody = [SKPhysicsBody bodyWithPolygonFromPath:physicsPath]; //build physics body
platSprite.physicsBody.categoryBitMask = otherMask; //assign a category mask to the physics body
platSprite.physicsBody.contactTestBitMask = objectiveMask; //create a contact test mask for physics body contact callbacks
platSprite.physicsBody.usesPreciseCollisionDetection = YES;
CGPathRelease(physicsPath);//release the path now that we are done with it
}
[self addChild:platSprite];
}
}
We'll get to what all the property declarations mean in a bit. For now, focus on the creation of each body. The square and the rectangular platforms each create their bodies in a one line declaration, using the sprite's bounding box as the body size. The triangle platform's body requires drawing a path; this also uses the sprite's bounding box, but calculates a triangle at the corners and halfway points of the frame.
The objective object, a star, is similarly created, but we will use a circular physics body.
-(void)addObjectives:(NSArray*)objectives {
for (NSDictionary* objective in objectives) {
//Grab the position information from the dictionary provided from the plist
CGPoint position = CGPointFromString(objective[@"objectivePosition"]);
//create a sprite based on the info from the dictionary above
SKSpriteNode *objSprite = [SKSpriteNode spriteNodeWithImageNamed:@"star"];
objSprite.position = position;
objSprite.name = @"objective";
//Assign a physics body and physic properties to the sprite
objSprite.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:objSprite.size.width/2];
objSprite.physicsBody.categoryBitMask = objectiveMask;
objSprite.physicsBody.contactTestBitMask = otherMask;
objSprite.physicsBody.usesPreciseCollisionDetection = YES;
objSprite.physicsBody.affectedByGravity = NO;
objSprite.physicsBody.allowsRotation = NO;
//add the child to the scene
[self addChild:objSprite];
//Create an action to make the objective more interesting
SKAction *turn = [SKAction rotateByAngle:1 duration:1];
SKAction *repeat = [SKAction repeatActionForever:turn];
[objSprite runAction:repeat];
}
}
Ready, Set, Fire!
The cannon itself doesn't need any bodies attached, as it has no need for collision detection. We will simply use it as a starting point for our projectile.
Here is the method for creating a projectile:
-(void) addProjectile {
//Create a sprite based on our image, give it a position and name
projectile = [SKSpriteNode spriteNodeWithImageNamed:@"ball"];
projectile.position = cannon.position;
projectile.zPosition = 20;
projectile.name = @"Projectile";
//Assign a physics body to the sprite
projectile.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:projectile.size.width/2];
//Assign properties to the physics body (these all exist and have default values upon the creation of the body)
projectile.physicsBody.restitution = 0.5;
projectile.physicsBody.density = 5;
projectile.physicsBody.friction = 1;
projectile.physicsBody.dynamic = YES;
projectile.physicsBody.allowsRotation = YES;
projectile.physicsBody.categoryBitMask = otherMask;
projectile.physicsBody.contactTestBitMask = objectiveMask;
projectile.physicsBody.usesPreciseCollisionDetection = YES;
//Add the sprite to the scene, with the physics body attached
[self addChild:projectile];
}
Here we see a more complete declaration of some properties assignable to a physics body. When playing with the sample project later, try altering the restitution, friction, and density of the projectile to see what effects they have on the overall gameplay. (You can find definitions for each property in What's in a Projectile Physics Engine?)
The next step is to create the code to actually shoot this ball at the target. For this, we'll apply an impulse to a projectile based on a touch event:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
NSLog(@"Touched x:%f, y:%f", location.x, location.y);
//Check if there is already a projectile in the scene
if (!isThereAProjectile) {
//If not, add it
isThereAProjectile = YES;
[self addProjectile];
//Create a Vector to use as a 2D force value
projectileForce = CGVectorMake(18, 18);
for (SKSpriteNode *node in self.children){
if ([node.name isEqualToString:@"Projectile"]) {
//Apply an impulse to the projectile, overtaking gravity and friction temporarily
[node.physicsBody applyImpulse:projectileForce];
}
}
}
}
}
Another fun alteration to the project might be to play with the impulse vector value. Forces—and therefore impulses—are applied using vectors, giving magnitude and direction to any force value.
Now we have our structure and our objective, and we can shoot at them, but how do we see if we scored a hit?
Collision Course
First, a quick pair of definitions:
A contact is used when two bodies touch.
A collision is used to prevent two bodies from intersecting.
Contact Listener
So far, the physics engine has been handling contacts and collisions for us. What if we wanted to do something special when two particular objects touch? To start with, we need to tell our game that we want to listen for the contact. We will use a delegate and a declaration to accomplish this.
Before we can use this method, though, we need to discuss categories.
Categories
We can assign categories to our various physics bodies, as a property, to sort them into groups.
Sprite Kit in particular uses bit-wise categories, meaning we are limited to 32 categories in any given scene. I like to define my categories using a static constant declaration like this:
Note the use of bit-wise operators in the declaration (a discussion on bitwise operators and bit variables is beyond the scope of this tutorial; just know that they are essentially just numbers stored in a very quickly accessed variable, and that you can have 32 maximum).
We assign the categories using the following properties:
platSprite.physicsBody.categoryBitMask = otherMask; //assign a category mask to the physics body
platSprite.physicsBody.contactTestBitMask = objectiveMask; //create a contact test mask for physics body contact callbacks
Doing the same for the other variables in the project, let's us now complete our contact listener method stub from earlier, and also this discussion!
-(void)didBeginContact:(SKPhysicsContact *)contact
{
//this is the contact listener method, we give it the contact assignments we care about and then perform actions based on the collision
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask); //define a collision between two category masks
if (collision == (otherMask| objectiveMask)) {
//handle the collision from the above if statement, you can create more if/else statements for more categories
if (!isGameReseting) {
NSLog(@"You Win!");
isGameReseting = YES;
//Set up a little action/animation for when an objective is hit
SKAction *scaleUp = [SKAction scaleTo:1.25 duration:0.5];
SKAction *tint = [SKAction colorizeWithColor:[UIColor redColor] colorBlendFactor:1 duration:0.5];
SKAction *blowUp = [SKAction group:@[scaleUp, tint]];
SKAction *scaleDown = [SKAction scaleTo:0.2 duration:0.75];
SKAction *fadeOut = [SKAction fadeAlphaTo:0 duration:0.75];
SKAction *blowDown = [SKAction group:@[scaleDown, fadeOut]];
SKAction *remove = [SKAction removeFromParent];
SKAction *sequence = [SKAction sequence:@[blowUp, blowDown, remove]];
//Figure out which of the contact bodies is an objective by checking its name, and then run the action on it
if ([contact.bodyA.node.name isEqualToString:@"objective"]) {
[contact.bodyA.node runAction:sequence];
} else if ([contact.bodyB.node.name isEqualToString:@"objective"]) {
[contact.bodyB.node runAction:sequence];
}
//after a few seconds, restart the level
[self performSelector:@selector(gameOver) withObject:nil afterDelay:3.0f];
}
}
}
Conclusion
I hope that you've enjoyed this tutorial! We have learned all about 2D physics and how they can be applied to a 2D projectile game. I hope you now have a better understanding of what you can do to start using physics in your own games, and how physics can lead to some new and fun gameplay. Let me know in the comments below what you think, and if you use anything you've learned here today to create projects of your own, I'd love to hear about it.
A Note on the Example Project
I have included a working example of the code provided in this project as a GitHub repo. The fully commented source code is there for all to use.
Some minor portions of the working project unrelated to physics were not discussed in this tutorial. For instance, the project is built to be expandable, so the code allows the loading of multiple levels using a property list file to create different platform arrangements and multiple objectives to hit. The game over section, and the code to remove objects and timers, were also not discussed, but are fully commented and available within the project files.
Some ideas for features you could add to expand on the project:
In the final part of this series, we put the finishing touches on our grid-based Unity puzzle game, and make it playable. By the end of this part, the player will be able to win or lose the game.
Now that you've completed the previous tutorials, our game can create a field of tiles, and assign mines randomly to them. We also have a nice light-up effect when the player hovers over a tile with the mouse, and it's possible to place and remove flags.
Internally, each tile also knows about their neighboring tiles, and can already calculate how many mines are nearby.
Uncovering Tiles
We've already added the ability to place flags with a right click. Now, let's add the ability to uncover tiles with a left click.
In the OnMouseOver() function, where we have the click recognition code, we need to recognize a left click. Adapt the function so that it looks like this:
function OnMouseOver()
{
if(state == "idle")
{
renderer.material = materialLightup;
if (Input.GetMouseButtonDown(0))
UncoverTile();
if (Input.GetMouseButtonDown(1))
SetFlag();
}
else if(state == "flagged")
{
renderer.material = materialLightup;
if (Input.GetMouseButtonDown(1))
SetFlag();
}
}
When the left mouse button is pressed, the UncoverTile() function will be called. Make sure that you create this function, so that this won't cause a bug!
function UncoverTile()
{
if(!isMined)
{
state = "uncovered";
displayText.renderer.enabled = true;
renderer.material = materialUncovered;
}
else
Explode();
}
For this to work, we need to introduce a new material.
public var materialUncovered: Material;
Create something that has a different color than the basic tiles—so if your basic tiles are blue, you could choose green for the uncovered state. But don't use red; we'll need that later to show that we've triggered a mine.
When call that function, the following happens:
First, we check whether the tile is actually mined.
If not, we set the state to uncovered, activate the text display that shows us the number of nearby mines, and set the material to the uncovered material.
Afterwards, the tile cannot be clicked again, and also won't light up again, which means the passive feedback of tiles reacting to the mouse cursor will only happen on tiles we can actually click.
Before we can try this out, we need to make sure that the material isn't changed when the mouse cursor exits the tile. For this, adapt the OnMouseExit() function like so:
function OnMouseExit()
{
if(state == "idle" || state == "flagged")
renderer.material = materialIdle;
}
This way, the color only gets switched back if the tile has not yet been uncovered.
Try it out! You should be able to uncover tiles. If a tile is mined, though, nothing will happen right now.
Making Empty Tiles Uncover Each Other
This will be a bit tricky. In Minesweeper, when you uncover a tile with nomines
next to, it will uncover all the tiles adjacent to it that also have no mines, and the tiles adjacent to them that have no mines, and so on.
Consider this field:
We don't actually see the numbers or mines, only regular tiles.
When a tile with zero nearby mines is uncovered, all tiles next to it should automatically be uncovered, too. The uncovered tile then uncovers all neighbors.
These newly uncovered tiles will then check their neighbors, too, and, if there are no mines, uncover them as well.
This will ripple through the field until we reach tiles that actually have mines adjacent to them, where it will stop.
This creates the empty areas we can see in Minesweeper.
To make this work, we need two more functions, UncoverAdjacentTiles() and UncoverTileExternal():
private function UncoverAdjacentTiles()
{
for(var currentTile: Tile in adjacentTiles)
{
//uncover all adjacent nodes with 0 adjacent mines
if(!currentTile.isMined && currentTile.state == "idle" && currentTile.adjacentMines == 0)
currentTile.UncoverTile();
//uncover all adjacent nodes with more than 1 adjacent mine, then stop uncovering
else if(!currentTile.isMined && currentTile.state == "idle" && currentTile.adjacentMines > 0)
currentTile.UncoverTileExternal();
}
}
public function UncoverTileExternal()
{
state = "uncovered";
displayText.renderer.enabled = true;
renderer.material = materialUncovered;
}
We also need to make this modification to the UncoverTile() function:
function UncoverTile()
{
if(!isMined)
{
state = "uncovered";
displayText.renderer.enabled = true;
renderer.material = materialUncovered;
if(adjacentMines == 0)
UncoverAdjacentTiles();
}
}
When we uncover a tile, and there are no mines next to it, we call the UncoverAdjacentTiles() function. This then checks each neighboring tile to see whether it has mines or not. too. If there aren't any, it uncovers this tile as well, and initiates another round of checking. If there are mines nearby, it only uncovers the tile it is currently at.
Now, try it out. To get good chance of an empty field appearing, create a rather large field with a few mines—say, 81 tiles, with nine tiles per row, and 10 mines in total.
You can actually now play this as a game, except that you cannot trigger mines yet. We'll add that feature next.
Triggering Mines
When we uncover a tile that is mined, the game stops and the player loses. Additionally, all other mined tiles become visible. For this to happen, we need one more material, for the detonated mine tiles:
public var materialDetonated: Material;
I suggest using something red for this.
Also, we need to add two more functions to handle exploding all of the mines:
function Explode()
{
state = "detonated";
renderer.material = materialDetonated;
for (var currentTile: Tile in Grid.tilesMined)
currentTile.ExplodeExternal();
}
function ExplodeExternal()
{
state = "detonated";
renderer.material = materialDetonated;
}
We trigger those methods in the UncoverTile() function:
If a tile is mined, the tile explodes. The Explode() function then sends an "explode" command to all other tiles with mines, revealing them all.
Winning the Game
The game is won once all tiles with mines have been flagged correctly. At this point, all tiles that are not uncovered are uncovered too. So how do we track that?
Let's start by adding a state variable to the Grid class, so that we can track which part of the game we are currently in (still playing, lost, or won).
static var state: String = "inGame";
While we're at it, we can also begin to add a simple GUI, so that we can display necessary information on the screen. Unity comes with its own GUI system which we'll use for this.
function OnGUI()
{
GUI.Box(Rect(10,10,100,50), state);
}
This will show us which state we are currently in. We'll call these states inGame, gameOver, and gameWon.
We can also add checks to the Tile, to make sure we can only interact with the tiles while the current game state is inGame.
In the OnMouseOver() and OnMouseExit functions, move all the existing code into an if block that checks whether Grid.state is currently inGame, like so:
function OnMouseOver()
{
if(Grid.state == "inGame")
{
if(state == "idle")
{
renderer.material = materialLightup;
if (Input.GetMouseButtonDown(0))
UncoverTile();
if (Input.GetMouseButtonDown(1))
SetFlag();
}
else if(state == "flagged")
{
renderer.material = materialLightup;
if (Input.GetMouseButtonDown(1))
SetFlag();
}
}
}
function OnMouseExit()
{
if(Grid.state == "inGame")
{
if(state == "idle" || state == "flagged")
renderer.material = materialIdle;
}
}
There are actually two ways to check whether the game has been won: we can count how many mines have been marked correctly, or we can check whether all tiles that are not mines have been uncovered. For that, we need the following variables; add them to the Grid class:
static var minesMarkedCorrectly: int = 0;
static var tilesUncovered: int = 0;
static var minesRemaining: int = 0;
Don't forget to set minesRemainingin the Start() function to numberOfMines, and the other variables to 0. The Start() function should now look like this:
function Start()
{
CreateTiles();
minesRemaining = numberOfMines;
minesMarkedCorrectly = 0;
tilesUncovered = 0;
state = "inGame";
}
The last line sets the state for the game. (This will be important when we want to introduce a "restart" function later.)
We then check for our end-game conditions in the Update() function:
We finish the game by setting the state to gameWon, uncovering all remaining tiles, and flagging all remaining mines:
function FinishGame()
{
state = "gameWon";
//uncovers remaining fields if all nodes have been placed
for(var currentTile: Tile in tilesAll)
if(currentTile.state == "idle" && !currentTile.isMined)
currentTile.UncoverTileExternal();
//marks remaining mines if all nodes except the mines have been uncovered
for(var currentTile: Tile in Grid.tilesMined)
if(currentTile.state != "flagged")
currentTile.SetFlag();
}
For all this to actually work, we need to increment the variables that track our progress at the right spots. Adapt the UncoverTile() function to do that:
That's it! We have created a simple puzzle game with Unity, which you can use as a basis to create your own. I hope you've enjoyed this series; please ask any questions you have in the comments!
For my One Game a Month projects, I
have chosen to undertake a unique challenge. Every other month I choose
one "bad" video game and remake it into something playable and
hopefully even entertaining.
For May, I decided to remake the NES classic Hyldide, and combine it with its official remake, Virtual
Hydlide. Together, they would create Virtually Super Hydlide Special!
While Hydlide is considered a
groundbreaking classic in Japan, its late American release made
it a laughing stock prime for AVGN. Virtual Hydlide, on the other hand, was pretty much universally panned. At best, it was a poorly
implemented game with some good ideas.
Combining a game that half the world
hates with a game the whole world hates... What could possibly go
wrong?
The Plan
One of the biggest issues players have
with Hydlide is the combat system. Long before Zelda's exciting blend
of action and exploration, Hydlide was all about walking into
things.
No, I'm not kidding.
To attack an enemy in Hydlide, you walk
into him. You and the enemy each trade blows every time you step onto
his tile or vice-versa. The deepest strategy you can apply is to hold the A
button to enter Attack Mode. While in Attack Mode, the player
inflicts more damage, but also suffers more. If it looks like you
might lose the battle, you can just move away and wait for your HP to
recover.
Fortunately, we have a genre of games
that is beloved despite its similar lack of gameplay: the MMO.
In
classic MMO format, the player chooses a target enemy and trades blows automatically, until either the player dies or the enemy dies. This was actually the core concept I used when I started this remake, because it solved many issues:
If I made this first person, I wouldn't need custom attack animations and could tie into the Virtual Hydlide style of gameplay.
Because MMO combat-style trading of blows is so similar to the old style, I could keep the stats exactly the same and maintain the original balance.
I could even keep the Attack Mode and Defense Mode distinction, and have it function the same.
The other major advantage is that I'd been working on a 3D sprite engine the previous month, and this would allow me to use the original NES sprites in a 3D
world!
Note: The gameplay images in this article use custom sprites to avoid copyright issues. Virtually Super Hydlide Special uses the original NES sprites.
Finally, the sprite engine allowed me
to import maps from a directly from a bitmap. In order to create my
game's maps, all I needed to do was trace the original maps with
solid colors and shrink the image to a reasonable size. The engine
does the rest.
Looking back, it really was actually a
pretty good plan. But, you know what they say about the best laid plans...
What Went Horribly Wrong
I Vastly Overestimated My Engine
I'd built my engine for
old-school dungeon crawls. The largest map that I had built was about
30x30. The smallest I could make Hydlide's world map while keeping
that expansive feel was 83x83.
At almost triple the tested size, this lead to a long loading
sequence. This is problematic, because the dungeons are not large and
you'll be loading the world map often. I ended up spending a few days
implementing a streaming map, only to cut the feature later because I
realized the loading screens were a good way to give the player information they needed.
The days I spent making the map stream
were wasted. If I had taken the time to think about things prior to attempting to work through the problem, I'd have saved time and
stress.
The other set of issues came from
modifying the engine to use a looping map. The tiles that I used were very
small and I needed to draw a lot of these to fill a reasonable draw
distance. This lead to visible slowdown as the map tiles looped around.
My solution? I loaded more tiles!
During the loading screen, I loaded
about twice the tiles that I needed to fill the draw distance. This
means that, as you walk, the map is already fully loaded and in
place, but tiles in the distance are loading in real time.
At this point, I modified the system
to load only a few tiles each frame. To the player, it looks like the
map is streaming around seamlessly, but beyond the camera there are
holes in the world where it's actually being built a little bit at a time.
Overall, the engine worked, but it sure as heck wasn't as smooth as I had intended. I had wanted my core gameplay to be implemented by Day Seven, but didn't actually finish until almost a week later.
I Underestimated the Conversion to 3D
Because I put so much time into making the world map work, I didn't foresee this second major issue until I was well into the project. I have enough experience that I should have seen it coming a mile away.
It was forgivable in the original game, because a bird's eye view allows you to see the correct paths. But, as a first person game, directly using the dungeons' maps as I had planned would make things frustrating.
I couldn't import the levels as I'd planned, and so I needed to hand-make new ones. While creating short and functional maps was not a major problem, it was an unplanned expense.
I Was Overconfident and This Made Me Stupid
Two months earlier, my previous remake project, Ghostbusters Inc., had been amazing from a work standpoint. Everything fell into place, and I ended up implementing nearly every feature I had hoped for, while still working a reasonable schedule.
My last #1GAM project had gone extremely smoothly as well. I completely designed and implemented Tactical Strike Micro in a week. It had used the same engine as Hydlide, and everything worked out well.
I went into this month with good projects on the brain, and I ignored one of my most important tools: planning!
I'm usually a fanatic about taking the time to write down a schedule, plan features and dependencies, and correctly prioritize everything. I've seen and often taken part in the stupidity that comes from "winging it".
On the 13th>, I was still implementing core gameplay features that should have been either implemented or cut by now. Stress was beginning to get to me, and I could feel the developer tunnel vision coming over me. I was working hard, despite having lost sight of the big picture.
Honestly, I wasn't sure I'd finish on time. Half a month on a small project seems like a long time, but there was a lot that needed to be done, and it wasn't going well.
I often warn people about the dangers of blind passion, yet this project was a fine reminder that I'm not above it.
The Good
I Didn't Panic
I've worked with myself enough to know that this is an accomplishment. When things go south I usually enter a purely reactive emotional state—highly effective, but misguided. But I didn't do that here.
On the 13th, I realized that I was in trouble, and I stepped back to review my process. It didn't take long to see that I was so focused on controlling the steering wheel that I wasn't watching the road. I was fixing issues without any consideration for how they fit into the final product.
I took the entire day of the 14th off from development to outline a proper plan:
Dates by which each part should be ready.
A prioritized list of features and bug fixes.
Questions that I needed to think about, such as "How will I help guide the player without NPCs?" With this list, I knew what to think about when I wasn't working.
When the plan was ready, I sat down and relaxed for the rest of the evening. I knew that stress had started to affect my thinking and I needed to clear my head.
Starting on the 15th, my productivity skyrocketed. I accomplished more in the next three days than I had in the previous week.
The Style
I was amazed how good the 2D NES sprites looked in the 3D world. All the enemies, dungeon walls, and terrain tiles are straight from the NES game, yet they stand out and make the game look unique.
While I've designed better games over the years, this one seemed to catch people's eyes. I actually received a lot of positive feedback on the way the game looks.
My Early Assumptions Were Correct
Thankfully, most of my original assumptions were valid. The combat system worked fine and was reasonably balanced, and even with the flaws, the engine did what I needed it to do.
Despite everything that went poorly, the game is fun.
While I did modify the combat system to be more action-oriented and less of a grind, I had a strong start thanks to the links to the original game.
My Dev Network
While this was a solo project that I built on my own, I didn't actually do it alone. Many of my friends are experienced game developers and they were an immense help.
The combat redesign came after talking to my friend Josh about the MMO-style combat. He expressed concern that it wouldn't be exciting enough. As the project continued, I realized that he was right, and that I needed to stray from the original vision.
The same goes for other features ,such as the "fairy guide" I implemented after my friend Rob got lost, or the new attack animations I coded upon his observation that I could just rotate the sprites to decent effect. Even Twitter came to my aid, linking me to information I needed to help guide the player wordlessly.
You cannot underestimate the value of having people to talk to, even on solo projects.
My Biggest Takeaway
Paperwork and scheduling are tedious and rarely accurate, but they are still beneficial.
Taking the time to put your plan on paper will force you to examine the project as a whole. As you break it down into specific features, you'll see which pieces are reliant on one another so that you can tackle them in an effective order. Then, you can stay in the zone between tasks because you don't need to switch between details thinking and big picture thinking.
The other nifty advantage is that having a list means that you can add to it during development. If you encounter a bug or feature that should be implemented, you have a place to write it down and stay organized.
I thought I could get away with avoiding the tedium, but I was wrong, No matter how experienced I might be, I'm not immune to mistakes. Pre-production is an important step, no matter how good you think you are.
From
Space Invaders to Super Mario, pixel art is well known within the
game industry of yore. It's quite likely that you grew up seeing
a great deal of the art form through gaming consoles or PCs without a
great deal of investigation into the process of creating it. If, however, you were anything like me as a child, simply
guiding Link through Hyrule was not enough: you wanted to create the
artwork he swung his sword in, too.
As
pixel art in game design, illustration, and other media has made
quite a comeback in recent years (likely due to nostalgia and an
appreciation of a beautiful, if sometimes tedious, style of artwork),
it's a great time to ask the question: “What's the deal with pixel
art?”
What Qualifies as Pixel Art?
Considering
that everything you are viewing on your monitor, tablet, or phone is
comprised of many, many pixels, the often asked question is “how is
this not pixel art?” It's art, it's made of pixels, so surely all
digital art is pixel art. While technically correct, when talking
about “pixel art”, we're focused on a specific style of artwork
most often employed within the gaming industry. Pixel art is a
raster-based digital work that is created on a pixel-by-pixel level.
Typically very small, the art form is similar to mosaics or
cross-stitch in that it focuses on small pieces placed individually
to create a larger piece of art.
Many
image editing programs can be used to generate pixel art, so long as
the program allows artwork to be drawn on a one pixel by one pixel
scale. As such, the popularity of artists using MS Paint arose due to
its being readily available to Windows users. In the case of other
image editing programs, tools outside of hard-edged pencils and
erasers are typically discouraged. A hallmark of pixel art tends to
be the artist's ability to render complex designs and scenes without
the use tools like Dodge, Burn, or shape tools.
What Techniques are Used?
Often,
the color palette within pixel art is limited. In previous years (we're talking a couple decades at this point), the limit in color
count was due to the limits of game consoles or display on a computer
monitor. As such, a technique known as dithering was employed.Dithering is the staggering of two colors in order to blend them
together without having to involve extra colors. The pattern an
artist uses, either style of staggering pixels or density of
dithering, contributes to how well the colors blend. It's similar in
style to the artistic technique of stippling.
Another
technique used is anti-aliasing. This allows a an object or game
sprite to blend easily into the background or another object.
Depending on the overall look an artist is striving to achieve, anti-aliasing
may not be used at all. Often, anti-aliasing takes the form of
pre-rendered backgrounds and leads to painterly work which allows a
game sprite to stand out from the background and be easily seen by
the player.
Both
techniques can either be done by hand or with the help of tools
within a program like Adobe Photoshop. When saving pixel art in
either the GIF or PNG format (both of which are the best formats due
to the addition of JPEG artifacts often ruining pixel art quality),
Photoshop allows for color limiting options, dithering, and hard or
anti-aliased edges. The same goes for how an image is re-sized within
the program, allowing users to enlarge pixel art without losing its
hard edges.
What Does 8-bit Mean Anyway?
It's
terrible trendy for pixel art inspired designs to be called 8-bit
whether they are truly 8-bit or not. Within pixel art, 8-bit is in
reference to the color. An 8-bit console, like the Nintendo
Entertainment System, was able to display up to 256 colors . Each
color was based on a set of integers, 8 being the highest number of
integers that could be stored at the time by that machine. So the
color profile that was used held 3 bits (or bytes of data) of red, 3
bits of green, and 2 bits of blue, creating 256 colors that were
displayable. Additional limits were placed on video games depending
on how much information was stored and accessed on a game cartridge.
While a console could display a multitude of colors and animations,
limits set allowed the games to render quickly during game play and
process faster.
In
the early 1990's, consoles like Super Nintendo and Sega Genesis were
16-bit, upping the color display count to a whopping 65,536. This
allows for smoother gradients and more complex artwork to be created
and animated within video games. By the time consoles and computers
displayed 32-bit graphics (think Playstation One), 3-D rendered work
was already taking hold and artists rendering pixels were now
rendering polygons. Additionally,
game consoles were able to render said graphics at a higher speed
than their predecessors thanks to advances in technology over the
years.
What
is Isometric Pixel Art?
Let's
say you're playing a side-scrolling video game like Contra (well
known as an arcade game in the late 1980's and on the Famicon/NES
console). You'll notice that the artwork is in profile and no
vanishing point exists. There's no perspective going on at all in
games like this. The same goes for Super Mario games throughout the
80's and 90's. Additionally, games like The Legend of Zelda: A Link to the Past
showed a top-down view (showing the top or the top and one side),
where the player was able to peer into buildings from above. This
showed an added dimension to the graphics being displayed, as well as
characters within the game, but the overall look was still very flat
in comparison to 3-D rendered games produced later.
When
someone refers to pixel art being “isometric”, they're talking
about a type of parallel projection that takes on a 3/4-like view
more accurately referred to as “dimetric projection”. It's not
quite 3-D, but no longer as flat as the aforementioned perspective
styles seen in other pixel art. A well known example of isometric
perspective in gaming would be the 1982 classic “Q*Bert”. While
the character of Q*Bert himself is flat, the levels on which he hops
show the top and two sides of each box. Such a view made the played
move Q*Bert in a mostly diagonal fashion.
Creating
isometric or dimetric pixel art is far more complicated than a side
or top-down view. Often artists work on a grid in order to keep their
vertical, horizontal, and diagonal lines from straying into the wrong
perspective and their angles at the correct degree for the scene.
It's quite similar to working with perspective in technical drawing
and takes a fair bit of planning, measuring, and understanding of
shapes, space, and how they coordinate in order to form accurate
objects, sprites, and environments. Once 3-D graphics became more
prevalent, the isometric pixel art style gave way to perspective
projection, which is easier for an artist working within a 3-D space
to create, as it's the type of space we exist within as well as
what's most often taught and used within multiple disciplines of art.
What
About Non-gaming Uses of Pixel Art?
While
the most prevalent use of pixel art has been in video games, it's an
art form unto its own all the same. Pixel artists known as “dollers”
(as in, those who make dolls) use the style and techniques from 8-bit
and 16-bit video games in order to create base bodies, hair,
clothing, and environment for digital doll-like avatars.
Many
websites from the late 1990's into the mid-Millenium were filled with
animated GIFs, avatars, and layouts rendered entirely in pixel art.
This was most prevalent in South Korea where the popularity of
websites like iBravo and Sayclub had users purchasing components for
their profiles or to interact with other users. Additionally,
doll-makers were created from the artwork on websites like these (and
those like them worldwide) whereupon users would dress up base bodies
in pre-made clothing and accessories to display within their profiles
on websites like Myspace.
Emoticons
and kaoani (a Japanese term derived from “kao” meaning “face”,
and “ani” meaning “animated”) were all initially rendered in
a pixel format. In the case of both, they were often animated
allowing users on early social media, message boards, and within
instant messengers to display qualities such as mood, activities, or
various wordless communications. Animated buddy icons became
extremely popular for users of AOL Instant Messenger some fifteen
years ago.
Computer
icons throughout the 90's were pixel art pieces. Your mouse cursor,
unchanged for decades, is still a simple pixel art graphic.
Interestingly, most of these uses of pixel art have been replaced by
vector graphics (or the popularity of them has) within the past
decade. Doll-makers, website avatars, full website layouts, and more
are all vector graphics (presented as raster-images) likely due to
the need for multiple display sizes within each device (computer,
tablet, phone, etc).
Nostalgia
as an Art Form
Leaving
aside the practical uses of pixel art, artists nostalgic for the
style of work within video games from their younger years create
illustrations and pieces of design for art's sake. Some pieces are
enlarged, retaining the fidelity of each pixel edge, rendering the
piece mosaic-like, whereas other artwork is created on the
small-scale over a large picture plane rendering the work something
akin to “Where's Wally?” (Waldo for my fellow North Americans). In
either case (or any other creation based on the style), it's a part
of the growing movement to capture the past in the form of art. By
creating pieces of work reminiscent of media of the past, our
interaction with it is involved within sharing memories we've had
with similar styles within video games, internet browsers, and early
social media.
Alternatively,
artists may just really enjoy the look and feel of pixel art versus
having some higher agenda for engaging with the art form. In any
case, its popularity has been on the rise appearing in art galleries,
on clothing and other accessories, and right back in various gaming
platforms.
Care to dive into pixel art yourself? Why not check out these wonderfully relevant tutorials and take some pixels for a spin:
We play games to have fun. Most (but not all) games use some sort of competition to drive this fun: from chess to Street Fighter, players enjoy pitting their skills against each other.
A competitive game without real competition isn't fun. If I go up against a chess grand master, or a Street Fighter pro player, I will be obliterated. Short of my opponent being seized by temporary insanity, the likelihood of me winning is approximately zero. There's no competition; it's not fun for me.
So why isn't it fun for me to play against them? Because I know I'm going to lose. This burden of knowledge removes any enjoyment I can get from the game. Unfortunately, this "inevitable defeat" situation is common throughout gaming, even outside of skill mismatches. If we're playing Monopoly and I complete two streets (with hotels) while everyone else is squabbling over railroads, then my victory is virtually guaranteed—I can afford to sit back and wait for everyone else to slowly lose everything they have.
The main reason for my inevitable Monopoly victory is the snowball effect. Once I've gained some advantage, then that advantage continues to grow—like a snowball rolling down a mountain, picking up more snow, growing bigger and bigger. When players land on my properties, I gain more money (which I can use to buy more properties) and they lose money (giving them fewer options); it's a situation which can be very hard to recover from.
Similarly, in Risk, once you've safely captured a few continents, your extra troop income will make you you incredibly difficult to defeat.
When Do We Snowball?
Snowballing exists in nearly any game where resources give you more resources. Or, to put it in a simple form: wherever you can use money to buy stuff which gives you more money (or minerals, gold pieces, wood, or any in-game forms of currency).
In games like Monopoly or Civilisation, there’s an obvious correlation between acquisitions and power. You have cities; you have more money to build more cities. In most RTS games, you build workers to mine gold to build more workers to mine more gold. And Farmville uses snowballing as a central tenet of its design: you buy crops to make money to buy better crops to make more money to buy better crops...
Snowballing can be especially brutal in games like Quake or Unreal Tournament. When a player dies, they respawn with nothing, while the victor keeps their weapons, their armour, and any bonuses they picked up. In 1v1 matches, its fairly common to see an endgame score of 15-3, even for a "close" game.
Some games don't allow you to buy resources, but do allow you to remove enemy resources. In chess, you do this by "taking" enemy pieces—every pawn killed removes options for your enemy and reduces their overall board presence.
And some games have resources which are not relative to your position in the game. In Street Fighter or Pong, it generally doesn't matter how badly you're doing; as long as the game isn't over, you can pull it back. Because there is no feedback loop, these games don't really suffer from snowballing, so we won't discuss them further.
Why Do We Care?
So why do we even care about snowballing? Because for many games, it's simply not fun. As I said earlier, when the end result of a game has been established, the game stops being fun for the loser (and maybe even the winner).
If the inevitable losing player can concede with grace, then that's fine—but sometimes, conceding gracefully isn't possible. When you're playing a multiplayer game, then one player leaving can radically alter the game state. In turn-based games, the next player to go may be able to snatch up the absent player's resources, causing an unpredictable and massive power swing. Similarly, if a player leaves during a 5v5 game, then the resulting 4v5 may simply be too unbalanced, infuriating the former team-mates of the absent player.
A good game should be competitive throughout. The chess term endgame can be used to describe the final state of a game in which all that remains is to finalise the victory or defeat. An endgame state isn't harmful, as long as the players are able to finish up in a respectable amount of time.
An Important Caveat
So, we need to add a caveat: snowballing isn't necessarily bad, as long as the game ends once a victor becomes apparent. In other words: a game is no longer fun when a player becomes unable to influence the end result.
This point is vital, not just to "snowballing", but also to general game design. A player should always be able to win. If a player can't win, then the game is over, and forcing people to play out a defeat is punishing and unfun in a serious way.
Its worth noting, though, that snowballing isn't all bad. For the victor, it can feel great: attaining god-like status, crushing all those beneath you, and generally laying waste to everything in your path. And achieving "perfection" in a game is often a goal of players outside of simply winning. For single player games, this is fine: AIs don't get bored and rage-quit. When playing against humans, though, we need to be more discerning.
Snowballing in Competitive Play: A Look at the Data shows some interesting statistics regarding the percentage of winrates by objective in League of Legends. Note that a simple objective, such as achieving the first kill of the game (first blood), gives the team a 61 to 79% chance of winning the game overall.
So how do we deal with the problems that come with snowballing? Let's look at some possible fixes.
Fix: Resource Management
One option is to make resources "bad", so that the player wants to get rid of them. It might seem strange, but this is already present in games like billiards: having balls on the table is a bad thing. This is an excellent balancing mechanic, as the more balls you pot, the fewer options and shots you have available to you.
Counter-Strike had an interesting "gun game" mod, a variant of which also contained a self-balancing mechanic. Players start with one of the best weapons (often the sniper rifle), and killing other players would downgrade their weapon, to a rifle and then a pistol. After a certain number of kills, the player is left with just a knife—if they can score a kill with that, then they win.
Although using a reduction mechanic might feel counter-intuitive, there's no reason it can't be cleverly worked into a game. Imagine if, in Monopoly, the goal wasn't to become the richest, but to become the poorest; players would be assigned properties and houses at the start of the game, and through careful trading would have to get rid of all their acquisitions.
Fix: Punishment
Its also possible to add certain "winner-punishment" mechanics. Mario Kart has the infamous blue shell weapon, a turbo-powered missile that homes in on the player that's in the lead and stuns them upon collision. It's nearly impossible to avoid, and is incredibly damaging for a player to be hit by one. Because of this, many good players will deliberately avoid taking too much of a lead, so if a blue shell appears they can drop back to second place and let someone else take the hit.
At face value, this seems like an excellent system; it encourages players to stick together, which means that the game is a constant struggle, rather than one player taking an early lead and zooming off to victory. However, as many Mario Kart players will attest, blue shells feel unfair. There's very little you can do to predict the arrival of a blue shell, and, as we've talked about before, randomly punishing players often has a very negative effect on "fun".
On top of this, Mario Kart is a racing game, so it seems counter-intuitive to punish players for racing well. While “Gun Game” hinders any player that gains an advantage, Mario Kart is an unpredictable, specific punishment against a single player. If that player finds themselves on the receiving end of two or three blue shells, they may begin to feel victimised.
Of course, that's not to say that winner punishment mechanics are necessarily bad, but it's preferable to apply them with a light touch, rather than making them feel like targeted punishment. For example, some racing games will put previous race winners to the back of the starting line-up. This gives them a little further to race and prevents them from taking an easy lead, but generally won't feel like specifically singling that player out—after all, someone has to start at the back.
Now, it may seem obvious that players dislike being punished and like being rewarded. This isn't particularly noteworthy, but what makes it interesting is that we can sometimes change punishment into reward with simple rewording.
In early builds of World of Warcraft, there was an experience penalty for players who played too long. After a certain amount of time, players would find their experience progression halved, putting casual gamers on slightly more equal footing with players who could spend their whole day playing. Players, of course, hated it.
To fix this, the designers simply halved the normal experience progression rate, and gave players a "rest bonus": spending time out of game would net them double experience for a certain amount of time. Of course, this is exactly the same mechanic as before, but rather than it being a punishment for playing, it was a reward for not playing. And players loved it.
Simple renaming might not work for all cases, but its worth examining how players perceive these aspects of your game. If something is frustrating, then try to understand why players dislike it, and see if a minor change can make a difference.
Fix: Rubber Banding
Rubber banding means giving losing players a bonus or boost of some sort. Much like how a rubber band stretches and pulls, a rubber banding mechanic will pull players towards the current game leader. The further behind you are, the stronger the pull.
Rubber banding only really works in games when one player is clearly in the lead. In a strategic game like chess, simply counting the pieces on each side isn't enough to determine this: positioning and the ability to dictate the game matter immensely. But for most games, being able to determine a winner is often as simple as checking lives or gold.
Mario Kart famously uses a rubber banding system which gives players bonuses when they fall behind. Players at the end of the track can expect to pick up items like the Bullet Bill, which will often shoot them into third or fourth place with no effort required. Players leading the race can expect to find green shells and banana peels, which are considerably less advantageous. Additionally, CPU racers will automatically speed up when the player shoots ahead, and slow down when the player lags behind.
League of Legends uses a reward system that emulates rubber banding. Killing enemy players is worth gold—which then makes it easier to kill enemy players. To mitigate this, players that die constantly are worth less gold each time they die, which helps ensure that one bad player on a team does not completely determine the outcome of the match. At the same time, players that do exceptionally well, earning killing sprees, find their bounty increased, so when a player does manage to take them down, they may find they've earned nearly double the normal reward.
Implementing rubber banding depends on what you're aiming to achieve. For some games, basic rubber banding might feel cheap, and a more complicated method may be required. For casual games or minor game elements, a simple damage boost or resource bonus may be sufficient. Its important, however, that these bonus are used to help the player claw themselves back into the game, and not something the player can rely on for sudden victories.
Fix: Reset the Board
Points systems are another way to "reset" the playing field, and stop snowballing. Super Smash Bros has an interesting snowball mechanic: the more hits you take, the longer you are incapacitated for. A "smash" move on a healthy player might stun them for a fraction of a second, whereas "smashing" a seriously damaged player will stun them for much longer, giving their opponent time to collect items or line up a secondary attack. The result of this is that a damaged player will find it harder and harder to defend themselves, until they die.
Dying, though, completely resets your damage counter. Upon death, you are placed back on the field of battle (after losing a life) and—assuming you previously managed to get a few hits in—you now have the advantage as your opponent will still be damaged. When similarly matched players fight, they might end a game with a score of 5 to 4; without the damage reset, then a score of 5-0 would be much more likely.
Counter-Strike has a similar reset mechanic: rounds will last a set amount of time, and then be reset. This allows players to recover from expired weapons, low health, death, and poor positioning. Although a minor form of snowballing exists in the form of cash, an abundance of money does not automatically confer an advantage, as the best weapons are not necessarily the most expensive. A hard cap on the amount of money carried also helps to mitigate this.
Fix: Game Over
Of course, you can simply end the game early. If the game never enters a state where it becomes "unfair", then no issues will occur. In chess, the game ends when the enemy king is checkmated. You don't have to take every enemy piece, or achieve a certain amount of points: you simply move towards a single goal (checkmate), and you win.
The Civilisation series of games may be, at their core, a war game, but players are able to achieve victory through a variety of means. If you choose not to crush all your opponents, then winning the space race or convincing other players to elect you as their leader are valid options for technological or diplomatic victories.
Finally, it's worth noting that it's not always necessary to include balancing effects. Sometimes, you can just let a player concede. This is fairly easy for 1v1 games, and its common to see chess players concede once they find themselves in an unwinnable position. But for multiplayer games, it can be harder to let players exit gracefully. This is often one of the problems that team games face—MOBAs, such as League of Legends, are notorious for poor sportsmanship. While it's not fair to blame a game's design for poor player behaviour, when players face punishment for leaving games (such as temporary bans), it can exacerbate a problem which already exists.
Letting a player leave a game in progress can lead to further difficulties, though. If you keep them in the game, then how do you control them in a sensible way? If you remove them entirely, then can someone else come in and take the items or settlements they leave behind? You can replace them with an AI player, but will the AI act appropriately? You might be able to replace them with another player, but what if the original player comes back from a network disconnection? There is, sadly, no perfect way to deal with losing a player mid-game; there's only a "least bad" option, the nature of which will vary wildly with the type of game you're making.
Conclusion
Remember, people play games to have fun. No-one enjoys losing, and if you force someone to play an unwinnable game, then they'll end up frustrated and angry. If you end the game properly then while the player might not be happy about losing, they'll hopefully be more willing to play again.
Adding these solutions is not a magic bullet to make your game perfect, and poor implementation can cause problems of their own. When done well, players will be engaged by the constant challenge provided. When done poorly, players will feel cheated by others gaining sudden boosts, or an AI that cheats itself to victory. At the end of the day, snowball mitigation is another aspect of game design, and we need to consider how best to implement it.
As you may know, the third edition of the js13kGames competition is here: the official start is set for August 13th, 13:00 CEST. Js13kGames is a competition for HTML5 game developers where the fun and challenging part of the compo is keeping your entire game under 13KB.
This article should be a great starting point if you want to learn how to generate the assets, and minify and compress the code, so you can meet the requirements for the competition. I'll also provide you with tools that can help you in your day-to-day projects if you need to keep your resources light.
What Exactly is the js13kGames Competition?
The js13kGames competition is dedicated to the HTML5 game developers and JavaScript programmers who want to test their skills in battle with other developers, follow the rules, stick to the deadline, and win some prizes. The competition runs from August 13th till September 13th—you have the whole month to code and submit your entry. No external libraries or resources like Google Fonts are allowed, though; everything you want to use in your game must fit into 13 kilobytes of a ZIP package. The competition is free for all, but the source code has to be hosted on GitHub so that others can learn from it in the future.
The 13 kilobyte limit is very restrictive, but limitations often spawn creativity: you have to carefully think about how to implement your ideas, as every byte really counts.
Why Take Part?
The main purpose of the compo is fun. The deadline helps to keep it fun, because you have to end the project at some point and can't keep slaving away at it forever.
Taking part in the competition improves your skill, helps you manage your time spent on the project, and gives you the opportunity to cooperate with the community. Plus there's a chance you can win lots of interesting prizes, become well known, and eventually earn a bucket load of money being a game developer. What else do you need?
Tips and Tricks
Let's go through the specific tips and tricks you can use to minify your game's source code and all the assets used, from JavaScript minification, through cutting image sizes, to procedural level and audio generation.
General Tips
You have a whole month to code your game, so you don't have to spend sleepless nights through the weekend drinking coffee and energy drinks to compete with others. You can work at your own pace, whenever you have the time and whenever you feel like it.
Due to the tight restrictions on the size of the final package, it's almost impossible to use any framework. Of course, if you can prepare a small set of helper functions that will fit into the 13 kilobyte limit, you're more than welcome to do that.
The same goes with the images—screenshots of the games are often bigger than the games themselves, so you have to be smart. You'll probably generate everything on your own anyway, or use very small, compressed assets; that's the best way to fit the whole game into the size limit.
JavaScript Code Minification
The main core of your JavaScript game is the source code—you may be able to generate absolutely everything, without using any other resources like images or sounds, so optimizing this code is very important.
The easiest thing to do is to minify the code, which means it will be stripped of whitespace (tabs, spaces, newlines, and so on), without the code itself being changed.
You can take this further by using other tools that will modify your original source code to compress its size as much as possible, by using shorter variable names and other such tricks. As a side effect, these tools will also hide the source code and make it unreadable—called obfuscation. One of the main competition rules is that you have to have a readable version of your submission on GitHub anyway, so squeezing every byte by making the code in the zipped package unreadable is totally fine.
There won't be many image files in your game if you want to fit it into 13 kilobytes, but still, if you want to use an image you'll have to compress it as much as possible. There are online tools like TinyPNG and Optimizilla, installable applications like ImageOptim, command line tools, and build scripts to do that, so you'll be able to find something to fit your workflow.
You could also code your game in low resolution with small images and then scale everything up, or throw away all the images and generate everything on the canvas from scratch.
Procedural Level Generation
Given the limited space available, it would be wise to think about randomizing the levels in your game. The best way to keep the high replay value of your game is to generate your levels procedurally, so that instead of having one or two fixed levels, you can deliver a different experience each time the game is played.
The best examples in that category are roguelikes that use mazes and dungeons for their levels. You can generate a vast world from only a few small pieces, and it can be different every time you start the game. Thanks to this approach, your players won't get bored too quickly.
Adding audio to your game boosts the overall experience, but with songs typically weighing in at 5MB or more, how can you fit any into your js13k entry? Jsfxr to the rescue!
Instead of shrinking an MP3, you can generate your own music and sound
effects. Jsfxr is a JavaScript port of the sfxr library, and was
widely used by the participants of last year's competition, which means it's battle tested and gives great results.
Beside the tools already mentioned, you can help yourself by automating some of the tasks you have; build systems like Grunt or Gulp can make preparing all your assets much easier.
If you're a fan of Gulp, there's a whole variety of build tasks to pick from: Jack Rugile suggests a Gulp combo of gulp-uglify + gulp-htmlmin + gulp-zip + gulp-filesize while Csaba Csecskedi addsgulp-imagemin to this collection. You don't have to use it if you're not feeling comfortable with Gulp or just want to work the good old way, but this set can greatly improve your overall workflow for your js13kGames entry.
Boilerplate Code
The only structural requirement beside the size limit is that you must have the index.html file in the main directory of the package—everything else is optional. You can structure your code how you like, include folders for JavaScript, CSS and image files separately, or just put everything inside the HTML file and forget about everything else. You can do everything by hand, or use browserify, enhance your CSS using LESS or SASS, or even lint your code with ESLint. (That's what Florent Cailhol prepared in his experimental js13k boilerplate repository on GitHub.) Again: this could all help you, but none of it is required.
Choose the Right Type of Game
This might be obvious, but don't forget about carefully choosing a suitable type of game to fit in 13 kilobytes, because some of the games are harder to build (and to keep small) than others. I'm not saying you can't create a 3D first person shooter, real time strategy, city simulator, 3D racing game, traffic lights manager, or even jogging naked yellow block game like some crazy developers did in past years, but the vast majority of the entries are about simple games with one core mechanic that you wrap your game around, some generated images, and sometimes simple sound.
Remember that finishing anything is better than having a huge, unfinished project that people will never see. Follow the One Game a Month initiative, stick to the deadline and try to finish your entry in time. Keep it small in scope as well as size; if you're happy with the working prototype and have some free space available, you can always add new features to the game later on. Polish your project as much as possible and you'll be able to win the competition by building games like SpacePi or Radius Raid.
These are the basic tips and techniques that can help you code your game for the js13kGames competition—but you don't have to use them. There are many tools you can use in your game to keep it in the size limit; it depends on your preferences. If you don't have any experience, though, the best thing to do is to learn from others.
You can check the source code of the entries from the previousyears, play the games and see what's possible within the limit, dig through the blog posts explaining people's experiences, and read their source code and learn from it. Ask questions through social media, discuss your ideas and problems with others. That's the beauty of a competition—you're not alone; you can cooperate with others, form teams, and level up your skills in no time.
Summary
All the tools and services listed in this article should help you prepare for the js13kGames competition. It is important to not fix your attention on the tools alone; you should also look at what others are doing, learn from their experiences, and be part of the community.
If you have different ways to prepare yourself for the competition, please share them in the comments! Let's all benefit, learn and help each other. After all, the competition was started to be fun and entertaining, with a little bit of learning along the way.
Resources
Check out these additional resources for the competition:
Released after successfully finding funding on Kickstarter, Shovel Knight was one of the most highly anticipated indie games of the summer. The game showed promise because of its unique premise: it aimed to capture the feel of an NES-era classic on a modern device. The result is a level-based action platformer, complete with chiptune music and an authentic 8-bit art style.
Shovel Knight was highly praised upon release, with the developers at Yacht Club Games successfully managing to provoke a feeling of nostalgia in older gamers, while at the same time offering a new and compelling game even for those who never experienced the classics. Shovel Knight does a lot of things right in its design, and in this article we'll take a look at four important things we can learn from it.
A Cohesive Theme and Style Can Carry Your Game
Shovel Knight has an almost ridiculous adherence to its core theme of recreating the feel of a classic NES game. Everything about the experience, from the title screen's pixelated font to the entirely chiptune soundtrack, simply oozes retro. This isn't just an aesthetic thing, many game mechanics are borrowed directly from old NES games, and the level design is heavily inspired by the most popular platformers of the time. The game is so authentic that it really does feel like an old NES game that someone somehow forgot to release.
This thematic consistency is a core part of why Shovel Knight is such a great game. It's impossible not to be charmed by the game because it feels so well put together; every part of the experience feels like it's only there to further the goal of creating a game that is as retro as it can possibly be. Even though Shovel Knight isn't always perfect, the game as a whole feels inscrutable because of how consistent it is in its style, both from a gameplay and an aesthetic point of view.
Criticizing Shovel Knight can sometimes feel like complaining about the artistic direction of a painting in a gallery: you may not like it, but that's just because you don't understand what it's trying to say.
We can learn from this that a consistent style can really help a game feel well constructed, sometimes even causing players to ignore some of the game's shortcomings. When everything in a game feels like it's been deliberately made the way it is in pursuit of a clear artistic goal, it's easier for players to get immersed in the experience and enjoy themselves.
This obviously isn't limited to games emulating old systems; this sort of artistic immunity applies to any game committed to a particular theme or style. Having a clear artistic direction that drives every facet of your game's development can help make the end product feel cohesive and well constructed in a way that significantly benefits the overall experience.
Don't Be Afraid to Borrow From Others
Shovel Knight is fun to play—and I mean really fun to play. The moment to moment gameplay is consistently enjoyable, with tight controls, simple yet enjoyable combat, and sufficiently tricky platforming. This is because Shovel Knight plays like a greatest hits for action platformers: it's got boss design reminiscent of Mega Man, Scrooge McDuck's pogo attack from DuckTales, and items that wouldn't be out of place in any old-school Castlevania game.
Despite borrowing so much from other platformers, Shovel Knight never feels derivative, and instead feels like the natural evolution of the mechanics seen in the titles it takes from. This is because mainstream video game design has always been an iterative affair, with new titles in a genre often consisting of a few new ideas supported by a set of key mechanics that have worked in the past.
A great example of this is the convention that a player should only be able to hold two weapons in most first person shooters. It's a fun gameplay constraint that worked in a few popular games, and has thus been adopted by many imitators. As long as a game doesn't rely on this borrowed mechanic as its only form of entertainment, there's nothing wrong with doing what has been proven to work in the past.
Unfortunately, there is often a reticence towards this kind of iterative design among the indie community. Many developers feel the need for their games to be entirely unique, or at least present a new gameplay twist on an established genre. Shovel Knight shows us that this isn't necessary to be successful. Most of the time players don't particularly care where a game's ideas came from, or how original they are—they care about how the game actually plays.
As long as there is some uniqueness in the implementation, borrowing ideas and mechanics from other games can be a great tool when creating your own designs. As is evident in Shovel Knight, sometimes something as simple as combining ideas from a few separate games into one unified package can be enough to create something entirely new and engaging.
The level of challenge a game presents players with has always been an important consideration during video game development. Players come in all skill levels, and developers are tasked with fine-tuning their game's difficulty so that it will appeal to the maximum number of players possible in their target audience. This is usually very difficult to do, and so the practice of including multiple different difficulty levels has become the norm.
Shovel Knight eschews this tradition in favor of its own unique take on player challenge. The game doesn't have lives or a traditional game over system; instead, each level has a series of checkpoints that the player can respawn at infinitely. What makes the system interesting is that players are given the option to destroy checkpoints. Destroying a checkpoint is a gamble: it does gives the player some extra loot, but they then have to beat the rest of the level without the use of that particular respawn point.
Unfortunately, this system feels inconsequential in practice, since the rewards given for destroying checkpoints are rarely large enough to offset the amount of loot that will be lost by repeatedly dying. However, it's an interesting idea on a conceptual level, because it lets players govern the difficulty of the game on the fly. Unlike a simple difficulty level setting, players aren't locked into playing the entire game at a particular level of challenge. Those looking for a greater challenge can destroy checkpoints—and are even rewarded for doing so—but this commitment to a high level of difficulty is not permanent. It only lasts until the next checkpoint is found, at which point players are then given the choice again as to whether or not they want to play with the increased challenge.
This type of dynamic player-driven difficulty level isn't seen very often. Even though Shovel Knight stumbled a bit in its execution of the concept, it does show that this type of system could be worth pursuing. Allowing players to adjust the difficulty of a game with thematically relevant systems helps pacing by allowing them to experience the level of challenge they want at any given time, without the feeling of cheating one gets by changing a difficulty setting in the options menu.
Throughout Shovel Knight, players are able to acquire a significant arsenal of upgrades and items, as is par for the course in most adventure games. These range from typical upgrades like new suits of armor and special attacks, all the way to more esoteric items like a fishing rod and something called the chaos sphere. In theory, these items should add a lot of variety to the gameplay, giving players multiple tools to use in any given scenario, as well as allowing for scenarios tailored specifically to the use of a particular item.
Unfortunately, this doesn't quite pan out for Shovel Knight. Other than certain bonus levels that require the use of specific items, there is very little incentive for players to toy around with their arsenal during the game's primary stages. This is because these items vary wildly in effectiveness, with some being useful in almost every scenario and others bordering on uselessness. The key offenders are the chaos sphere, a highly damaging bouncing projectile, and the phase locket, an item that grants the player temporary invulnerability.
If abused, these two items can be used to trivialize most of the content in the game. When coupled with the armor that increases a player's maximum amount of item uses, the phase locket can be used to avoid almost all damage in any level and the chaos sphere can defeat several of the game's bosses in a matter of seconds. Players don't need to use this combination of items, and many surely won't, so the game isn't entirely ruined, but it raises the question of why cheating through the game is even possible.
Many single player games focus on empowering the player as much as possible, without really considering balance in the same way multiplayer games do. However, through Shovel Knight's example, we can see that this isn't always the right way of thinking. Unless it's something you explicitly want, it's always a good idea to go through your game's systems and make sure there aren't any options available to the player that allow them to trivialize the content you've created.
Likewise, it's also important to make sure there aren't any obviously useless inclusions. If you want your game to allow multiple gameplay approaches, make sure they are as equivalent in their effectiveness as possible. Overpowered or underpowered items can be balanced by patches in multiplayer games, but this type of consideration is often not present in development for single player experiences. Just because there isn't a vocal multiplayer community to complain about a single player game's balance, doesn't mean it isn't an aspect of the design that can seriously harm players' enjoyment of a title.
Conclusion
Shovel Knight does a lot of things right, even though it does stumble occasionally. Though it might, at face value, appear simply to be an oddity that aims to replicate the old days of the NES, there's actually a lot of modern considerations baked into its design. This isn't evident on the surface, but if you take a closer look at why the game succeeded there's a lot to be learned from it.
Turning a critical eye on a successful product can often be an enriching experiment, and I guess that's one last lesson we can learn from Shovel Knight.
This tutorial is the final part in the process of coding a hockey game using steering behaviors and finite state machines. Here, we will improve our athletes' artificial intelligence to allow them to defend their goal against their opponents. We'll also make our athletes perform some attack tactics while they are defending, so they can recover the puck and terminate the opponent's offensive.
A Few Words About Defending
In a competitive game like hockey, the defense process is much more than just rushing to the team's goal area to prevent the opponent from scoring. Prevent the opponent from scoring is just one of the many tasks involved.
If a team focuses on score prevention tactics alone, all athletes will become merely obstacles along the way. The opponent will keep pushing, trying to find a spot in the defense formation. It will take time, but eventually the opponent will score.
The defense process is a mixture of defensive and offensive actions. The best way to terminate the opponent's attack, which is the defense objective, is to attack while defending. It might sound a bit confusing, but it makes perfect sense.
An athlete defending his team should move towards his goal, preventing the opponent from scoring. Along the way, he must try to steal the puck from the opponent who is carrying it, or intercept the puck when it is exchanged among the opponents. That's exactly what this tutorial will try to implement: a defensive tactic with attack actions.
Combining Attack and Defense
In order to achieve a defensive behavior that has some attack aspects in it, we'll add two new states to the AI finite-state machine:
The defend state will be the foundational stone in the defense process. While in that state, athletes will move towards their side of the rink, always trying to recover the puck to terminate the opponent's offensive.
The patrol state will complement the defense process. It will prevent athletes from standing still when they reach their defense position in the rink. This state will keep athletes moving and patrolling the area, which will produce a more convincing result.
Understanding the Defend State
The defend state is based on a very simple idea. When it is active, each athlete will move towards their initial position in the rink. We already used this position, described by the mInitialPosition property in the Athlete class, to implement the prepareForMatch state in the first tutorial in this series.
While moving towards his initial position, an athlete will try to perform some attack actions against the opponent if he is close enough and is carrying the puck. For instance, if the athlete is moving and the opponent's leader (the one with the puck) becomes a neighbor, the defend state will be replaced with something more appropriate, such as the stealPuck state.
Since athletes tend to be spread through the whole rink while attacking, when they switch to defend and start returning to their initial position, they will cover a significant area, ensuring a convincing defense pattern:
Some athletes will not encounter opponents along the way, so they will just move towards their initial position. Other athletes, however, might get close to some interesting opponents, such as the leader (the one carrying the puck).
Implementing the Defend State
The defend state will have four transitions:
Three of them, team has the puck, close to opponent leader, and puck has no owner, are related to attack actions. They will be responsible for making athletes look like they are attacking opponents while moving to defend the team's goal. The in position transition will be triggered when the athlete finally arrives at his initial position in the rink.
The first step in implementing the defend state is to make the athlete move towards his initial position. Since he must slow down as he gets closer to the destination, the arrive steering behavior is a perfect fit:
class Athlete {
// (...)
private function defend() :void {
var aPuckOwner :Athlete = getPuckOwner();
// Move towards the initial position, arriving there smoothly.
mBoid.steering = mBoid.steering + mBoid.arrive(mInitialPosition);
// Does the puck has an owner?
if (aPuckOwner != null) {
// Yeah, it has. Who has it?
if (doesMyTeamHasThePuck()) {
// My team has the puck, time to stop defending and start attacking!
mBrain.popState();
mBrain.pushState(attack);
} else if (Utils.distance(aPuckOwner, this) < 150) {
// An opponent has the puck and he is close to us!
// Let's try to steal the puck from him.
mBrain.popState();
mBrain.pushState(stealPuck);
}
} else {
// No, the puck has no owner, it is running in the rink.
// There is no point to keep defending the goal, because nobody has the puck.
// Let's switch to 'pursuePuck' and try to get the puck to our team.
mBrain.popState();
mBrain.pushState(pursuePuck);
}
}
// (...)
}
The arrive behavior will create a force that will push the athlete towards his initial position (mInitialPosition) while the defend state is active. After the arrive force calculation, in this code, we run a sequence of tests that will check the puck's ownership and the proximity of opponents, popping the defend state from the brain and pushing a new one according to the situation.
If the puck has no owner, it is probably moving freely in the rink. In that case, the pursuePuck state will be pushed into the brain (line 29). If the puck has a team owner, it means the defense process is over and it is time to attack (line 16). Finally if the puck's owner belongs to the opponent team and he is close enough, stealPuck will be pushed into the brain (line 22).
The result is a team that is able to defend their goal, pursuing and trying to steal the puck from the opponent carrying it. Below is a demonstration of the current defend implementation:
Patrolling the Area
The current defense behavior is acceptable, but it can be tweaked a little bit to be more convincing. If you analyse the previous demo, you may eventually notice that athletes will stop and stand still after they reach their initial position while defending.
If an athlete returns to his initial position without encountering any opponents along the way, he will remain still until an opponent with the puck passes by or the team recovers the puck.
We can improve this behavior by adding a patrol state, which gets pushed into the brain by the defend state when the athlete reaches his initial position:
The patrol state is extremely simple. When active, it will make athletes move around randomly for a short time, which visually mimics the expected behavior from an athlete trying to defend a spot in the rink.
When the distance between the athlete and his initial position is grater than 10, for instance, patrol pops itself from the brain and pushes defend. If the athlete arrives at his initial position again while defending, patrol is pushed once more into the brain and the process repeats:
The random movement pattern required by the patrol state can be easily achieved with the wander steering behavior. The implementation of the patrol state is:
class Athlete {
// (...)
private function patrol() :void {
mBoid.steering = mBoid.steering + mBoid.wander();
// Am I too far away from my initial position?
if (Utils.distance(mInitialPosition, this) > 10) {
// Yeah, I am. It's time to stop patrolling and go back to
// my initial position.
mBrain.popState();
mBrain.pushState(defend);
}
}
// (...)
}
The distance check (line 8) ensures that the athlete will patrol a small area around his initial position instead of leaving his initial defense position completely unattended.
The results of using the patrol state is a more convincing behavior:
Putting It All Together
During the implementation of the stealPuck state in the previous tutorial, there was a situation where athletes should switch to the defend state. However that state was not implemented back then.
While trying to steal the puck (the stealPuck state), if the opponent is too far away from the athlete, it's pointless to keep trying to steal the puck. The best option in that situation is to pop the stealPuck state and push defend, hoping that a teammate will be closer to the opponent's leader to steal the puck.
The stealPuck state must be changed (lines 28 and 29) to allow athletes to push the defend state in that situation:
class Athlete {
// (...)
private function stealPuck() :void {
// Does the puck has any owner?
if (getPuckOwner() != null) {
// Yeah, it has, but who has it?
if (doesMyTeamHasThePuck()) {
// My team has the puck, so it's time to stop trying to steal
// the puck and start attacking.
mBrain.popState();
mBrain.pushState(attack);
} else {
// An opponent has the puck.
var aOpponentLeader :Athlete = getPuckOwner();
// Is the opponent with the puck close to me?
if (Utils.distance(aOpponentLeader, this) < 150) {
// Yeah, he is close! Let's pursue him while mantaining a certain
// separation from the others to avoid that everybody will ocuppy the same
// position in the pursuit.
mBoid.steering = mBoid.steering + mBoid.pursuit(aOpponentLeader.boid);
mBoid.steering = mBoid.steering + mBoid.separation(50);
} else {
// No, he is too far away. Let's switch to 'defend' and hope
// someone closer to the puck can steal it for us.
mBrain.popState();
mBrain.pushState(defend);
}
}
} else {
// The puck has no owner, it is probably running freely in the rink.
// There is no point to keep trying to steal it, so let's finish the 'stealPuck' state
// and switch to 'pursuePuck'.
mBrain.popState();
mBrain.pushState(pursuePuck);
}
}
// (...)
}
After updating the stealPuck state, athletes are now able to organize attack and defense tactics, making two AI-controlled teams able to play against each other.
The result is demonstrated below:
Conclusion
In this tutorial, we implemented a defense tactic used by athletes to defend their goal from opponents. We then improved the defend state by adding some attack actions, such as to attempt to steal the opponent's puck, which made the defense tactic feel more natural and convincing.
We also improved the feel of the defense behavior by adding an extremely simple, yet powerful state, the patrol. The idea is to prevent athletes from standing still while defending their team's goal.
And with that, we've created a full AI system for our hockey game!
Community is vital. We're social creatures, and this is especially true for the increasingly common work-from-home remote gamedevs and the lone wolf indie developers. Internet communities are great, but the chance to physically mingle with others and share your experiences is key to staying motivated and staying sane.
Unfortunately, there may not be an existing game development group in your area—but fear not! In this article, I'll give you some pointers on starting your own local game developer community.
Why Build a Community?
Building a community can take some work, but is it worth the effort? The short answer is yes: the many benefits to having a local community vastly outweigh the effort it takes to start one. Not convinced? Here's a quick look at what having a local game community can bring:
presentations by game professionals
social gatherings
networking opportunities with other developers
game jams
mentoring opportunities
potential collaborators for projects
employment opportunities
knowledge about relevant local companies
feedback on your games
a look at what other gamedevs are making
local microbrewery beer samples
new friends
good fun!
and much more...
As you can see, a local community can provide many benefits as it grows and develops. It's also worth noting that each local community has its own unique character that can distinguish itself from its peers and attract new people to it. People will often move to cities because that city has a community with a good reputation.
Start With the Basics
What's in a Name?
Once you've decided to start your own group, the first thing to do is come up with a snazzy name for yourselves.
This should be something simple that describes what your group is about, but is still interesting enough to get people's attention. When creating our group, we chose LevelUp Victoria because of its connection to games (the idea of levelling up or getting to the next level in a game) and our geographic region: Victoria, British Columbia, Canada. (Not to mention the geeky use of camel-casing.) It's fairly playful, which reflects the character of our group, but you should feel free to choose something that fits your group a bit closer. Something like Victoria Game Developer League or Game Creators of Vancouver Island might work if we were starting up a new group now.
Bonus points if you can come up with a clever acronym—Vancouver Island Game Oriented Rascals (VIGOR), anyone? Okay, maybe it's not that clever...
The Internet is Your Friend
Once you have a name, you should set up some manner of Internet presence for your group. This a really easy way to provide both a place for your members to congregate online and a spot for potential members to find out more about you. (Confession: I have no idea how people managed to organize groups before the internet. I suspect sorcery.)
I recommend using free services as much as possible in the beginning. Social media such as Facebook and Google+ allow for a simple web presence for free. Beware of Facebook Pages, however: they're structured more for commercial businesses; you'd be better served to go with a Facebook group instead.
My group began by using as many social media outlets as possible (no doubt due to my own masochism), but is now scaling back to the ones that are most used by our members. We also use a few paid services, but we'll discuss those more in the Growing Your Group section below.
Firsties!
Now that you have the basic structure for your group set up, you'll want to think about recruiting some members. Hopefully, you know a few like-minded folks who would be happy to join up. If not, don't despair; there may be a few out there that you're not aware of yet. It's time to schedule a meeting to get them to come out of the woodwork.
Avengers Assemble!
Game folk tend to be a bit geeky, and that often means that they can be a bit introverted. But if you provide them with an event that piques their interest, in this case a meeting of game developers, they will happily leave their homes to satisfy their curiosity.
Extra! Extra! Read All About It!
Through your web presence, and by whatever other means you can devise, announce a regular monthly meet-up.
It should be at the same time and place each month, and it should be casual and relaxed. If possible, set up an event through your web channels and get folks to RSVP so that you know roughly how many people to expect. Share this via any related groups that may be in your area: programming groups, artist groups, and so on.
Don't forget to give the meeting a name that gets folks' attention. We call our monthly meeting the Main Event, and it's only occasionally mistaken for a wrestling match.
Look, Robin! The Bat Signal!
You may want to consider placing a small stand-up sign on your table with your group name or logo on it. This will assist new members in discovering you, including those who haven't heard of your group before. Wearing game-themed T-shirts also doesn't hurt, as we can often recognize our own kind by these secret signs and symbols (such as the Triforce).
Location, Location, Location
Choosing the right place to hold a meeting can make a big difference. I recommend a public place with enough room to accommodate a half-dozen people, to start with.
Cafes and pubs seem to work well for these type of meet-ups. There's food and beverages available to those who want them, they're usually not too loud, and there's often free Wi-Fi. Be sure to pick a location that is not too busy so that you can hold on to a table or two without keeping them from other patrons. Also, keep local liquor laws in mind, if you're considering meeting at a pub and you wish to keep your group open to all ages.
Looking For Group?
You may not get anyone new coming out for the first few meetings. This is normal, so don't beat yourself up about it. This could happen for any number of reasons: it may take time for word to get around about your group, potential members may want to come but are tied up with other commitments or need to overcome social nervousness, or any number of other things that you can't predict.
The founders of my group had to wait a few months before someone new showed up to a meeting, but now we've grown to over 350 members strong.
Where to Go From Here
Okay, let's say you start getting some new people showing up regularly for your meetings and you're thinking about taking the next step. The problem is, you don't know what that next step is. Luckily for you, I do.
Levelling up
Casual meetings are a great place to start, but once you start growing you may wish to hold meetings with a bit more structure to them, including such things as group announcements, presentations, and show and tell sessions. This will require a more private location than the common area of a cafe or pub. If the place you're currently meeting happens to have a private room that you can use, you may be in luck. If not, you'll need to track down a suitable location.
Here are some of the things you may need—keep these in mind:
space enough for your current members, plus some room for growth.
a large-screen TV or projector screen (plus projector) that you can use for presentations.
a central location, close to downtown or bus routes.
food and beverage service (optional).
LevelUp - IGDA Victoria uses a private room at a pub in downtown Victoria with a projector screen in the room, but with us providing our own projector. Because we meet on the first Monday of the month, which happens to be a slow night for the business, they've waived the regular cost for the space for our group. They provide regular food and beverage service for us, and most of our members will buy at least one beverage, so the situation works out to everyone's benefit. I highly recommend trying to find a similar arrangement.
You may also wish to consider using a community halls or similar space. Some may require a payment for use, but others can be hired for free by non-profit groups and organizations. Don't be afraid to approach the administrators and ask about options. It never hurts to ask.
The Beginning of a Beautiful Friendship
If you can't find free digs for your meetings, or if you have other plans that require funds (such as running events like game jams and parties), it may be time to look at finding ways to offset those costs.
One way to do this is through partnerships with game companies and other related organizations. If there are game companies in the area that are successful enough to have budgets for public relations and marketing, they may be willing to become sponsors for your group. Generally, these tend to be win-win situations: the company gets some good PR for sponsoring the local community, and your group gets the means to grow and do more fun and interesting activities. Another bonus is that your new partners may share some good ideas about which directions your group could take, and what kinds of events might work well for your members.
I'd be remiss if I didn't mention partnering up with the International Game Developers Association (IGDA) as an option. Our group was invited to become the official IGDA chapter for Victoria, BC shortly after we became established, hence our current name of LevelUp - IGDA Victoria. The IGDA is an excellent resource for game development knowledge of all flavours, and, more importantly, is a great way to get in touch with other chapter organizers to discuss best practices for running a game development group.
Go Forth and Prosper
Hopefully, I've given you enough information to get a start on building a healthy and happy community of game creators in your neck of the woods. It can take a bit of work to get going, but once things are set in motion you may be surprised at how well your community runs with just a minimum of effort.
Below is a list of links to my group and others so that you can see how things are done in other communities. Good luck and get building!
As you may know, the third edition of the js13kGames competition is here: the official start is set for August 13th, 13:00 CEST. Js13kGames is a competition for HTML5 game developers where the fun and challenging part of the compo is keeping your entire game under 13KB.
This article should be a great starting point if you want to learn how to generate the assets, and minify and compress the code, so you can meet the requirements for the competition. I'll also provide you with tools that can help you in your day-to-day projects if you need to keep your resources light.
What Exactly is the js13kGames Competition?
The js13kGames competition is dedicated to the HTML5 game developers and JavaScript programmers who want to test their skills in battle with other developers, follow the rules, stick to the deadline, and win some prizes. The competition runs from August 13th till September 13th—you have the whole month to code and submit your entry. No external libraries or resources like Google Fonts are allowed, though; everything you want to use in your game must fit into 13 kilobytes of a ZIP package. The competition is free for all, but the source code has to be hosted on GitHub so that others can learn from it in the future.
The 13 kilobyte limit is very restrictive, but limitations often spawn creativity: you have to carefully think about how to implement your ideas, as every byte really counts.
Why Take Part?
The main purpose of the compo is fun. The deadline helps to keep it fun, because you have to end the project at some point and can't keep slaving away at it forever.
Taking part in the competition improves your skill, helps you manage your time spent on the project, and gives you the opportunity to cooperate with the community. Plus there's a chance you can win lots of interesting prizes, become well known, and eventually earn a bucket load of money being a game developer. What else do you need?
Tips and Tricks
Let's go through the specific tips and tricks you can use to minify your game's source code and all the assets used, from JavaScript minification, through cutting image sizes, to procedural level and audio generation.
General Tips
You have a whole month to code your game, so you don't have to spend sleepless nights through the weekend drinking coffee and energy drinks to compete with others. You can work at your own pace, whenever you have the time and whenever you feel like it.
Due to the tight restrictions on the size of the final package, it's almost impossible to use any framework. Of course, if you can prepare a small set of helper functions that will fit into the 13 kilobyte limit, you're more than welcome to do that.
The same goes with the images—screenshots of the games are often bigger than the games themselves, so you have to be smart. You'll probably generate everything on your own anyway, or use very small, compressed assets; that's the best way to fit the whole game into the size limit.
JavaScript Code Minification
The main core of your JavaScript game is the source code—you may be able to generate absolutely everything, without using any other resources like images or sounds, so optimizing this code is very important.
The easiest thing to do is to minify the code, which means it will be stripped of whitespace (tabs, spaces, newlines, and so on), without the code itself being changed.
You can take this further by using other tools that will modify your original source code to compress its size as much as possible, by using shorter variable names and other such tricks. As a side effect, these tools will also hide the source code and make it unreadable—called obfuscation. One of the main competition rules is that you have to have a readable version of your submission on GitHub anyway, so squeezing every byte by making the code in the zipped package unreadable is totally fine.
There won't be many image files in your game if you want to fit it into 13 kilobytes, but still, if you want to use an image you'll have to compress it as much as possible. There are online tools like TinyPNG and Optimizilla, installable applications like ImageOptim, command line tools, and build scripts to do that, so you'll be able to find something to fit your workflow.
You could also code your game in low resolution with small images and then scale everything up, or throw away all the images and generate everything on the canvas from scratch.
Procedural Level Generation
Given the limited space available, it would be wise to think about randomizing the levels in your game. The best way to keep the high replay value of your game is to generate your levels procedurally, so that instead of having one or two fixed levels, you can deliver a different experience each time the game is played.
The best examples in that category are roguelikes that use mazes and dungeons for their levels. You can generate a vast world from only a few small pieces, and it can be different every time you start the game. Thanks to this approach, your players won't get bored too quickly.
Adding audio to your game boosts the overall experience, but with songs typically weighing in at 5MB or more, how can you fit any into your js13k entry? Jsfxr to the rescue!
Instead of shrinking an MP3, you can generate your own music and sound
effects. Jsfxr is a JavaScript port of the sfxr library, and was
widely used by the participants of last year's competition, which means it's battle tested and gives great results.
Beside the tools already mentioned, you can help yourself by automating some of the tasks you have; build systems like Grunt or Gulp can make preparing all your assets much easier.
If you're a fan of Gulp, there's a whole variety of build tasks to pick from: Jack Rugile suggests a Gulp combo of gulp-uglify + gulp-htmlmin + gulp-zip + gulp-filesize while Csaba Csecskedi addsgulp-imagemin to this collection. You don't have to use it if you're not feeling comfortable with Gulp or just want to work the good old way, but this set can greatly improve your overall workflow for your js13kGames entry.
Boilerplate Code
The only structural requirement beside the size limit is that you must have the index.html file in the main directory of the package—everything else is optional. You can structure your code how you like, include folders for JavaScript, CSS and image files separately, or just put everything inside the HTML file and forget about everything else. You can do everything by hand, or use browserify, enhance your CSS using LESS or SASS, or even lint your code with ESLint. (That's what Florent Cailhol prepared in his experimental js13k boilerplate repository on GitHub.) Again: this could all help you, but none of it is required.
Choose the Right Type of Game
This might be obvious, but don't forget about carefully choosing a suitable type of game to fit in 13 kilobytes, because some of the games are harder to build (and to keep small) than others. I'm not saying you can't create a 3D first person shooter, real time strategy, city simulator, 3D racing game, traffic lights manager, or even jogging naked yellow block game like some crazy developers did in past years, but the vast majority of the entries are about simple games with one core mechanic that you wrap your game around, some generated images, and sometimes simple sound.
Remember that finishing anything is better than having a huge, unfinished project that people will never see. Follow the One Game a Month initiative, stick to the deadline and try to finish your entry in time. Keep it small in scope as well as size; if you're happy with the working prototype and have some free space available, you can always add new features to the game later on. Polish your project as much as possible and you'll be able to win the competition by building games like SpacePi or Radius Raid.
These are the basic tips and techniques that can help you code your game for the js13kGames competition—but you don't have to use them. There are many tools you can use in your game to keep it in the size limit; it depends on your preferences. If you don't have any experience, though, the best thing to do is to learn from others.
You can check the source code of the entries from the previousyears, play the games and see what's possible within the limit, dig through the blog posts explaining people's experiences, and read their source code and learn from it. Ask questions through social media, discuss your ideas and problems with others. That's the beauty of a competition—you're not alone; you can cooperate with others, form teams, and level up your skills in no time.
Summary
All the tools and services listed in this article should help you prepare for the js13kGames competition. It is important to not fix your attention on the tools alone; you should also look at what others are doing, learn from their experiences, and be part of the community.
If you have different ways to prepare yourself for the competition, please share them in the comments! Let's all benefit, learn and help each other. After all, the competition was started to be fun and entertaining, with a little bit of learning along the way.
Resources
Check out these additional resources for the competition: