问题描述
抱歉,但是几何从来都不是我在学校最喜欢的科目,所以...
目前,我正在编码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.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坐标对时间的依赖性为
X = X0 + Vx * t
其中Vx
是速度的x分量:
Vx = CharacterSpeed * dx / sqrt(dx*dx + dy*dy)
其中dx,dy
是沿轴的距离。在您的情况下,例如:
dx = this.TargetX - this.StartX
,
正如我在评论中提到的,一个简单的向量类将大大简化此过程。如果使用的是.Net的更高版本,则可以使用System.Numerics中的Vector2类。如果您不这样做,则只需添加我在本文结尾处包含的简单向量类(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结构(也可以作为类编写):
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);
}
}