Catlike Coding

Catlike Coding

Unity C# Tutorials

Clock

A Simple Time Display

  • Create an object hierarchy.
  • Write a script and attach it to an object.
  • Access namespaces.
  • Update objects through methods.
  • Rotate things based on time.

In this tutorial we'll write a small C# script to animate the arms of a very simple clock.

You're assumed to already have a basic understanding of Unity's editor. If you've played with it for a few minutes then you're good to go.

You will create this in no time.

Creating the clock

We start by creating a new Unity project without any packages. The default scene contains a camera positioned at (0, 1, -10) looking down the Z axis. To get a similar perspective as the camera in the scene view, select the camera and perform GameObject / Align View to Selected from the menu.

We need an object structure to represent the clock. Create a new empty GameObject via GameObject / Create Empty, set its position to (0, 0, 0), and name it Clock. Create three empty child objects for it and name them Hours, Minutes, and Seconds. Make sure they are all positioned at (0, 0, 0) as well.

We'll use simple boxes to visualize the arms of the clock. Create a child cube for each arm via GameObject / Create Other / Cube. Give the cube for Hours position (0, 1, 0) and scale (0.5, 2, 0.5). For the minutes cube it's position (0, 1.5, 0) and scale (0.25, 3, 0.25). For seconds cube it's (0, 2, 0) and (0.1, 4, 0.1).

Clock construction and hierarchy.
unitypackage

Animating the clock

We need a script to animate the clock. Create a new C# script via Create / C# Script in the Project view and name it ClockAnimator. Open the script and empty it so we can start fresh.

First, we indicate that we want to use stuff from the UnityEngine namespace. Then we declare the existence of the ClockAnimator. We describe it as a publicly available class that inherits from MonoBehaviour.

using UnityEngine;

public class ClockAnimator : MonoBehaviour {
}

This gives us a minimal class that can be used to create components. Save it, then attach it to the the Clock object by dragging from the Project view to the Hierarchy view, or via the Add Component button.

ClockAnimator attached to Clock.

To animate the arms, we need access to their Transform components first. Add a public Transform variable for each arm to the script, then save it. These public variables will become component properties which you can assign object to in the editor. The editor will then grab the Transform components of these objects and assign them to our variables. Select the Clock object, then drag the corresponding objects to the new properties.

using UnityEngine;

public class ClockAnimator : MonoBehaviour {

	public Transform hours, minutes, seconds;
}
empty filled
ClockAnimator with empty and filled properties.

Next, we'll add an update method to the script. This is a special method that will be called once every frame. We'll use it to set the rotation of the clock arms.

using UnityEngine;

public class ClockAnimator : MonoBehaviour {

	public Transform hours, minutes, seconds;

	private void Update () {
		// currently do nothing
	}
}

After saving the script, the editor will notice that our component has an update method and will show a checkbox that allows us to disable it. Of course we keep it enabled.

Updating ClockAnimator adorned with a checkbox.

Each hour, the Hours arm has to rotate 360/12 degrees. The Minutes arm has to rotate 360/60 degrees per minute. Finally, the Seconds arm has to rotate 360/60 degrees every second. Let's define these values as private constant floating-point values for convenience.

using UnityEngine;

public class ClockAnimator : MonoBehaviour {

	private const float
		hoursToDegrees = 360f / 12f,
		minutesToDegrees = 360f / 60f,
		secondsToDegrees = 360f / 60f;

	public Transform hours, minutes, seconds;

	private void Update () {
		// currently do nothing
	}
}

Each update we need to know the current time to get this thing to work. The System namespace contains the DateTime struct, which is suited for this job. It has a static property named Now that always contains the current time. Each update we need to grab it and store it in a temporary variable.

using UnityEngine;
using System;

public class ClockAnimator : MonoBehaviour {

	private const float
		hoursToDegrees = 360f / 12f,
		minutesToDegrees = 360f / 60f,
		secondsToDegrees = 360f / 60f;

