Last active
November 11, 2018 19:21
-
-
Save JSandusky/1dfe49a2fcf600f667f96f3338ddfcfb to your computer and use it in GitHub Desktop.
Angelscript camera shake
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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