Ryan Nielson

The personal site and blog of Ryan Nielson.

© 2014. Ryan Nielson All rights reserved.

Saving Games in Unity

Unity has ways to save game data like PlayerPrefs but it is quite limited and can store information in strange locations on certain platforms. In this post, I'll demonstrate a more object oriented approach that allows you to save almost any kind of data structure to a file. This method is going to be based off of how Unreal Engine 4 handles saving games.

To start, we'll create a SaveGame object that will be used as an abstract base class for all of our saved game objects. This class is marked as [Serializable] so that C# is able to serialize it, and it's also marked as abstract because we won't be using it directly to save games.

using System;

[Serializable]
public abstract class SaveGame
{
}

Next comes the static SaveGameSystem class that does most of the heavy lifting of saving, loading, and deleting save files.

using UnityEngine;
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

public static class SaveGameSystem
{
    public static bool SaveGame(SaveGame saveGame, string name)
    {
        BinaryFormatter formatter = new BinaryFormatter();

        using (FileStream stream = new FileStream(GetSavePath(name), FileMode.Create))
        {
            try
            {
                formatter.Serialize(stream, saveGame);
            }
            catch (Exception)
            {
                return false;
            }
        }

        return true;
    }

    public static SaveGame LoadGame(string name)
    {
        if (!DoesSaveGameExist(name))
        {
            return null;
        }

        BinaryFormatter formatter = new BinaryFormatter();

        using (FileStream stream = new FileStream(GetSavePath(name), FileMode.Open))
        {
            try
            {
                return formatter.Deserialize(stream) as SaveGame;
            }
            catch (Exception)
            {
                return null;
            }
        }
    }

    public static bool DeleteSaveGame(string name)
    {
        try
        {
            File.Delete(GetSavePath(name));
        }
        catch (Exception)
        {
            return false;
        }

        return true;
    }

    public static bool DoesSaveGameExist(string name)
    {
        return File.Exists(GetSavePath(name));
    }

    private static string GetSavePath(string name)
    {
        return Path.Combine(Application.persistentDataPath, name + ".sav");
    }
}

The SaveGame method takes a SaveGame object and a name, and saves it to a file. The LoadGame method takes a name and loads the file back into a usable SaveGame object. The DeleteGame method takes a name and deletes the associated save game file. All of these methods use GetSavePath to determine where the save game file should be located. By default, it's saved to the Application.persistantDataPath which is different on each platform. On Windows, it should be located somewhere similar to C:\Users\[username]\AppData\LocalLow\[companyname]\[projectname]. If you want to customize the saved game location, just modify this method.

Finally, create a custom class to store save game data that will be written to a file. This class should be marked as [Serializable] and inherit from the SaveGame class. It should contain any fields you wish to save to a file. By default C#'s BinaryFormatter class serializes all public and private fields, and public and private properties. To prevent a field from being serialized, it should be marked with the [NonSerialized] attribute.

using System;

[Serializable]
public class MySaveGame : SaveGame
{
    public string playerName = "Ryan";

    public int HighScore { get; set; }

    [NonSerialized]
    public string secret = "Nope";
}

Below is an example of how you could use this system to save and load a saved game.

// Saving a saved game.
MySaveGame mySaveGame1 = new MySaveGame();
mySaveGame1.playerName = "Ryan";
mySaveGame1.HighScore = 1000000;
mySaveGame1.secret = Random.Range(0, 1000).ToString();
SaveGameSystem.SaveGame(mySaveGame1, "MySaveGame"); // Saves as MySaveGame.sav

// Loading a saved game.
MySaveGame mySaveGame2 = SaveGameSystem.LoadGame("MySaveGame") as MySaveGame;
Debug.Log(mySaveGame2.playerName); // Will log Ryan
Debug.Log(mySaveGame2.HighScore);  // Will log 1000000
Debug.Log(mySaveGame2.secret);     // Will log null since this field was marked [NonSerialized]

// Deleting a saved game.
SaveGameSystem.DeleteSaveGame("MySaveGame");

I think this approach is much better than using PlayerPrefs because of its added flexibility, and hopefully you do as well. If you have any further questions please feel free to message me on Twitter @RyanNielson or comment below.

Snapping Objects to the Pixel Grid - Better 2D in Unity Part 1

Unity is a fantastic engine, but its history as a 3D engine sometimes shows when using it to develop 2D games. This is especially apparent when games use a pixel art style. This series will demonstrate some common problems, and provide solutions to make developing 2D games in Unity easier.

This first post in the series will focus on the pixel grid and how to lock items to it. Unity uses floating point positions for objects, unlike many 2D specific engines which use pixel locations. This means that sub-pixel movement is a common problem in Unity games and can lead to rendering artifacts or inconsistent visuals. Sub-pixel movement refers to objects moving between pixels causing pixels to not align properly. Though this may not always be an issue, depending on your game it can be an eyesore. The image below is an example of sub-pixel movement leading to pixels on the screen not lining up properly.

