当给出开始点、结束点、速度和移动开始时间时,有没有更简单的方法来计算 2D 中的对象当前坐标?
Any less ugly way to calculate object current coords in 2D when start pt, end pt, speed and movement start time are given?
抱歉,几何从来不是我在学校最喜欢的科目,所以...
目前我正在编写 2D MMORPG 服务器模拟器,想改进我当前的坐标检测算法。
客户端向服务器发送带有 start point coords
和 finish point coords
的数据包。
服务器接收它并将 movement start
变量分配给 DateTime.Now
。
服务器知道角色在 1 秒内可以移动多远(即 speed
)。
如何计算他开始移动后 some
秒后的角色位置?
因为我不擅长几何,所以我根据行进距离的百分比编写了这个……垃圾……。
正在运行,但是计算量太大了。
public ushort X;
public ushort Y;
public ushort TargetX;
public ushort TargetY;
public DateTime MovementStartTime;
public ushort CalculatedX
{
get
{
if (this.X == this.TargetX && this.Y == this.TargetY)
return this.X;
float total_dst = CF.GetEuclideanDistanceBetween(this.X, this.Y, this.TargetX, this.TargetY);
float seconds_since_movement_start = (float)(DateTime.Now - this.MovementStartTime).TotalSeconds;
float passed_dst = Limits.CharacterSpeed * seconds_since_movement_start;
if (passed_dst > total_dst)
return this.TargetX;
float passed_dst_in_normalized_percents = (passed_dst * 100 / total_dst) / 100;
return (ushort)(this.X - ((this.X - this.TargetX) * passed_dst_in_normalized_percents));
}
}
public ushort CalculatedY
{
get
{
if (this.X == this.TargetX && this.Y == this.TargetY)
return this.Y;
float total_dst = CF.GetEuclideanDistanceBetween(this.X, this.Y, this.TargetX, this.TargetY);
float seconds_since_movement_start = (float)(DateTime.Now - this.MovementStartTime).TotalSeconds;
float passed_dst = Limits.CharacterSpeed * seconds_since_movement_start;
if (passed_dst > total_dst)
return this.TargetY;
float passed_dst_in_normalized_percents = (passed_dst * 100 / total_dst) / 100;
return (ushort)(this.Y - ((this.Y - this.TargetY) * passed_dst_in_normalized_percents));
}
}
想法是根据它的速度确定已经通过了多少百分比的线字符,然后将它与start X
和end X
之间的平坦距离结合起来。
也许有人知道一种不那么丑陋的方法?..
物体匀速运动时,X-coordinate对时间的依赖性为
X = X0 + Vx * t
其中 Vx
是速度的 x-component:
Vx = CharacterSpeed * dx / sqrt(dx*dx + dy*dy)
其中 dx, dy
是沿轴的距离。在你的情况下是这样的:
dx = this.TargetX - this.StartX
正如我在评论中提到的,一个简单的向量 class 将大大简化这一过程。如果您使用的是更高版本的 .Net,那么您可以在 System.Numerics 中使用 Vector2 class。如果你不这样做,那么你可以只添加我在这个 post.
末尾包含的简单向量 class (Vec2d)
然后您可以像这样将两个属性重写为一个 属性:
Vec2d calculatedXY
{
get
{
Vec2d source = new Vec2d((float)this.X, (float)this.Y);
Vec2d target = new Vec2d((float)this.TargetX, (float)this.TargetY);
Vec2d diff = target - source;
if(source == target)
return source;
float total_dst = diff.length;
float seconds_since_movement_start = (float)(DateTime.Now - this.MovementStartTime).TotalSeconds;
float passed_dst = Limits.CharacterSpeed * seconds_since_movement_start;
if(passed_dst > total_dst)
return target;
return source + ((diff/total_dst) * passed_dst);
}
}
如果您需要,这里是 Vec2d 结构(也可以写成 class):
public struct Vec2d
{
public float X;
public float Y;
public Vec2d(float x_, float y_)
{
X = x_;
Y = y_;
}
// calculated properties:
public float length
{
get { return (float)Math.Sqrt(X * X + Y * Y); }
}
// class operator definitions:
// equality
public static bool operator ==(Vec2d left, Vec2d right)
{
return (left.X == right.X) && (left.Y == right.Y);
}
public static bool operator !=(Vec2d left, Vec2d right)
{
return !(left == right);
}
// addition
public static Vec2d operator +(Vec2d left, Vec2d right)
{
return new Vec2d(left.X + right.X, left.Y + right.Y);
}
// subtraction
public static Vec2d operator -(Vec2d left, Vec2d right)
{
return new Vec2d(left.X - right.X, left.Y - right.Y);
}
// unary negation
public static Vec2d operator -(Vec2d value)
{
return new Vec2d(-value.X, -value.Y);
}
// scalar multiplication
public static Vec2d operator *(float scalar, Vec2d value)
{
return new Vec2d(scalar * value.X, scalar * value.Y);
}
public static Vec2d operator *(Vec2d value, float scalar)
{
return new Vec2d(scalar * value.X, scalar * value.Y);
}
// multiplication (vector dot product, NOT scalar dot product)
public static Vec2d operator *(Vec2d left, Vec2d right)
{
return new Vec2d(left.X * right.X, left.Y * right.Y);
}
// scalar division
public static Vec2d operator /(Vec2d value, float scalar)
{
return new Vec2d(value.X / scalar, value.Y / scalar);
}
}
抱歉,几何从来不是我在学校最喜欢的科目,所以...
目前我正在编写 2D MMORPG 服务器模拟器,想改进我当前的坐标检测算法。
客户端向服务器发送带有 start point coords
和 finish point coords
的数据包。
服务器接收它并将 movement start
变量分配给 DateTime.Now
。
服务器知道角色在 1 秒内可以移动多远(即 speed
)。
如何计算他开始移动后 some
秒后的角色位置?
因为我不擅长几何,所以我根据行进距离的百分比编写了这个……垃圾……。 正在运行,但是计算量太大了。
public ushort X;
public ushort Y;
public ushort TargetX;
public ushort TargetY;
public DateTime MovementStartTime;
public ushort CalculatedX
{
get
{
if (this.X == this.TargetX && this.Y == this.TargetY)
return this.X;
float total_dst = CF.GetEuclideanDistanceBetween(this.X, this.Y, this.TargetX, this.TargetY);
float seconds_since_movement_start = (float)(DateTime.Now - this.MovementStartTime).TotalSeconds;
float passed_dst = Limits.CharacterSpeed * seconds_since_movement_start;
if (passed_dst > total_dst)
return this.TargetX;
float passed_dst_in_normalized_percents = (passed_dst * 100 / total_dst) / 100;
return (ushort)(this.X - ((this.X - this.TargetX) * passed_dst_in_normalized_percents));
}
}
public ushort CalculatedY
{
get
{
if (this.X == this.TargetX && this.Y == this.TargetY)
return this.Y;
float total_dst = CF.GetEuclideanDistanceBetween(this.X, this.Y, this.TargetX, this.TargetY);
float seconds_since_movement_start = (float)(DateTime.Now - this.MovementStartTime).TotalSeconds;
float passed_dst = Limits.CharacterSpeed * seconds_since_movement_start;
if (passed_dst > total_dst)
return this.TargetY;
float passed_dst_in_normalized_percents = (passed_dst * 100 / total_dst) / 100;
return (ushort)(this.Y - ((this.Y - this.TargetY) * passed_dst_in_normalized_percents));
}
}
想法是根据它的速度确定已经通过了多少百分比的线字符,然后将它与start X
和end X
之间的平坦距离结合起来。
也许有人知道一种不那么丑陋的方法?..
物体匀速运动时,X-coordinate对时间的依赖性为
X = X0 + Vx * t
其中 Vx
是速度的 x-component:
Vx = CharacterSpeed * dx / sqrt(dx*dx + dy*dy)
其中 dx, dy
是沿轴的距离。在你的情况下是这样的:
dx = this.TargetX - this.StartX
正如我在评论中提到的,一个简单的向量 class 将大大简化这一过程。如果您使用的是更高版本的 .Net,那么您可以在 System.Numerics 中使用 Vector2 class。如果你不这样做,那么你可以只添加我在这个 post.
末尾包含的简单向量 class (Vec2d)然后您可以像这样将两个属性重写为一个 属性:
Vec2d calculatedXY
{
get
{
Vec2d source = new Vec2d((float)this.X, (float)this.Y);
Vec2d target = new Vec2d((float)this.TargetX, (float)this.TargetY);
Vec2d diff = target - source;
if(source == target)
return source;
float total_dst = diff.length;
float seconds_since_movement_start = (float)(DateTime.Now - this.MovementStartTime).TotalSeconds;
float passed_dst = Limits.CharacterSpeed * seconds_since_movement_start;
if(passed_dst > total_dst)
return target;
return source + ((diff/total_dst) * passed_dst);
}
}
如果您需要,这里是 Vec2d 结构(也可以写成 class):
public struct Vec2d
{
public float X;
public float Y;
public Vec2d(float x_, float y_)
{
X = x_;
Y = y_;
}
// calculated properties:
public float length
{
get { return (float)Math.Sqrt(X * X + Y * Y); }
}
// class operator definitions:
// equality
public static bool operator ==(Vec2d left, Vec2d right)
{
return (left.X == right.X) && (left.Y == right.Y);
}
public static bool operator !=(Vec2d left, Vec2d right)
{
return !(left == right);
}
// addition
public static Vec2d operator +(Vec2d left, Vec2d right)
{
return new Vec2d(left.X + right.X, left.Y + right.Y);
}
// subtraction
public static Vec2d operator -(Vec2d left, Vec2d right)
{
return new Vec2d(left.X - right.X, left.Y - right.Y);
}
// unary negation
public static Vec2d operator -(Vec2d value)
{
return new Vec2d(-value.X, -value.Y);
}
// scalar multiplication
public static Vec2d operator *(float scalar, Vec2d value)
{
return new Vec2d(scalar * value.X, scalar * value.Y);
}
public static Vec2d operator *(Vec2d value, float scalar)
{
return new Vec2d(scalar * value.X, scalar * value.Y);
}
// multiplication (vector dot product, NOT scalar dot product)
public static Vec2d operator *(Vec2d left, Vec2d right)
{
return new Vec2d(left.X * right.X, left.Y * right.Y);
}
// scalar division
public static Vec2d operator /(Vec2d value, float scalar)
{
return new Vec2d(value.X / scalar, value.Y / scalar);
}
}