Friday, October 14, 2011

Value Controller : Features





Recently our team released our very first Unity asset, the Value Controller. VC is a nifty component designed to take some of the pain out of dealing with timers and values that need to change over time.

Read on to find out how it can help you in your projects.

What it is...
Simply put it's a bucket to keep a bunch of timers in. In short it's the next best thing since duct tape.

What it is not!
Value Controller is not a visual component nor an editor script. It doesn't include any artsy stuff.
Well almost.

Deeply insightful summary, wouldn't you say? Jokes aside let's look under the hood of this thing.

Value Controller
The Value Controller package consists of two major components: the Controller class and a Dynamic Value class. The Controller manages all your Dynamic values, tells them when to update their running values and so on. It can also Start or Suspend the update process on all of the values it's keeping track of.

A Dynamic value is the actual workhorse of this whole system. In essence it's a timer. It can have any kind of value, intervals, loops, stacks and so on.

VC also keeps track of Constant values. These are basically just values. They do not change over time and unless you change their values directly they will stay the same through out the lifetime of the Controller.

To make the whole system even cooler :) we've provided users with the ability to assign callbacks to various types of events raised by VC and its components. You can get notified when a value lapses (finishes updating), a stack on a stackable value lapses, or an interval on counter value lapses.

So, in simple terms the Value Controller is a class with two buckets in it. One bucket keeps Constant values the other keeps all the Dynamic ones. You can get notified about various events taking place and at any point in time you can ask VC to tell you the total of all the values it currently has. That last bit is actually the best part about the whole system.

You throw all kinds of values into these buckets and then simply get their total whenever you want. This means that an instance of the VC could be used to back your Healthbar, Castbar, Shield Device, Battery Meter or anything else that needs a numeric value of some sort to support it. There are hundreds of possible applications for this system. Hell, in the tutorial project that we included with the package we used the VC to move our Sun and Moon according to the time of day.

Anyway. Let's take it one step at a time. Now that you have a basic idea of what VC is all about, we can examine each component in detail.

Constant Values
Even though constant values just sit there and don't actually do anything they are an integral part of this system. They primarily act as offsets to your Dynamic values making things like rechargeable device effects extremely easy to create.
By keeping Constant values under the same roof with the Dynamic ones we can deal with more complex scenarios without breaking even a bit of finger sweat.

Dynamic Values
As we already mentioned above Dynamic value is the glue that holds this whole thing together. Depending on its type and the value you assign to it, you can get some real interesting results.

There are 7 types of Dynamic values available in the VC package. Let's have a quick look at each one.

Simple
As the name suggests this is the most basic Dynamic value type. It gradually increases or decreases its object value over a fixed period of time.

One possible application for this kind of values would be to create Healing or Damage over time effects. Since the value is gradually changed over a specified period of time you can easily use it to 'animate' your health bars and whatnot.

Here is a list of its parameters:
  • Value - This is the object value we want to mess with; 
  • Duration - The amount of time over which the target value should be reached; 
  • Update Mode - Tells VC if we are moving away from a value toward zero or the other way around; 
  • Disposal Mode - Tells VC what to do with the value when it's done updating it; 
This value will change every frame and invoke a ValueLapsed callback when done.
Here is one of the examples of how you would create this value type from code:

// Simple Dynamic value
myValueController.AddDynamicValue(-25, 10, FromValueToZero, Automatic);


Here we have a value that will start out at -25 and over 10 seconds it will increase to 0. As soon as the value fully updates, VC will invoke a ValueLapsed callback (if you specified a reference to one) and then it will get automatically disposed (removed from the internal collection) by the VC.



Simple Stackable
This is an extension of the Simple dynamic value type that supports stacks. For those of you who play modern MMOs this concept should be quite familiar :)

This value type was created to simplify the task of dealing with buffs and other similar mechanisms common to RTS and RPG games.

List of parameters:
  • Value - This is the object value we want to change; 
  • Duration - The amount of time over which the target value should be reached; 
  • Stacks - Number of initial stacks for this value; 
  • Update Mode - Tells VC if we are moving away from a value toward zero or the other way around; 
  • Disposal Mode - Tells VC what to do with the value when it's done updating it; 
This value will change every frame and invoke a ValueStackLapsed callback when a running stack lapses. Once all stacks lapse the ValueLapsed callback will be invoked.

