给定开始点,结束点,速度和运动开始时间时,在二维中计算对象当前坐标的方法是否更丑陋?

问题描述

抱歉,但是几何从来都不是我在学校最喜欢的科目,所以...

目前,我正在编码2D MMORPG服务器仿真器,并希望改进当前的坐标检测算法。

客户端使用start point coordsfinish 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 Xend X间的平坦距离结合起来。

也许有人知道一种不太丑陋的方法

enter image description here

解决方法

当物体以恒定速度运动时,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);
    }
}