【问题标题】:Javascript object color change dynamically?Javascript对象颜色动态变化?
【发布时间】:2012-09-04 19:12:24
【问题描述】:

这是当两个球碰撞时将球的颜色变为红色的代码。我快到了,但我似乎没有找到故障,因为一个球没有改变颜色。请帮帮我!

 //generate a random number within a range
    function randomXToY(minVal,maxVal,floatVal)
    {
      var randVal = minVal+(Math.random()*(maxVal-minVal));
      return typeof floatVal=='undefined'?Math.round(randVal):randVal.toFixed(floatVal);
    }

    // The Ball class
    Ball = (function() {

      // constructor
      function Ball(x,y,radius,color){
        this.center = {x:x, y:y};  
        this.radius = radius;               
        this.color = color;
        this.dx = 2;               
        this.dy = 2;        
        this.boundaryHeight = $('#ground').height();
        this.boundaryWidth = $('#ground').width();

        this.dom  = $('<p class="circle"></p>').appendTo('#ground');

        // the rectange div a circle
        this.dom.width(radius*2);
        this.dom.height(radius*2);
        this.dom.css({'border-radius':radius,background:color});

        this.placeAtCenter(x,y);         
      }

      // Place the ball at center x, y
      Ball.prototype.placeAtCenter = function(x,y){
        this.dom.css({top: Math.round(y- this.radius), left: Math.round(x - this.radius)});
        this.center.x = Math.round(x);        
        this.center.y = Math.round(y);             
      };

      Ball.prototype.setColor = function(color) {
        if(color) {
          this.dom.css('background',color);
        } else {
          this.dom.css('background',this.color);
        }           
      };

      // move and bounce the ball
      Ball.prototype.move = function(){
        var diameter = this.radius * 2;                                               
        var radius = this.radius;  
        if (this.center.x - radius < 0 || this.center.x + radius > this.boundaryWidth ) {
          this.dx = -this.dx;
        }
        if (this.center.y - radius < 0 || this.center.y  + radius > this.boundaryHeight ) {
          this.dy = -this.dy;
        }
        this.placeAtCenter(this.center.x + this.dx ,this.center.y +this.dy);

      };



      return Ball;
    })();

    var number_of_balls = 5;
    var  balls = [];   
      var x; 
    var y;
    $('document').ready(function(){
      for (i = 0; i < number_of_balls; i++) { 
        var boundaryHeight = $('#ground').height();
        var boundaryWidth = $('#ground').width();
         y = randomXToY(30,boundaryHeight - 50);
         x = randomXToY(30,boundaryWidth - 50);
        var radius = randomXToY(15,30);
        balls.push(new Ball(x,y,radius, '#'+Math.floor(Math.random()*16777215).toString(16))); 
      }
      loop(); 
      check();

    });

    check = function(){
      for (var i = 0; i < balls.length; i++){

      for(var j=0;j<balls.length;j++){
        if (i!=j) {
          if (Math.pow(balls[j].center.x - balls[i].center.x, 2) + Math.pow(balls[j].center.y - balls[i].center.y, 2) <= Math.pow(balls[i].radius + balls[j].radius, 2)) {
            console.log(true);
            balls[j].setColor('red');
            balls[i].setColor('red');
          } else {
            balls[j].setColor(balls[j].color);

          } 
        }

     }}

       setTimeout(check,8);  
    };

    loop = function(){
      for (var i = 0; i < balls.length; i++){
        balls[i].move();
      }

      setTimeout(loop, 8);    
    };

这是 jsbin:http://jsbin.com/imofat/790/edit

【问题讨论】:

  • @RobinMaben 我在 21.0.1180.89,有时它对某些球不起作用。尝试更换更多的球并再次测试。

标签: javascript jquery css collision-detection euclidean-distance


【解决方案1】:

球都在碰撞;碰撞的公式是正确的,即:

(dx * dx) + (dy * dy) <= sum of the circles' radii

问题在于,由于 JavaScript 的单线程特性以及重置颜色的 ifelse 部分,有时屏幕不会更新以反映新颜色。

例如,当ball[0]ball[1] 碰撞时,您在if 中将ball[0] 的颜色设置为red,即OK。但是,如果ball[0] ball[2] 在内循环的下一次迭代(j=2)发生冲突,例如,它将reset ball[0] 的颜色恢复到原来的颜色,并且由于屏幕只会在 循环结束后渲染(同样,由于 JavaScript 的单线程特性),在这种情况下您永远不会看到 red 颜色。

所以,您有两个选择。 1) 发生碰撞时,break 将其排除在 inner 循环之外(如果您不需要每隔一个碰撞进行测试) ; 2) 标记哪些球已经碰撞,并且只重置循环中之前从未碰撞过的球的颜色,例如使用Array

var collisions = [];
for (var i = 0; i < balls.length; i++) {
  for (var j = 0; j < balls.length; j++) {
    if (i!=j) {
      if (Math.pow(balls[j].center.x - balls[i].center.x, 2) + Math.pow(balls[j].center.y - balls[i].center.y, 2) <= Math.pow(balls[i].radius + balls[j].radius, 2)) {
        collisions[i] = true;
        balls[i].setColor('red');
      } else {
        if (!collisions[i]) {
          balls[i].setColor(balls[i].color);
        }
      } 
    }
  }
}

另外,第二个循环可以简化为从i + 1 开始,而不是0。这样,您不仅减少了碰撞测试的次数,还删除了i != j 测试。

DEMO.

【讨论】:

    【解决方案2】:

    如果你想让红色在碰撞发生后保持不变,你需要设置小球的颜色:

    Ball.prototype.setColor = function(color) {        
        if(color) {
          this.color = color;  // The ball's color is now this value. 
          this.dom.css('background',color);
        } else {
          this.dom.css('background',this.color); // so when this is called, the ball will be that color going forward.
        }           
    };
    

    【讨论】:

    • 为什么不直接删除check() 的嵌套for 循环中的else?也可以。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-10
    • 1970-01-01
    • 2016-01-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多