我正在制作一款能够击退对物理力量作出反应的射弹的游戏。我在游戏中使用内置的Unity物理,但是我在射击之前绘制了射弹的轨迹。为此,我使用LineRenderer和一个简单的Physics类来计算位置:
public class SlingPhysics
{
private Vector3 HalfGravity;
private float ForceMultiplier;
public void Init(Vector3 gravity, float slingForce, float mass, float drag)
{
HalfGravity = gravity / 2.0f;
ForceMultiplier = slingForce / mass / (1 + drag);
}
public Vector3 GetPosition(Vector3 start, Vector3 direction, float timeDelta)
{
Vector3 pos = direction * (timeDelta * ForceMultiplier);
pos.y += (HalfGravity.y * timeDelta * timeDelta);
return start + pos;
}
/// <summary>
/// Computes an array of Trajectory object positions by time.
/// </summary>
/// <returns>Number of positions filled into the buffer</returns>
/// <param name="startPos">Starting Position</param>
/// <param name="direction">Direction (and magnitude) vector</param>
/// <param name="timeIncrement">Time increment of the samples</param>
/// <param name="yFloor">Minimum height, below which is clipped</param>
/// <param name="positions">Buffer to fill with positions</param>
public int GetPositions(Vector3 startPos, Vector3 direction, float timeIncrement, float yFloor, Vector3[] positions)
{
int maxItems = positions.Length;
int i = 0;
for (; i < maxItems; i++)
{
Vector3 pos = GetPosition(startPos, direction, timeIncrement * i);
if (pos.y < yFloor)
break;
positions[i] = pos;
}
return i;
}
}
这很有效,并且(有些令人惊讶地)完全匹配射弹在发射时最终行进的实际轨迹,并由Unity物理引擎控制。
但是现在,我们决定将拖拽引入刚体,并且轨迹不再完美。我可以继续尝试改变我的物理模型以匹配Unity正在做的事情,但这似乎是一场失败的战斗。
有没有办法使用Unity Physics引擎预先计算和绘制轨迹?
如果没有,在Unity Physics中如何以数学方式实现拖动和角度拖动?
是否有Unity(5.3.4)物理实现的文档源?
答案 0 :(得分:5)
我可以继续尝试改变我的物理模型以匹配Unity 正在做
不,不要这样做。每当Unity更新时,物理学的东西就会破坏。例如,Unity 4和5物理学不一样。不得不大量修改我的Unity 4物理代码以使其正常工作。
解决您问题的最简单方法是不计算任何内容。我这样做的方法是创建两个射弹。 Projectile1 是可以看到和射击的主要射弹。 Projectile2 是隐藏的射弹,不能被玩家看到。
在拖动模式下,拍摄 Projectile2 (隐藏),然后存储它在List
中经过的路径或位置(Vector3)。使用该存储的路径绘制Projectile Trajectory
。
您只需要拍摄 Projectile2 (隐藏)一次并存储路径。如果在拖动模式下,手指,鼠标或拖动移动到另一个位置,则必须清除 List
,重新拍摄 Projectile2 (隐藏)一次再次,将位置存储到List
,然后再次更新Projectile Trajectory
。
当释放手指时,您现在可以拍摄播放器可见的 Projectile1 (主射弹)。
如果您使用lineRenderer
,则SetVertexCount
的数量与List.Count
的数量相同。通过循环List
。
无论Unity更新多少次,结果总是相同的。
答案 1 :(得分:3)
计算拖拽以匹配Unity引擎的方法是在FixedUpdate中计算并跟踪速度,然后更新Drag的速度。
这里提供了Drag的Unity公式: http://forum.unity3d.com/threads/drag-factor-what-is-it.85504/
这确实很简单;关键部分是:
velocity *= Mathf.Clamp01(1f - Drag * Time.fixedDeltaTime);
自定义Physics类必须重新设计,要求时间增量为Unity的Time.fixedDeltaTime(FixedUpdate调用之间的时间)
public class SlingPhysics
{
private Vector3 Gravity;
private float Force, Mass, Drag;
public void Init(Vector3 gravity, float force, float mass, float drag)
{
Gravity = gravity;
Force = force;
Mass = mass;
Drag = drag;
}
/// <summary>
/// Computes an array of Trajectory object positions by time.
/// </summary>
/// <returns>Number of positions filled into the buffer</returns>
/// <param name="startPos">Starting Position</param>
/// <param name="direction">Direction (and magnitude) vector</param>
/// <param name="yFloor">Minimum height, below which is clipped</param>
/// <param name="positions">Buffer to fill with positions</param>
public int GetPositions(Vector3 startPos, Vector3 direction, float yFloor, Vector3[] positions)
{
float timeIncrement = Time.fixedDeltaTime;
int maxItems = positions.Length;
int i = 0;
Vector3 velocity = direction * Force / Mass;
Vector3 pos = startPos;
for (; i < maxItems; i++)
{
velocity += Gravity * timeIncrement;
velocity *= Mathf.Clamp01(1f - Drag * timeIncrement);
pos += velocity * timeIncrement;
if (pos.y < yFloor)
break;
positions[i] = pos;
}
return i;
}
}