M

Grid-based movement in Unity

Hi! This is just a quick reminder of how easy it is to implement simple grid-based movement in Unity, 2D (or 3D, although this post is not about 3D).

Grid is a bit broad term here, as all you need is to decide on a common distance between things - 1 distance unit is a good idea - and scale your world accordingly. Moving in that world becomes easy, as you just displace things by 1 or more full units of distance at a time. Of course there are great plugins to visualise the grid and manipulate it via the Unity editor, but the basic premise is simple.

Simple grid-like layout

You won't necessarily need to juggle with tile arrays, just divide your scene to 1 by 1 squares and scale your sprites accordingly. Protip: check your pixels-to-units ratio so you won't have to actually scale any gameobjects to fit them into 1x1 space.

A classic gotcha - complexity kills

A game I'm currently working on needs an old-skool grid movement mixed with pseudo-physics where you can advance a pre-defined amount of tiles either to left or to right, but there also needs to be a platformer element so I need collision detection and some kind of gravity. The first intuition I had was to slap a RigidBody2D along with a collider to my player object. Then I started wondering how to move it as easily as possible, and ended up writing a lengthy script involving a lot of linear algebra and angular force calculations.

As you might have guessed, after I slept on it I scrapped the whole thing when I realised the player movement could be done much easier, with less code. The less code, the less I have to come back to it at further stages of development, plus it is much quicker to tweak when fine-tuning the player movement. Reality-based physics rarely provide a good control feeling to the player, so in the end it's all just lots of playtesting and magic numbers.

Mecanim to the rescue?

At first I scrapped my movement script and opened up Unity's Mecanim animation tool. Now we're talking - just a trigger to call from the code and everything else is nicely handled by Mecanim! I added some keyframes and was very pleased with the animation, until I realised it will not work.

I animated the player object's position, thinking it would apply only the movement delta to the current position of the transform. It seems that this is not the case and the position is always strictly related to parent, meaning that each step leads back to the position the animation was recorded in. I would have to put the player inside some container object which I would have to move around quite precisely in sync with the animation... Nope.

The player can't reach the end of the game. Great success!

Mecanim is absolutely great when it comes to actual animation, though - but in this case, it is not a viable solution for actually moving the player from one position to another.

Simple solution: tweening

Animation is all about doing stuff between points in time, and that is a common enough task in game development that it is widely known as tweening. Martin Jonasson and Petri Purho touch the subject a bit in their talk about juicing up a game - Juice it or lose it.

Tweening is a word for taking something and doing things to it over time. In other words, tweening is the stuff that happens between point A and B. It can be movement, colour change, audio fading... Whatever you come up with. The great thing about tweening is that you can apply different easing curves to the tween, and with a bunch of waypoints you can create a path and animate stuff with B├ęzier curves.

You can tween things very easily by hand, but it's a common task and there are tools for simplifying the process even more. Whenever you can simplify and reduce the amount of your own code, go for it. I remembered that I had briefly used iTween at a previous workplace to move the camera around in a demo application and checked if the library still exists. Turns out it is flourishing! Great!


void Update()
{
    if (Input.GetButtonDown("Horizontal"))
    {
        // moving to right
        if (Input.GetAxis("Horizontal") > 0)
        {
            iTween.MoveBy(this.gameObject, new Vector3(1, 0, 0), time);
        } 
        // moving to left
        else if (Input.GetAxis("Horizontal") < 0)
        {
            iTween.MoveBy(this.gameObject, new Vector3(-1, 0, 0), time);
        }
    }
} 

The result: Yay, the game is almost ready!

Now this simple code allows the basic horizontal movement. There are probably even more efficient ways to move the player, but this is a nice way for me in this particular game to get the basic movement out of the way (hopefully) without it backfiring at some point in the future. Of course my player will get once again more complicated, since there are a few things to consider before the controls feel great, but the basic idea is very simple.

This article was written by argontus .