Javascript 画布上的正弦运动:在转折点调用函数

Javascript 画布上的正弦运动:在转折点调用函数,javascript,math,canvas,Javascript,Math,Canvas,在画布上,圆在椭圆路径上移动: 守则的有关部分: function step() { x = Math.sin(counter) * 10 + 100; y = Math.cos(counter) * 50 + 100; // draw Circle with x / y position counter += 0.025; window.requestAnimationFrame(step); } window.requestAnimationFr

在画布上,圆在椭圆路径上移动:

守则的有关部分:

function step() {

    x = Math.sin(counter) * 10 + 100;
    y = Math.cos(counter) * 50 + 100;

    // draw Circle with x / y position

    counter += 0.025;
    window.requestAnimationFrame(step);
}
window.requestAnimationFrame(step);
现在我想在椭圆运动的垂直转折点调用一个函数,所以当
y
处于其最高/最低值时。最好的方法是什么

我尝试将以前的
y
值与当前的
y
值进行比较,但结果不正确。(或仅在一个方向上。)

提前感谢您的帮助

微积分

通过取其导数并找到导数等于
0
的位置,可以找到
y
的局部极值(最高值和最低值)

如果你对微积分知之甚少,一种用于计算直线在任意给定点的斜率的导数,
y
的导数(有时)表示为
y'
,发音为“y-prime”

知道斜率有帮助的原因是,当给定点的导数为
0
时,函数的瞬时斜率为
0
,这意味着原始函数既不增加也不减少,因此我们必须处于局部最大值或局部最小值。(你可以通过更多的微积分魔法来了解自己是处于最小值还是最大值。)

如果这不合理,想象你正在爬山。当你向上走的时候,坡度是正的。一旦到达顶部,坡度为
0
,因为您不会上下斜坡。在两座山之间行走也是一样——一旦你到达山谷,那里所有东西都是平坦的(
0
slope),你就到了谷底

所以。。。如果你想学习如何求导数,请查看。否则,快速的答案是
Math.cos(counter)*50+100的导数是
-50*Math.sin(counter)
。从这里开始,你需要做的就是找到这个导数的位置
0
,它每
n*180
度或
n*Math.PI
弧度发生一次,以你使用的为准

快速回答

无论何时
计数器%180==0
都需要调用函数

然而,问题是,
计数器
变量递增的时间间隔永远不会等于
Math.PI
,因此永远不会得到精确的
0
斜率。我建议将您的时间间隔切换到接近您拥有的时间间隔,但将平均分为
3.14159..
,如
0.008*Math.PI
(大约为.02513,但您可以根据需要进行微调):

var canvas=document.querySelector('canvas'),
ctx=canvas.getContext('2d'),
w=画布宽度,
h=画布高度,
x=y=0;
计数器=0;
函数步骤(){
如果(计数器Math.PI*2){
var maxY=数学最大值(数学cos(计数器)*50+100,数学cos(计数器+0.025)*50+100);
console.log(“maxY:+maxY”);
}
如果(计数器Math.PI){
var minY=数学最小值(数学cos(计数器)*50+100,数学cos(计数器+0.025)*50+100);
console.log(“minY:+minY”);
}
x=数学sin(计数器)*10+100;
y=数学cos(计数器)*50+100;
ctx.clearRect(0,0,w,h);
ctx.save();
ctx.beginPath();
弧(x,y,4,0,2*Math.PI,false);
ctx.fill();
ctx.restore();
计数器+=0.025;
如果(计数器>数学PI*2){
计数器%=数学PI*2;
}
window.requestAnimationFrame(步骤);
}
window.requestAnimationFrame(步骤);

这是。我想这正是您所要求的。

在处理浮点值时,您需要检查角度是否有一定的公差,因为由于舍入误差,您可能永远无法获得精确的值进行比较

我建议采取以下办法:

  • 使用步长值(如您所做)
  • 定义顶部和底部角度
  • 定义公差=步骤/2
例如:

var step = 0.025,            // angle step
    bottom = 0.5 * Math.PI,  // bottom angle (=90 deg)
    top = 1.5 * Math.PI,     // top angle (=270 deg)
    tol = step * 0.5;        // tolerance, 50% of step
现在,您可以通过以下方式比较该角度和公差:

if (counter > bottom - tol && counter < bottom + tol) {...bottom...}
else if (counter > top - tol && counter < top + tol) {...top...};

还有几件事:

  • 你已经切换了cos/sin。Cos代表x,sin代表y,否则它会朝相反的方向发展
  • var x=y=0不会做您认为它会做的事情,这里不会声明y

不需要太多数学知识,你可以做的一件事就是始终计算上一个
y
的值,然后当方向改变时,更改标志的值以帮助你确定每种情况,基本上是这样的:

var canvas = document.querySelector('canvas'),
ctx = canvas.getContext('2d'),
w = canvas.width,
h = canvas.height,
x = y = prev_y = 0;
counter = 0;
flag = 1;

function step() {

    x = Math.sin(counter) * 10 + 100;
    y = Math.cos(counter) * 50 + 100;

    if(prev_y > y && flag == 1){
         //Function for lowest position goes here
        flag = 0;
    }
    if(prev_y < y && flag == 0){
        //Function for highest position goes here
        flag = 1;
    }

    ctx.clearRect(0, 0, w, h);
    ctx.save();    
    ctx.beginPath();
    ctx.arc(x, y, 4, 0, 2*Math.PI, false);
    ctx.fill();    
    ctx.restore();

    counter += 0.025;
    window.requestAnimationFrame(step);

    prev_y = y;   

}

window.requestAnimationFrame(step);
var canvas=document.querySelector('canvas'),
ctx=canvas.getContext('2d'),
w=画布宽度,
h=画布高度,
x=y=prev_y=0;
计数器=0;
flag=1;
函数步骤(){
x=数学sin(计数器)*10+100;
y=数学cos(计数器)*50+100;
如果(上一个y>y&&flag==1){
//最低位置的函数在这里
flag=0;
}
如果(上一个y

或者,可能更简单,不要寻找导数sin(计数器)==0的确切位置,因为使用浮点数学,几乎永远不会达到该精确值。相反,只需寻找
sin(counter)
符号改变的点。幸运的是,您已经为另一个轴计算了
sin(counter)
,因此这不需要花费任何成本。甚至,您可以进行浮点舍入,但我同意,这总是有可能无法捕捉到所有的0。舍入还可能会多次调用“hit zero”函数,如果d
if (counter > bottom - tol && counter < bottom + tol) {...bottom...}
else if (counter > top - tol && counter < top + tol) {...top...};
counter = counter % (2 * Math.PI);
var canvas = document.querySelector('canvas'),
ctx = canvas.getContext('2d'),
w = canvas.width,
h = canvas.height,
x = y = prev_y = 0;
counter = 0;
flag = 1;

function step() {

    x = Math.sin(counter) * 10 + 100;
    y = Math.cos(counter) * 50 + 100;

    if(prev_y > y && flag == 1){
         //Function for lowest position goes here
        flag = 0;
    }
    if(prev_y < y && flag == 0){
        //Function for highest position goes here
        flag = 1;
    }

    ctx.clearRect(0, 0, w, h);
    ctx.save();    
    ctx.beginPath();
    ctx.arc(x, y, 4, 0, 2*Math.PI, false);
    ctx.fill();    
    ctx.restore();

    counter += 0.025;
    window.requestAnimationFrame(step);

    prev_y = y;   

}

window.requestAnimationFrame(step);