147 lines
4.6 KiB
C#
147 lines
4.6 KiB
C#
using UnityEngine;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
|
||
public class ClawBubble : MonoBehaviour
|
||
{
|
||
public ClawBubbleType type;
|
||
private Rigidbody rb;
|
||
public MeshRenderer bottomMeshRenderer;
|
||
public GameObject Wolf;
|
||
// ---------- 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 Start()
|
||
{
|
||
Invoke(nameof(WolfEnabler), 0.03f);
|
||
}
|
||
void WolfEnabler()
|
||
{
|
||
if (type == ClawBubbleType.Wolf) { Wolf.SetActive(true); }
|
||
}
|
||
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;
|
||
}
|
||
}
|
||
}
|