在 JavaScript Canvas 中沿线移动点

发布于 2024-11-06 11:52:04 字数 84 浏览 4 评论 0原文

假设我有一条线的坐标(25,35 45,65, 30,85 - 这将是一条由两部分组成的线)。我需要每帧沿着该线以恒定距离移动一个点(汽车)。我该怎么做?

Let's say that I have the coordinates of a line (25,35 45,65, 30,85 - It would be a two part line). I need to move a point (car) along that line at a constant distance every frame. How can I do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

ぃ双果 2024-11-13 11:52:04

嘿,所以你的 2 条线的坐标为 (25,35) (45,65) (30,85),你想要移动的点将被放置在这些坐标的第一个 (25,35) 处,您希望它向第二个坐标 (45,65)(第一条线段的末端)移动。

第一步是获取点将要移动的方向,方向是点位置与目标位置之间的角度。要找到这个角度,您可以使用 Math.atan2(),将目标位置 Y - 点位置 Y 作为第一个参数传入,将第二个参数传入目标位置X - 点位置X

var Point = {X: 25, Y: 35};
var Target = {X:45, Y:65};

var Angle = Math.atan2(Target.Y - Point.Y, Target.X - Point.X);

现在获取该角度的正弦和余弦,正弦是沿 Y 轴移动的值,余弦是在 X 轴上移动的量。将正弦和余弦乘以每帧要移动的距离。

var Per_Frame_Distance = 2;
var Sin = Math.sin(Angle) * Per_Frame_Distance;
var Cos = Math.cos(Angle) * Per_Frame_Distance;

好的,现在剩下要做的就是设置重绘方法,在每次调用时将正弦添加到点的 Y 位置,将余弦添加到点的 X 位置。检查该点是否已到达目的地,然后执行相同的过程以移向第二条线段的末端。

Hey, so you have the coordinates (25,35) (45,65) (30,85) for your 2 lines, The point you want to move is going to be placed at the first of these coordinates (25,35) and you want it to move towards the second coordinate (45,65) (the end of the first line segment).

The first step is to get the orientation in which the point is going to move, the orientation is the angle between the point position and the target position. To find this angle you can use the Math.atan2(), passing in as the first argument the target position Y - the point position Y, and as the second argument the target position X - the point position X.

var Point = {X: 25, Y: 35};
var Target = {X:45, Y:65};

var Angle = Math.atan2(Target.Y - Point.Y, Target.X - Point.X);

Now get the Sine and Cosine of that angle, the Sine is the value to move along the Y axis, and the Cosine is how much to move on the X axis. Multiply the sine and cosine by the distance you want to move each frame.

var Per_Frame_Distance = 2;
var Sin = Math.sin(Angle) * Per_Frame_Distance;
var Cos = Math.cos(Angle) * Per_Frame_Distance;

Ok, what is left do to now is just setup the redraw method where you add the sine to the point's Y position and the cosine to the point's X position at each call. Check if the point has arrived to it's destination then do the same process to move towards the end of the second line segment.

陪你到最终 2024-11-13 11:52:04

晚了 8 年,但有人可能会发现这很有用。这种方法要快得多,因为它不使用 atan、cos、sin 和平方根等都很慢的东西。

function getPositionAlongTheLine(x1, y1, x2, y2, percentage) {
    return {x : x1 * (1.0 - percentage) + x2 * percentage, y : y1 * (1.0 - percentage) + y2 * percentage};
}

将百分比作为 0 到 1 之间的值传递,其中 0 是行的开头,1 是行的结尾。

var xy = getPositionAlongTheLine(100, 200, 500, 666, 0.5);
console.log(xy.x, xy.y);

8 years too late but someone may find this useful. This method is far faster given it doesn't uses stuff like atan, cos, sin and square root of which all are slow.

function getPositionAlongTheLine(x1, y1, x2, y2, percentage) {
    return {x : x1 * (1.0 - percentage) + x2 * percentage, y : y1 * (1.0 - percentage) + y2 * percentage};
}

Pass percentage as value between 0 and 1 where 0 is start of the line and 1 being the end.

var xy = getPositionAlongTheLine(100, 200, 500, 666, 0.5);
console.log(xy.x, xy.y);
太傻旳人生 2024-11-13 11:52:04

考虑这条线 (25,35 45,65)。从开始到结束的向量是(20, 30)。要沿该方向移动点 (x,y),我们只需添加该向量即可:

