当给定起始点、终止点、速度和运动开始时间时,有没有更少丑陋的方法来计算2D中对象的当前坐标?

3

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

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

客户端向服务器发送带有起点坐标终点坐标的数据包。 服务器接收并将运动开始变量分配给DateTime.Now。 服务器知道角色每秒可以行进的距离(即速度)。 如何计算角色自开始运动一些秒后的位置?

由于我不擅长几何学,我根据已行驶路程的百分比编写了这个...垃圾...代码。 虽然它能工作,但需要进行太多计算。

        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 Xend X 之间的平面距离相结合。

也许有人知道更不丑陋的方法?... enter image description here


一些向量类可能会使这更容易。 - RBarryYoung
你正在使用哪个版本的 .net?稍后的版本中内置了一些向量类。 - RBarryYoung
@RBarryYoung - 谢谢您的回答。我使用的是 .net 4.0。 - Kosmo零
我也是,这就是为什么我需要自己的向量类。我认为在4.6之前,.Net没有得到它们。 - RBarryYoung
客户端发送带有起点坐标和终点坐标的数据包到服务器。- 切勿忘记客户端在敌人手中。 - AakashM
2个回答

2
当物体以恒定速度运动时,X坐标与时间的关系为
X = X0 + Vx * t

其中Vx是速度的x分量:

Vx = CharacterSpeed * dx / sqrt(dx*dx + dy*dy) 

其中dx, dy是沿轴的距离。在您的情况下,类似于:

dx = this.TargetX - this.StartX
 

未来阅读的答案可以通过链接到维基百科(或更适合的网站)进行改进。 - user2864740

1

正如我在评论中提到的,一个简单的向量类将大大简化此过程。如果您使用的是较新版本的.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);
    }
}

(注意:我已纠正了几处拼写错误) - RBarryYoung

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接