KiwiJS v1.2.0 – Improved Clocks and Time

Hello, and welcome to a new feature in KiwiJS v1.2.0! Today we’ll be doing the Time Warp (again?), taking a long look at Clocks and all the new things they can do to control your game.

The Clock code isn’t restricted to just clocks, of course. It includes upgrades for animation, timers, and tweening, which in turn can control just about any part of your game.

At the end of this article, we’ll discuss best practice when it comes to time. You can save yourself a lot of pain if you develop with a full understanding of time and the tools available to control it!

Time Hierarchy

We’ve given time a real overhaul in KiwiJS v1.2.0. Just how major an upgrade is this? Let’s take a look.

Old Time

Once upon a time, there was one clock, and it was either playing or not playing. Time flowed something like this:

  • Master Clock
    • Game Clock
      • Animations
      • Timers
      • Tween Manager

There are several issues with this system. For example, say you want to pause the game. Pause the Game Clock, and all your animations and tweens will stop. But what if you have a beautiful animated UI, with tweened transitions and animated buttons and special effects? None of that will play while the Game Clock is paused. You could always put a check on everything that refers to a universal pause variable, but now we’re back to something a lot more complex than this.game.time.clock.pause().

New Time

In KiwiJS v.1.2.0, we’ve turned the clocks up to 11. Here’s an example of a new hierarchy:

  • Master Clock
    • World Clock
      • Animations
      • Timers
      • Tween Manager
      • Rate
    • UI Clock
      • Animations
      • Timers
      • Tween Manager
      • Rate

Immediately, you can see that everything is better. Pause the game world by pausing the world clock, and the UI remains intact.

But you can do even more cool stuff.

Using Clocks

Clock Management

To create a new Clock, use the game’s clock manager game.time.

And as simple as that, you’ve got two new clocks to play with.

Clock Properties

We’ve added some useful properties and methods to the Clock. These make it much easier to create smooth movement – and some other tricks.

rate

The rate property was first introduced in v1.1.0 on ClockManager. It proved so useful that we’ve expanded it onto the clocks themselves.

rate is simply actual frame time divided by desired frame time. If the two are identical, rate = 1. If actual frame time is taking too long, rate > 1.When the frame rate drops, rate increases proportionally. Multiplying by rate makes your properties change at the same rate no matter what frame rate you encounter.

We strongly advise that any animation over time incorporate * rate to keep it smooth. This will also allow it to take advantage of other new time features.

maxFrameDuration

Using rate lets you skip dead time and get on to where you should be by now. But sometimes that skip is just too massive. For example, if your browser hiccups and freezes for six seconds, you might not want to skip that far ahead in time. That’s long enough for characters to move through walls, jump halfway across the screen, and otherwise exhibit unwanted behavior.

We’ve implemented maxFrameDuration to fix these issues. By default, maxFrameDuration = -1 and has no effect. If set to a positive number of milliseconds, however, it will clamp the effective frame duration to that level. This prevents major skips.

We advise that you set maxFrameDuration during a state create method, not earlier. If you try to set it just after game creation, you may find that clocks have not yet been created.

elapsed()

This method returns the number of clock units (default: seconds) since the Clock was started. This does not include time spent paused. In the event that time runs backwards, the total will diminish.

timeScale

Pay attention; this is awesome.

The timeScale parameter controls how fast time elapses on that clock. By default it is 1, which means time advances into the future at 1 second per second.

You can change timeScale. Set it to 2 to induce fast-forward. Set it to 0.5 to go into slow motion. Set it to 0 to freeze time. Set it to -1 to rewind time.

This is another reason why you should use rate in all your animations. If you are using rate, it will be affected by timeScale.

If you are running different parts of your game on different clocks, you can change the timeScale to create targeted temporal distortions. For example, you might drop a time bomb on an enemy and freeze them in place while the player’s speed is unaffected. Or you might send the whole game into slow-mo while your user interface remains at full speed.

