Add background
This commit is contained in:
@@ -40,9 +40,6 @@ public class RopeBreaker : MonoBehaviour
|
||||
|
||||
[Tooltip("Initial downward impulse for falling rope end")]
|
||||
[SerializeField] private float initialFallImpulse = 2.0f;
|
||||
|
||||
[Tooltip("Force Y position reset on start to ensure proper falling")]
|
||||
[SerializeField] private bool forceYReset = true;
|
||||
|
||||
// Private references
|
||||
private Rope originalRope;
|
||||
@@ -122,10 +119,9 @@ public class RopeBreaker : MonoBehaviour
|
||||
|
||||
// Set specific transform to follow instead of using tag
|
||||
follower.SetTargetTransform(originalStartPoint);
|
||||
|
||||
follower.canFall = false; // Player rope end doesn't fall
|
||||
follower.followSpeed = ropeFollowSpeed;
|
||||
follower.trailing = ropeTrailing;
|
||||
follower.useGravity = true; // Player rope end doesn't use gravity
|
||||
|
||||
// Create second break point (for the rock-attached end)
|
||||
GameObject secondBreakObj = new GameObject("RopeBreakPoint_Second");
|
||||
@@ -138,15 +134,13 @@ public class RopeBreaker : MonoBehaviour
|
||||
|
||||
// Set specific transform to follow instead of using tag
|
||||
secondFollower.SetTargetTransform(originalEndPoint);
|
||||
|
||||
secondFollower.canFall = true; // Rock end can fall
|
||||
secondFollower.followSpeed = ropeFollowSpeed;
|
||||
secondFollower.trailing = ropeTrailing;
|
||||
secondFollower.useGravity = true; // Enable gravity for hanging rope end
|
||||
secondFollower.gravityStrength = ropeGravityStrength;
|
||||
secondFollower.verticalHangStrength = ropeVerticalHangStrength;
|
||||
secondFollower.damping = ropeDamping;
|
||||
secondFollower.initialFallImpulse = initialFallImpulse;
|
||||
secondFollower.forceYReset = forceYReset;
|
||||
|
||||
// Create initial separation
|
||||
Vector3 direction = (originalEndPoint.position - breakPointPosition).normalized;
|
||||
|
||||
@@ -4,43 +4,196 @@ using UnityEngine;
|
||||
public class RopeEndPhysicsFollower : MonoBehaviour
|
||||
{
|
||||
[Header("Target Settings")]
|
||||
[Tooltip("Tag of the object this endpoint should follow (used if targetTransform is not set)")]
|
||||
public string targetTag;
|
||||
[Tooltip("Transform this endpoint should follow (takes precedence over targetTag)")]
|
||||
[Tooltip("Transform this endpoint should follow")]
|
||||
public Transform targetTransform;
|
||||
[Tooltip("How quickly the endpoint follows the target")]
|
||||
[Tooltip("Tag of the object this endpoint should follow (only used if targetTransform is not set)")]
|
||||
public string targetTag;
|
||||
[Tooltip("How quickly the endpoint follows the target when not using physics")]
|
||||
public float followSpeed = 5f;
|
||||
[Tooltip("How much trailing (0 = instant, 1 = very slow)")]
|
||||
public float trailing = 0.2f;
|
||||
|
||||
[Header("Physics Simulation")]
|
||||
[Tooltip("Enable/disable gravity effect")]
|
||||
public bool useGravity = true;
|
||||
[Tooltip("Gravity strength")]
|
||||
public float gravityStrength = 9.8f;
|
||||
[Tooltip("How strongly the rope attempts to hang vertically")]
|
||||
public float verticalHangStrength = 2f;
|
||||
[Tooltip("Damping for physics movement (higher = less bouncy)")]
|
||||
public float damping = 0.3f;
|
||||
[Tooltip("Initial downward impulse when gravity is enabled")]
|
||||
[Tooltip("Initial downward impulse when enabled")]
|
||||
public float initialFallImpulse = 2.0f;
|
||||
[Tooltip("Force a Y position reset on start to ensure falling occurs")]
|
||||
public bool forceYReset = true;
|
||||
[Tooltip("Whether this end can fall with gravity (false for player-attached ends)")]
|
||||
public bool canFall = true;
|
||||
|
||||
// Private variables
|
||||
private Transform target;
|
||||
private Vector3 velocity;
|
||||
private Vector2 physicsVelocity;
|
||||
private Vector2 offset;
|
||||
private Vector3 lastTargetPosition;
|
||||
private bool initialized = false;
|
||||
private bool debugLog = true;
|
||||
|
||||
|
||||
// Rope reference to get the actual rope length
|
||||
private Rope attachedRope;
|
||||
private float maxDistance;
|
||||
|
||||
void Start()
|
||||
{
|
||||
// Find the Rope component to determine the maximum distance
|
||||
FindAttachedRope();
|
||||
|
||||
// Use targetTransform if set, otherwise try to find by tag
|
||||
if (targetTransform != null)
|
||||
{
|
||||
target = targetTransform;
|
||||
if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Using assigned target transform: {target.name}");
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(targetTag))
|
||||
{
|
||||
GameObject found = GameObject.FindGameObjectWithTag(targetTag);
|
||||
if (found)
|
||||
{
|
||||
target = found.transform;
|
||||
if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Found target by tag '{targetTag}': {target.name}");
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize offset and velocities
|
||||
if (target)
|
||||
{
|
||||
// Only store horizontal offset, not vertical for physics simulation
|
||||
Vector2 offsetVec = transform.position - target.position;
|
||||
offset.x = offsetVec.x;
|
||||
offset.y = 0; // Don't preserve vertical offset for gravity simulation
|
||||
lastTargetPosition = target.position;
|
||||
|
||||
// Apply initial falling impulse if this end can fall
|
||||
if (canFall)
|
||||
{
|
||||
physicsVelocity = new Vector2(0, -initialFallImpulse);
|
||||
if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Initialized with target: {target.name}, initial Y velocity: {physicsVelocity.y}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = Vector2.zero;
|
||||
lastTargetPosition = transform.position;
|
||||
if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] No target found");
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!target) return;
|
||||
|
||||
// Calculate deltaTime for physics stability
|
||||
float deltaTime = Time.deltaTime;
|
||||
|
||||
// Get target velocity
|
||||
Vector3 targetVelocity = (target.position - lastTargetPosition) / deltaTime;
|
||||
lastTargetPosition = target.position;
|
||||
|
||||
// Current position relative to target
|
||||
Vector2 relativePos = new Vector2(
|
||||
transform.position.x - target.position.x,
|
||||
transform.position.y - target.position.y
|
||||
);
|
||||
|
||||
// Get the straight-line distance between target and this transform
|
||||
float currentDistance = relativePos.magnitude;
|
||||
|
||||
// Normalized direction from target to this transform
|
||||
Vector2 directionToTarget = relativePos.normalized;
|
||||
|
||||
// Apply forces based on whether this end can fall
|
||||
if (canFall)
|
||||
{
|
||||
// 1. Gravity - always pulls down
|
||||
physicsVelocity.y -= gravityStrength * deltaTime;
|
||||
}
|
||||
|
||||
// 2. Vertical hanging force - try to align X with target when stationary
|
||||
if (Mathf.Abs(targetVelocity.x) < 0.1f)
|
||||
{
|
||||
// Use the actual X position of the target as the desired X position
|
||||
float xOffset = transform.position.x - target.position.x;
|
||||
physicsVelocity.x -= xOffset * verticalHangStrength * deltaTime;
|
||||
|
||||
// Debug log to track vertical hanging behavior
|
||||
if (debugLog && Time.frameCount % 120 == 0)
|
||||
{
|
||||
Debug.Log($"[RopeEndPhysicsFollower] Vertical hanging: target X={target.position.x}, my X={transform.position.x}, offset={xOffset}");
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Rope length constraint - apply a force toward the target if we're exceeding the rope length
|
||||
if (currentDistance > maxDistance)
|
||||
{
|
||||
// Calculate constraint force proportional to how much we're exceeding the rope length
|
||||
float exceededDistance = currentDistance - maxDistance;
|
||||
|
||||
// Apply a stronger constraint force the more we exceed the max distance
|
||||
Vector2 constraintForce = -directionToTarget * exceededDistance * 10f;
|
||||
|
||||
// Apply to velocity
|
||||
physicsVelocity += constraintForce * deltaTime;
|
||||
|
||||
if (debugLog && Time.frameCount % 60 == 0)
|
||||
{
|
||||
Debug.Log($"[RopeEndPhysicsFollower] Exceeding max distance: {exceededDistance}, applying constraint");
|
||||
}
|
||||
}
|
||||
|
||||
// Apply damping to physics velocity
|
||||
physicsVelocity *= (1f - damping * deltaTime);
|
||||
|
||||
// Log physics state periodically for debugging
|
||||
if (debugLog && Time.frameCount % 60 == 0)
|
||||
{
|
||||
Debug.Log($"[RopeEndPhysicsFollower] Y position: {transform.position.y}, Y velocity: {physicsVelocity.y}, Distance: {currentDistance}/{maxDistance}");
|
||||
}
|
||||
|
||||
// Apply physics velocity to position
|
||||
Vector3 newPos = transform.position;
|
||||
newPos.x += physicsVelocity.x * deltaTime;
|
||||
|
||||
// Only apply vertical movement if this end can fall
|
||||
if (canFall)
|
||||
{
|
||||
newPos.y += physicsVelocity.y * deltaTime;
|
||||
}
|
||||
|
||||
transform.position = newPos;
|
||||
|
||||
// Final distance check - hard constraint to ensure we never exceed the rope length
|
||||
// This prevents numerical instability from causing the rope to stretch
|
||||
float finalDistance = Vector2.Distance(
|
||||
new Vector2(transform.position.x, transform.position.y),
|
||||
new Vector2(target.position.x, target.position.y)
|
||||
);
|
||||
|
||||
if (finalDistance > maxDistance)
|
||||
{
|
||||
// Calculate the direction from target to this transform
|
||||
Vector2 direction = new Vector2(
|
||||
transform.position.x - target.position.x,
|
||||
transform.position.y - target.position.y
|
||||
).normalized;
|
||||
|
||||
// Set position to be exactly at the maximum distance
|
||||
Vector3 constrainedPos = new Vector3(
|
||||
target.position.x + direction.x * maxDistance,
|
||||
target.position.y + direction.y * maxDistance,
|
||||
transform.position.z
|
||||
);
|
||||
|
||||
transform.position = constrainedPos;
|
||||
}
|
||||
}
|
||||
|
||||
private void FindAttachedRope()
|
||||
{
|
||||
// Find the Rope component on the same GameObject or parent
|
||||
attachedRope = GetComponent<Rope>();
|
||||
@@ -82,172 +235,6 @@ public class RopeEndPhysicsFollower : MonoBehaviour
|
||||
maxDistance = 2f;
|
||||
if (debugLog) Debug.Log("[RopeEndPhysicsFollower] No attached rope found, using default max distance");
|
||||
}
|
||||
|
||||
// Use targetTransform if set, otherwise try to find by tag
|
||||
if (targetTransform != null)
|
||||
{
|
||||
target = targetTransform;
|
||||
if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Using assigned target transform: {target.name}");
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(targetTag))
|
||||
{
|
||||
GameObject found = GameObject.FindGameObjectWithTag(targetTag);
|
||||
if (found)
|
||||
{
|
||||
target = found.transform;
|
||||
if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Found target by tag '{targetTag}': {target.name}");
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize offset and velocities
|
||||
if (target)
|
||||
{
|
||||
// Only store horizontal offset, not vertical
|
||||
Vector2 offsetVec = transform.position - target.position;
|
||||
offset.x = offsetVec.x;
|
||||
offset.y = 0; // Don't preserve vertical offset for gravity simulation
|
||||
lastTargetPosition = target.position;
|
||||
|
||||
// Apply initial falling impulse if using gravity
|
||||
if (useGravity)
|
||||
{
|
||||
physicsVelocity = new Vector2(0, -initialFallImpulse);
|
||||
|
||||
// Force an initial position change to ensure things start moving
|
||||
if (forceYReset)
|
||||
{
|
||||
Vector3 pos = transform.position;
|
||||
pos.y = target.position.y; // Reset to target's Y position
|
||||
transform.position = pos;
|
||||
}
|
||||
|
||||
if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Initialized with target: {target.name}, gravity enabled, initial Y velocity: {physicsVelocity.y}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = Vector2.zero;
|
||||
lastTargetPosition = transform.position;
|
||||
if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] No target found");
|
||||
}
|
||||
|
||||
velocity = Vector3.zero;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (!target) return;
|
||||
|
||||
// Calculate deltaTime for physics stability
|
||||
float deltaTime = Time.deltaTime;
|
||||
|
||||
// Get target velocity
|
||||
Vector3 targetVelocity = (target.position - lastTargetPosition) / deltaTime;
|
||||
lastTargetPosition = target.position;
|
||||
|
||||
// Basic position the endpoint should be at based on target position and horizontal offset
|
||||
Vector3 basePosition = target.position + new Vector3(offset.x, 0, 0);
|
||||
|
||||
// Apply physics simulation if enabled
|
||||
if (useGravity)
|
||||
{
|
||||
// Get the straight-line distance between target and this transform
|
||||
float currentDistance = Vector2.Distance(
|
||||
new Vector2(transform.position.x, transform.position.y),
|
||||
new Vector2(target.position.x, target.position.y)
|
||||
);
|
||||
|
||||
// Current position relative to target
|
||||
Vector2 relativePos = new Vector2(
|
||||
transform.position.x - target.position.x,
|
||||
transform.position.y - target.position.y
|
||||
);
|
||||
|
||||
// Normalized direction from target to this transform
|
||||
Vector2 directionToTarget = relativePos.normalized;
|
||||
|
||||
// Apply forces:
|
||||
// 1. Gravity - always pulls down
|
||||
physicsVelocity.y -= gravityStrength * deltaTime;
|
||||
|
||||
// 2. Vertical hanging force - try to align X with target (not with world origin)
|
||||
if (Mathf.Abs(targetVelocity.x) < 0.1f)
|
||||
{
|
||||
// Use the actual X position of the target as the desired X position
|
||||
float xOffset = transform.position.x - target.position.x;
|
||||
physicsVelocity.x -= xOffset * verticalHangStrength * deltaTime;
|
||||
|
||||
// Debug log to track vertical hanging behavior
|
||||
if (debugLog && Time.frameCount % 120 == 0)
|
||||
{
|
||||
Debug.Log($"[RopeEndPhysicsFollower] Vertical hanging: target X={target.position.x}, my X={transform.position.x}, offset={xOffset}");
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Rope length constraint - apply a force toward the target if we're exceeding the rope length
|
||||
if (currentDistance > maxDistance)
|
||||
{
|
||||
// Calculate constraint force proportional to how much we're exceeding the rope length
|
||||
float exceededDistance = currentDistance - maxDistance;
|
||||
|
||||
// Apply a stronger constraint force the more we exceed the max distance
|
||||
Vector2 constraintForce = -directionToTarget * exceededDistance * 10f;
|
||||
|
||||
// Apply to velocity
|
||||
physicsVelocity += constraintForce * deltaTime;
|
||||
|
||||
if (debugLog && Time.frameCount % 60 == 0)
|
||||
{
|
||||
Debug.Log($"[RopeEndPhysicsFollower] Exceeding max distance: {exceededDistance}, applying constraint");
|
||||
}
|
||||
}
|
||||
|
||||
// Apply damping to physics velocity
|
||||
physicsVelocity *= (1f - damping * deltaTime);
|
||||
|
||||
// Log physics state periodically for debugging
|
||||
if (debugLog && Time.frameCount % 60 == 0)
|
||||
{
|
||||
Debug.Log($"[RopeEndPhysicsFollower] Y position: {transform.position.y}, Y velocity: {physicsVelocity.y}, Distance: {currentDistance}/{maxDistance}");
|
||||
}
|
||||
|
||||
// Apply physics velocity to position
|
||||
Vector3 newPos = transform.position;
|
||||
newPos.x += physicsVelocity.x * deltaTime;
|
||||
newPos.y += physicsVelocity.y * deltaTime;
|
||||
transform.position = newPos;
|
||||
|
||||
// Final distance check - hard constraint to ensure we never exceed the rope length
|
||||
// This prevents numerical instability from causing the rope to stretch
|
||||
float finalDistance = Vector2.Distance(
|
||||
new Vector2(transform.position.x, transform.position.y),
|
||||
new Vector2(target.position.x, target.position.y)
|
||||
);
|
||||
|
||||
if (finalDistance > maxDistance)
|
||||
{
|
||||
// Calculate the direction from target to this transform
|
||||
Vector2 direction = new Vector2(
|
||||
transform.position.x - target.position.x,
|
||||
transform.position.y - target.position.y
|
||||
).normalized;
|
||||
|
||||
// Set position to be exactly at the maximum distance
|
||||
Vector3 constrainedPos = new Vector3(
|
||||
target.position.x + direction.x * maxDistance,
|
||||
target.position.y + direction.y * maxDistance,
|
||||
transform.position.z
|
||||
);
|
||||
|
||||
transform.position = constrainedPos;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Original smooth follow behavior without physics
|
||||
transform.position = Vector3.SmoothDamp(transform.position, basePosition, ref velocity, trailing, followSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetTargetTransform(Transform newTarget)
|
||||
@@ -273,8 +260,8 @@ public class RopeEndPhysicsFollower : MonoBehaviour
|
||||
offset.y = 0; // Don't preserve vertical offset for gravity simulation
|
||||
}
|
||||
|
||||
// Apply initial falling impulse if using gravity
|
||||
if (useGravity)
|
||||
// Apply initial falling impulse if this end can fall
|
||||
if (canFall)
|
||||
{
|
||||
physicsVelocity = new Vector2(physicsVelocity.x, -initialFallImpulse);
|
||||
if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Reset Y velocity to {physicsVelocity.y} after target change to {target.name}");
|
||||
@@ -289,30 +276,7 @@ public class RopeEndPhysicsFollower : MonoBehaviour
|
||||
GameObject found = GameObject.FindGameObjectWithTag(targetTag);
|
||||
if (found)
|
||||
{
|
||||
targetTransform = found.transform;
|
||||
target = found.transform;
|
||||
lastTargetPosition = target.position;
|
||||
|
||||
// Only update horizontal offset to maintain current vertical position
|
||||
if (initialized)
|
||||
{
|
||||
Vector2 newOffset = transform.position - target.position;
|
||||
offset.x = newOffset.x;
|
||||
// Don't update offset.y to allow gravity to work
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector2 newOffset = transform.position - target.position;
|
||||
offset.x = newOffset.x;
|
||||
offset.y = 0; // Don't preserve vertical offset for gravity simulation
|
||||
}
|
||||
|
||||
// Apply initial falling impulse if using gravity
|
||||
if (useGravity)
|
||||
{
|
||||
physicsVelocity = new Vector2(physicsVelocity.x, -initialFallImpulse);
|
||||
if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Reset Y velocity to {physicsVelocity.y} after target change");
|
||||
}
|
||||
SetTargetTransform(found.transform);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,16 +287,16 @@ public class RopeEndPhysicsFollower : MonoBehaviour
|
||||
{
|
||||
// Reset velocity with a strong downward impulse
|
||||
physicsVelocity = new Vector2(0, -initialFallImpulse * 2f);
|
||||
|
||||
|
||||
// Reset position to be at the same level as the target
|
||||
Vector3 pos = transform.position;
|
||||
pos.y = target.position.y;
|
||||
transform.position = pos;
|
||||
|
||||
|
||||
if (debugLog) Debug.Log($"[RopeEndPhysicsFollower] Physics forcibly reset, new Y velocity: {physicsVelocity.y}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Method to manually set the maximum distance
|
||||
public void SetMaxDistance(float distance)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user