提前预测刚体移动轨迹 预测运动轨迹
- 一、效果
- 二、介绍
- 三、脚本
- RigidbodyExtension.cs 计算工具类
- DrawLine.cs 画线工具类
- 四、资源分享
一、效果
二、介绍
通过计算Unity物理系统的运动方位来判断下一步移动的位置,主要用于物体运动的提前预测,通常使用于炮弹发射,机枪发射,足球篮球网球的运动等多种真实运动的物体。
三、脚本
RigidbodyExtension.cs 计算工具类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Dweiss
{
public static class RigidbodyExtension
{
public static Vector3[] CalculateMovement(this Rigidbody that,
int stepCount, float timeBeteenStep)
{
return that.CalculateMovement(stepCount, timeBeteenStep, Vector3.zero, Vector3.zero);
}
public static Vector3[] CalculateMovement(this Rigidbody that,
int stepCount, float timeBeteenStep, Vector3 addedSpeed)
{
return that.CalculateMovement(stepCount, timeBeteenStep, addedSpeed, Vector3.zero);
}
/// <summary>
///
/// </summary>
/// <param name="that"></param>
/// <param name="stepCount">Number of steps</param>
/// <param name="timeBeteenStep">number of frames to skip</param>
/// <param name="addedSpeed"></param>
/// <param name="addedForce"></param>
/// <returns></returns>
public static Vector3[] CalculateMovement(this Rigidbody that,
int stepCount, float timeBeteenStep, Vector3 addedSpeed, Vector3 addedForce)
{
//var ret = new Vector3[stepCount];
// var addedV = (addedForce / that.mass) * Time.fixedDeltaTime;
var v = (that.isKinematic == false ? that.velocity : Vector3.zero);// + addedSpeed + addedV;
var a = (that.useGravity && that.isKinematic == false ? Physics.gravity : Vector3.zero);
return CalculateMovement(that.transform.position, v, a, stepCount, timeBeteenStep, addedSpeed, addedForce, that.mass, that.drag);
//var x = that.transform.position;
//var calc = new Vector3[] { x, v };
//for (var i = 0; i < stepCount; ++i)
//{
// calc = CalculateNewPos(calc[0], calc[1], a, that.drag, timeBeteenStep);
// ret[i] = calc[0];
//}
//return ret;
}
public static Vector3[] CalculateMovement(Vector3 position, Vector3 velocity, Vector3 acc,
int stepCount, float timeBeteenStep, Vector3 addedSpeed, Vector3 addedForce, float mass, float drag)
{
var ret = new Vector3[stepCount];
var addedV = (addedForce / mass) * Time.fixedDeltaTime;
var v = velocity + addedSpeed + addedV;
var a = acc;
var x = position;
var calc = new Vector3[] { x, v };
for (var i = 0; i < stepCount; ++i)
{
calc = CalculateNewPos(calc[0], calc[1], a, drag, timeBeteenStep);
ret[i] = calc[0];
}
return ret;
}
private static Vector3[] CalculateNewPos(Vector3 x, Vector3 v, Vector3 a, float drag, float deltaTimeCount)
{
var dt = Time.fixedDeltaTime;
var aDt = a * dt;
var dragDt = 1 - drag * dt;
dragDt = dragDt < 0 ? 0 : dragDt;
var acc = .5f * a * dt * dt;
for (int i = 0; i < deltaTimeCount; ++i)
{
v = (v + aDt) * dragDt;
x = x + v * dt + acc;
}
return new Vector3[]{ x, v };
}
private static Vector3 CalculateVDrag(Vector3 v, Vector3 a, float drag, int deltaTimeCount)
{
var dt = Time.fixedDeltaTime;
for(int i=0; i < deltaTimeCount; ++i)
v = (v + a * dt) * (1 - drag * dt);
return v;
}
Doesn't supports
public static Vector3[] CalculateTime(this Rigidbody that, Vector3 targetPos)
{
return CalculateTime(that, targetPos, Vector3.zero, Vector3.zero);
}
public static Vector3[] CalculateTime(this Rigidbody that, Vector3 targetPos,
Vector3 addedSpeed)
{
return CalculateTime(that, targetPos, addedSpeed, Vector3.zero);
}
public static Vector3[] CalculateTime(this Rigidbody that, Vector3 targetPos,
Vector3 addedSpeed, Vector3 addedForce)
{
var addedV = (addedForce / that.mass) * Time.fixedDeltaTime;
var v = that.velocity + addedSpeed + addedV;
var a = (that.useGravity && that.isKinematic == false ? Physics.gravity : Vector3.zero);
var x0 = that.transform.position;
//x = x0 +vt + .5*a*t^2
//-b +- SQR(b*b - 4*a*c)/2*a // a= .5*a//b=v//a=x0-x
//t12 = -v +- SQR(v*v -4 * .5 * a * (x0-x))/ 2 * .5 * a
var x = x0 - targetPos;
var sqr = (v.PointMul(v) - 4 * .5f * a.PointMul(x)).Sqrt();
var t1 = (-v + sqr).PointDiv(2 * .5f * a);
var t2 = (-v - sqr).PointDiv(2 * .5f * a);
// a=0: (x0-x) + vt -> t = (x-x0)/v
var tWhenA0 = x.PointDiv(v);
//a = 0
if (float.IsNaN(t1.x)) { t2.x = t1.x = tWhenA0.x; }
if (float.IsNaN(t1.y)) { t2.y = t1.y = tWhenA0.y; }
if (float.IsNaN(t1.z)) { t2.z = t1.z = tWhenA0.z; }
// a = 0 && v = 0
if (float.IsNaN(t1.x) && x0.x == targetPos.x) { t2.x = t1.x = 0; }
if (float.IsNaN(t1.y) && x0.y == targetPos.y) { t2.y = t1.y = 0; }
if (float.IsNaN(t1.z) && x0.z == targetPos.z) { t2.z = t1.z = 0; }
return new Vector3[] { t1, t2 };
}
public static Vector3 Sqrt(this Vector3 v)
{
return new Vector3(Mathf.Sqrt(v.x), Mathf.Sqrt(v.y), Mathf.Sqrt(v.z));
}
public static Vector3 PointMul(this Vector3 v1, Vector3 v2)
{
return new Vector3(v1.x*v2.x, v1.y*v2.y, v1.z*v2.z);
}
public static Vector3 PointDiv(this Vector3 v1, Vector3 v2)
{
return new Vector3(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z);
}
}
}
DrawLine.cs 画线工具类
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Dweiss;
[RequireComponent(typeof(LineRenderer))]
public class DrawLine : MonoBehaviour {
/// <summary>
/// 引导线
/// </summary>
public LineRenderer _lr;
/// <summary>
/// 刚体
/// </summary>
public Rigidbody _rb;
/// <summary>
/// 跨度
/// </summary>
public float timeBeteenStep = 1;
/// <summary>
/// 跨度数量
/// </summary>
public int stepCount = 30;
/// <summary>
/// 加速度
/// </summary>
public Vector3 addedV, addedF;
void Start() {
//找引导线
_lr = GetComponent<LineRenderer>();
//找刚体
_rb = GetComponent<Rigidbody>();
}
public void AddPower(Vector3 dir)
{
CalcTime();
_rb.velocity += addedV;
addedV = Vector3.zero;
_rb.AddForce(dir, ForceMode.Force);
addedF = Vector3.zero;
}
private void CalcTime()
{
Vector3[] t = _rb.CalculateTime(new Vector3(0, 0, 0),
addedV, addedF);
var timeT = new Vector3[]{
new Vector3(Time.time + t[0].x, Time.time + t[0].y, Time.time + t[0].z),
new Vector3(Time.time + t[1].x, Time.time + t[1].y, Time.time + t[1].z)
};
}
#region 抛物曲线
/// <summary>
/// 移动走向曲线
/// </summary>
private void DrawMovementLine()
{
var res = _rb.CalculateMovement(stepCount, timeBeteenStep, addedV, addedF);
_lr.positionCount = stepCount + 1;
_lr.SetPosition(0, transform.position);
for (int i = 0; i < res.Length; ++i)
{
_lr.SetPosition(i + 1, res[i]);
}
}
#endregion
void Update ()
{
DrawMovementLine();
if (Input.GetKeyDown(KeyCode.W))
{
AddPower((Vector3.right + Vector3.up) * 500f);
}
}
}
四、资源分享
CSDN下载链接
在我的资源中搜索 RigidBodyExtension