The timeScale isn’t magic, and it isn’t a timeline. You can’t undo events or reverse physics. At least, not with the core library. timeScale is the foundation upon which you can build the most sublime paradox, should you desire it.

setTimeout()

KiwiJS has a robust timing system, but it was always a little bit tricky to use. Here’s the old way of making a single-use timer event that prints a message after 1 second:

That’s a bit of an eyeful, isn’t it?

To fix this, we’ve taken inspiration from standard JavaScript functions. Clocks now have a setTimeout() method, which works very much like the normal browser version. It even uses milliseconds. Now you can simply call:

Much nicer.

The main difference with the KiwiJS setTimeout() is that it takes an extra optional parameter:

The context parameter defines the object which is this inside the callback. Experienced JavaScript developers will appreciate that this is often not this, so we make it easy.

You may also specify any number of arguments after context. These will be passed to the callback.

setInterval()

Just like setTimeout, setInterval() mimics the JavaScript command. It repeats a given callback function once per given number of milliseconds.

This will simply repeat the callback once every second forever and ever.

As both setTimeout() and setInterval() return a Timer object, you can store it and use it to clear the timer later. Unlike basic JavaScript, there is no “clearInterval” command. You should simply use the standard Timer management systems:

Using Other Time-Based Features

Clocks are cool, but they just give out time. Other features actually use it. Let’s take a look at some of the new things you can do in v1.2.0 with Animation, Timer, and Tween.

Animation

An Animation is a single sequence of spritesheet cells. It is stored in an AnimationManager. Upon playback, the game will display cells one by one, switching at a particular time interval.

There’s that keyword: time. Yes, an animation is controlled by a Clock. In v1.2.0, you can alter the flow of time, and the animation will play back at the altered speed. You can even reverse time, and animations will play backwards.

Note that if your animation does not loop and plays back to its own beginning, it will dispatch onComplete and stop.

In v1.2.0, animations will automatically use the Clock of their entity. If you set the Clock directly on an animation, it will use that clock instead.

(In more technical terms, an animation will use a clock if it is set. If its clock is instead set to null, it will attempt to use this._parent.entity.clock; that is, the Entity of an AnimationManager. Animations are created with clock null, so this behavior is default.)

Timer

The Timer object executes TimerEvent objects after a time interval. We’ve added helpers to make Timer use simpler (see Clock.setTimeout and Clock.setInterval, above), and those should make everything much easier. However, there are some advanced tips that you might find useful.

Timers work on clocks. This means that you can pause and resume clocks, and all timers on that clock will respect that.

You can also alter the timeScale of a clock, and its timers will also respect that. There are some non-obvious consequences of this. When time runs backwards, a Timer will start “un-counting”. It will not fire events when played backwards.

Further, if a Timer rewinds to before its start time, it will clear its events and stop itself. This reflects the fact that, when time goes forwards again, game logic will probably add these events and start the timer again. Note that this can cause “orphan timers” to appear. An “orphan timer” is a timer that was scheduled to remove itself, such as in a setTimeout, but was rewound and cleared itself, so it will never remove itself. That orphan will sit on the clock doing nothing forever. If you are using negative time, you must audit your timers, or you may get unexpected accumulation and slowdown.

Tween and TweenManager

A Tween is a one-off transition from one number to another. It’s usually used for animation, but it can be applied to any number on any object.

Tweens use time. In previous versions of KiwiJS, they used game.time.clock exclusively. We’ve upgraded them in v1.2.0 to use any clock.

Tween are created on a TweenManager, so that’s where we set the clock. For example, if you were creating separate tweens for world and UI space, you might do this:

You may now call these new TweenManagers to obtain tweens that use custom clocks. You can pause, resume, and timeScale these clocks as you wish, and the tweens will follow along.

Because a Tween is a one-off, it should not act outside the bounds of its duration. Accordingly, if you rewind time to before the Tween began, it will consider itself finished, and signal itself for removal. (It will not fire its onCompleteCallback signal, however. This will only fire if it finishes at the end.)

