In this article, we will cover the basics of creating immersive areas where players can walk around and interact, as well as some of the techniques used to manage those areas.
This article will give you some practical tips and tricks of the spritesheet system introduced with Unity 4.3 and how to get it to work for you.
Lastly, we will also have a cursory look at how shaders work in the 2D world and the considerations you need to keep in mind when using them. However, we won't be implementing shaders as that could be another book in itself.
The following is the list of topics that will be covered in this article:
(For more resources related to this topic, see here.)
Now that we have our hero in play, it would be nice to give him a place to live and walk around, so let's set up the home town and decorate it.
Firstly, we are going to need some more assets. So, from the asset pack you downloaded earlier, grab the following assets from the Environments pack, place them in the AssetsSpritesEnvironment folder, and name them as follows:
It is always better to pack many of the same images on to a single asset/atlas and then use the Sprite Editor to define the regions on that texture for each sprite, as long as all the sprites on that sheet are going to get used in the same scene. The reason for this is when Unity tries to draw to the screen, it needs to send the images to draw to the graphics card; if there are many images to send, this can take some time. If, however, it is just one image, it is a lot simpler and more performant with only one file to send.
There needs to be a balance; too large an image and the upload to the graphics card can take up too many resources, too many individual images and you have the same problem.
The basic rule of thumb is as follows:
You basically want to keep as much stuff together as makes sense and not send unnecessary images that won't get used to the graphics card. Find your balance.
First, let's add a background for the town using the AssetsSpritesEnvironmentbackground01 texture. It is shown in the following screenshot:
With the background asset, we don't need to do anything else other than ensure that it has been imported as a sprite (in case your project is still in 3D mode), as shown in the following screenshot:
For the steampunk environmental assets (AssetsSpritesEnvironmentenvironmentalAssets) that are shown in the following screenshot, we need a bit more work; once these assets are imported, change the Sprite Mode to Multiple and load up the Sprite Editor using the Sprite Editor button.
Next, click on the Slice button, leave the settings at their default options, and then click on the Slice button in the new window as shown in the following screenshot:
Click on Apply and close the Sprite Editor. You will have four new sprite textures available as seen in the following screenshot:
We saw what happens when you use a grid type split on a spritesheet and when the automatic split works well, so what about when it doesn't go so well? If we look at the Fantasy environment pack (AssetsSpritesEnvironmentenvironmentalAssets2), we will see the following:
After you have imported it and run the Split in Sprite Editor, you will notice that one of the sprites does not get detected very well; altering the automatic split settings in this case doesn't help, so we need to do some manual manipulation as shown in the following screenshot:
In the previous screenshot, you can see that just two of the rocks in the top-right sprite have been identified by the splicing routine. To fix this, just delete one of the selections and then expand the other manually using the selection points in the corner of the selection box (after clicking on the sprite box). Here's how it will look before the correction:
After correction, you should see something like the following screenshot:
This gives us some nice additional assets to scatter around our towns and give it a more homely feel, as shown in the following screenshot:
So, now that we have some nice assets to build with, we can start building our first town.
Returning to the scene view, you should see the following:
If, however, we add our town background texture (AssetsSpritesBackgroundsBackground.png) to the scene by dragging it to either the project hierarchy or the scene view, you will end up with the following:
Be sure to set the background texture position appropriately once you add it to the scene; in this case, be sure the position of the transform is centered in the view at X = 0, Y = 0, Z = 0.
Unity does have a tendency to set the position relative to where your 3D view is at the time of adding it—almost never where you want it.
Our player has vanished!
The reason for this is simple: Unity's sprite system has an ordering system that comes in two parts.
Sorting Layers (Edit | Project Settings | Tags and Layers) are a collection of sprites, which are bulked together to form a single group. Layers can be configured to be drawn in a specific order on the screen as shown in the following screenshot:
Sprites within an individual layer can be sorted, allowing you to control the draw order of sprites within that layer. The sprite Inspector is used for this purpose, as shown in the following screenshot:
Sprite's Sorting Layers should not be confused with Unity's rendering layers. Layers are a separate functionality used to control whether groups of game objects are drawn or managed together, whereas Sorting Layers control the draw order of sprites in a scene.
So the reason our player is no longer seen is that it is behind the background. As they are both in the same layer and have the same sort order, they are simply drawn in the order that they are in the project hierarchy.
To resolve the update of the scene's Sorting Layers, let's organize our sprite rendering by adding some sprite Sorting Layers. So, open up the Tags and Layers inspector pane as shown in the following screenshot (by navigating to Edit | Project settings | Tags and Layers), and add the following Sorting Layers:
You can reorder the layers underneath the default anytime by selecting a row and dragging it up and down the sprite's Sorting Layers list.
With the layers set up, we can now configure our game objects accordingly. So, set the Sorting Layer on our background01 sprite to the Background layer as shown in the following screenshot:
Then, update the PlayerSprite layer to Player; our character will now be displayed in front of the background.
You can just keep both objects on the same layer and set the Sort Order value appropriately, keeping the background to a Sort Order value of 0 and the player to 10, which will draw the player in front. However, as you add more items to the scene, things will get tricky quickly, so it is better to group them in a layer accordingly.
Now when we return to the scene, our hero is happily displayed but he is seen hovering in the middle of our village. So let's fix that next by simply changing its position transform in the Inspector window.
Setting the Y position transform to -2 will place our hero nicely in the middle of the street (provided you have set the pivot for the player sprite to bottom), as shown in the following screenshot:
Feel free at this point to also add some more background elements such as trees and buildings to fill out the scene using the environment assets we imported earlier.
If you try and move the player left and right at the moment, our hero happily bobs along. However, you will quickly notice that we run into a problem: the hero soon disappears from the edge of the screen. To solve this, we need to make the camera follow the hero.
When creating new scripts to implement something, remember that just about every game that has been made with Unity has most likely implemented either the same thing or something similar. Most just get on with it, but others and the Unity team themselves are keen to share their scripts to solve these challenges. So in most cases, we will have something to work from. Don't just start a script from scratch (unless it is a very small one to solve a tiny issue) if you can help it; here's some resources to get you started:
Unity sample projects: http://Unity3d.com/learn/tutorials/projects
Unity Patterns: http://unitypatterns.com/
Unity wiki scripts section: http://wiki.Unity3d.com/index.php/Scripts (also check other stuff for detail)
Once you become more experienced, it is better to just use these scripts as a reference and try to create your own and improve on them, unless they are from a maintained library such as https://github.com/nickgravelyn/UnityToolbag.
To make the camera follow the players, we'll take the script from the Unity 2D sample and modify it to fit in our game. This script is nice because it also includes a Mario style buffer zone, which allows the players to move without moving the camera until they reach the edge of the screen.
Create a new script called FollowCamera in the AssetsScripts folder, remove the Start and Update functions, and then add the following properties:
using UnityEngine;
public class FollowCamera : MonoBehavior {
// Distance in the x axis the player can move before the
// camera follows.
public float xMargin = 1.5f;
// Distance in the y axis the player can move before the
// camera follows.
public float yMargin = 1.5f;
// How smoothly the camera catches up with its target
// movement in the x axis.
public float xSmooth = 1.5f;
// How smoothly the camera catches up with its target
// movement in the y axis.
public float ySmooth = 1.5f;
// The maximum x and y coordinates the camera can have.
public Vector2 maxXAndY;
// The minimum x and y coordinates the camera can have.
public Vector2 minXAndY;
// Reference to the player's transform.
public Transform player;
}
The variables are all commented to explain their purpose, but we'll cover each as we use them.
First off, we need to get the player object's position so that we can track the camera to it by discovering it from the object it is attached to. This is done by adding the following code in the Awake function:
void Awake()
{
// Setting up the reference.
player = GameObject.Find("Player").transform;
if (player == null)
{
Debug.LogError("Player object not found");
}
}
An alternative to discovering the player this way is to make the player property public and then assign it in the editor. There is no right or wrong way—just your preference.
It is also a good practice to add some element of debugging to let you know if there is a problem in the scene with a missing reference, else all you will see are errors such as object not initialized or variable was null.
Next, we need a couple of helper methods to check whether the player has moved near the edge of the camera's bounds as defined by the Max X and Y variables. In the following code, we will use the settings defined in the preceding code to control how close you can get to the end result:
bool CheckXMargin()
{
// Returns true if the distance between the camera and the
// player in the x axis is greater than the x margin.
return Mathf.Abs
(transform.position.x - player.position.x) > xMargin;
}
bool CheckYMargin()
{
// Returns true if the distance between the camera and the
// player in the y axis is greater than the y margin.
return Mathf.Abs
(transform.position.y - player.position.y) > yMargin;
}
To finish this script, we need to check each frame when the scene is drawn to see whether the player is close to the edge and update the camera's position accordingly. Also, we need to check if the camera bounds have reached the edge of the screen and not move it beyond.
There is usually a lot of debate about which update method should be used within a Unity game. To put it simply, the FixedUpdate method is called on a regular basis throughout the lifetime of the game and is generally used for physics and time sensitive code. The Update method, however, is only called after the end of each frame that is drawn to the screen, as the time taken to draw the screen can vary (due to the number of objects to be drawn and so on). So, the Update call ends up being fairly irregular.
For more detail on the difference between Update and FixedUpdate see the Unity Learn tutorial video at http://unity3d.com/learn/tutorials/modules/beginner/scripting/update-and-fixedupdate.
As the player is being moved by the physics system, it is better to update the camera in the FixedUpdate method:
void FixedUpdate()
{
// By default the target x and y coordinates of the camera
// are it's current x and y coordinates.
float targetX = transform.position.x;
float targetY = transform.position.y;
// If the player has moved beyond the x margin...
if (CheckXMargin())
// the target x coordinate should be a Lerp between
// the camera's current x position and the player's
// current x position.
targetX = Mathf.Lerp(transform.position.x,
player.position.x, xSmooth *
Time.fixedDeltaTime );
// If the player has moved beyond the y margin...
if (CheckYMargin())
// the target y coordinate should be a Lerp between
// the camera's current y position and the player's
// current y position.
targetY = Mathf.Lerp(transform.position.y,
player.position.y, ySmooth *
Time. fixedDeltaTime );
// The target x and y coordinates should not be larger
// than the maximum or smaller than the minimum.
targetX = Mathf.Clamp(targetX, minXAndY.x, maxXAndY.x);
targetY = Mathf.Clamp(targetY, minXAndY.y, maxXAndY.y);
// Set the camera's position to the target position with
// the same z component.
transform.position =
new Vector3(targetX, targetY, transform.position.z);
}
As they say, every game is different and how the camera acts can be different for every game. In a lot of cases, the camera should be updated in the LateUpdate method after all drawing, updating, and physics are complete. This, however, can be a double-edged sword if you rely on math calculations that are affected in the FixedUpdate method, such as Lerp. It all comes down to tweaking your camera system to work the way you need it to do.
Once the script is saved, just attach it to the Main Camera element by dragging the script to it or by adding a script component to the camera and selecting the script.
Finally, we just need to configure the script and the camera to fit our game size as follows:
Set the orthographic Size of the camera to 2.7 and the Min X and Max X sizes to 5 and -5 respectively.
When dealing with cameras, there is always one thing that will trip us up as soon as we try to build for another platform—resolution.
By default, the Unity player in the editor runs in the Free Aspect mode as shown in the following screenshot:
The Aspect mode (from the Aspect drop-down) can be changed to represent the resolutions supported by each platform you can target. The following is what you get when you switch your build target to each platform:
To change the build target, go into your project's Build Settings by navigating to File | Build Settings or by pressing Ctrl + Shift + B, then select a platform and click on the Switch Platform button. This is shown in the following screenshot:
When you change the Aspect drop-down to view in one of these resolutions, you will notice how the aspect ratio for what is drawn to the screen changes by either stretching or compressing the visible area. If you run the editor player in full screen by clicking on the Maximize on Play button () and then clicking on the play icon, you will see this change more clearly. Alternatively, you can run your project on a target device to see the proper perspective output.
The reason I bring this up here is that if you used fixed bounds settings for your camera or game objects, then these values may not work for every resolution, thereby putting your settings out of range or (in most cases) too undersized. You can handle this by altering the settings for each build or using compiler predirectives such as #if UNITY_METRO to force the default depending on the build (in this example, Windows 8).
To read more about compiler predirectives, check the Unity documentation at http://docs.unity3d.com/Manual/PlatformDependentCompilation.html.
If you are only targeting one device/resolution or your background scrolls indefinitely, then the preceding manual approach works fine. However, if you want it to be a little more dynamic, then we need to know what resolution we are working in and how much space our character has to travel. We will perform the following steps to do this:
// The maximum x and y coordinates the camera can have.
private Vector2 maxXAndY;
// The minimum x and y coordinates the camera can have.
private Vector2 minXAndY;
// Get the bounds for the background texture - world size
var backgroundBounds = GameObject.Find("background") .renderer.bounds;
// Get the viewable bounds of the camera in world
// coordinates
var camTopLeft = camera.ViewportToWorldPoint (new Vector3(0, 0, 0));
var camBottomRight = camera.ViewportToWorldPoint (new Vector3(1, 1, 0));
// Automatically set the min and max values
minXAndY.x = backgroundBounds.min.x - camTopLeft.x;
maxXAndY.x = backgroundBounds.max.x - camBottomRight.x;
In the end, it is up to your specific implementation for the type of game you are making to decide which pattern works for your game.
So our camera follows our player, but our hero can still walk off the screen and keep going forever, so let us stop that from happening.
As you saw in the preceding section, you can use Unity's camera logic to figure out where things are on the screen. You can also do more complex ray testing to check where things are, but I find these are overly complex unless you depend on that level of interaction.
The simpler answer is just to use the native Box2D physics system to keep things in the scene. This might seem like overkill, but the 2D physics system is very fast and fluid, and it is simple to use.
Once we add the physics components, Rigidbody 2D (to apply physics) and a Box Collider 2D (to detect collisions) to the player, we can make use of these components straight away by adding some additional collision objects to stop the player running off.
To do this and to keep things organized, we will add three empty game objects (either by navigating to GameObject | Create Empty, or by pressing Ctrl + Shift +N) to the scene (one parent and two children) to manage these collision points, as shown in the following screenshot:
I've named them WorldBounds (parent) and LeftBorder and RightBorder (children) for reference. Next, we will position each of the child game objects to the left- and right-hand side of the screen, as shown in the following screenshot:
Next, we will add a Box Collider 2D to each border game object and increase its height just to ensure that it works for the entire height of the scene. I've set the Y value to 5 for effect, as shown in the following screenshot:
The end result should look like the following screenshot with the two new colliders highlighted in green:
Alternatively, you could have just created one of the children, added the box collider, duplicated it (by navigating to Edit | Duplicate or by pressing Ctrl + D), and moved it. If you have to create multiples of the same thing, this is a handy tip to remember.
If you run the project now, then our hero can no longer escape this town on his own. However, as we want to let him leave, we can add a script to the new Boundary game object so that when the hero reaches the end of the town, he can leave.
Now that we have collision zones on our town's borders, we can hook into this by using a script to activate when the hero approaches.
Create a new C# script called NavigationPrompt, clear its contents, and populate it with the following code:
using UnityEngine;
public class NavigationPrompt : MonoBehavior {
bool showDialog;
void OnCollisionEnter2D(Collision2D col)
{
showDialog = true;
}
void OnCollisionExit2D(Collision2D col)
{
showDialog = false;
}
}
The preceding code gives us the framework of a collision detection script that sets a flag on and off if the character interacts with what the script is attached to, provided it has a physics collision component. Without it, this script would do nothing and it won't cause an error.
Next, we will do something with the flag and display some GUI when the flag is set. So, add the following extra function to the preceding script:
void OnGUI()
{
if (showDialog)
{
//layout start
GUI.BeginGroup(new Rect(Screen.width / 2 - 150, 50, 300, 250));
//the menu background box
GUI.Box(new Rect(0, 0, 300, 250), "");
// Information text
GUI.Label(new Rect(15, 10, 300, 68), "Do you want to travel?");
//Player wants to leave this location
if (GUI.Button(new Rect(55, 100, 180, 40), "Travel"))
{
showDialog = false;
// The following line is commented out for now
// as we have nowhere to go :D
//Application.LoadLevel(1);}
//Player wants to stay at this location
if (GUI.Button(new Rect(55, 150, 180, 40), "Stay"))
{
showDialog = false;
}
//layout end
GUI.EndGroup();
}
}
The function itself is very simple and only activates if the showDialog flag is set to true by the collision detection. Then, we will perform the following steps:
If you now add the NavigationPrompt script to the two world border (LeftBorder and RightBorder) game objects, this will result in the following simple UI whenever the player collides with the edges of our world:
We can further enhance this by tagging or naming our borders to indicate a destination. I prefer tagging, as it does not interfere with how my scene looks in the project hierarchy; also, I can control what tags are available and prevent accidental mistyping.
To tag a game object, simply select a Tag using the drop-down list in the Inspector when you select the game object in the scene or project. This is shown in the following screenshot:
If you haven't set up your tags yet or just wish to add a new one, select Add Tag in the drop-down menu; this will open up the Tags and Layers window of Inspector. Alternatively, you can call up this window by navigating to Edit | Project Settings | Tags and layers in the menu. It is shown in the following screenshot:
You can only edit or change user-defined tags. There are several other tags that are system defined. You can use these as well; you just cannot change, remove, or edit them. These include Player, Respawn, Finish, Editor Only, Main Camera, and GameController.
As you can see from the preceding screenshot, I have entered two new tags called The Cave and The World, which are the two main exit points from our town.
Unity also adds an extra item to the arrays in the editor. This helps you when you want to add more items; it's annoying when you want a fixed size but it is meant to help. When the project runs, however, the correct count of items will be exposed.
Once these are set up, just return to the Inspector for the two borders, and set the right one to The World and the left to The Cave.
Now, I was quite specific in how I named these tags, as you can now reuse these tags in the script to both aid navigation and also to notify the player where they are going. To do this, simply update the Do you want to travel to line to the following:
//Information text
GUI.Label(new Rect(15, 10, 300, 68), "Do you want to travel to " + this.tag + "?");
Here, we have simply appended the dialog as it is presented to the user with the name of the destination we set in the tag. Now, we'll get a more personal message, as shown in the following screenshot:
Now for small games, the preceding implementation is fine; however, if you are planning a larger world with a large number of interactions, provide complex decisions to prevent the player continuing unless they are ready.
As the following diagram shows, there are several paths the player can take and in some cases, these is only one way. Now, we could just build up the logic for each of these individually as shown in the screenshot, but it is better if we build a separate navigation system so that we have everything in one place; it's just easier to manage that way.
This separation is a fundamental part of any good game design. Keeping the logic and game functionality separate makes it easier to maintain in the future, especially when you need to take internationalization into account (but we will learn more about that later).
Now, we'll change to using a manager to handle all the world/scene transitions, and simplify the tag names we use as they won't need to be displayed.
So, The Cave will be renamed as just Cave, and we will get the text to display from the navigation manager instead of the tag.
So, by separating out the core decision making functionality out of the prompt script, we can build the core manager for navigation. Its primary job is to maintain where a character can travel and information about that destination.
First, we'll update the tags we created earlier to simpler identities that we can use in our navigation manager (update The Cave to Cave01 and The World to World).
Next, we'll create a new C# script called NavigationManager in our AssetsScripts folder, and then replace its contents with the following lines of code:
public static class NavigationManager
{
public static Dictionary<string,string> RouteInformation = new Dictionary<string,string>()
{
{ "World", "The big bad world"},
{ "Cave", "The deep dark cave"},
};
public static string GetRouteInfo(string destination)
{
return RouteInformation.ContainsKey(destination) ? RouteInformation[destination] : null;
}
public static bool CanNavigate(string destination)
{
return true;
}
public static void NavigateTo(string destination)
{
// The following line is commented out for now
// as we have nowhere to go :D
//Application.LoadLevel(destination);
}
}
Notice the ? and : operators in the following statement:
RouteInformation.ContainsKey(destination) ? RouteInformation[destination] : null;
These operators are C# conditional operators. They are effectively the shorthand of the following:
if(RouteInformation.ContainsKey(destination)) { return RouteInformation[destination]; } else { return null; }
Shorter, neater, and much nicer, don't you think?
For more information, see the MSDN C# page at http://bit.ly/csharpconditionaloperator.
The script is very basic for now, but contains several following key elements that can be expanded to meet the design goals of your game:
The script you will notice is different to the other scripts used so far, as it is a static class. This means it sits in the background, only exists once in the game, and is accessible from anywhere. This pattern is useful for fixed information that isn't attached to anything; it just sits in the background waiting to be queried.
Later, we will cover more advanced types and classes to provide more complicated scenarios.
With this class in place, we just need to update our previous script (and the tags) to make use of this new manager. Update the NavigationPrompt script as follows:
void OnCollisionEnter2D(Collision2D col)
{
//Only allow the player to travel if allowed
if (NavigationManager.CanNavigate(this.tag))
{
showDialog = true;
}
}
//Dialog detail - updated to get better detail
GUI.Label(new Rect(15, 10, 300, 68), "Do you want to travel to " + NavigationManager.GetRouteInfo(this.tag) + "?");
//Player wants to leave this location
if (GUI.Button(new Rect(55, 100, 180, 40), "Travel"))
{
showDialog = false;
NavigationManager.NavigateTo(this.tag);
}
The functionality I've shown here is very basic and it is intended to make you think about how you would need to implement it for your game. With so many possibilities available, I could fill several articles on this kind of subject alone.
A slightly more advanced option when building game worlds is to add a level of immersive depth to the scene. Having a static image to show the village looks good, especially when you start adding houses and NPCs to the mix; but to really make it shine, you should layer the background and add additional active elements to liven it up.
We won't add them to the sample project at this time, but it is worth experimenting with in your own projects (or try adding it to this one)—it is a worthwhile effect to look into.
If we look at the 2D sample provided by Unity, the background is split into several panes—each layered on top of one another and each moving at a different speed when the player moves around. There are also other elements such as clouds, birds, buses, and taxes driving/flying around, as shown in the following screenshot:
Implementing these effects is very easy technically. You just need to have the art assets available. There are several scripts in the wiki I described earlier, but the one in Unity's own 2D sample is the best I've seen.
To see the script, just download the Unity Projects: 2D Platformer asset from https://www.assetstore.unity3d.com/en/#!/content/11228, and check out the BackgroundParallax script in the AssetsScripts folder.
The BackgroundParallax script in the platformer sample implements the following:
Implementing this same model in your game would be fairly simple provided you have texture assets that could support it. Just replicate the structure used in the platformer 2D sample and add the script. Remember to update the FollowCamera script to be able to update the base background, however, to ensure that it can still discover the size of the main area.
The other thing you can do to liven up your game is to add random foreground objects that float across your scene independently. These don't collide with anything and aren't anything to do with the game itself. They are just eye candy to make your game look awesome.
The process to add these is also fairly simple, but it requires some more advanced Unity features such as coroutines, which we are not going to cover here. So, we will come back to these later.
In short, if you examine the BackgroundPropSpawner.cs script from the preceding Unity platformer 2D sample, you will have to perform the following steps:
This allows them to run on their own without impacting the gameplay itself and just adds that extra bit of depth. In some cases, I've seen particle effects are also used to add effect, but they are used sparingly.
Believe it or not, all 2D elements (even in their default state) are drawn using a shader—albeit a specially written shader designed to light and draw the sprite in a very specific way. If you look at the player sprite in the inspector, you will see that it uses a special Material called Sprites-Default, as shown in the following screenshot:
This section is purely meant to highlight all the shading options you have in the 2D system. Shaders have not changed much in this update except for the addition of some 2D global lighting found in the default sprite shader.
For more detail on shaders in general, I suggest a dedicated Unity shader book such as https://www.packtpub.com/game-development/unity-shaders-and-effects-cookbook.
Clicking on the button next to Material field will bring up the material selector, which also shows the two other built-in default materials, as shown in the following screenshot:
However, selecting either of these will render your sprite invisible as they require a texture and lighting to work; they won't inherit from the Sprite Renderer texture. You can override this by creating your own material and assigning alternate sprite style shaders.
To create a new material, just select the AssetsMaterials folder (this is not crucial, but it means we create the material in a sensible place in our project folder structure) and then right click on and select Create | Material. Alternatively, do the same using the project view's Edit... menu option, as shown in the following screenshot:
This gives us a basic default Diffuse shader, which is fine for basic 3D objects. However, we also have two default sprite rendering shaders available. Selecting the shader dropdown gives us the screen shown in the following screenshot:
Now, these shaders have the following two very specific purposes:
Creating one of these materials and applying it to the Sprite Renderer texture of a sprite will override its default constrained behavior. This opens up some additional shader options in the Inspector, as shown in the following screenshot:
These options include the following:
Achieving pixel perfection in your game in Unity can be a challenge due to the number of factors that can affect it, such as the camera view size, whether the image texture is a Power Of Two (POT) size, and the import setting for the image. This is basically a trial and error game until you are happy with the intended result.
If you are feeling adventurous, you can extend these default shaders (although this is out of the scope of this article). The full code for these shaders can be found at http://Unity3d.com/unity/download/archive.
If you are writing your own shaders though, be sure to add some lighting to the scene; otherwise, they are just going to appear dark and unlit. Only the default sprite shader is automatically lit by Unity. Alternatively, you can use the default sprite shader as a base to create your new custom shader and retain the 2D basic lighting.
Another worthy tip is to check out the latest version of the Unity samples (beta) pack. In it, they have added logic to have two sets of shaders in your project: one for mobile and one for desktop, and a script that will swap them out at runtime depending on the platform. This is very cool; check out on the asset store at https://www.assetstore.unity3d.com/#/content/14474 and the full review of the pack at http://darkgenesis.zenithmoon.com/unity3dsamplesbeta-anoverview/.
If you are the adventurous sort, try expanding your project to add the following:
This certainly has been a very busy article just to add a background to our scene, but working out how each scene will work is a crucial design element for the entire game; you have to pick a pattern that works for you and your end result once as changing it can be very detrimental (and a lot of work) in the future.
In this article, we covered the following topics:
For learning Unity 2D from basic you can refer to https://www.packtpub.com/game-development/learning-unity-2d-game-development-example.
Further resources on this subject: