【问题标题】:How to randomize the speed of rotating circle?如何随机化旋转圆周的速度?
【发布时间】:2018-10-01 07:02:38
【问题描述】:

我有两个圆圈围绕圆圈旋转,我希望圆圈在经过一圈后随机改变速度。两个圆圈的速度应该不同,或者它们可能是相同的速度(然后会发生碰撞)。例如,在第一次运行期间,两个圆都以 10m/s 的速度移动,当它到达旋转结束后,它们会发生碰撞。假设在旋转之后,它将圆 1 变为 15m/s,圆 2 变为 30m/s,那么它们就不会发生碰撞。我想知道如何实现这一点。这只是我想要实现的一个想法。如果每转后速度随机化就更好了。

任何帮助将不胜感激。

代码:

(function() {
  var ctx = document.getElementById("canvas").getContext("2d"),
    x1 = 160,
    y1 = 120,
    x2 = 330,
    y2 = 280,
    radius = 20;
  angle = 0,
    velX = 0,
    velY = 0,
    thrust = 3,
    rotation = 0;

  function draw() {
    velX = Math.cos(angle * Math.PI / 180) * thrust;
    velY = Math.sin(angle * Math.PI / 180) * thrust;
    x1 += velX;
    y1 += velY;
    angle += 1;
    ctx.fillStyle = "#000";
    ctx.clearRect(0, 0, 550, 400);
    ctx.beginPath();
    ctx.arc(x1, y1, radius, 0, Math.PI * 2);
    ctx.closePath();
    ctx.fill();

    draw2();
    setTimeout(function() {
      draw()
    }, 30);
  }

  function draw2() {
    velX = Math.cos(angle * Math.PI / 180) * thrust;
    velY = Math.sin(angle * Math.PI / 180) * thrust;
    x2 += -velX;
    y2 += -velY;
    angle += 1;
    ctx.fillStyle = "#80ced6";
    ctx.beginPath();
    ctx.arc(x2, y2, radius, 0, Math.PI * 2);
    ctx.closePath();
    ctx.fill();

    collisiondetection();
  }

  var distance = 0;
  var totalcounter = 0;
  var collide = false;

  function collisiondetection() {
    distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));

    if (distance < radius * 2) {
      if (collide == false) {
        totalcounter = totalcounter + 1;
        document.getElementById("cTotal").innerHTML = "Total collisions:" + totalcounter;
        collide = true;
      }

    } else {
      collide = false;
    }

  }
  draw();
})();
<canvas id="canvas" width="550" height="400" style="background:#eee;"></canvas>
<span id="cTotal">Total collisions: </span>

【问题讨论】:

  • 欢迎。你应该展示你的代码并告诉我们它到底有什么问题,并且没有按你的意愿工作。
  • 怎么样。 Math.floor(Math.random() * 101); // returns a random integer from 0 to 100 ?旋转后只需生成一个随机的speed 数字。
  • 只需声明一个可变速度并使其随机,并将值发送到setTimeout(function(){draw()}, speed)
  • 我不听你的解释
  • 我尝试了您关于声明速度变量并使其随机化的建议。问题是这两个圈子在每次革命中总是“碰撞”。这个想法是两个圆圈在不同的旋转中具有不同的速度,因此它们可能会发生碰撞或不会发生碰撞。我希望我说得通

标签: javascript html random settimeout


【解决方案1】:

您可以做的是向draw() 函数声明一个本地speed 变量,然后将其传递给setTimeout() 回调,如下所示:

var speed = Math.floor(Math.random() * 11);
draw2();
setTimeout(function() {
    draw()
}, speed);

代码Math.floor(Math.random() * 11) 会给你一个介于010 之间的随机数,所以setTimeout 每次都会以不同的速度被调用。

演示:

