2025-09-06 00:08:22 +05:00

139 lines
4.4 KiB
C#
Raw Blame History

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class ClawBubble : MonoBehaviour
{
public ClawBubbleType type;
private Rigidbody rb;
public MeshRenderer bottomMeshRenderer;
// ---------- Non-physics separation settings ----------
[Header("Non-Physics Separation")]
[Tooltip("Enable separation without physics collisions.")]
public bool enableSeparation = true;
[Tooltip("Minimum center-to-center distance you want between balls (world units).")]
public float minDistance = 0.28f; // tweak to your ball size
[Tooltip("Max frames to try separating on spawn (0 = skip on spawn).")]
public int relaxFramesOnSpawn = 10; // try a few frames right after spawn
[Tooltip("Max frames to try separating after landing on Carousel.")]
public int relaxFramesOnLand = 20;
[Tooltip("How strongly to push each frame (larger = faster, but can jitter).")]
public float pushStrength = 0.6f;
[Tooltip("Clamp to avoid big jumps per frame.")]
public float maxPushPerFrame = 0.06f;
// Registry of all live bubbles (for neighbor checks)
private static readonly List<ClawBubble> All = new List<ClawBubble>();
private void Awake()
{
rb = GetComponent<Rigidbody>();
}
private void OnEnable()
{
if (!All.Contains(this)) All.Add(this);
// Optional: a tiny relax pass right after spawn (before landing)
if (enableSeparation && relaxFramesOnSpawn > 0)
StartCoroutine(RelaxOverlap(frames: relaxFramesOnSpawn, onlyWithSameParent: false));
}
private void OnDisable()
{
All.Remove(this);
}
void FreezeAllConstraints()
{
if (rb) rb.constraints = RigidbodyConstraints.FreezeAll;
}
public void LaunchUp(float force)
{
if (!rb) return;
rb.velocity = Vector3.zero;
rb.AddForce(Vector3.up * force, ForceMode.Impulse);
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Carousel"))
{
transform.parent = collision.transform;
FreezeAllConstraints();
isKinematicor(true);
// After we <20>stick<63> to the Carousel, run a separation pass
if (enableSeparation && relaxFramesOnLand > 0)
StartCoroutine(RelaxOverlap(frames: relaxFramesOnLand, onlyWithSameParent: true));
}
}
public void isKinematicor(bool flag)
{
if (rb) rb.isKinematic = flag;
}
// -------------------------------------------------------
// Non-physics relaxation: resolves overlaps on the XZ plane
// -------------------------------------------------------
private IEnumerator RelaxOverlap(int frames, bool onlyWithSameParent)
{
// Small stagger to avoid every ball moving in the same frame
yield return null;
float minSqr = minDistance * minDistance;
for (int f = 0; f < frames; f++)
{
Vector3 pos = transform.position;
Vector3 totalPush = Vector3.zero;
for (int i = 0; i < All.Count; i++)
{
var other = All[i];
if (!other || other == this) continue;
if (onlyWithSameParent && other.transform.parent != transform.parent)
continue;
Vector3 delta = pos - other.transform.position;
delta.y = 0f; // only separate on the platform plane
float sqr = delta.sqrMagnitude;
if (sqr < 0.000001f) continue;
if (sqr < minSqr)
{
float dist = Mathf.Sqrt(sqr);
float needed = minDistance - dist; // how much more spacing we need
Vector3 dir = delta / dist; // normalized on XZ
totalPush += dir * needed;
}
}
if (totalPush.sqrMagnitude > 0f)
{
// Clamp and scale the push so we don<6F>t jump too far
if (totalPush.magnitude > maxPushPerFrame)
totalPush = totalPush.normalized * maxPushPerFrame;
transform.position += totalPush * pushStrength;
}
else
{
// Already clear; stop early
break;
}
yield return null;
}
}
}