Skip to content

Instantly share code, notes, and snippets.

@hvent90
Created April 5, 2020 01:53
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 hvent90/63c5f8cd9312462521d820c97cc5134d to your computer and use it in GitHub Desktop.
Save hvent90/63c5f8cd9312462521d820c97cc5134d to your computer and use it in GitHub Desktop.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SphereShake : MonoBehaviour
{
public bool gravity;
[Header("Shake")]
// When enabled, the object will shake.
public bool addRandomForce;
// The strength of force applied to the object.
public float forceStrength;
// The interval between each time the force is applied.
public float forceInterval = 1;
// The type of force applied. I personally use impulse.
public ForceMode forceMode;
// The interval between each time the object
// is reset to position 0, 0, 0 in local space.
public float reset = 1f;
[Header("Rotate")]
// When enabled, the object will rotate.
public bool addRandomRotation;
// The interval between each time the object
// has a new target to rate towards.
public float rotationFrequency = 1f;
// The speed at which the object rotates.
public float rotationSpeed = 1f;
// The limit in degrees in which the object will rotate.
// Example: rotationLimit of 180 will mean that the object will never
// rotate more than 180 degrees from a rotation of (0, 0, 0).
public float rotationLimit = 45f;
/** Properties used for shaking */
// The rigidbody for which we use to shake by applying force.
private Rigidbody rb;
// The time when we began adding force. This is used to keep track
// of when the next time force should be applied.
private float lastAddForceTime;
// This is used to determine when an inverse force should
// be applied. Check the comments on Twitch() for more info.
private int forceUsageCount;
// The direction of the current force.
private Vector3 force;
// The time when we last reset the local position. This is
// used to keep track of the next time to reset the position.
private float lastResetTime;
/** Properties used for rotating */
// The time when we started rotating towards a new target rotation.
// This is used to keep track of when the next time a new
// target rotation should be set.
private float lastRotateTime;
// The target rotation that the object is rotating towards.
private Quaternion endingRotation;
// Start is called before the first frame update
void Start()
{
rb = gameObject.AddComponent<Rigidbody>();
}
void Update()
{
if (addRandomForce)
Twitch();
if (addRandomRotation)
Rotate();
// Shaking sphere tends to drift away from home.
// Occasionally reset it to (0, 0, 0) in local space.
Reset();
}
// Reset the object to local position (0, 0, 0).
void Reset() {
if (Time.time - lastResetTime > reset) {
lastResetTime = Time.time;
transform.localPosition = Vector3.zero;
}
}
// Rotate the object towards the target rotation.
void Rotate() {
float currentTime = Time.time;
if (currentTime - lastRotateTime > rotationFrequency) {
lastRotateTime = currentTime;
endingRotation = NewRotation();
}
transform.rotation =
Quaternion.RotateTowards(
transform.rotation,
endingRotation, rotationSpeed * Time.deltaTime);
}
// Generate a new random rotation that is
// within the rotationLimit.
Quaternion NewRotation() {
Vector3 angles = new Vector3(
Random.Range(-rotationLimit, rotationLimit),
Random.Range(-rotationLimit, rotationLimit),
Random.Range(-rotationLimit, rotationLimit)
);
return Quaternion.Euler(angles);
}
// Semi-randomly twitch the object.
// First, apply a force in vector N.
// Then, apply a force in vector -N so that the object goes back towards 0, 0, 0.
// Then, apply a new force in vector M.
// Apply a new force in vector -M. Rinse and repeat.
void Twitch()
{
float currentTime = Time.time;
if (currentTime - lastAddForceTime < forceInterval)
{
return;
}
lastAddForceTime = currentTime;
// Set gravity
rb.useGravity = gravity;
// Determine whether to create a new vectorized force
bool changeForce = forceUsageCount % 2 == 0;
if (changeForce)
{
// Stop the orb's current velocity vector
rb.AddRelativeForce(-force, forceMode);
// Generate a new vectorized force
force = NewForce();
} else {
// Go in opposite direction
rb.velocity = Vector3.zero;
force *= -1f;
}
rb.AddRelativeForce(force, forceMode);
forceUsageCount++;
}
Vector3 NewForce()
{
return new Vector3(Random.value * forceStrength, Random.value * forceStrength, Random.value * forceStrength);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment