147 lines
4.6 KiB
C#
147 lines
4.6 KiB
C#
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using Unity.VisualScripting;
|
||
using UnityEngine;
|
||
|
||
public class RingManager : MonoBehaviour
|
||
{
|
||
public int initCount = 12;
|
||
public float radius = 3f;
|
||
|
||
[Tooltip("角度间隔")]
|
||
public float splitAngle = 0f;
|
||
[Tooltip("是否一直朝前")]
|
||
public bool isAlwaysForward = true;
|
||
[Tooltip("最大左右旋转角度绝对值")]
|
||
public float maxRotationAngle = 90; // 限制角度
|
||
public Transform qiu;
|
||
public float rotationalSpeed = 5f;
|
||
|
||
private List<Transform> qiuList = new List<Transform>();
|
||
|
||
private float beforePositionX = 0;
|
||
private float targetRotationalSpeed = 0;
|
||
private bool isToLeftRotation = false;
|
||
private bool isCanRotation = false;
|
||
|
||
// 【新增】用于记录当前整体偏离初始位置的角度
|
||
private float currentRingAngle = 0f;
|
||
|
||
void Awake()
|
||
{
|
||
// ... (Awake中的初始化代码保持不变) ...
|
||
var qiuCollider = qiu.GetComponentInChildren<Collider>();
|
||
// 注意:如果 qiuCollider 为空这里会报错,建议加个判空
|
||
float ringLen = 2 * Mathf.PI * radius;
|
||
// 简单防错
|
||
float qiuRadius = qiuCollider != null ? qiuCollider.bounds.extents.magnitude : 0.5f;
|
||
float len = Mathf.FloorToInt(ringLen / (qiuRadius * qiu.localScale.x) / 2);
|
||
|
||
for (int i = 0; i < initCount; i++)
|
||
{
|
||
float angle = Mathf.PI * 2 / initCount * i + splitAngle;
|
||
Vector3 pos = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * radius;
|
||
pos += transform.position;
|
||
|
||
var qiuInst = Instantiate(qiu, pos, Quaternion.identity);
|
||
qiuInst.SetParent(transform, true);
|
||
|
||
Rigidbody rb = qiuInst.GetComponent<Rigidbody>();
|
||
if (rb == null) rb = qiuInst.AddComponent<Rigidbody>();
|
||
rb.useGravity = false;
|
||
rb.constraints = RigidbodyConstraints.FreezePositionY | RigidbodyConstraints.FreezeRotation;
|
||
|
||
qiuList.Add(qiuInst);
|
||
}
|
||
|
||
beforePositionX = transform.position.x;
|
||
}
|
||
|
||
void FixedUpdate()
|
||
{
|
||
// 1. 运动状态检测
|
||
isCanRotation = true;
|
||
if (Mathf.Abs(beforePositionX - transform.position.x) < 0.03f)
|
||
{
|
||
isCanRotation = false;
|
||
}
|
||
|
||
if (isCanRotation)
|
||
{
|
||
if (transform.position.x < beforePositionX)
|
||
isToLeftRotation = true;
|
||
else
|
||
isToLeftRotation = false;
|
||
}
|
||
|
||
beforePositionX = transform.position.x;
|
||
|
||
// 2. 计算目标速度(平滑插值)
|
||
if (isCanRotation)
|
||
{
|
||
targetRotationalSpeed = Mathf.Lerp(targetRotationalSpeed, rotationalSpeed, Time.deltaTime * 5);
|
||
}
|
||
else
|
||
{
|
||
targetRotationalSpeed = Mathf.Lerp(targetRotationalSpeed, 0, Time.deltaTime * 5);
|
||
}
|
||
|
||
// 如果速度非常小,就不进行旋转计算了,节省性能
|
||
if (targetRotationalSpeed < 0.01f) return;
|
||
|
||
// 3. 计算本帧【原本想要】旋转的角度量
|
||
float rotationStep = targetRotationalSpeed * Time.deltaTime * Mathf.Rad2Deg;
|
||
|
||
// 确定方向符号 (左移往负方向转,右移往正方向转,根据你的需求调整正负)
|
||
// 假设:向左移动(isToLeftRotation=true)对应负角度(-),向右对应正角度(+)
|
||
float direction = isToLeftRotation ? -1f : 1f;
|
||
float finalStep = rotationStep * direction;
|
||
|
||
// 4. 【核心逻辑】限制角度
|
||
// 预测下一帧的角度
|
||
float nextAngle = currentRingAngle + finalStep;
|
||
|
||
// 如果预测角度超出了范围,需要进行截断
|
||
if (nextAngle > maxRotationAngle)
|
||
{
|
||
// 如果超出了最大值,本帧只转到最大值剩下的那一丢丢
|
||
finalStep = maxRotationAngle - currentRingAngle;
|
||
currentRingAngle = maxRotationAngle;
|
||
}
|
||
else if (nextAngle < -maxRotationAngle)
|
||
{
|
||
// 如果超出了最小值
|
||
finalStep = -maxRotationAngle - currentRingAngle;
|
||
currentRingAngle = -maxRotationAngle;
|
||
}
|
||
else
|
||
{
|
||
// 没超出,直接累加
|
||
currentRingAngle = nextAngle;
|
||
}
|
||
|
||
// 5. 应用旋转
|
||
// 只有当 finalStep 不接近0时才执行,避免浮点数抖动
|
||
if (Mathf.Abs(finalStep) > 0.0001f)
|
||
{
|
||
foreach (var ball in qiuList)
|
||
{
|
||
// 使用计算好的 finalStep 进行旋转
|
||
ball.RotateAround(transform.position, Vector3.up, finalStep);
|
||
|
||
if (isAlwaysForward)
|
||
{
|
||
ball.eulerAngles = Vector3.zero;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
foreach (var ball in qiuList)
|
||
{
|
||
if (ball != null) Destroy(ball.gameObject);
|
||
}
|
||
}
|
||
} |