	public Transform hours, minutes, seconds;

	private void Update () {
		DateTime time = DateTime.Now;
	}
}

To get the arms to rotate, we need to change their local rotation. We do this by directly setting the localRotation of the arms, using quaternions. Quaternion has a nice method we can use to define an arbitrary rotation.

Because we're looking down the Z axis and Unity uses a left-handed coordinate system, the rotation must be negative around the Z axis.

using UnityEngine;
using System;

public class ClockAnimator : MonoBehaviour {

	private const float
		hoursToDegrees = 360f / 12f,
		minutesToDegrees = 360f / 60f,
		secondsToDegrees = 360f / 60f;

	public Transform hours, minutes, seconds;

	private void Update () {
		DateTime time = DateTime.Now;
		hours.localRotation =
			Quaternion.Euler(0f, 0f, time.Hour * -hoursToDegrees);
		minutes.localRotation =
			Quaternion.Euler(0f, 0f, time.Minute * -minutesToDegrees);
		seconds.localRotation =
			Quaternion.Euler(0f, 0f, time.Second * -secondsToDegrees);
	}
}
Clock showing it's 12:44.
unitypackage

Improving the clock

This works! When in play mode, our clock shows the current time. However, it behaves much like a digital clock as it only shows discrete steps. Let's include an option to show analog time as well. Add a public boolean variable analog to the script and use it to determine what to do in the update method. We can toggle this value in the editor, even when in play mode.

using UnityEngine;
using System;

public class ClockAnimator : MonoBehaviour {

	private const float
		hoursToDegrees = 360f / 12f,
		minutesToDegrees = 360f / 60f,
		secondsToDegrees = 360f / 60f;

	public Transform hours, minutes, seconds;

	public bool analog;

	private void Update () {
		if (analog) {
			// currently do nothing
		}
		else {
			DateTime time = DateTime.Now;
			hours.localRotation =
				Quaternion.Euler(0f, 0f, time.Hour * -hoursToDegrees);
			minutes.localRotation =
				Quaternion.Euler(0f, 0f, time.Minute * -minutesToDegrees);
			seconds.localRotation =
				Quaternion.Euler(0f, 0f, time.Second * -secondsToDegrees);
		}
	}
}
ClockAnimator allowing analog mode.

For the analog option we need a slightly different approach. Instead of DateTime.Now we'll use DateTime.Now.TimeOfDay, which is a TimeSpan. This allows us easy access to the fractional elapsed hours, minutes, and seconds. Because these values are provided as doubles – double precision floating-point values – we need to cast them to floats.

using UnityEngine;
using System;

public class ClockAnimator : MonoBehaviour {

	private const float
		hoursToDegrees = 360f / 12f,
		minutesToDegrees = 360f / 60f,
		secondsToDegrees = 360f / 60f;

	public Transform hours, minutes, seconds;
	public bool analog;

	private void Update () {
		if (analog) {
			TimeSpan timespan = DateTime.Now.TimeOfDay;
			hours.localRotation = Quaternion.Euler(
				0f, 0f, (float)timespan.TotalHours * -hoursToDegrees);
			minutes.localRotation = Quaternion.Euler(
				0f, 0f, (float)timespan.TotalMinutes * -minutesToDegrees);
			seconds.localRotation = Quaternion.Euler(
				0f, 0f, (float)timespan.TotalSeconds * -secondsToDegrees);
		}
		else {
			DateTime time = DateTime.Now;
			hours.localRotation =
				Quaternion.Euler(0f, 0f, time.Hour * -hoursToDegrees);
			minutes.localRotation =
				Quaternion.Euler(0f, 0f, time.Minute * -minutesToDegrees);
			seconds.localRotation =
				Quaternion.Euler(0f, 0f, time.Second * -secondsToDegrees);
		}
	}
}
Clock in analog mode showing it's 12:56.

Now our clock works analog too!

unitypackage PDF