using UnityEngine; [RequireComponent(typeof(Rigidbody))] public class ElevatorSpringyButton : MonoBehaviour { public Transform buttonDirectionRoot; public ElevatorOuter ElevatorOuter; public ElevatorBox box; [Header("Movement limits")] public float minX = 0f; public float maxX = 0f; public float minY = 0f; public float maxY = 0f; public float minZ = 0.005f; public float maxZ = 0f; [Header("Visuals")] public Renderer[] targetRenderers; public Material defaultMaterial; public Material pressedMaterial; [Header("Spring Settings")] public float springForce = 300f; // how strong it returns public float damping = 8f; // prevents vibration [Header("Button Type Settings")] public bool isFloorButton; public bool isInsideButton; public bool isCloseDoorsButton; public int designatedFloor; private Rigidbody rb; private Vector3 restLocalPos; public bool disabled; private bool isAwaitingResponse = false; void Start() { rb = GetComponent(); rb.useGravity = false; // initial local rest position restLocalPos = buttonDirectionRoot.InverseTransformPoint(transform.position); } void FixedUpdate() { // 1. Local pos Vector3 localPos = buttonDirectionRoot.InverseTransformPoint(transform.position); // 2. Spring in LOCAL space Vector3 spring = (restLocalPos - localPos) * springForce; // 3. Damping also must be in LOCAL space!! Vector3 localVelocity = buttonDirectionRoot.InverseTransformDirection(rb.velocity); localVelocity *= damping; spring -= localVelocity; // 4. Convert spring to WORLD space Vector3 worldSpring = buttonDirectionRoot.TransformDirection(spring); // 5. Apply rb.AddForce(worldSpring, ForceMode.Acceleration); // --- 3. Compute new local pos after physics --- Vector3 newLocalPos = buttonDirectionRoot.InverseTransformPoint(transform.position); //Debug.Log(spring); // --- 4. Clamp to allowed ranges --- newLocalPos.x = Mathf.Clamp(newLocalPos.x, minX, maxX); newLocalPos.y = Mathf.Clamp(newLocalPos.y, minY, maxY); newLocalPos.z = Mathf.Clamp(newLocalPos.z, minZ, maxZ); // --- 5. Convert back to world and move via Rigidbody --- Vector3 worldPos = buttonDirectionRoot.TransformPoint(newLocalPos); rb.MovePosition(worldPos); //Keeping the buttons firing until their needs have been met if (!isAwaitingResponse || disabled) return; if (!isInsideButton && box != null) { if (box.currentFloor == designatedFloor) StartCoroutine(DeactivateAfterDelay(0.5f)); else Pressed(); return; } if (isInsideButton && box != null) { if (isFloorButton) { if (designatedFloor == box.currentFloor) StartCoroutine(DeactivateAfterDelay(0.5f)); else Pressed(); return; } if (isCloseDoorsButton) { if (box.state == ElevatorState.ClosingDoors|| box.state == ElevatorState.Moving) StartCoroutine(DeactivateAfterDelay(0.5f)); else Pressed(); return; } else { if (box.state == ElevatorState.OpeningDoors || box.state == ElevatorState.Moving) StartCoroutine(DeactivateAfterDelay(0.5f)); else Pressed(); return; } } } public void Pressed() { isAwaitingResponse = true; foreach (Renderer renderer in targetRenderers) { renderer.material = pressedMaterial; } //Debug.Log("Button is pressed"); if (ElevatorOuter != null && !isInsideButton) ElevatorOuter.CallElevator(); if (disabled) { StartCoroutine(DeactivateAfterDelay(0.5f)); return; } if (box != null && isInsideButton) { if (isFloorButton) { box.targetFloor = designatedFloor; if (box.targetFloor != box.currentFloor) { Debug.Log("Lift transfer sequence"); StartCoroutine(box.LiftTransferSequence()); } else StartCoroutine(box.OpenDoors()); return; } if (isCloseDoorsButton) { //Debug.Log("Closing Doors"); StartCoroutine(box.CloseDoors()); return; } else { StartCoroutine(box.OpenDoors()); //Debug.Log("Opening Doors"); return; } } } public void Deactivate() { Debug.Log("Deactivating"); //if (isAwaitingResponse) return; isAwaitingResponse = false; foreach (Renderer renderer in targetRenderers) { renderer.material = defaultMaterial; } } private System.Collections.IEnumerator DeactivateAfterDelay(float delay) { yield return new WaitForSeconds(delay); //isAwaitingResponse = false; Deactivate(); } }