Skip to content

Instantly share code, notes, and snippets.

@Ooseykins
Created August 15, 2022 02:52
Show Gist options
  • Save Ooseykins/917670cd36ef6106e88911b8bcd65c76 to your computer and use it in GitHub Desktop.
Save Ooseykins/917670cd36ef6106e88911b8bcd65c76 to your computer and use it in GitHub Desktop.
Script for sliding bracelets up and down a character's arm, or other simple incline-plane-like simulations. SliderTransform origins will be placed along the topmost edge of the rendered gizmo.
using UnityEngine;
public class TransformSlider : MonoBehaviour {
[Min(0.01f)]
public float length = 0.1f;
float totalOffset;
public float scale = 0.05f;
public AnimationCurve scaleCurve = AnimationCurve.Linear(0f,1f,1f,0.5f);
public Vector3 gravity;
[System.Serializable]
public struct SliderTransform {
public Transform transform;
[HideInInspector]
public float t;
[HideInInspector]
public float velocity;
[Range(0,1)]
public float staticFriction;
[Range(0, 1)]
public float slidingFriction;
[Range(0, 180)]
public float maxAngleStart;
[Range(0, 180)]
public float maxAngleEnd;
public float width;
[HideInInspector]
public float offset;
}
[HideInInspector]
public AudioSource audioSource;
[Min(0)]
public float velocityVolumeMultiplier;
public AudioClip[] audioClips;
public SliderTransform[] sliderTransforms;
private void OnDrawGizmosSelected() {
Gizmos.color = Color.red;
Gizmos.DrawLine(transform.position,transform.position + transform.forward * length);
int sphereCount = 13;
for( int i = 0; i < sphereCount; i++) {
float prog = (float)i*(1f/((float)sphereCount-1));
Vector3 pos = Vector3.Lerp(transform.position,transform.position+transform.forward * length, prog);
Gizmos.DrawWireSphere(pos, scaleCurve.Evaluate(prog) * scale);
}
}
private void Start() {
audioSource = GetComponent<AudioSource>();
totalOffset = 0f;
for( int i = 0; i < sliderTransforms.Length; i++) {
sliderTransforms[i].t = 1f;
sliderTransforms[i].offset = totalOffset;
totalOffset += sliderTransforms[i].width/length;
}
}
private void Update() {
float inclineAngle = Mathf.Deg2Rad * (Vector3.Angle(gravity, transform.forward) - 90f);
float angleSign = Mathf.Sign(inclineAngle);
inclineAngle = Mathf.Abs(inclineAngle);
float maxCollisionVel = 0f;
for (int i = 0; i < sliderTransforms.Length; i++) {
float mu = sliderTransforms[i].staticFriction;
if( sliderTransforms[i].velocity != 0f) {
mu = sliderTransforms[i].slidingFriction;
}
float a = gravity.magnitude * ( Mathf.Sin(inclineAngle) - Mathf.Cos(inclineAngle) * mu);
bool negForce = a < 0;
a = a * -angleSign;
sliderTransforms[i].velocity += a * Time.deltaTime;
if( negForce ) {
if( sliderTransforms[i].velocity > 0f && angleSign > 0 ) {
sliderTransforms[i].velocity = 0f;
}
if (sliderTransforms[i].velocity < 0f && angleSign < 0) {
sliderTransforms[i].velocity = 0f;
}
}
float collisionVel = 0f;
float lastT = sliderTransforms[i].t;
float sign = Mathf.Sign(sliderTransforms[i].velocity);
sliderTransforms[i].t += sliderTransforms[i].velocity / length * Time.deltaTime;
if ( sign > 0) {
int index = i + (int)sign;
if( index >= 0 && index < sliderTransforms.Length && sliderTransforms[i].t+sliderTransforms[i].width/length/4f > sliderTransforms[index].t-sliderTransforms[index].width/length/4f ) {
collisionVel = Mathf.Abs(sliderTransforms[i].velocity);
sliderTransforms[index].velocity += sliderTransforms[i].velocity / 2f;
sliderTransforms[i].velocity = sliderTransforms[i].velocity / 2f;
sliderTransforms[i].t = lastT;
}
}
else if( sign < 0) {
int index = i + (int)sign;
if (index >= 0 && index < sliderTransforms.Length && sliderTransforms[i].t-sliderTransforms[i].width/length/4f < sliderTransforms[index].t+sliderTransforms[index].width/length/4f) {
collisionVel = Mathf.Abs(sliderTransforms[i].velocity);
sliderTransforms[index].velocity += sliderTransforms[i].velocity / 2f;
sliderTransforms[i].velocity = sliderTransforms[i].velocity / 2f;
sliderTransforms[i].t = lastT;
}
}
if( sliderTransforms[i].t >= 1f-(totalOffset-sliderTransforms[i].offset)) {
sliderTransforms[i].t = 1f - (totalOffset - sliderTransforms[i].offset);
sliderTransforms[i].velocity = 0f;
collisionVel = 0f;
}
if (sliderTransforms[i].t <= sliderTransforms[i].offset) {
sliderTransforms[i].t = sliderTransforms[i].offset;
sliderTransforms[i].velocity = 0f;
collisionVel = 0f;
}
maxCollisionVel = Mathf.Max(collisionVel, maxCollisionVel);
float targetAngle = Mathf.Lerp(sliderTransforms[i].maxAngleStart, sliderTransforms[i].maxAngleEnd, sliderTransforms[i].t);
MoveToPosition(sliderTransforms[i].transform, targetAngle, sliderTransforms[i].t);
}
if( audioSource != null && audioSource.enabled && maxCollisionVel > 0f && audioClips.Length > 0 ) {
if( !audioSource.isPlaying) {
audioSource.PlayOneShot(audioClips[Random.Range(0, audioClips.Length - 1)],Mathf.Clamp01(maxCollisionVel*velocityVolumeMultiplier));
audioSource.pitch = Random.Range(0.95f, 1.05f);
}
}
}
void MoveToPosition(Transform trans, float targetAngle, float t) {
float rad = scaleCurve.Evaluate(t) * scale;
trans.position = Vector3.Lerp(transform.position, transform.position + transform.forward * length, t);
trans.LookAt(transform.position + transform.forward * length * 2f, -gravity);
trans.position = trans.position + trans.up * rad;
Quaternion prevRot = trans.rotation;
trans.LookAt(trans.position + gravity, trans.forward);
trans.rotation = trans.rotation * Quaternion.Euler(-90, 0, 0);
trans.rotation = Quaternion.RotateTowards(prevRot, trans.rotation, targetAngle);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment