模拟物理弧线运动(模拟飞盘)
- 介绍
- 实现代码
- 总结
介绍
模拟弧线的运动,并且对象始终朝向运动的方向,模拟飞盘子弹的运动轨迹。这里我是没有加重力这么一个概念的,当然了重力其实比较简单可以参考我之前写的模拟抛物线运动里面我模拟了重力。
实现代码
可控制速度、以及弧线的轨迹大小(-的值为反方向运动)
using UnityEngine;
/// <summary>
/// 模拟飞盘运行轨迹
/// </summary>
public class ArcMoveClass
{
/// <summary>
/// 开始位置
/// </summary>
public Vector3 m_startPos;
/// <summary>
/// 结束位置
/// </summary>
public Vector3 m_endPos;
/// <summary>
/// 弧度
/// </summary>
public float m_arcWidth;
/// <summary>
/// 运行的速度
/// </summary>
public float m_speed;
/// <summary>
/// 最终方向
/// </summary>
public Vector3 m_finalDir;
/// <summary>
/// 计时使用
/// </summary>
private float timer;
/// <summary>
/// 运行轨迹弧度的长度
/// </summary>
public float m_arcLength;
/// <summary>
/// 飞盘构造函数
/// </summary>
/// <param name="startPos">开始位置</param>
/// <param name="endPos">结束位置</param>
/// <param name="arcWidth">弧度</param>
/// <param name="speed">速度</param>
public ArcMoveClass(Vector3 startPos, Vector3 endPos, float arcWidth, float speed)
{
Init(startPos, endPos, arcWidth, speed);
}
/// <summary>
/// 初始化
/// </summary>
/// <param name="startPos">开始位置</param>
/// <param name="endPos">结束位置</param>
/// <param name="arcWidth">弧度</param>
/// <param name="speed">速度</param>
public void Init(Vector3 startPos, Vector3 endPos, float arcWidth, float speed)
{
m_startPos = startPos;
m_endPos = endPos;
m_arcWidth = arcWidth;
m_speed = speed;
// 计算最终方向
Vector3 mid = (startPos + endPos) / 2;
Vector3 controlPoint = mid + Vector3.Cross(endPos - startPos, Vector3.up).normalized * arcWidth;
m_finalDir = (endPos - controlPoint).normalized;
// 计算弧线长度
m_arcLength = CalculateArcLength(controlPoint, 100);
timer = 0;
}
/// <summary>
/// 获取弧线运行轨迹的长度
/// </summary>
/// <param name="start"></param>
/// <param name="end"></param>
/// <param name="control"></param>
/// <param name="segments"></param>
/// <returns></returns>
private float CalculateArcLength(Vector3 control, int segments)
{
float length = 0f;
Vector3 previousPoint = m_startPos;
for (int i = 1; i <= segments; i++)
{
float t = i / (float)segments;
Vector3 currentPoint = Mathf.Pow(1 - t, 2) * m_startPos + 2 * (1 - t) * t * control + Mathf.Pow(t, 2) * m_endPos;
length += Vector3.Distance(previousPoint, currentPoint);
previousPoint = currentPoint;
}
return length;
}
public void UpdatePos(Transform trans)
{
if (timer < 1f)
{
timer += Time.deltaTime * m_speed / m_arcLength;
//计算从A到B的弧线轨迹
Vector3 currentPos = GetArcPoint(timer);
trans.position = currentPos;
//更新物体朝向
Vector3 nextPos = GetArcPoint(timer + Time.deltaTime * m_speed / m_arcLength);
Vector3 direction = nextPos - currentPos;
trans.rotation = Quaternion.LookRotation(direction);
}
else
{
//继续沿最终方向运动
trans.position += m_finalDir * Time.deltaTime * m_speed;
//朝向
trans.rotation = Quaternion.LookRotation(m_finalDir);
}
}
/// <summary>
/// 根据时间获取朝向
/// </summary>
/// <param name="time"></param>
/// <returns></returns>
Vector3 GetArcPoint(float time)
{
// 找到A和B的中点
Vector3 mid = (m_startPos + m_endPos) / 2;
// 在X和Z轴上创建一个垂直于A和B的点,以创建弧线效果
Vector3 controlPoint = mid + Vector3.Cross(m_endPos - m_startPos, Vector3.up).normalized * m_arcWidth;
// 使用二次贝塞尔曲线计算位置
Vector3 point = Mathf.Pow(1 - time, 2) * m_startPos + 2 * (1 - time) * time * controlPoint + Mathf.Pow(time, 2) * m_endPos;
// 返回弧线点
return point;
}
}
总结
这个轨迹运动是用了弧线的知识,可以上我上述的代码。感谢大家的支持!