Best Practice

We’ve spent a lot of time working with time, and we have some recommendations that will help you create to your full potential. These guidelines will help you create an integrated, functional timespace that is easy to control and to understand. You don’t need to be making a time-warp game to use these practices; they’re a good idea even for basic animations.

Use Time for Everything

You may think this goes without saying, but it’s an important guideline. There are many ways to animate your game world, and all of them seem to give you time-based animations, but some are more reliable than others.

For example, if you have a line that reads this.rotation += 0.01, you might think that this will rotate an object at a steady rate. It will fire once per frame, and that’s nice and even, right?

I’m afraid you’ve fallen into my trap. Frames are supposed to be even, but in practice they often aren’t. Browser performance can change based on system activity, background pages, etc. This rotation might slow and chop at unexpected times.

Use Rate

If you iterate a number on a per-frame basis, such as in this.rotation += 0.01, you should always multiply by clock.rate. This number will compensate for any slowdown on the previous frame.

Ensure that you use the rate of a clock. The default game.time.rate cannot be controlled as well as clock rates.

Note that rate cannot tell you how long the current frame will take to render, because it hasn’t happened yet. We must estimate from the previous frame. However, it has the sum effect of keeping everything very close to where it should be.

Use Tweens

Tweens are handy aids. Whenever you want to perform a single movement, consider using a tween. For example, if you want to lower the drawbridge on a castle, use a tween. There are many flavours available, which you can see in our tween tutorial.

Use Timers

When you want to schedule events, just use Clock.setTimeout or Clock.setInterval. They’re easy and reliable, and they work with game clocks.

Use Custom Clocks

It’s hard to retroactively add clocks into a scene, so if you think you’ll ever need more than one, do it at the start. We recommend creating “world” and “ui” clocks at a minimum.

When you create a clock, you should also create an associated TweenManager that uses that clock.

When you create entities, make sure you set their clock property to the correct clock. This will ensure that their animations use the correct clock as well. It will also give them onboard access to the custom clock, which is useful for accessing rate.

Pause Efficiently

Now that everything in your scene is controlled by time, you can ensure that they pause with a single command.

As of KiwiJS v1.2.1, these are functionally identical, but each have unique considerations. The timeScale method allows you to tween pause on and off, creating a brief slo-mo effect. However, if you are also using time manipulation elsewhere in your scene, you may find it difficult to track both paused and manipulated time. We recommend you use clock.pause() unless otherwise necessary.

Use maxFrameDuration on All Clocks

The maxFrameDuration property can prevent excessive skipping if the frame rate is very low. We find that this will often happen on the first frame of a scene, right after loading, or upon returning to a web page game after visiting another tab. Game objects can jump far outside their predicted boundaries, disrupting gameplay.

Use maxFrameDuration = 500 to limit this skip to half a second. This is usually enough to prevent objects from jumping too far, but still permits smooth movement even in the event of very slow or irregular frame rates. Don’t forget that it is a per-clock property; you should set it on all your clocks at once during State.create.

It Is Time

You have learned much about time management today. We hope that it is useful. Understanding the nature of time gives you access to tools that make your life as a developer much easier. Please give them a go, and let us know how you get on! And remember – where we’re going, we don’t need roads. (Oh yeah, we’re subtle.)

Next time: All the colors of the rainbow, or at least anything that fits into an RGBA color space.

New Time Properties and Animation (Kiwi.js v1.1.0)

Hello, and welcome to the sixth in a series of in-depth articles about Kiwi.js v1.1.0, now available for use at www.kiwijs.org. Today we’re talking about time and how it relates to smooth motion. I’m Ben Richards, and today I’ll show you some incredibly useful, incredibly simple animation tools.

Who Needs to Read This Post?

All users. Kiwi.js is built to move sprites around the screen, and these tools make it possible to do this much more smoothly.

