Alpha Accesswebsite_badges_steamwishlistwebsite_badges_steamwishlist

Archive

Simple and flexible scrolling behavior


One of the staples of 2D games pioneered in the old school days is seamless scrolling. More specifically, having an endless scrolling behavior that seems infinite. This is usually applied to background layers, and when you combine different layers with varying speeds, you can achieve a very nice parallax effect that sells depth on a flat screen. I’ll be honest – I’m a sucker for anything with sensible parallax. To me, the effect never gets old and instantly makes smaller worlds feel expansive.

The technique is very, very simple. Perhaps it’s one of the first effects that many beginner game programmers are introduced to. It’s also probably one of the most satisfying results you’ll get in a very short amount of time.

In essence, if you create 2 copies of your scrolling layer and place them side by side, you can have them both scrolling in the intended direction, and when one of them is completely off screen, simply move it to the opposite edge. You can see the illusion illustrated here. If you pay attention to the center camera and the two hills, you can see that they appear to be seamless.

parallaxExample

In Unity, it’s simple enough to create a small behavior script that gives the game object a speed to be scrolling at, and to snap back to the other side when off screen. If you apply this script to two identical side-by-side game objects, you can get this seamless behavior. The nice thing about the approach in Unity is that you just need to translate the objects in your Update() method, but you don’t need the offscreen-check performed every update. You can use the MonoBehaviour callback OnBecameInvisible() to handle this:

using UnityEngine;
using System.Collections;

public class Scrolling : MonoBehaviour
{
	public float xSpeed;
	public float ySpeed;

	void Update()
	{
		transform.Translate(new Vector3(xSpeed, ySpeed, 0f));
	}

	void OnBecameInvisible()
	{
		Vector3 newPosition = transform.localPosition;
		Vector3 viewportPoint = Camera.main.WorldToViewportPoint(transform.position);
		
		// move to opposite edge of screen (horizontally)
		if (xSpeed != 0 && (viewportPoint.x < 0f || viewportPoint.x > 1f))
		{
			newPosition.x = -transform.localPosition.x;
		}

		// move to opposite edge of screen (vertically)
		if (ySpeed != 0 && (viewportPoint.y < 0f || viewportPoint.y > 1f))
		{
			newPosition.y = -transform.localPosition.y;
		}

		// move to the new position
		transform.localPosition = newPosition;
	}
}

Give life to explosions and debris


Update 2014.08.22
I did figure out a much better approach. Read the update here!

Update: 2014.07.22
So… my hunch “this is probably too expensive in the end” turned out to be true. I’ve optimized it a little, but this is too expensive to apply to large numbers of game objects (but perfectly fine for just a few). I’ll figure out a more efficient approach for the same effect since I’ll require a lot of debris, and include the new method in a future post.

bouncingDebris2.96

I love debris. Physical particle debris is one of the things that, in my opinion, brings modern low-res games to life. It’s also a technique that simply wasn’t feasible in the 8- and 16-bit eras due to hardware limitations. This is another reason why I would wholeheartedly argue that low-res is not simply “retro,” but a legitimate, timeless aesthetic style all its own. It is familiar yet evolving. I digress!

There are two limitations in Unity 4.3+ that I’ve had to work around to get the effect that I wanted.

The first is that the built in shuriken particle system does not support 2D physics. This means that I must use individual game objects for my debris if I want them to physically interact with the rest of my 2D colliders. So far, this hasn’t been a performance issue as I am keeping my debris in a shared object pool – a topic for a future post.

The second issue is that Unity won’t let you specify gravity in the z-direction; it’s strictly limited to x and y for 2D. My project is top-down, so to get gravity effects along the z-axis, I’m forced to use old school visual tricks to sell it. One such technique is growing sprites as they are closer to you and shrinking as they move away, and also moving them along parabolic arcs in the y direction (while adding this to their “real” y-position).

Going back to my introduction, debris should feel “alive” and dynamic, and in my case I wanted each particle to collide with the environment, and to slightly bounce until they came to rest. You can see in this example that the bounce is quite subtle, but it serves to “ground” everything and when you see it without the bounce, you’ll realize just how much it adds. I’ve always loved this sort of attention to detail in my favorite games, and they really add polish and “glue” to otherwise static objects.

For the bouncing itself, I’m running some simple tweens (using the excellent GoKit tweening library) in the y direction on each particle. The rest of their motion path all comes from a physical force I apply when they are spawned. I created a simple vertical bounce behavior script that I can attach to game objects to simulate this effect, and you can see a version of the script here. This script actually has some issues and will most likely change dramatically before the game is done, but the general idea will be the same. In fact, this is probably too expensive in the end, but so far my performance is still good:

using UnityEngine;
using System.Collections;

public class VerticalBounce : MonoBehaviour
{
    public float minAmplitude = 0.25f;
    public float maxAmplitude = 0.5f;
    public float minBounceTime = 0.25f;
    public float maxBounceTime = 0.5f;
    public int numberOfBounces = 2;
    public float bounceChance = 0.33f;
    
    private float amplitude;
    private float bounceTime;
    private Vector3 currentPosition;

    private float _offset;
    [HideInInspector]
    public float offset
    {
        get { return _offset; }
        set { _offset = value; }
    }

    void OnEnable()
    {
        // sometimes, don't bounce at all
        if (Random.value > bounceChance)
        {
            return;
        }

        // choose a random amplitude and time between the specified range
        amplitude = Random.Range(minAmplitude, maxAmplitude);
        bounceTime = Random.Range(minBounceTime, maxBounceTime);
        
        // create a tween chain that raises and lowers the offset x numberOfBounces times
        GoTweenChain bounceChain = new GoTweenChain();
        for (int i = 1; i <= numberOfBounces; i++)
        {
            _offset = 0f;
            GoTween riseTween = new GoTween(this, bounceTime, new GoTweenConfig()
                .floatProp("offset", amplitude, false)
                .setEaseType(GoEaseType.SineOut)
            );
            GoTween fallTween = new GoTween(this, bounceTime, new GoTweenConfig()
                .floatProp("offset", -amplitude, false)
                .setEaseType(GoEaseType.SineIn)
            );
            bounceChain.append(riseTween).append(fallTween);

            // each bounce should have a lower amplitude and take less time
            amplitude /= 2;
            bounceTime /= 2;
        }
        bounceChain.setOnCompleteHandler((x) => {
            _offset = 0f;
        });
        bounceChain.play();
    }

    void FixedUpdate()
    {
        // add the fake vertical bounce on top of the current y position (additive)
        currentPosition = gameObject.transform.localPosition;
        gameObject.transform.localPosition = new Vector3(currentPosition.x, (currentPosition.y + _offset), currentPosition.z);
    }
}

Screen effects and shaders


I knew that I wanted to implement a variety of fullscreen and object shader effects to pull off some of the visuals for this project, so one of my first asset store purchases was the unbelievably full-featured Shader Forge shader editor by Joachim Holmér. At $80, it’s a steal if you’re doing any creative shader work and are looking for a good visual editor. The good thing is that it spits out shader code directly, so you can always go in and optimize/tweak the resulting shaders.

Bird's eye view of my screen effects shader in Shader Forge

Shader Forge lets you create complicated graphs quite easily and intuitively. Here’s a bird’s eye view of my screen effects shader in Shader Forge.

One of the neat things is that it provides a Scene Color node that will give you the pixels behind the object. That lets me apply this shader to a rectangle quad over only the portion of the game screen that I want to affect. Since I plan to have some UI around my central game screen, this lets me perform visual effects to the pixels “behind” this quad without affecting the rest of the UI/screen. When I am not doing anything crazy, the pixels come through unaffected as if the quad was not there, showing an unaltered game area. Note: this is one of the very few things in Shader Forge that requires Unity Pro, as the only way it can accomplish this is using a render texture.

An example of chromatic aberration in Shader Forge

An example of chromatic aberration in Shader Forge

One of the effects I wanted to implement was chromatic aberration, or color-shifting, over this gameplay area. I’m still somewhat new to shader editing, though I did a little bit of work on it for Hawken while at Adhesive. Shader Forge made it pretty easy to experiment though, and eventually I had it figured out. There is probably a more optimal way to do this, but this works and is easy to modify later when I want to improve it.

sheenExample

This is another example of a simple effect that was pretty easy to achieve in the shader editor. I wanted sort of a threshold-highlighting sheen effect, where objects would highlight to a key color based on a brightness threshold that is set (and can be animated). Here’s an example of the effect, and the corresponding shader.

Threshold-highlighting shader

Threshold-highlighting shader

Surround yourself with inspiration


Something that cannot be understated is setting yourself up with a work environment that motivates you. Personally, I know that I have some trouble consistently being productive and meeting my own deadlines if I am completely isolated. When surrounded by talented like-minded individuals (from any discipline), it’s a constant source of inspiration to keep on going.

desk

Being self-funded, it may seem like a waste of money to rent a workspace when you could theoretically work at home (especially for a one- to two-person team), but to me it’s a fundamental tool in keeping the project on track. Of course, it should be financially reasonable; it’s not the wisest move to go full on fancy pants with your office space. It helps if you can find a group of peers, colleagues, or friends working on similar goals and you can split the cost of a workspace that fulfills your most basic requirements. For me, this includes space for a desk, wifi, and good people. At first I was looking for a nice coworking space, but there doesn’t seem to be any options around Pasadena, California (yet). However, I was fortunate enough (perfect timing) to find a close-to-home location with former game dev workmates, friends, and some new faces. It’s in the heart of a commercial district with plenty of walkable food for distractions fuel.

Home music & audio production studio

Home music & audio production studio

It works out perfectly for me as I now handle music and audio production at my home studio, and most game development at the office. Google Drive and Dropbox are my best friends in this scenario, and I’m currently using GIT for version control and syncing my Unity project and game assets with Bitbucket. This allows me to pick up where I left off on any part of the project (graphics, code, audio, etc) on my work PC and home Macbook Pro.

While it is certainly feasible to be very productive in a “bubble” – and I know many people that excel at this – it’s good to self-evaluate your own tendencies and put yourself in positions that are conducive to the way you operate. For game development in particular, it’s also healthy to receive periodic feedback when you have something new to test, or a gameplay mechanic idea, or an art test – but make sure it’s from intelligent people you trust who are just as likely to point out shortcomings in your game as they are to offer praise. You don’t want to be delusional about the merits of your project until it’s too late!

Tiled map tools with Unity


The arrival of Unity 4.3 brought solid 2D support. Though some issues are being fixed with dot releases and some support is still outstanding, it already provided a solid foundation to prototype (and continue development on) this project. Without giving too much away, one thing that I needed from the outset was an easy way to build tile-base maps quickly, with variable flexibility.

Of course, I began researching existing tools, which are quite mature at this point. One of the favorites is Tiled, and another relative newcomer is Pyxel Edit (which I’ve been using for design and animation production). Getting Unity to play with Tiled was pretty painless and surprisingly simple. I saved my Tiled maps in .json format, and wrote a simple loader (using SimpleJSON) that would import a map into my project. Here’s some example code for the importer:

public void LoadMap(string mapPath)
{
	// read in and parse the .json map file exported from Tiled
	TextAsset mapData = (TextAsset)Resources.Load(mapPath);
	JSONNode json = JSON.Parse(mapData.text);
	
	// bitmasks defined from the Tiled map format specification
	uint flippedHorizontally = 0x80000000;
	uint flippedVertically = 0x40000000;
	uint flippedDiagonally = 0x20000000;

	int width;
	int height;
	int row;
	int column;
	uint tileID;
	int tileIDOffset;
	float xscale;
	float yscale;

	// for each Tiled layer
	for (int layer = 0; layer < json["layers"].AsArray.Count; layer++)
	{
		// get the width and height of the layer (in tiles)
		width = json["layers"][layer]["width"].AsInt;
		height = json["layers"][layer]["height"].AsInt;
		
		// for each tile in the layer
		for (int i = 0; i < (width * height); i++)
		{
			// pull the tileID, and use bitmasks to determine any transformations
			tileID = json["layers"][layer]["data"][i].AsUInt;
			xscale = ((tileID & flippedHorizontally) != 0) ? -1.0f : 1.0f;
			yscale = ((tileID & flippedVertically) != 0) ? -1.0f : 1.0f;
			tileID = (tileID & ~(flippedVertically | flippedHorizontally | flippedDiagonally));

			if (tileID != 0)
			{
				// get tile information
				tileIDOffset = json["tilesets"][0]["firstgid"].AsInt;
				row = (int)(i / width);
				column = (int)(i % width);

				// do stuff pertaining to your game with your tileID here
				// ...
			}
		}
	}
}