window.onload = function() {
  (function() {
    var ctx = document.getElementById("canvas").getContext("2d"),
      x1 = 160,
      y1 = 120,
      x2 = 330,
      y2 = 280,
      radius = 20;
    angle = 0,
      velX = 0,
      velY = 0,
      thrust = 3,
      rotation = 0;

    function draw() {
      velX = Math.cos(angle * Math.PI / 180) * thrust;
      velY = Math.sin(angle * Math.PI / 180) * thrust;
      x1 += velX;
      y1 += velY;
      angle += 1;
      ctx.fillStyle = "#000";
      ctx.clearRect(0, 0, 550, 400);
      ctx.beginPath();
      ctx.arc(x1, y1, radius, 0, Math.PI * 2);
      ctx.closePath();
      ctx.fill();

      var speed = Math.floor(Math.random() * 11);
      draw2();
      setTimeout(function() {
        draw()
      }, speed);
    }

    function draw2() {
      velX = Math.cos(angle * Math.PI / 180) * thrust;
      velY = Math.sin(angle * Math.PI / 180) * thrust;
      x2 += -velX;
      y2 += -velY;
      angle += 1;
      ctx.fillStyle = "#80ced6";
      ctx.beginPath();
      ctx.arc(x2, y2, radius, 0, Math.PI * 2);
      ctx.closePath();
      ctx.fill();

      collisiondetection();
    }

    var distance = 0;
    var totalcounter = 0;
    var collide = false;

    function collisiondetection() {
      distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));

      if (distance < radius * 2) {
        if (collide == false) {
          totalcounter = totalcounter + 1;
          document.getElementById("cTotal").innerHTML = "Total collisions:" + totalcounter;
          collide = true;
        }

      } else {
        collide = false;
      }

    }
    draw();
  })();
}
<canvas id="canvas" width="550" height="400" style="background:#eee;"></canvas>
<span id="cTotal">Total collisions: </span>

【讨论】:

  • 您的解决方案的问题是,每次迭代后,两个圆圈总是“碰撞”。我想要实现的可能是如果两个圆圈具有不同的速度(随机),那么它们可能会发生碰撞或不会发生碰撞。这可能吗?
  • 不,永远不要从具有随机间隔的动画循环中调用绘图方法。绘图方法应与屏幕刷新率同步。
  • @TomCold 其实这不是很清楚,你在问什么,你在寻找一个随机的速度,对吧?两个圈子需要不同吗?
  • @chŝdk 也许我的问题不清楚。但我编辑了它以获得许可。因为如果两个圆圈以不同的速度移动,那么它们就不会发生碰撞,否则它们就会发生碰撞。所以我的观点是我希望两个圆圈都具有随机速度(它们都不需要具有相同的速度),如果它们这样做,那么它们会发生碰撞,这很好。重点是我试图模拟随机发生碰撞的次数。你上面的回答改变了两个圈子的速度,所以勾结总是会发生的。
  • 其实防止碰撞的不是速度,而是造成碰撞的矩形和角度,因为你给的值是一样的。
【解决方案2】:

angle 变为 360 时,即旋转完成时,您可以更改 timeGap。因此,它会随着速度的变化而出现。

在您的 draw() 函数中:

if(angle % 360 == 0) {
    timeGap = Math.random() * 20 + 5;
}

(function() {
  var ctx = document.getElementById("canvas").getContext("2d"),
    x1 = 160,
    y1 = 120,
    x2 = 330,
    y2 = 280,
    radius = 20,
    angle1 = 0,
    angle2 = 0,
    velX = 0,
    velY = 0,
    thrust = 3,
    rotation = 0,
    timeGap1 = 10,
    timeGap2 = 10,
    diff = 20,
    minTimeGap = 20;

  function draw() {
    velX = Math.cos(angle1 * Math.PI / 180) * thrust;
    velY = Math.sin(angle1 * Math.PI / 180) * thrust;
    x1 += velX;
    y1 += velY;
    angle1 += 2;
    ctx.fillStyle = "#000";
    ctx.beginPath();
    ctx.arc(x1, y1, radius, 0, Math.PI * 2);
    ctx.closePath();
    ctx.fill();
    
    if(angle1 % 360 == 0) {
        timeGap1 = Math.random() * diff + minTimeGap;
    }
    
    setTimeout(function() {
      draw();
    }, timeGap1);
  }

  function draw2() {
    velX = Math.cos(angle2 * Math.PI / 180) * thrust;
    velY = Math.sin(angle2 * Math.PI / 180) * thrust;
    x2 += -velX;
    y2 += -velY;
    angle2 += 2;
    ctx.fillStyle = "#007700";
    ctx.beginPath();
    ctx.arc(x2, y2, radius, 0, Math.PI * 2);
    ctx.closePath();
    ctx.fill();

    if(angle2 % 360 == 0) {
        timeGap2 = Math.random() * diff + minTimeGap;
    }    
    
    setTimeout(function() {
      draw2();
    }, timeGap2);
  }
  
  function clearCanvas() {
  	ctx.fillStyle = 'rgba(220,220,220,0.5)';
    ctx.fillRect(0, 0, 550, 400);
    collisiondetection();
    
    setTimeout(function() {
      clearCanvas();
    }, timeGap2 + timeGap1);
  }

  var distance = 0;
  var totalcounter = 0;
  var collide = false;

  function collisiondetection() {
    distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));

    if (distance < radius * 2) {
      if (collide == false) {
        totalcounter = totalcounter + 1;
        document.getElementById("cTotal").innerHTML = "Total collisions:" + totalcounter + "<br/>Speed1: " + timeGap1 + "<br/>Speed2: " + timeGap2;
        collide = true;        
      }

    } else {
      collide = false;
    }
  }
  draw();
  draw2();
  clearCanvas();
})();
<canvas id="canvas" width="550" height="400" style="background:#eee;"></canvas>
<span id="cTotal">Total collisions: </span>

【讨论】:

  • 但每转一圈后两个圆圈总会发生碰撞。
  • @TomCold 我刚刚更新了我的答案以消除碰撞依赖性。
  • 这是否意味着两个圆圈的速度不同?
  • 不行,每转一圈,两个圆圈总会发生碰撞。
  • @TomCold,我说过两个圆圈的速度不同(与之前的旋转相比,但两者相对于彼此以相同的速度旋转)。它对我有用,什么对你不起作用,我不知道。你能解释更多吗?
【解决方案3】:

(function() {
  var ctx = document.getElementById("canvas").getContext("2d"),
    x1 = 160,
    y1 = 120,
    x2 = 330,
    y2 = 280,
    radius = 20;
  angle = 0,
    velX = 0,
    velY = 0,
    thrust = 3,
    rotation = 0,  
    maxSpeed = 100,      
    speed = Math.floor(Math.random() * 100) + 1;

  function draw() {
    velX = Math.cos(angle * Math.PI / 180) * thrust;
    velY = Math.sin(angle * Math.PI / 180) * thrust;
    x1 += velX;
    y1 += velY;
    angle += 1;
    ctx.fillStyle = "#000";
    ctx.clearRect(0, 0, 550, 400);
    ctx.beginPath();
    ctx.arc(x1, y1, radius, 0, Math.PI * 2);
    ctx.closePath();
    ctx.fill();

    draw2();
    SpeedCount();
  }

  function draw2() {
    velX = Math.cos(angle * Math.PI / 180) * thrust;
    velY = Math.sin(angle * Math.PI / 180) * thrust;
    x2 += -velX;
    y2 += -velY;
    angle += 1;
    ctx.fillStyle = "#80ced6";
    ctx.beginPath();
    ctx.arc(x2, y2, radius, 0, Math.PI * 2);
    ctx.closePath();
    ctx.fill();

    collisiondetection();
  }
  
  function SpeedCount(){
  (function(speed) {
  setTimeout(function() {
      draw()
    }, speed);
  })(speed);
}


  var distance = 0;
  var totalcounter = 0;
  var collide = false;

  function collisiondetection() {
    distance = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));

    if (distance < radius * 2) {
      if (collide == false) {
        totalcounter = totalcounter + 1;
        document.getElementById("cTotal").innerHTML = "Total collisions:" + totalcounter;
        collide = true;
      }

    } else {
      collide = false;
    }
    
    if((angle + 90) % 360 == 0){   
         speed = Math.floor(Math.random() * maxSpeed) + 1;
    }

  }
  draw();
})();
<canvas id="canvas" width="550" height="400" style="background:#eee;"></canvas>
<span id="cTotal">Total collisions: </span>

试试这个。

【讨论】:

    【解决方案4】:

    让我们稍微修改一下:

    首先,在编写图形动画时,您应该将对象逻辑和绘图操作分开。

    应根据屏幕刷新率定期进行绘制操作(以避免有时一帧绘制两次,有时根本不绘制)。

    Web API 中针对这种确切情况提供的一种便捷方法是requestAnimationFrame(callback)。它将在下一个屏幕刷新率之前将我们的回调加入队列。
    所以我们可以将它用作动画循环的核心,它始终以屏幕显示的相同速率(通常为 60FPS)触发。

    当场景中有动画对象时,js 中最简单的数据结构就是 Objects。您无需在任何地方都保存大量变量,而是将它们打包在自己的对象中。
    当你有多个这样的对象时,你把它们放在一起(例如在一个数组中)。

    现在,在我们的动画循环中,我们将首先更新对象位置,然后绘制它们。
    在更新部分,我们将控制对象的速度,只有在更新完所有对象后,我们才会检查它们是否发生碰撞。

    (function() {
      var ctx = document.getElementById("canvas").getContext("2d"),
    
        max_speed = Math.PI / 12,
        objects = [{
            center_x: 160,
            center_y: 120,
            speed: Math.random() % max_speed,
            angle: 0,
            color: '#000'
          },
          {
            center_x: 330,
            center_y: 280,
            speed: -(Math.random() % max_speed),
            angle: 0,
            color: "#80ced6"
          }
        ],
        radius = 20,
        outerRad = 120,
        totalcounter = 0,
        collide = true;
    
      anim(); // begin our main anim loop
    
      function anim() {
        update(); // our objects update logic
        draw(); // now we draw
        collisiondetection(); // DOM update
        requestAnimationFrame(anim); // start again @next-frame
      }
    
    
      function update() {
        // here we only change the object's properties
        // nothing graphical should come here
        objects.forEach(function(object) {
          var angle = object.angle;
          object.x = Math.cos(angle) * outerRad + object.center_x;
          object.y = Math.sin(angle) * outerRad + object.center_y;
          object.angle += object.speed;
        });
      }
    
      function draw() {
        // here is only the graphical part
        // no logic should come here
        ctx.clearRect(0, 0, 550, 400);
        objects.forEach(function(object) {
          ctx.fillStyle = object.color;
          ctx.beginPath();
          ctx.arc(object.x, object.y, radius, 0, Math.PI * 2);
          ctx.fill();
        });
      }
    
      function collisiondetection() {
        var o1 = objects[0],
          o2 = objects[1];
        var distance = Math.sqrt((o1.x - o2.x) * (o1.x - o2.x) + (o1.y - o2.y) * (o1.y - o2.y));
    
        if (distance < radius * 2) {
          if (collide == false) {
            totalcounter = totalcounter + 1;
            document.getElementById("cTotal").innerHTML = "Total collisions:" + totalcounter;
            collide = true;
          }
    
        } else {
          collide = false;
        }
    
      }
    
      // and now if you want to update randomly these object's speed, you can do from anywhere
      document.onclick = function() {
        objects[0].speed = Math.random() % max_speed;
        objects[1].speed = -(Math.random() % max_speed);
      };
    
    })();
    <canvas id="canvas" width="550" height="400" style="background:#eee;"></canvas>
    <p id="cTotal">Total collisions: </p>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-24
      • 1970-01-01
      • 1970-01-01
      • 2017-11-07
      相关资源
      最近更新 更多