This commit is contained in:
wuyanchen 2025-12-18 18:35:56 +08:00
parent f9dbe4765d
commit 07e5633102
2 changed files with 65 additions and 71 deletions

View File

@ -283,6 +283,7 @@ MonoBehaviour:
radius: 1.8
splitAngle: 0
isAlwaysForward: 1
maxRotationAngle: 170
qiu: {fileID: 1083892317890881295, guid: 83c0dc6728f2e3a4ab110648310fc920, type: 3}
rotationalSpeed: 5
--- !u!1 &49123918
@ -3116,6 +3117,7 @@ MonoBehaviour:
radius: 1.8
splitAngle: 0
isAlwaysForward: 1
maxRotationAngle: 60
qiu: {fileID: 1083892317890881295, guid: 83c0dc6728f2e3a4ab110648310fc920, type: 3}
rotationalSpeed: 2.8
--- !u!1 &1581003589

View File

@ -12,95 +12,55 @@ public class RingManager : MonoBehaviour
public float splitAngle = 0f;
[Tooltip("ÊÇ·ñÒ»Ö±³¯Ç°")]
public bool isAlwaysForward = true;
[Tooltip("最大左右旋转角度绝对值")]
public float maxRotationAngle = 90; // 限制角度
public Transform qiu;
public float rotationalSpeed = 5f; // 改为角速度(弧度/秒),更直观
// 旋转力大小可在Inspector面板调整
//public float rotationalForce = 5f;
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.bounds.extents.magnitude;
// 简单防错
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;
//if (initCount == 2)
//{
// if (i == 1)
// {
// angle = Mathf.PI + splitAngle;
// }
//}
//else
//{
// angle = 360 - (i / len) * Mathf.PI * 2 + splitAngle; // 角度计算逻辑
//}
Vector3 pos = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * radius;
pos.x += transform.position.x;
pos.y += transform.position.y;
pos.z += transform.position.z;
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>();
// 配置刚体属性(避免重力影响,冻结不必要的运动)
if (rb == null) rb = qiuInst.AddComponent<Rigidbody>();
rb.useGravity = false;
rb.constraints = RigidbodyConstraints.FreezePositionY | RigidbodyConstraints.FreezeRotation;
qiuList.Add(qiuInst);
}
//targetRotationalSpeed = rotationalSpeed;
beforePositionX = transform.position.x;
// 初始施加旋转力
//ApplyRotationalForce();
}
// 给所有小球施加旋转力的方法
//void ApplyRotationalForce()
//{
// foreach (var ball in qiuList)
// {
// Rigidbody rb = ball.GetComponent<Rigidbody>();
// if (rb == null) continue;
// // 1. 计算小球相对于中心的径向向量(从中心指向小球)
// Vector3 radialDirection = (ball.position - transform.position).normalized;
// // 2. 计算切线方向垂直于径向绕Y轴旋转的方向
// // Vector3.Cross(radialDirection, Vector3.up) = 逆时针旋转方向
// // Vector3.Cross(Vector3.up, radialDirection) = 顺时针旋转方向
// Vector3 tangentialDirection = Vector3.Cross(radialDirection, -Vector3.up).normalized;
// // 3. 施加切线方向的力(使小球绕中心旋转)
// //rb.AddForce(tangentialDirection * rotationalForce);
// // 可选:如果想保持恒定速度,可直接设置角速度而非持续加力
// float angularSpeed = rotationalForce / radius;
// rb.velocity = tangentialDirection * angularSpeed * radius;
// }
//}
// 可选在FixedUpdate中持续施加力会让小球加速旋转
void FixedUpdate()
{
// 1. 运动状态检测
isCanRotation = true;
if (Mathf.Abs(beforePositionX - transform.position.x) < 0.03f)
{
isCanRotation = false;
@ -109,16 +69,14 @@ public class RingManager : MonoBehaviour
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);
@ -127,20 +85,54 @@ public class RingManager : MonoBehaviour
{
targetRotationalSpeed = Mathf.Lerp(targetRotationalSpeed, 0, Time.deltaTime * 5);
}
// 或逐个旋转小球(如果需要独立控制)
foreach (var ball in qiuList)
// 如果速度非常小,就不进行旋转计算了,节省性能
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)
{
if (isToLeftRotation)
// 如果超出了最大值,本帧只转到最大值剩下的那一丢丢
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)
{
ball.RotateAround(transform.position, Vector3.up, -targetRotationalSpeed * Time.deltaTime * Mathf.Rad2Deg);
}
else
{
ball.RotateAround(transform.position, Vector3.up, targetRotationalSpeed * Time.deltaTime * Mathf.Rad2Deg);
}
if (isAlwaysForward)
{
ball.eulerAngles = Vector3.zero;
// 使用计算好的 finalStep 进行旋转
ball.RotateAround(transform.position, Vector3.up, finalStep);
if (isAlwaysForward)
{
ball.eulerAngles = Vector3.zero;
}
}
}
}
@ -149,7 +141,7 @@ public class RingManager : MonoBehaviour
{
foreach (var ball in qiuList)
{
Destroy(ball.gameObject);
if (ball != null) Destroy(ball.gameObject);
}
}
}