The issue I had with these (and most other) tilemap editors is that they are based on single tilemap image atlases. This is understandable for their purpose, but it also assumes that during an entire development cycle, your tilemap shouldn’t change and is complete from the start. If you have a bunch of maps based on a certain image atlas, the entire system becomes fragile. Unless you are simply adding new sprites, you don’t have the option of rearranging tiles, or replacing content, without affecting all maps based on it. Not only that, but Unity Pro supports automatic image atlasing, which means my tilemap image shouldn’t have to be pre-determined – I don’t need a tilemap atlas. I needed an editor that was based on soft-links to tiles, and in Unity’s case, prefabs.

I began exploring the notion of creating my own editor panel, and in just a few days, I had a completely working, flexible prefab-based tile editor that suited my needs perfectly. The nice thing about this is that it is easily extendable to support more features that this specific project requires without finding workarounds using other tools, or being “locked in” to a specific workflow.

Custom prefab-based tiled map editor using Editor Window in Unity.

Custom prefab-based tiled map editor using Editor Window in Unity. I know it’s weird that the “Bottom” layer is actually on top. :)

Some research brought me to an excellent tutorial by Daniel Branicki for tuts+ with the basics of creating your own editor window, drawing a grid, and snapping prefabs to the grid. I started my work extending Unity’s Editor Window class using this tutorial as a guide, and here are just a few notes that might help you in your tools:

DrawLines()
Rather than use the Gizmos.DrawLine() method, I used Handles.DrawLine() instead. The reason is that Gizmos.DrawLine() seems to be called continuously, slowing down execution, and if you draw transparent lines they quickly stack to create solid lines.

Clean OnGUI()
I like to break out my OnGUI() code into functions based on sections of the UI, for easier editing and maintainability. As an example, you can see how these match up to the UI screenshot above:

void OnGUI() 
{
    SectionFileOperations();
    SectionMapInformation();
    SectionLayers();
    SectionSettings();
    SectionTools();
    SectionTiles();
}

Easy Layers
My “layers” are based on Unity’s Renderer.sortingOrder. This is just a series of GUILayout.Toggle() controls that map to sortingOrders .

Respond to the Scene
To listen for input and respond to events in the Scene window (in my case to “paint” with prefabs and use keyboard shortcuts to activate tools), you need to add your Editor Window class as a delegate to OnSceneGUI, then implement the OnSceneGUI() function for your custom logic.

void OnFocus()
{
    SceneView.onSceneGUIDelegate -= this.OnSceneGUI;
    SceneView.onSceneGUIDelegate += this.OnSceneGUI;
}

void OnDestroy()
{
    SceneView.onSceneGUIDelegate -= this.OnSceneGUI;
}

void OnSceneGUI(SceneView sceneView)
{
    // custom scene & drawing logic here
}

Snap to Grid
In your Update() function, you can easily snap the selected object to a grid by setting the Selection.transforms position:

private Vector3 Snap(Vector3 point)
{
    Vector3 snappedPoint = new Vector3
    (
        (snapValue * Mathf.Round((point.x / snapValue))),
        (snapValue * Mathf.Round((point.y / snapValue))),
        (snapValue * Mathf.Round((point.z / snapValue)))
    );
    return snappedPoint;
}

void Update()
{
    foreach (Transform transform in Selection.transforms)
    {
	    transform.transform.position = Snap(transform.transform.position);
    }
}
©2017 Sombr Studio LLC