Ropes breaking and shit
This commit is contained in:
376
Assets/Scripts/Minigames/DivingForPictures/RopeBreaker.cs
Normal file
376
Assets/Scripts/Minigames/DivingForPictures/RopeBreaker.cs
Normal file
@@ -0,0 +1,376 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using GogoGaga.OptimizedRopesAndCables;
|
||||
|
||||
/// <summary>
|
||||
/// Component that allows breaking a rope in half.
|
||||
/// Attach this to the same GameObject that has a Rope and LineRenderer component.
|
||||
/// </summary>
|
||||
public class RopeBreaker : MonoBehaviour
|
||||
{
|
||||
[Header("Break Settings")]
|
||||
[Tooltip("Position along rope where break occurs (0-1)")]
|
||||
[Range(0f, 1f)]
|
||||
[SerializeField] private float breakPosition = 0.5f;
|
||||
|
||||
[Tooltip("Effect to spawn at break point (optional)")]
|
||||
[SerializeField] private GameObject breakEffect;
|
||||
|
||||
[Tooltip("Sound to play when rope breaks (optional)")]
|
||||
[SerializeField] private AudioClip breakSound;
|
||||
|
||||
[Header("Animation Settings")]
|
||||
[Tooltip("How quickly the rope ends fall after breaking")]
|
||||
[SerializeField] private float fallSpeed = 2f;
|
||||
|
||||
[Tooltip("How much the rope ends swing after breaking")]
|
||||
[SerializeField] private float swingAmount = 0.5f;
|
||||
|
||||
[Header("Physics Settings")]
|
||||
[Tooltip("Follow speed for the rope physics simulation")]
|
||||
[SerializeField] private float ropeFollowSpeed = 5f;
|
||||
|
||||
[Tooltip("Trailing amount for the rope physics simulation")]
|
||||
[SerializeField] private float ropeTrailing = 0.2f;
|
||||
|
||||
[Tooltip("Oscillation amplitude for the rope physics simulation")]
|
||||
[SerializeField] private float ropeOscillationAmplitude = 0.15f;
|
||||
|
||||
[Tooltip("Oscillation frequency for the rope physics simulation")]
|
||||
[SerializeField] private float ropeOscillationFrequency = 2f;
|
||||
|
||||
// Private references
|
||||
private Rope originalRope;
|
||||
private LineRenderer originalLineRenderer;
|
||||
private GameObject firstHalfRope;
|
||||
private GameObject secondHalfRope;
|
||||
private Rope firstHalfRopeComponent;
|
||||
private Rope secondHalfRopeComponent;
|
||||
private Transform breakPointTransform;
|
||||
private Transform secondBreakTransform;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// Get references to the required components
|
||||
originalRope = GetComponent<Rope>();
|
||||
originalLineRenderer = GetComponent<LineRenderer>();
|
||||
|
||||
if (originalRope == null || originalLineRenderer == null)
|
||||
{
|
||||
Debug.LogError("RopeBreaker requires both Rope and LineRenderer components on the same GameObject");
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Breaks the rope at the specified position.
|
||||
/// </summary>
|
||||
/// <param name="breakPositionOverride">Optional override for break position (0-1)</param>
|
||||
/// <returns>True if rope was broken successfully, false otherwise</returns>
|
||||
public bool BreakRope(float? breakPositionOverride = null)
|
||||
{
|
||||
if (originalRope == null || !originalRope.StartPoint || !originalRope.EndPoint)
|
||||
{
|
||||
Debug.LogError("Cannot break rope: Missing rope component or endpoints");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use override position if provided
|
||||
float breakPos = breakPositionOverride ?? breakPosition;
|
||||
breakPos = Mathf.Clamp01(breakPos);
|
||||
|
||||
// Get the world position at the break point
|
||||
Vector3 breakPointPosition = originalRope.GetPointAt(breakPos);
|
||||
|
||||
// Create a transform at the break point to use as an anchor
|
||||
CreateBreakPointTransform(breakPointPosition);
|
||||
|
||||
// Create two new rope GameObjects
|
||||
CreateRopeSegments();
|
||||
|
||||
// Hide the original rope
|
||||
originalLineRenderer.enabled = false;
|
||||
|
||||
// Play effects
|
||||
PlayBreakEffects(breakPointPosition);
|
||||
|
||||
// Start the animation coroutine
|
||||
StartCoroutine(AnimateRopeBreak());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a transform at the break point to use as an anchor
|
||||
/// </summary>
|
||||
private void CreateBreakPointTransform(Vector3 breakPointPosition)
|
||||
{
|
||||
// Create a new GameObject for the break point
|
||||
GameObject breakPointObj = new GameObject("RopeBreakPoint");
|
||||
breakPointTransform = breakPointObj.transform;
|
||||
breakPointTransform.position = breakPointPosition;
|
||||
breakPointTransform.SetParent(transform.parent); // Parent to the same parent as the rope
|
||||
|
||||
// Add the physics follower component to the break point
|
||||
RopeEndPhysicsFollower follower = breakPointObj.AddComponent<RopeEndPhysicsFollower>();
|
||||
follower.targetTag = "Player";
|
||||
follower.followSpeed = ropeFollowSpeed;
|
||||
follower.trailing = ropeTrailing;
|
||||
follower.oscillationAmplitude = ropeOscillationAmplitude;
|
||||
follower.oscillationFrequency = ropeOscillationFrequency;
|
||||
follower.disableOscillation = true; // Disable oscillation for player-attached rope
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates two new rope GameObjects for the broken segments
|
||||
/// </summary>
|
||||
private void CreateRopeSegments()
|
||||
{
|
||||
// Create the first half rope (from start to break point)
|
||||
firstHalfRope = new GameObject("Rope_FirstHalf");
|
||||
firstHalfRope.transform.position = transform.position;
|
||||
firstHalfRope.transform.rotation = transform.rotation;
|
||||
firstHalfRope.transform.SetParent(transform.parent);
|
||||
|
||||
// Add Rope component which automatically adds LineRenderer due to RequireComponent
|
||||
firstHalfRopeComponent = firstHalfRope.AddComponent<Rope>();
|
||||
|
||||
// Get the LineRenderer that was automatically added
|
||||
LineRenderer firstLineRenderer = firstHalfRope.GetComponent<LineRenderer>();
|
||||
if (firstLineRenderer == null)
|
||||
{
|
||||
// Only add if somehow not created (shouldn't happen, but safety check)
|
||||
firstLineRenderer = firstHalfRope.AddComponent<LineRenderer>();
|
||||
}
|
||||
CopyLineRendererProperties(originalLineRenderer, firstLineRenderer);
|
||||
|
||||
// Create the second half rope (from break point to end)
|
||||
secondHalfRope = new GameObject("Rope_SecondHalf");
|
||||
secondHalfRope.transform.position = transform.position;
|
||||
secondHalfRope.transform.rotation = transform.rotation;
|
||||
secondHalfRope.transform.SetParent(transform.parent);
|
||||
|
||||
// Add Rope component which automatically adds LineRenderer due to RequireComponent
|
||||
secondHalfRopeComponent = secondHalfRope.AddComponent<Rope>();
|
||||
|
||||
// Get the LineRenderer that was automatically added
|
||||
LineRenderer secondLineRenderer = secondHalfRope.GetComponent<LineRenderer>();
|
||||
if (secondLineRenderer == null)
|
||||
{
|
||||
// Only add if somehow not created (shouldn't happen, but safety check)
|
||||
secondLineRenderer = secondHalfRope.AddComponent<LineRenderer>();
|
||||
}
|
||||
CopyLineRendererProperties(originalLineRenderer, secondLineRenderer);
|
||||
|
||||
// Configure the first half rope
|
||||
firstHalfRopeComponent.SetStartPoint(originalRope.StartPoint);
|
||||
firstHalfRopeComponent.SetEndPoint(breakPointTransform, false); // Don't recalculate yet
|
||||
|
||||
// Copy properties from original rope
|
||||
CopyRopeProperties(originalRope, firstHalfRopeComponent);
|
||||
|
||||
// Explicitly initialize the rope
|
||||
firstHalfRopeComponent.Initialize();
|
||||
|
||||
// Now force recalculation after initialization
|
||||
firstHalfRopeComponent.RecalculateRope();
|
||||
|
||||
// Configure the second half rope - REVERSED: Rock (End) is now Start, Break point is now End
|
||||
secondHalfRopeComponent.SetStartPoint(originalRope.EndPoint);
|
||||
secondHalfRopeComponent.SetEndPoint(breakPointTransform, false); // Don't recalculate yet
|
||||
|
||||
// Copy properties from original rope
|
||||
CopyRopeProperties(originalRope, secondHalfRopeComponent);
|
||||
|
||||
// Explicitly initialize the rope
|
||||
secondHalfRopeComponent.Initialize();
|
||||
|
||||
// Now force recalculation after initialization
|
||||
secondHalfRopeComponent.RecalculateRope();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies properties from one LineRenderer to another
|
||||
/// </summary>
|
||||
private void CopyLineRendererProperties(LineRenderer source, LineRenderer destination)
|
||||
{
|
||||
// Copy material
|
||||
destination.material = source.material;
|
||||
|
||||
// Copy colors
|
||||
destination.startColor = source.startColor;
|
||||
destination.endColor = source.endColor;
|
||||
|
||||
// Copy width
|
||||
destination.startWidth = source.startWidth;
|
||||
destination.endWidth = source.endWidth;
|
||||
|
||||
// Copy other properties
|
||||
destination.numCornerVertices = source.numCornerVertices;
|
||||
destination.numCapVertices = source.numCapVertices;
|
||||
destination.alignment = source.alignment;
|
||||
destination.textureMode = source.textureMode;
|
||||
destination.generateLightingData = source.generateLightingData;
|
||||
destination.useWorldSpace = source.useWorldSpace;
|
||||
destination.loop = source.loop;
|
||||
destination.sortingLayerID = source.sortingLayerID;
|
||||
destination.sortingOrder = source.sortingOrder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies properties from one Rope to another
|
||||
/// </summary>
|
||||
private void CopyRopeProperties(Rope source, Rope destination)
|
||||
{
|
||||
destination.linePoints = source.linePoints;
|
||||
destination.stiffness = source.stiffness;
|
||||
destination.damping = source.damping;
|
||||
destination.ropeLength = source.ropeLength / 2f; // Halve the rope length for each segment
|
||||
destination.ropeWidth = source.ropeWidth;
|
||||
destination.midPointWeight = source.midPointWeight;
|
||||
destination.midPointPosition = source.midPointPosition;
|
||||
|
||||
// Recalculate the rope to update its appearance
|
||||
destination.RecalculateRope();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Plays visual and audio effects at the break point
|
||||
/// </summary>
|
||||
private void PlayBreakEffects(Vector3 breakPointPosition)
|
||||
{
|
||||
// Spawn break effect if assigned
|
||||
if (breakEffect != null)
|
||||
{
|
||||
Instantiate(breakEffect, breakPointPosition, Quaternion.identity);
|
||||
}
|
||||
|
||||
// Play break sound if assigned
|
||||
if (breakSound != null)
|
||||
{
|
||||
AudioSource.PlayClipAtPoint(breakSound, breakPointPosition);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Animates the rope break with falling and swinging effects
|
||||
/// </summary>
|
||||
private IEnumerator AnimateRopeBreak()
|
||||
{
|
||||
float elapsedTime = 0f;
|
||||
Vector3 originalBreakPosition = breakPointTransform.position;
|
||||
|
||||
// Create a second break point that will move in the opposite direction
|
||||
GameObject secondBreakPoint = new GameObject("RopeBreakPoint_Second");
|
||||
secondBreakTransform = secondBreakPoint.transform;
|
||||
secondBreakTransform.position = originalBreakPosition;
|
||||
secondBreakTransform.SetParent(transform.parent);
|
||||
|
||||
// Add the physics follower component to the second break point
|
||||
RopeEndPhysicsFollower secondFollower = secondBreakPoint.AddComponent<RopeEndPhysicsFollower>();
|
||||
secondFollower.targetTag = "Rock";
|
||||
secondFollower.followSpeed = ropeFollowSpeed;
|
||||
secondFollower.trailing = ropeTrailing;
|
||||
secondFollower.oscillationAmplitude = ropeOscillationAmplitude * 1.5f; // Slightly more oscillation for falling piece
|
||||
secondFollower.oscillationFrequency = ropeOscillationFrequency;
|
||||
secondFollower.disableOscillation = true; // Enable oscillation for rock-attached end
|
||||
|
||||
// Update the second rope to use this new break point as the end point
|
||||
// (since we reversed the rope direction, the break point is now the end)
|
||||
secondHalfRopeComponent.SetEndPoint(secondBreakTransform);
|
||||
secondHalfRopeComponent.RecalculateRope();
|
||||
|
||||
// Get the directions for swinging
|
||||
Vector3 direction1 = (originalRope.StartPoint.position - breakPointTransform.position).normalized;
|
||||
Vector3 direction2 = (originalRope.EndPoint.position - breakPointTransform.position).normalized;
|
||||
|
||||
// Make sure the directions have horizontal components
|
||||
direction1.y = 0;
|
||||
direction2.y = 0;
|
||||
|
||||
// Normalize to prevent zero vectors
|
||||
if (direction1.magnitude < 0.01f) direction1 = Vector3.right;
|
||||
if (direction2.magnitude < 0.01f) direction2 = Vector3.left;
|
||||
|
||||
direction1.Normalize();
|
||||
direction2.Normalize();
|
||||
|
||||
// Initial separation to create a visual gap
|
||||
float separationDistance = originalLineRenderer.startWidth * 2f; // Base the gap on the rope width
|
||||
breakPointTransform.position += -direction2 * separationDistance * 0.5f;
|
||||
secondBreakTransform.position += direction2 * separationDistance * 0.5f;
|
||||
|
||||
// Recalculate the ropes after initial separation
|
||||
firstHalfRopeComponent.RecalculateRope();
|
||||
secondHalfRopeComponent.RecalculateRope();
|
||||
|
||||
while (elapsedTime < 0.75f) // Animate for 1 second
|
||||
{
|
||||
elapsedTime += Time.deltaTime;
|
||||
|
||||
// Calculate swing motion using sine wave (with different phases for each end)
|
||||
float swingFactor1 = Mathf.Sin(elapsedTime * 4f) * swingAmount * Mathf.Exp(-elapsedTime);
|
||||
float swingFactor2 = Mathf.Sin(elapsedTime * 4f + Mathf.PI * 0.5f) * swingAmount * Mathf.Exp(-elapsedTime);
|
||||
|
||||
// First break point (attached to player) - maintain Y position but allow swinging
|
||||
Vector3 pos1 = originalBreakPosition;
|
||||
pos1.y = originalBreakPosition.y; // Keep original Y position - no falling
|
||||
pos1 += direction1 * swingFactor1;
|
||||
pos1 += -direction2 * (separationDistance * 0.5f); // Maintain separation
|
||||
breakPointTransform.position = pos1;
|
||||
|
||||
// Second break point (hanging rope end) - allow small amount of falling
|
||||
Vector3 pos2 = originalBreakPosition;
|
||||
float fallDistance = fallSpeed * elapsedTime;
|
||||
pos2.y = originalBreakPosition.y - fallDistance; // Limited falling
|
||||
pos2 += direction2 * swingFactor2;
|
||||
pos2 += direction2 * (separationDistance * 0.5f); // Maintain separation
|
||||
secondBreakTransform.position = pos2;
|
||||
|
||||
// Recalculate the ropes each frame
|
||||
firstHalfRopeComponent.RecalculateRope();
|
||||
secondHalfRopeComponent.RecalculateRope();
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// After the initial animation, let the physics followers take over
|
||||
// They will continue to move and animate the rope endpoints
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restores the original rope and cleans up the broken pieces
|
||||
/// </summary>
|
||||
public void RestoreRope()
|
||||
{
|
||||
// Re-enable the original rope
|
||||
if (originalLineRenderer != null)
|
||||
{
|
||||
originalLineRenderer.enabled = true;
|
||||
}
|
||||
|
||||
// Clean up the broken rope pieces
|
||||
if (firstHalfRope != null)
|
||||
{
|
||||
Destroy(firstHalfRope);
|
||||
}
|
||||
|
||||
if (secondHalfRope != null)
|
||||
{
|
||||
Destroy(secondHalfRope);
|
||||
}
|
||||
|
||||
// Clean up both break points
|
||||
if (breakPointTransform != null)
|
||||
{
|
||||
Destroy(breakPointTransform.gameObject);
|
||||
}
|
||||
|
||||
// Find and destroy the second break point if it exists
|
||||
Transform secondBreakPoint = transform.parent?.Find("RopeBreakPoint_Second");
|
||||
if (secondBreakPoint != null)
|
||||
{
|
||||
Destroy(secondBreakPoint.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user