击中物体后停球

时间:2015-12-12 21:36:50

标签: javascript canvas

我想知道如何在击中物体时阻止移动的球。我正在使用帆布。 这是一个小例子:

    <!DOCTYPE html>
  <html>
  <head>
      <title>Ball Race</title>
  </head>

  <body>

      <script src="https://code.jquery.com/jquery-2.1.0.js"></script>
<canvas id="canvas" width="800" height="200"></canvas>
      <script>

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;




var circle = function (x, y, radius, fillCircle) {
  ctx.beginPath();
  ctx.arc(x, y, radius, 0, Math.PI * 2, false);
  if (fillCircle) {
    ctx.fill();
  } else {
    ctx.stroke();
  }
};

var drawRect = function (x, y) {
ctx.fillRect(x, y, 20, 20)
}

var Object = function (xPos, yPos) {
this.x = xPos;
this.y = yPos;
}
// The Ball constructor
var Ball = function () {
  this.x = width / 2;
  this.y = height / 2;
  this.xSpeed = 0;
  this.ySpeed = 0;
  this.radius = 10;
};

// Update the ball's position based on its speed
Ball.prototype.move = function () {
  this.x += this.xSpeed;
  this.y += this.ySpeed;

  if (this.x < 11) {
    this.x = 11;
  } else if (this.x > width - 11) {
    this.x = width - 11;
  } else if (this.y < 11) {
    this.y = 11;
  } else if (this.y > height - 11) {
    this.y = height - 11;
  }
};

// Draw the ball at its current position
Ball.prototype.draw = function () {
  circle(this.x, this.y, 10, true);
};

Object.prototype.draw = function () {
    drawRect(this.x, this.y)
}

//collision types



Object.prototype.checkCollision = function (direction) {
    return (ball.x-ball.radius < this.x + 20)
      && (ball.x+ball.radius > this.x)
      && (ball.y-ball.radius < this.y + 20)
      && (ball.y+ball.radius > this.y)
      ;
}

function draw() {
    ctx.clearRect(0, 0, width, height);

    ball.draw();
    object1.draw();
    object2.draw();
    object3.draw();
    object4.draw();
    object5.draw();

    ctx.strokeRect(0, 0, width, height);
}

function simulate() {
  for (z = 0; z < 5; z++) {
    var prev_ball_x = ball.x;
    var prev_ball_y = ball.y;
    ball.move();
    // handle collision here
    if (object1.checkCollision() || object2.checkCollision() || object3.checkCollision() || object4.checkCollision() || object5.checkCollision()) {
        ball.setDirection('stop');
        // reset ball's position so they do not overlap
        ball.x = prev_ball_x;
        ball.y = prev_ball_y;
    }

  }

  if ($("body").keyup()) {
      ball.setDirection('stop');
    }
}

setInterval(function () {
    // separate drawing and simulating phases
    simulate();
    draw();
}, 30);

// Set the ball's direction based on a string
Ball.prototype.setDirection = function (direction) {
  if (direction === "up") {
     this.xSpeed = 0;
     this.ySpeed = -1;
  } else if (direction === "down") {
     this.xSpeed = 0;
     this.ySpeed = 1;
  } else if (direction === "left") {
     this.xSpeed = -1;
     this.ySpeed = 0;
  } else if (direction === "right") {
     this.xSpeed = 1;
     this.ySpeed = 0;
  } else if (direction === "stop") {
     this.xSpeed = 0;
     this.ySpeed = 0;
  }
};

// Create the ball object
var ball = new Ball();
var object1 = new Object(50, 0);
var object2 = new Object(50, 20);
var object3 = new Object(50, 40);
var object4 = new Object(50, 60);
var object5 = new Object(50, 80);


// An object to convert keycodes into action names
var keyActions = {
  32: "stop",
  37: "left",
  38: "up",
  39: "right",
  40: "down"
};

// The keydown handler that will be called for every keypress
$("body").keydown(function (event) {
  var direction = keyActions[event.keyCode];
  ball.setDirection(direction);
});



       </script>
   </body>
   </html>

我知道可以将速度设置为0,但是setInterval会自动更新它以再次移动。我怎么解决这个问题才能让球停下来?

1 个答案:

答案 0 :(得分:0)

您可以在碰撞时将速度设置为0。但请注意,对象将保持重叠,因此即使用户试图移动球,碰撞检查也会将设置速度恢复为0。

我还将两个区间合并为一个,因为第二个区间做了很多 不必要的工作。

这是您编写物理引擎时迈出的第一步。幸运的是,这里只有球在移动,而且实际上并不是基于物理学,所以我们可以通过在碰撞时将球重新定位到非重叠位置来做一些“黑客攻击”。

Object.prototype.checkCollision = function (direction) {
    var colx = (ball.x-ball.radius<this.x&&ball.x+ball.radius>this.x)||(ball.x-ball.radius<this.x+20&&ball.x+ball.radius>this.x+20);
    var coly = (ball.y-ball.radius<this.y&&ball.y+ball.radius>this.y)||(ball.y-ball.radius<this.y+20&&ball.y+ball.radius>this.y+20);

    // it really just checks but takes no action
    return colx&&coly;
}

// ...