The first image is an example of sub-pixel character movement where the player sprite pixels aren't lined up properly with other pixels in the scene. The second is a gif that shows how sub-pixel camera movement can lead to strange rendering artifacts where pixels have different widths. It's subtle in the gif, but if you focus on the ground sprite pixels you can see them changing width as the camera moves.

Sub-pixel Movement

Sub-pixel Camera

I've created a simple script that you can add to child objects to lock their positions to a grid. For example, you'd have a parent GameObject which handles the player's movement, and a child GameObject that contains a SpriteRenderer. This ensure that the player can move in a sub-pixel way ensuring smooth movement, while still locking the sprite to the pixel grid.

using UnityEngine;

public class SnapToPixelGrid : MonoBehaviour 
{
    [SerializeField]
    private int pixelsPerUnit = 16;

    private Transform parent;

    private void Start()
    {
        parent = transform.parent;
    }

    /// <summary>
    /// Snap the object to the pixel grid determined by the given pixelsPerUnit.
    /// Using the parent's world position, this moves to the nearest pixel grid location by 
    /// offseting this GameObject by the difference between the parent position and pixel grid.
    /// </summary>
    private void LateUpdate() 
    {
        Vector3 newLocalPosition = Vector3.zero;

        newLocalPosition.x = (Mathf.Round(parent.position.x * pixelsPerUnit) / pixelsPerUnit) - parent.position.x;
        newLocalPosition.y = (Mathf.Round(parent.position.y * pixelsPerUnit) / pixelsPerUnit) - parent.position.y;

        transform.localPosition = newLocalPosition;
    }
}

LateUpdate() runs every frame after all Update() calls are completed, and offsets the GameObject so it lies on the pixel grid determined by pixelsPerGrid and it's parent's location.

Download the Windows demo or Mac demo to see this in action. You can also download the example project to experiment with the script.

Hopefully this approach is enough to get you started and alleviate any 2D pixel art rendering issues. If you have any further questions please feel free to message me on Twitter @RyanNielson or comment below.

Enter the Murderdome - Our Ludum Dare 31 Submission

Ludum Dare is a game jam in which participants are required to develop a game in 48 hours, using a given theme. My friend Matt and decided to participate in Ludum Dare 31 this past weekend. The theme this time around was Entire Game on One Screen.

After about an hour of brainstorming on Friday night, we came up with the idea for our game Enter the Murderdome. From Friday night to Sunday afternoon we worked on the game, Matt doing the art and sound and me doing the programming. In the end, I think the result was a super fun game with a lot of polish which you can play using the link below.

Play Enter the Murderdome

Title screen

Gameplay

If you have any comments or suggestions feel free to vote/comment on the page linked above, or post a comment here. The ugly source code is also available on GitHub if you're interesting in seeing how the game works under the hood.

Thanks for checking out our game, and I hope you enjoy it.

Awesome Unity: A Curated List of Unity Assets and Resources

There is a recent trend in the development community of creating curated lists of resources for various frameworks, languages, and tools. Some examples of these lists include Awesome Ruby and Awesome Django. The advantage of these lists being hosted on GitHub is that other users can contribute additions and changes to be included.

I recently created Awesome Unity in the hopes of creating the defacto list of Unity assets, projects, and resources. It's open to pull requests on GitHub, which allows anyone to submit additions or changes if they wish. With enough contributions, I think this list could become a great resource for new and experienced users alike.

Sprite Lighting in Unity

With the release of Unity 4.3, built in support for 2D sprites was added. This makes it easy to import, animate, and render sprites. Unfortunetely, by default the Unity sprite renderer does not support lighting. This means that putting lights in your scene will not have any affect on the rendered image. Luckily, this behaviour is easy to correct on a per-sprite basis.

I've started with a blank project and imported the 2D/Sprites folder from the Standard Assets in the asset store. I then placed a few instances of the prototype_green_2x2 sprite and a point light in the middle of the scene, and you can see that there is no lighting applied to the sprites.

Unlit Sprites

To get lighting to working on sprites, it's just a matter of creating a material and changing its shader to Sprites/Diffuse in the shader dropdown in the inspector. You can now drag and drop the new material into the material section of the Sprite Renderer component of any sprite you want to be affected by lighting. Also, ensure that your light is in front of any sprites that should be affected by lighting. In the example below, the blocks on the right have the new lit material, while the blocks on the left do not.

Lit Sprites

I hope you found this short post helpful. If you have any further questions please feel free to message me on Twitter @RyanNielson or comment on this post's page.