Jump to content
  • Advertisement
  • entries
    503
  • comments
    1888
  • views
    334889

Under-drive & Over-drive

Sign in to follow this  
EDI

315 views

Under-drive & Over-drive

This is a situation that comes up a lot in game development; It recently reared its head again when adding a 'ghost writer' text effect to our NPC dialogue system.

I thought I would take a moment to talk about the crux of the issue so that some folks might understand it better.


The Problem

When developing a 'ghost writer' text feature, I found myself first doing a word for word string build up.

An update event would happen, and I would simply move my nextWordIndex forward by one.

To throttle this I had a countdownTimer, which, when a new word was shown, I added an amount to; and would decay this timer in the update method.

So to recap, new word shown, timer set, timer elapses, show next word.


My co-developer Brian, saw this effect and felt it was too choppy; instead he wanted it to spit out single characters, instead of discrete words.

I made some quick modifications to test this, and found that adjusting my CPS (characters per second) did nothing up to a point.

Since I have seen this effect before, I quickly realized what was wrong.


Discrete Incrementing

Because in my update method, I would check for timer expiration, and perform the wordIncrement (now character increment) this meant, I could NEVER achieve faster word incrementing than One Character per Frame.

At a 1:1 ratio this is considered 'Drive' the input shaft (the game loop) is turning the output shaft (the cps incrementor) at 100%.

When I was doing words per second I was working at a comfortable Under-Drive, or, a ratio less than 1:1; such that multiple discrete frames would have to pass before the next word was shown.

[sub]I often relate programming to real-world mechanics, in this case, some may see that a game-loop, to me feels a lot like a drivetrain of some machine.[/sub]


Simply increasing my CPS in an effort to speed up the incrementor saturated into 1CPS.


The Solution

The root of the problem here, is that I am relying on a timer expiration and a single fixed increment of an index.

This conditional discrete operation means that it is fixed to a maximum of the frame rate.

Thankfully the solution is very simple

First, it probably makes sense to generalize how we are displaying the ghost-written string; to instead of string-building, using a sub-string instead:

Imagine text.subString(0,Math.floor(ll)); where 0 is the starting index, and ll is lineLength; the number of characters to display (with a max of text.length, of course).

[sub]Note the Math.floor(), ll is a floating point variable (this is essential) but we can only display integer length strings, so a truncation is needed.[/sub]

With this, we can remove our countdownTimer machinery, and instead, simply 'drive' ll:

ll += frameTimeSeconds * CPS;

We can see above that we push ll forward using our measured frame time, and a constant 'Characters Per Second' the throttle by which you wish to print characters.

a typical under-drive scenario might be when we are achieving a frame time of 0.016 or 60FPS; meaning each frame is executing at 1/60th of a second.

If we imagine a CPS of 1 (one character printed per second) we see that we will push ll forward only 0.016 'characters' per frame: this is under-drive because the game loop is 'rotating' multiple 'revolutions' to only a single 'revolution' (character increment).


In an over-drive scenario; let us imagine we are operating with a low frame rate '0.033' (30FPS); and a higher CPS of 40 (40 characters printed per second).

[sub]1.32 = 0.033 * 40[/sub]

We can see here we are now pushing ll one whole character and about 1/3 of a character per frame, this means we are operating at a ratio over 1:1, or 'Over-drive'.

The important effect here is that we are preserving non-integral time accumulation, instead of just clamping/saturating it away, as over-drive increases, we could/would begin to see multiple discrete characters being printed per-frame, in order to 'keep up'.
Sign in to follow this  


0 Comments


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!