UMiniGame/Assets/Game1/Scripts/RingManager.cs
2025-12-18 18:35:56 +08:00

147 lines
4.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
}
}