球力学——这是最好的方法吗?
Ball Mechanics - Is this the best approach?
美好的一天,
我想编写一个在两个静止物体(object1
、object2
)之间传递的不断移动的球(object3
),并能够设置最大高度Y
动态传球轨迹。
您认为为这个概念编写球物理程序的最佳方法是什么?
我研究过在带刚体的默认球体上使用 addForce
。似乎应该有一个方程式来表达 object3
从 object1
的 x 到 object2
的 x... 的轨迹,给定 speed
,具有已知的集合 mass
和已知的重力环境。
但是,目前我有一个 Vector3.Lerp
在每个 FixedUpdate()
和 t
上的两个对象之间插值球,表示为:
`(Mathf.Sin(speed * Time.time) + 1.0f) / 2.0f;`
一切正常,但是使用这种方法,似乎没有明确的方法可以将 height
添加到球路径的轨迹中。我考虑过将 height
添加到 object2
中的 Y
值,直到球到达那里的一半,然后将其设置回原来的 Y
位置...但就是感觉不对!想法?
谢谢!
好的,如果我理解正确的话,你现在正在做的事
privte void FixedUpdate()
{
var factor = (Mathf.Sin(speed * Time.time) + 1.0f) / 2.0f;
object1.MovePosition(Vector3.Lerp(object2.position, object3.position, factor));
}
它在 object1
和 object2
位置之间移动乒乓球,但只是平面的。
假设现在物体只会在 XZ 平面内移动并且永远不会有不同的 Y 位置为了获得具有高度的曲线,您可以单独处理:
- 像以前一样在两个位置之间进行插值
- 用正弦函数或任何其他数学曲线函数单独计算 Y 位置 - 对于现实物理学可能实际上是抛物线
可能看起来有点像
public class Example : MonoBehaviour
{
public Rigidbody object1;
public Transform object2;
public Transform object3;
// adjust in the Inspector
public float speed = 1;
public float Amplitude = 0;
// Just for debug
[Range(0, 1)] [SerializeField] private float linearFactor;
[SerializeField] private float yPosition;
private void FixedUpdate()
{
// This always returns a value between 0 and 1
// and linearly pingpongs forth and back
linearFactor = Mathf.PingPong(Time.time * speed, 1);
// * Mathf.PI => gives now a value 0 - PI
// so sinus returns correctly 0 - 1 (no need for +1 and /2 anymore)
// then simply multiply by the desired amplitude
var sinus = Mathf.Sin(linearFactor * Mathf.PI);
yPosition = sinus * Amplitude;
// As before interpolate between the positions
// later we will ignore/replace the Y component
var position = Vector3.Lerp(object2.position, object3.position, linearFactor);
object1.MovePosition(new Vector3(position.x, yPosition, position.z));
}
}
您也可以选择尝试在 Y 方向添加一些倾斜,以使垂直运动更逼真(到达峰值时减速)。我尝试使用倒 SmoothStep
like
// just for debug
[Range(0, 1)] [SerializeField] private float dampedSinusFactor;
[Range(0, 1)] [SerializeField] private float linearFactor;
[SerializeField] private float yPosition;
private void FixedUpdate()
{
// Use two different factros:
// - a linear one for movement in XZ
// - a smoothed one for movement in Y (in order to slow down when reaching the peak ;) )
linearFactor = Mathf.PingPong(Time.time * speed, 1);
dampedSinusFactor = InvertSmoothStep(linearFactor);
// * Mathf.PI => gives now a value 0 - PI
// so sinus returns correctly 0 - 1 ()
// then simply multiply by the desired amplitude
var sinus = Mathf.Sin(dampedSinusFactor * Mathf.PI);
yPosition = sinus * Amplitude;
// later we will ignore/replace the Y component
var position = Vector3.Lerp(object2.position, object3.position, linearFactor);
object1.position = new Vector3(position.x, yPosition, position.z);
}
// source:
private float InvertSmoothStep(float x)
{
return x + (x - (x * x * (3.0f - 2.0f * x)));
}
然而对于缓慢的运动,这看起来有点奇怪。但是您可以想出任何其他数学曲线,这些曲线会导致 x=[0,1]
;)
的预期行为
美好的一天,
我想编写一个在两个静止物体(object1
、object2
)之间传递的不断移动的球(object3
),并能够设置最大高度Y
动态传球轨迹。
您认为为这个概念编写球物理程序的最佳方法是什么?
我研究过在带刚体的默认球体上使用 addForce
。似乎应该有一个方程式来表达 object3
从 object1
的 x 到 object2
的 x... 的轨迹,给定 speed
,具有已知的集合 mass
和已知的重力环境。
但是,目前我有一个 Vector3.Lerp
在每个 FixedUpdate()
和 t
上的两个对象之间插值球,表示为:
`(Mathf.Sin(speed * Time.time) + 1.0f) / 2.0f;`
一切正常,但是使用这种方法,似乎没有明确的方法可以将 height
添加到球路径的轨迹中。我考虑过将 height
添加到 object2
中的 Y
值,直到球到达那里的一半,然后将其设置回原来的 Y
位置...但就是感觉不对!想法?
谢谢!
好的,如果我理解正确的话,你现在正在做的事
privte void FixedUpdate()
{
var factor = (Mathf.Sin(speed * Time.time) + 1.0f) / 2.0f;
object1.MovePosition(Vector3.Lerp(object2.position, object3.position, factor));
}
它在 object1
和 object2
位置之间移动乒乓球,但只是平面的。
假设现在物体只会在 XZ 平面内移动并且永远不会有不同的 Y 位置为了获得具有高度的曲线,您可以单独处理: - 像以前一样在两个位置之间进行插值 - 用正弦函数或任何其他数学曲线函数单独计算 Y 位置 - 对于现实物理学可能实际上是抛物线
可能看起来有点像
public class Example : MonoBehaviour
{
public Rigidbody object1;
public Transform object2;
public Transform object3;
// adjust in the Inspector
public float speed = 1;
public float Amplitude = 0;
// Just for debug
[Range(0, 1)] [SerializeField] private float linearFactor;
[SerializeField] private float yPosition;
private void FixedUpdate()
{
// This always returns a value between 0 and 1
// and linearly pingpongs forth and back
linearFactor = Mathf.PingPong(Time.time * speed, 1);
// * Mathf.PI => gives now a value 0 - PI
// so sinus returns correctly 0 - 1 (no need for +1 and /2 anymore)
// then simply multiply by the desired amplitude
var sinus = Mathf.Sin(linearFactor * Mathf.PI);
yPosition = sinus * Amplitude;
// As before interpolate between the positions
// later we will ignore/replace the Y component
var position = Vector3.Lerp(object2.position, object3.position, linearFactor);
object1.MovePosition(new Vector3(position.x, yPosition, position.z));
}
}
您也可以选择尝试在 Y 方向添加一些倾斜,以使垂直运动更逼真(到达峰值时减速)。我尝试使用倒 SmoothStep
like
// just for debug
[Range(0, 1)] [SerializeField] private float dampedSinusFactor;
[Range(0, 1)] [SerializeField] private float linearFactor;
[SerializeField] private float yPosition;
private void FixedUpdate()
{
// Use two different factros:
// - a linear one for movement in XZ
// - a smoothed one for movement in Y (in order to slow down when reaching the peak ;) )
linearFactor = Mathf.PingPong(Time.time * speed, 1);
dampedSinusFactor = InvertSmoothStep(linearFactor);
// * Mathf.PI => gives now a value 0 - PI
// so sinus returns correctly 0 - 1 ()
// then simply multiply by the desired amplitude
var sinus = Mathf.Sin(dampedSinusFactor * Mathf.PI);
yPosition = sinus * Amplitude;
// later we will ignore/replace the Y component
var position = Vector3.Lerp(object2.position, object3.position, linearFactor);
object1.position = new Vector3(position.x, yPosition, position.z);
}
// source:
private float InvertSmoothStep(float x)
{
return x + (x - (x * x * (3.0f - 2.0f * x)));
}
然而对于缓慢的运动,这看起来有点奇怪。但是您可以想出任何其他数学曲线,这些曲线会导致 x=[0,1]
;)