Skip to content

Instantly share code, notes, and snippets.

@JSandusky
Last active November 11, 2018 19:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JSandusky/1dfe49a2fcf600f667f96f3338ddfcfb to your computer and use it in GitHub Desktop.
Save JSandusky/1dfe49a2fcf600f667f96f3338ddfcfb to your computer and use it in GitHub Desktop.
Angelscript camera shake
// Shakes an object using a # of shake intervals
// Intended behavior is to shake to random directions once per interval, optionally returning
// to the original reference direction
class Shake : ScriptObject
{
// internal state
private Vector3 referenceDirection;
private Vector3 shakeTowards;
private Vector3 shakeBase;
private float interval;
private float remainingInterval;
private int intervalsRun;
private float lastXSign = 0.0f;
private float lastYSign = 0.0f;
// editable configuration
Vector3 upAxis = Vector3(0, 1, 0); // up-axis for the look direction determination
float xShakePower = 0.2f; // scalar power of the random shake
float yShakePower = 0.5f; // scalar power of the random shake
float minInterval = 0.1f; // minimum duration of a shake interval
float maxInterval = 0.2f; // maximum duration of a shake interval
int intervalCount = 5; // how many shake intervals
float returnTime = 1.0f; // how long it should take to return to the initial reference direction
bool returnToRef = true; // whether to return to the recorded reference direction or not
bool oscillateX = true; // whether to enforce that each intervals X sign be different
bool oscillateY = false; // whether to enforce that each interval's Y sign be different
void Start()
{
BeginShake();
}
void BeginShake()
{
lastXSign = 0.0f;
lastYSign = 0.0f;
intervalsRun = 0;
// reference direction needs to be parent relative so we return to our parent relative direction
if (node.parent !is null)
referenceDirection = node.parent.worldTransform.Inverse() * node.worldDirection;
else
referenceDirection = node.worldDirection;
CalculateInterval();
}
void Update(float timeStep)
{
if (intervalsRun > intervalCount || (intervalsRun == intervalCount && !returnToRef))
{
self.Remove();
return;
}
if (remainingInterval - timeStep < 0)
CalculateInterval();
// this isn't a great way to smooth the positions ... it's quadratic or something (not bothering to plot)
// squaring would probably slow that down
float weight = 1.0f - (remainingInterval / interval);
if (intervalsRun >= intervalCount && returnToRef == true)
{
weight *= weight;
node.LookAt(node.worldPosition + node.worldDirection.Lerp(referenceDirection, weight));
}
else
node.LookAt(node.worldPosition + shakeBase.Lerp(shakeTowards, weight));
remainingInterval -= timeStep;
}
protected void CalculateInterval()
{
intervalsRun += 1;
shakeBase = node.worldDirection;
remainingInterval = interval = Random(minInterval, maxInterval);
shakeTowards = referenceDirection;
// determine right vector shake
float rightShake = Random(-xShakePower, xShakePower);
if (oscillateX && Sign(rightShake) == lastXSign)
rightShake = -rightShake;
lastXSign = Sign(rightShake);
// determine up vector shake
float upShake = Random(-yShakePower, yShakePower);
if (oscillateY && Sign(upShake) == lastYSign)
upShake = -upShake;
lastYSign = Sign(upShake);
shakeTowards += node.worldRight * rightShake;
shakeTowards += node.worldUp * upShake;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment