在 C# 中模拟重力:我的方法或实现有错误吗?
Simulating Gravity in C# : Error with my approach or implementation?
我正在尝试制作一个简单的 2D 物理引擎。引擎将重力定义为 90 度(垂直向下)时的 10 个单位。在宇宙中,有一些物理实体,每个实体都有一个由速度和方向组成的速度。每次实体更新时,我都会将重力矢量添加到每个实体的速度矢量。
如果实体是静止的或平行于重力矢量移动,它会掉落,否则它会成功一半。我的意思是,假设物体在表面上方 45 度角拍摄,它会上升,弯曲到顶点,然后继续平行于表面。重力似乎在上升时改变了速度,但不会使物体掉落。
我想知道我解决这个问题的方法是否有问题,或者我的解决方案在代码中的实现是否有问题。
更新函数:
public static void UpdateAll()
{
foreach (var entity in Entities)
{
entity.Velocity.AddVector(Universe.Gravity.Speed, Universe.Gravity.Direction);
}
var iterator = 1;
foreach (var entity in Entities)
{
for (var index = iterator; index < Entities.Count; index++)
{
//Collision Detection
}
entity.Update();
iterator++;
}
}
添加向量函数:
public void AddVector(float speed, int direction)
{
var radiansA = Angles.DegreesToRadians(SetDirection);
var radiansB = Angles.DegreesToRadians(direction);
var vAx = SetSpeed * (float) Math.Cos(radiansA);
var vAy = SetSpeed * (float) Math.Sin(radiansA);
var vBx = speed * (float) Math.Cos(radiansB);
var vBy = speed * (float) Math.Sin(radiansB);
var magX = vAx + vBx;
var magY = vAy + vBy;
var magnitude = (float) Math.Sqrt(Math.Pow(magX, 2) + Math.Pow(magY, 2));
var theta = Angles.RadiansToDegrees((float) Math.Atan2(magY, magX));
SetSpeed = magnitude;
SetDirection = theta;
}
编辑:我按照一些评论的建议删除了 if 语句,但结果仍然相同。
已解决:评论中指出了代码错误,我更新了添加功能以反映所需的更改。
不确定为什么需要测试方向。无论物体如何移动,都应添加重力矢量。如果它向上移动,它会减速。如果它向下移动,它会加速。如果它水平移动或根本不动,它就会开始下落。在任何情况下,这都是通过添加重力矢量来实现的。
速度也应该是一个向量。它应该有一个 x 和一个 y 分量。然后所有这些 "direction" 东西都可以被丢弃。因此,到处都使用由 x 和 y 定义的向量。然后,所有速度计算都将简化为简单的矢量加法。这使得所有数学运算比使用角度简单得多。
public struct Vector
{
public Vector(int x, int y)
{
this.X = x;
this.Y = y;
}
public int X { get; }
public int Y { get; }
public static Vector operator +(Vector a, Vector b)
{
return new Vector(a.X + b.X, a.Y + b.Y);
}
public float Magnitude
{
get
{
int d = X * X + Y * Y;
if (d == 1 || d == 0) {
return d;
} else {
return (float)Math.Sqrt(d);
}
}
}
public override string ToString()
{
return $"Vector({X}, {Y})";
}
}
也无需计算每次变速后的大小和角度。当您需要从适当的属性中获取这些值时,只需从向量中获取这些值即可。 (刚刚添加了一个 Magnitude 属性 作为例子)
Vector speed, gravity;
...
//Calculate new speed:
speed += gravity;
另一个有用的运算符重载是向量乘以常数
public static Vector operator *(double c, Vector a)
{
return new Vector((int)Math.Round(c * a.X), (int)Math.Round(c * a.Y));
}
我正在尝试制作一个简单的 2D 物理引擎。引擎将重力定义为 90 度(垂直向下)时的 10 个单位。在宇宙中,有一些物理实体,每个实体都有一个由速度和方向组成的速度。每次实体更新时,我都会将重力矢量添加到每个实体的速度矢量。
如果实体是静止的或平行于重力矢量移动,它会掉落,否则它会成功一半。我的意思是,假设物体在表面上方 45 度角拍摄,它会上升,弯曲到顶点,然后继续平行于表面。重力似乎在上升时改变了速度,但不会使物体掉落。
我想知道我解决这个问题的方法是否有问题,或者我的解决方案在代码中的实现是否有问题。
更新函数:
public static void UpdateAll()
{
foreach (var entity in Entities)
{
entity.Velocity.AddVector(Universe.Gravity.Speed, Universe.Gravity.Direction);
}
var iterator = 1;
foreach (var entity in Entities)
{
for (var index = iterator; index < Entities.Count; index++)
{
//Collision Detection
}
entity.Update();
iterator++;
}
}
添加向量函数:
public void AddVector(float speed, int direction)
{
var radiansA = Angles.DegreesToRadians(SetDirection);
var radiansB = Angles.DegreesToRadians(direction);
var vAx = SetSpeed * (float) Math.Cos(radiansA);
var vAy = SetSpeed * (float) Math.Sin(radiansA);
var vBx = speed * (float) Math.Cos(radiansB);
var vBy = speed * (float) Math.Sin(radiansB);
var magX = vAx + vBx;
var magY = vAy + vBy;
var magnitude = (float) Math.Sqrt(Math.Pow(magX, 2) + Math.Pow(magY, 2));
var theta = Angles.RadiansToDegrees((float) Math.Atan2(magY, magX));
SetSpeed = magnitude;
SetDirection = theta;
}
编辑:我按照一些评论的建议删除了 if 语句,但结果仍然相同。
已解决:评论中指出了代码错误,我更新了添加功能以反映所需的更改。
不确定为什么需要测试方向。无论物体如何移动,都应添加重力矢量。如果它向上移动,它会减速。如果它向下移动,它会加速。如果它水平移动或根本不动,它就会开始下落。在任何情况下,这都是通过添加重力矢量来实现的。
速度也应该是一个向量。它应该有一个 x 和一个 y 分量。然后所有这些 "direction" 东西都可以被丢弃。因此,到处都使用由 x 和 y 定义的向量。然后,所有速度计算都将简化为简单的矢量加法。这使得所有数学运算比使用角度简单得多。
public struct Vector
{
public Vector(int x, int y)
{
this.X = x;
this.Y = y;
}
public int X { get; }
public int Y { get; }
public static Vector operator +(Vector a, Vector b)
{
return new Vector(a.X + b.X, a.Y + b.Y);
}
public float Magnitude
{
get
{
int d = X * X + Y * Y;
if (d == 1 || d == 0) {
return d;
} else {
return (float)Math.Sqrt(d);
}
}
}
public override string ToString()
{
return $"Vector({X}, {Y})";
}
}
也无需计算每次变速后的大小和角度。当您需要从适当的属性中获取这些值时,只需从向量中获取这些值即可。 (刚刚添加了一个 Magnitude 属性 作为例子)
Vector speed, gravity;
...
//Calculate new speed:
speed += gravity;
另一个有用的运算符重载是向量乘以常数
public static Vector operator *(double c, Vector a)
{
return new Vector((int)Math.Round(c * a.X), (int)Math.Round(c * a.Y));
}