This class is one I turn to it again and again, especially when animating OSD components or creating camera controllers.
What it does is update an object's position and velocity towards a target destination over an arbitrary amount of time. The spring velocity will be damped over time meaning it slows down as it reaches its target.
To use it as a camera spring create one for the camera position and another for the target and update these values every frame, then call Update() passing the frame delta.
using Microsoft.Xna.Framework;
namespace Utils
{
public class CriticallyDampedSpring
{
public CriticallyDampedSpring()
{
SmoothTime = 100.0f;
}
public float SmoothTime { get; set; }
public Vector3 Current { get; set; }
public Vector3 SpringVelocity { get; set; }
public Vector3 Target
{
get { return mValTo; }
set
{
mValFrom = Current;
mValTo = value;
}
}
public void Update(float frameTime)
{
Vector3 diff, temp;
float omega, rX, expo;
omega = 2.0f / SmoothTime;
rX = omega * frameTime;
expo = 1.0f /
(1.0f + rX +
(kQuadraticCoef * rX * rX) +
(kCubicCoef * rX * rX * rX));
diff = mValFrom - mValTo;
temp = (SpringVelocity + (diff * omega)) * frameTime;
SpringVelocity = (SpringVelocity - (temp * omega)) * expo;
Current = mValTo + ((diff + temp) * expo);
}
// Start position of spring head
private Vector3 mValFrom = Vector3.Zero;
// Target position of spring head
private Vector3 mValTo = Vector3.Zero;
private const float kQuadraticCoef = 0.48f;
private const float kCubicCoef = 0.235f;
}
}
Boredom's a terrible thing but the website Dinosaur Comics is not. So when, in the midst of holiday boredom I stumbled across this comic I decided have a go at implementing it.
I don't often get to use PHP so I decided it'd be a good excercise for me to use the language. There's a few implementations of this online but mine's the only one I've seen which handles the "[goto panel two and play recursively] / [choose any ol' noun from the dictionary]" block.
You can see it in action here.
<?php
function RandomBool()
{
return 0.01 * rand(0, 100) >= 0.5;
}
function RandomLine($filename)
{
$lines = file($filename);
return $lines[array_rand($lines)];
}
function GetPrefix($noun)
{
$vowels = array("a", "e", "i", "o", "u");
if(in_array(strtolower($noun[0]), $vowels))
{
return "an";
}
else
{
return "a";
}
}
function RandomNoun()
{
return trim(RandomLine("../protected/data/nouns.txt"));
}
function RandomFromArray($array)
{
$key = array_rand($array);
return $array[$key];
}
function CharacterType($index)
{
$adjectives = array(
array("meat", "robot", "urban", "silver", "animal",
"sex", "fruit", "adult", "child", "famed",
"licensed", "problem"),
array("meaty", "famous", "infamous", "wide-eyed",
"sullen", "attractive", "competing", "powerful",
"space", "hairy", "social"));
$nouns = array(
array("stylist", "engineer", "astronaut", "ecologist",
"planner", "model", "smith", "dancer", "producer",
"lawyer", "loner", "priest", "criminal", "prodigy",
"terrorist", "dinosaur", "clone", "athelete",
"head of state"),
array("teen", "doctor", "ghost", "artist", "surgeon",
"corsetièr", "superhero", "cartoonist",
"spouse", "dog", "religion",
"medical health professional", "senior", "telepath",
"jerk", "family"));
$adj = RandomFromArray($adjectives[$index]);
$noun = RandomFromArray($nouns[$index]);
$prefix = GetPrefix($adj);
return $prefix . " " . $adj . " " . $noun;
}
function BuildCharacter()
{
$verbs = array("create", "destroy", "get over", "bewitch",
"unmask", "sex up", "steal", "hug", "give birth to",
"team up with", "profit from");
$result = CharacterType(0);
$result = $result . " who wants to " . RandomFromArray($verbs) .
" " . CharacterType(1);
$result = $result . " but is blocked in this desire by ";
if (RandomBool())
{
$result = $result . BuildCharacter();
}
else
{
$noun = RandomNoun();
$prefix = GetPrefix($noun);
$result = $result . $prefix . " " . $noun . ".";
}
return $result;
}
echo BuildCharacter();
?>