Time Properties

We’ve added some new properties to the Game and its components. Together with those already available, these will give you more control over your scene. Key properties include:

Technical Information

This explains exactly how these properties work.

game.frame

This property counts the number of frames that the game has drawn since it loaded up.

This value is potentially inaccurate, because some frames may be dropped by the browser if it is busy. We recommend you use game.idealFrame for most situations. However, game.frame is guaranteed to be regular: it increases 1 per frame. It is thus useful if you value even intervals more than smooth time.

You can set the value of game.frame yourself. This should not be done unless you know what you’re doing.

game.idealFrame

This property counts the number of frames that would have been drawn since the game loaded up, had it maintained a perfect frame rate.

Use this property to drive smooth cyclic animations. For example, consider a tree swaying in the wind. Simply set tree.rotation = 0.1 * Math.sin( game.idealFrame * 0.01 ) every frame, and it will sway smoothly, even if the frame rate slows.

Unlike game.frame, this property cannot be changed by the user.

game.frameRate

This property controls the number of frames Kiwi.js attempts to render per second.

The maximum value is defined by your browser. It is normally 60. Kiwi.js defaults to 60 frames per second. You do not normally need to change this.

The minimum value is any number larger than 0. You might want a frame rate of 0.016, if you intend to update only once per minute. However, you cannot have a frame rate of 0.

When you set frame rate, it communicates to several behind-the-scenes components and updates some properties. Key among these is game.time.master.idealDelta, which will be explained later.

game.time.delta

A delta is a unit of change. In this case, it refers to the number of milliseconds since the last frame.

Under normal circumstances, this should be about 16.7. There are 1000 milliseconds per second, and if you have 60 frames in that second, each frame takes (1000 / 60) = 16.7 ms.

This value is not as useful as some others, as we have provided useful derivatives, but it is available for your use.

game.time.elapsed

This measures the time, in milliseconds, since the game loaded up.

We use this value, divided by game.time.master.idealDelta, to determine game.idealFrame.

game.time.now

This property tells you the time as measured at the start of this frame. You should use this value instead of Date.now() to ensure that all game objects are using the same value. It may take a few milliseconds to process the entire scene, and this may throw off certain calculations if you do not use a synced value.

game.time.rate

This property tells you how many ideal frames have passed since the last frame. It is one of the most useful properties in the time toolbox, and we’ll be spending some time explaining its nuances later in this article.

rate is determined by the delta divided by the idealDelta. For example, if you have a framerate of 60, your ideal delta is 16.7ms. If your last frame took 16.7ms (the actual delta), then the rate is 1.0. But if your last frame took 33.4ms, then your rate is 2.0. This tells you that you should have had 2 whole frames in that time. This is very useful information for creating smooth animations.

Note that rate makes no guarantees about the current frame. It cannot tell how long it will take to render. It can only say how long the last frame was. If you are using rate to govern speed smoothing, and you have a very uneven frame rate, any individual frame may be slightly off from where it should be. However, this is better than the alternative, where any deviation in frame rate will permanently alter the offset. After 1000 frames of half-frame-rate performance, a non-compensated solution will be 500 frames off; but a solution that uses rate to compensate will only ever be 1 frame off.

game.time.master.idealDelta

This property is calculated from game.frameRate. It is precisely equal to the number of milliseconds that should be taken per frame. With the default frame rate of 60 frames per second, this is 16.7ms. Ideal delta is used to compute other parameters.

And Now, Physics

You probably don’t consider yourself a physicist. If you do, what are you doing here? We have a dark energy cosmological paradigm to analyse! Shoo, shoo! Back to your laboratories!

However, you know a thing or two about physics. You can’t help it. You know that, when a mushroom man jumps up in the air, he’ll come down again. And you know that he’ll sort of do a curving motion as he goes.

We’re not interested in drawing paths or elegant graphs. All we care about is movement between frames. Once a frame is gone, it’s forgotten forever. This makes it very easy to think about physics.

