Created
August 15, 2022 02:52
-
-
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.
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
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