我想知道如何在击中物体时阻止移动的球。我正在使用帆布。 这是一个小例子:
<!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会自动更新它以再次移动。我怎么解决这个问题才能让球停下来?
答案 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