An example of how you would create this value type from code:

// Simple Stackable Dynamic value
myValueController.AddDynamicValue(20, 3, 4, FromValueToZero, Automatic);


This will instantiate a Dynamic value that will start out with 4 stacks and then reduce from 20 to 0 over 3 seconds. Since it has 4 stacks it will do so 4 times.

Dynamic value class has many properties that let you easily check how many stacks you have left and work out all other derivative values such as remaining time, values etc.
You also have the option to add or remove stacks from a running value of this type. Making it very easy for you to compound or cancel its effects.

Counter 
This Dynamic value type was designed to make coding counters and pretty much anything that ticks as simple as humanly possible. Unlike Simple dynamic value this value type will not get updated every frame (well not as far as the user is concerned). Instead it will 'tick' once per specified period of time. Count up, down or sideways using any interval you want.

List of parameters:
  • ValueFrom - This is the starting value of the counter; 
  • ValueTo - This is the target value of the counter; 
  • IntervalValue - Value by which the difference between the ValueFrom and ValueTo should be changed every tick; 
  • IntervalDuration - The amount of time that should pass for the counter to tick; 
  • Disposal Mode - Tells VC what to do with the value when it's done updating it; 
This value will invoke a ValueIntervalLapsed callback every time an interval period lapses.
Once all intervals lapse the ValueLapsed callback will be invoked.

An example of how you would create this value type from code:

// Counter Dynamic Value
myValueController.AddDynamicValue(100, 0, 5, 1.5F, Automatic);



In this example we created a Counter dynamic value that will start out at 100 and countdown to 0. Each tick will reduce the count by 5 and take exactly 1.5 seconds to do so.
In short this thing will go from 100 to 0 in 30 seconds.

Note: As you may have noticed all the values we specified are positive. The dynamic value class will figure out the correct update direction based on the ValueFrom and ValueTo parameters. This way you don't have to worry about counting in the wrong direction.

Timer
This Dynamic value type is the simplest one of them all. The only thing it does is tick. It will 'tick' once per specified period of time until the end of time. Tick, tick, tick, tick...

List of parameters:
  • IntervalDuration - The amount of time that should pass for the counter to tick; 
This value will invoke a ValueIntervalLapsed callback every time an interval period lapses.
No other callbacks will be invoked by this value type.
Here is an example of how you would create this value type from code:

// Timer Dynamic value
myValueController.AddDynamicValue(2.35F);



This will create a dynamic value that will tick once every 2.35 seconds. Doesn't get any simpler than this.
There are hundreds of uses for this type of values. Can you find them all? Email us if you do.

Continuous
At some point during the development of the tutorial for this package we realized that there was a need for a dynamic value that is a bit more functional than a Timer and less constrained than a Counter. This value type is exactly that kind of mutant.

It doesn't have a target value because it just runs keeps updating forever. Well technically not forever, it will lapse when it reaches maximum / minimum allowed Float value.

List of parameters:
  • ValueFrom - This is the starting value of the counter; 
  • IntervalValue - Value by which ValueFrom should be increased or decreased for every tick; 
  • IntervalDuration - The amount of time that should pass for the counter to tick; 
  • Disposal Mode - Tells VC what to do with the value when it's done updating it; 
This value will invoke a ValueIntervalLapsed callback every time an interval period lapses.Once all intervals lapse the ValueLapsed callback will be invoked.

An example of how you would create this value type from code:

// Continuous Dynamic value
myValueController.AddDynamicValue(0, 1, 1, Automatic);



So, we created a dynamic value that would start out at 0 and increase by 1 every second. Pretty boring I know. Here is one more example, only it's way cooler this time, I promise.

We will create a dynamic value that will count elapsed game time for as long as the player is in game. Our game time passes fairly quickly, 1 game hour per 1 second and it is displayed by some fancy UI thingy elsewhere in our code.

// Continuous Dynamic value
myValueController.AddDynamicValue(0, 1, 0.0167F, Automatic);

// Somewhere in our ValueIntervalLapsed handler
var missionTime = myValueController.GetAllValuesTotal().ToDateTimeFromHours();

// Then format the DateTime value
var missionTimeString = missionTime.ToString("HH:mm");


Let's see what we did here. First, we created a value that would increase by 1, once per every 16.7 milliseconds, which roughly amounts to 1 hour of game time per second of real time. That's one thing we wanted.