V = (20, 30)
(x,y) => (x+20,y+30)。

如果我们从行的开头开始,我们就会到达行尾。
但这一步太大了。我们想要更小但方向相同的东西,所以我们将向量乘以 0.1:

V = (2, 3)
(x,y) => (x+2,y+3)=> (x+4,y+6)=> ...

归一化很方便,即使其长度为1,我们通过除以它的长度来实现:

V => V/|V| = (2,3)/sqrt(22 + 32) = (7.21, 10.82)

然​​后您可以将其乘以您想要的任何步长。

Consider the line (25,35 45,65). The vector from the beginning to the end is (20, 30). To move a point (x,y) in that direction, we could just add that vector:

V = (20, 30)
(x,y) => (x+20, y+30).

If we start at the beginning of the line, we'll arrive at the end.
But that's too big a step. We want something smaller but in the same direction, so we multiply the vector by, say, 0.1:

V = (2, 3)
(x,y) => (x+2, y+3) => (x+4, y+6) => ...

It's convenient to normalize, that is to make its length 1, which we do by dividing by its length:

V => V/|V| = (2,3)/sqrt(22 + 32) = (7.21, 10.82)

Then you can just multiply that by whatever step size you want.

倾城泪 2024-11-13 11:52:04

有时,如何将数学公式转换为代码并不是那么明显。以下是沿直线移动点指定距离的函数的实现。它使用矢量表示法:

function travel(x, y, dx, x1, y1, x2, y2)
{
    var point = new Vector(x, y),
        begin = new Vector(x1, y1),
        end = new Vector(x2, y2);
    return end.sub(begin).norm().mul(dx).add(point);
}

class Vector
{
    constructor(x = 0, y = 0) {
        this.x = x;
        this.y = y;
    }

    clone() {
        return new this.constructor(this.x, this.y);
    }

    add(v) {
        this.x += v.x;
        this.y += v.y;
        return this;
    }

    sub(v) {
        this.x = this.x - v.x;
        this.y = this.y - v.y;
        return this;
    }

    mul(x) {
        this.x *= x;
        this.y *= x;
        return this;
    }

    div(x) {
        this.x /= x;
        this.y /= x;
        return this;
    }

    get mag() {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    }

    norm() {
        var mag = this.mag;
        if (mag > 0) {
            this.div(mag);
        }
        return this;
    }
}

以及没有 Vector 类的版本:

function travel(x, y, dx, x1, y1, x2, y2)
{
    var a = {x: x2 - x1, y: y2 - y1},
        mag = Math.sqrt(a.x*a.x + a.y*a.y);
    if (mag == 0) {
        a.x = a.y = 0;
    }
    else {
        a.x = a.x/mag*dx;
        a.y = a.y/mag*dx;
    }
    return {x: x + a.x, y: y + a.y};
}

Sometimes it's not so obvious how to translate a mathematical formula into a code. The following is an implementation of a function which moves a point specified distance along a line. It uses vector notation:

function travel(x, y, dx, x1, y1, x2, y2)
{
    var point = new Vector(x, y),
        begin = new Vector(x1, y1),
        end = new Vector(x2, y2);
    return end.sub(begin).norm().mul(dx).add(point);
}

class Vector
{
    constructor(x = 0, y = 0) {
        this.x = x;
        this.y = y;
    }

    clone() {
        return new this.constructor(this.x, this.y);
    }

    add(v) {
        this.x += v.x;
        this.y += v.y;
        return this;
    }

    sub(v) {
        this.x = this.x - v.x;
        this.y = this.y - v.y;
        return this;
    }

    mul(x) {
        this.x *= x;
        this.y *= x;
        return this;
    }

    div(x) {
        this.x /= x;
        this.y /= x;
        return this;
    }

    get mag() {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    }

    norm() {
        var mag = this.mag;
        if (mag > 0) {
            this.div(mag);
        }
        return this;
    }
}

And a version without Vector class:

function travel(x, y, dx, x1, y1, x2, y2)
{
    var a = {x: x2 - x1, y: y2 - y1},
        mag = Math.sqrt(a.x*a.x + a.y*a.y);
    if (mag == 0) {
        a.x = a.y = 0;
    }
    else {
        a.x = a.x/mag*dx;
        a.y = a.y/mag*dx;
    }
    return {x: x + a.x, y: y + a.y};
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文