function draw() {
    ctx.clearRect(0, 0, width, height);

    ball.draw();
    object.draw();
    drawLives();

    ctx.strokeRect(0, 0, width, height);
}

function simulate() {
    var prev_ball_x = ball.x;
    var prev_ball_y = ball.y;
    ball.move();
    // handle collision here
    if (object.checkCollision()) {
        ball.setDirection('stop');
        // reset ball's position so they do not overlap
        ball.x = prev_ball_x;
        ball.y = prev_ball_y;
    }
}

setInterval(function () {
    // separate drawing and simulating phases
    simulate();
    draw();
}, 30);

编辑:

通过从头开始重写来修复checkCollision中的错误。

Object.prototype.checkCollision = function (direction) {
    return (ball.x-ball.radius < this.x + 20)
      && (ball.x+ball.radius > this.x)
      && (ball.y-ball.radius < this.y + 20)
      && (ball.y+ball.radius > this.y)
      ;
}

当从顶部接近时,存在间隙,因为球被重新定位到前一帧中的位置。你可以通过适当的重新定位来做得更好。

  

这很难,因为需要考虑多方面

是的,的确如此。这就是为什么我建议这个“转移到以前的位置”黑客。

你可以通过更多的小步骤让这种hacky方法看起来更好。您可以将ball.speed设置为1而不是5,并在for循环中执行simulate五次。

编辑:更改后的完整代码

<!DOCTYPE html>
  <html>
  <head>
      <title>Ball Race</title>
  </head>

  <body>

      <script src="https://code.jquery.com/jquery-2.1.0.js"></script>
<canvas id="canvas" width="800" height="200"></canvas>
      <script>

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var width = canvas.width;
var height = canvas.height;
var lives = 3;

var drawLives = function () {
    ctx.font = "20px Courier";
    ctx.fillStyle = "Black";
    ctx.textAlign = "left";
    ctx.textBaseline = "top";
    ctx.fillText("Lives left: " + lives, 10, 10);
  };

var circle = function (x, y, radius, fillCircle) {
  ctx.beginPath();
  ctx.arc(x, y, radius, 0, Math.PI * 2, false);
  if (fillCircle) {
    ctx.fill();
  } else {
    ctx.stroke();
  }
};

var drawRect = function (x, y) {
ctx.fillRect(x, y, 20, 20)
}

var Object = function () {
this.x = width / 4;
this.y = height / 4;
}
// The Ball constructor
var Ball = function () {
  this.x = width / 2;
  this.y = height / 2;
  this.xSpeed = 0;
  this.ySpeed = 0;
  this.radius = 10;
};

// Update the ball's position based on its speed
Ball.prototype.move = function () {
  this.x += this.xSpeed;
  this.y += this.ySpeed;

  if (this.x < 11) {
    this.x = 11;
  } else if (this.x > width - 11) {
    this.x = width - 11;
  } else if (this.y < 11) {
    this.y = 11;
  } else if (this.y > height - 11) {
    this.y = height - 11;
  }
};

// Draw the ball at its current position
Ball.prototype.draw = function () {
  circle(this.x, this.y, 10, true);
};

Object.prototype.draw = function () {
    drawRect(this.x, this.y)
}

//collision types



Object.prototype.checkCollision = function (direction) {
    return (ball.x-ball.radius < this.x + 20)
      && (ball.x+ball.radius > this.x)
      && (ball.y-ball.radius < this.y + 20)
      && (ball.y+ball.radius > this.y)
      ;
}


// Set the ball's direction based on a string
Ball.prototype.setDirection = function (direction) {
  if (direction === "up") {
     this.xSpeed = 0;
     this.ySpeed = -1;
  } else if (direction === "down") {
     this.xSpeed = 0;
     this.ySpeed = 1;
  } else if (direction === "left") {
     this.xSpeed = -1;
     this.ySpeed = 0;
  } else if (direction === "right") {
     this.xSpeed = 1;
     this.ySpeed = 0;
  } else if (direction === "stop") {
     this.xSpeed = 0;
     this.ySpeed = 0;
  }
};

// Create the ball object
var ball = new Ball();
var object = new Object();
// An object to convert keycodes into action names
var keyActions = {
  32: "stop",
  37: "left",
  38: "up",
  39: "right",
  40: "down"
};

// The keydown handler that will be called for every keypress
$("body").keydown(function (event) {
  var direction = keyActions[event.keyCode];
  ball.setDirection(direction);
});

function draw() {
    ctx.clearRect(0, 0, width, height);

    ball.draw();
    object.draw();
    drawLives();

    ctx.strokeRect(0, 0, width, height);
}

function simulate() {
    for (var i = 0; i < 5; i++) {
      var prev_ball_x = ball.x;
      var prev_ball_y = ball.y;
      ball.move();
      // handle collision here
      if (object.checkCollision()) {
          ball.setDirection('stop');
          // reset ball's position so they do not overlap
          ball.x = prev_ball_x;
          ball.y = prev_ball_y;
      }
    }
}

setInterval(function () {
    // separate drawing and simulating phases
    simulate();
    draw();
}, 30);

       </script>
   </body>
   </html>

编辑:

添加$("body").keyup(function (event) { ball.setDirection('stop'); });以停在keydown