Then in our tick handler we formatted the output value of our VC as a DateTime value. For that we used one of many cool extension methods that are included in this package (free of charge, I might add :D... ok that's a lie, nothing is free).

To make that DateTime value a little more appealing to our players we used a .NET framework method to format the resulting string.
All you would need to do now is draw the GUI element to show the time. And you can do that in whichever way you want.
Now your players will get to see how much time has passed since the beginning of the game and it took us 3 lines of code to set the whole thing up.

Continuous Looped
This value type is a variation of the Simple dynamic value. The only difference between the two is that this value restarts as soon as the target value is reached.

List of parameters:
  • ValueFrom - This is the starting value of the counter; 
  • ValueTo - This is the target value of the counter; 
  • Duration - The amount of time that should pass before the starting value reaches the target value; No callbacks will be invoked by this value type.
Looped value types NEVER get disposed by the VC and will keep running until you manually remove them.

An example of how you would create this value type from code:

// Continuous Looped Dynamic value
myValueController.AddDynamicValue(38, 12, 5);


This will create a dynamic value that will gradually reduce from 38 to 12 over the course of 5 seconds. At which point the whole thing will restart.

Intervals Looped
This value type is a variation of the Counter dynamic value. As the name suggests, the difference is that this dynamic value is looped. Furthermore, the ValueLapsed callback is not raised by this value.

List of parameters:
  • ValueFrom - This is the starting value of the counter; 
  • ValueTo - This is the target value of the counter; 
  • IntervalValue - Value by which ValueFrom should be increased or decreased for every tick; 
  • IntervalDuration - The amount of time that should pass for the counter to tick; 
This value will invoke a ValueIntervalLapsed callback every time an interval period lapses.
Once all intervals lapse and the target value is reached the dynamic value will be restarted.
No other callbacks will be invoked by this value type.

Looped value types never get disposed by the VC and will keep running until you manually remove them.

An example of how you would create this value type from code:

// Intervals Looped Dynamic Value
myValueController.AddDynamicValue(0, 12, 1, 60);


This will create a dynamic value that will tick once every 60 seconds, increasing the From value by 1 until it reaches 12. At that point the whole thing will restart. Sounds familiar right :)
Yes you guessed it, it's a clock!

This value type makes it very very very vewy very easy to make all kinds of time keeping devices.

Let's take a look at another example. This time we will make a timer that will keep time for our game world. So that your NPCs will know when it's time to go to work or pretend to go to work or pretend to pretend to go to work but actually stay home and sleep. (An option many of us here employ on a regular basis, by the way.)

First, a few requirements:
  • Game time should advance 60 times faster than real time (i.e. 1 minute = 1 game hour)
  • Displayed time should have 'hours : minutes' format and include minutes; 
  • We need to show current game world time somewhere on the user interface; 
We'll create the value that will act as our timer first.

// Intervals Looped Dynamic value
myValueController.AddDynamicValue(0, 1440, 1, 1);



Since we care about minutes we set the target value to 1440 (the number of minutes in a day). Then we said that the timer should tick once per second and count up 1 minute of game time.

// Somewhere in our ValueIntervalLapsed handler
var gameTime = myValueController.GetAllValuesTotal().ToDateTimeFromMinutes();


Similarly to the Continuous dynamic value example, we converted our value into DateTime. This time we used a different extension method though, since we are counting minutes and not hours.

// Then format the DateTime value
var gameTimeString = gameTime.ToString("HH:mm");


All you need to do now is draw the time string on your user interface.
Three lines of code and we have a fully functioning timer for our game.

Conclusion
This is just a basic overview of what you can do with the Value Controller package. In the tutorial project included with the package we have gone a step further and used VC to run a tiny little village :)

If you have questions about the package post a comment or send us an email.
We are constantly looking for ways to improve this component further so don't be shy to share your thoughts and criticisms.

Coming up : Digital Healthcare and You!
To demonstrate just how easy it is to use the Value Controller to create stuff that matters in your projects we will post a short tutorial over the weekend.

We will create a Health and Armor component that will track how many hit points the player has and also keep track of his or her armor. In addition, we will implement a mechanism to heal and damage the player.



A few dozen lines and you will have a self-contained system that will interact with your game logic and require ZERO maintenance :)


Laters,
Alex

No comments:

Post a Comment