Some Terms

We need four terms to make elegant motion: time, position, velocity and acceleration.

t = Time

Time is key to everything. It’s a one-dimensional arrow pointing ever forward.

p = Position

Position is simply where you are at this moment. It has no interest in time. Position will not change unless there is velocity.

Position, like velocity and acceleration, can be expressed as a vector of multiple dimensions. These are usually x and y, and sometimes z or other hyperdimensions. Fortunately, we can consider each dimension separately, so we will consider only one.

v = Velocity

Velocity is the change in position over time. In other words, when time passes, position changes. In coding terms, p += v * t. Velocity will not change unless there is acceleration. If velocity is negative, this simply means you are moving the other way. (This is in contrast with speed, which is always positive. A race car is not going at -100 if it turns around halfway down the track.)

a = Acceleration

Acceleration is the change in velocity over time. In other words, when time passes, velocity changes. In coding terms, v += a * t. Acceleration represents forces in the world: the thrust of an engine, friction of a surface, or gravity pulling you down.

Let’s Dash

Here’s a mushroom man. He’s off to rescue the President. But he’s on a time limit – he can’t dawdle! So he runs along.

This code will look familiar to anyone who’s completed basic Kiwi.js tutorials:

This seems pretty straightforward.

Let’s Hop

Imagine that our mushroom man decides to jump into the air. Here’s some code to govern his trajectory (please don’t expect this to look good on screen, or function at all in Kiwi.js):

This code will send our mushroom man up into the air at his base velocity. But this velocity will gradually change, slowing down, until he hangs at the peak of his jump. Then he will accelerate downwards until he reaches the ground again.

So far, so good.

Temporal Distortion Strikes

The mushroom man has 5 minutes to reach the President. At a normal pace, he’ll get there in 3 minutes. All seems well.

But what happens when the computer running our mushroom man slows down? Say it’s running at half speed. Now the mushroom man will get there in 6 minutes! That’s too slow! (And his animation will be too fast, because it works on time, not frames. He’ll be running in place!) What can we do?

Well, we could change our time limit based on the frame rate, but that would be complicated and it wouldn’t make the game run any faster.

It’s much better to smooth out the mushroom man’s movement. And to do this, we’re going to use the rate property.

Smooth Dash

This is a nice, simple fix. Remember that p += v * t. All we need to do is multiply velocity by time. We had previously assumed that time was always 1 (a single regular frame); but because rate tells us exactly how many frames should have passed since the last frame, we can use that instead.

Now, if the game is running at half frame rate, it doesn’t matter. The rate is 2, so the mushroom man runs twice as far per frame.

Note that we are not altering the actual value of mushroomMan.speed. This would quickly spiral out of our control: from 3 to 6 to 12 to 24. The mushroom man would hurtle uncontrollably into the distance. Soon he would reach the stars.

Smooth Hop

This one requires a little more thought. Velocity is not constant in a jump. It changes with time. However, this is no more complex than it has to be. When something changes with time, simply multiply by rate and it will be corrected. The code becomes as follows:

Now, when the mushroom man jumps in a low frame rate computer, he will move up further every frame, but his velocity will fall off faster every frame as well. Taken together, his trajectory is practically identical to that of a jump on a faster computer.

Rate-governed trajectories

As you can see, the trajectory has some artifacts because of its disjointed state, but it’s better than slowing down, right? This diagram exaggerates the artifacts; in reality, only extremely fast or forceful interactions would be distorted this much.

Going Slower? Go Faster!

This is the fundamental purpose of rate: to give you a speed governor, allowing you to move further when you slow down. We recommend you consider using rate as part of your standard workflow.

We’ve already found rate to be a useful asset in animating smooth action. We hope you do too!

In Review

When time slows down, you now have the tools to fix it. Just remember: if it changes with time, multiply by rate.

Benjamin D. Richards