我用JavaScript和DOM编写了一个程序,它显示了一个弹跳在一个盒子里的球;它是一个画布元素。唯一不能正常工作的是角度。直到角度很小,当球体没有正确地从盒子中弹回时,这是不明显的。角度可以逐渐进入盒子,然后非常陡峭地反弹回来。这似乎可能不是角度输入=角度输出,而是从输出角度开始的角度。这相当于一个角度和它的赞美。问题似乎只发生在一半的反弹类型:它可能不会发生在一个方向的墙上,而是会发生在另一个方向的墙上。
:http://i.stack.imgur.com/WviEd.gif
我已经发布了代码测试能力的所有代码,并且使用了渐变角度,因此可以看到问题,但问题的角度在checkAngle
函数中。 / p>
<!doctype html>
<script src="code/chapter/15_game.js"></script>
<script src="code/game_levels.js"></script>
<script src="code/chapter/16_canvas.js"></script>
<canvas width="400" height="400"></canvas>
<script>
var cx = document.querySelector("canvas").getContext("2d");
var lastTime = null;
function frame(time) {
if (lastTime != null)
updateAnimation(Math.min(100, time - lastTime) / 1000);
lastTime = time;
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
var x = y = 200//, angle = 2 * Math.PI * Math.random();
var angle = 2 * Math.PI / 40 + Math.PI;
function checkAngle(angle) {
if(x + 10 >= 400) {
if(angle <= Math.PI)
return angle = (Math.PI/2) + ((Math.PI / 2) - reduceAngle(angle));
else if(angle > Math.PI)
return angle = (3 * Math.PI / 2) - ((Math.PI / 2) - reduceAngle(angle));
}else if(x - 10 <= 0) {
if(angle <= Math.PI)
return angle = Math.PI/2 - reduceAngle(angle);
else if(angle > Math.PI)
return angle = 3* Math.PI/2 + (Math.PI/2 - reduceAngle(angle));
}else if(y - 10 <= 0) {
if(angle >= 3 * Math.PI /2)
return angle = Math.PI/2 - reduceAngle(angle);
else if(angle < 3 * Math.PI/2)
return angle = Math.PI - (Math.PI / 2 - reduceAngle(angle));
}else if(y + 10 >= 400) {
if(angle <= Math.PI/2)
return angle = 2*Math.PI - (Math.PI / 2 - reduceAngle(angle));
else if(angle > Math.PI/2)
return angle = Math.PI + (Math.PI / 2 - reduceAngle(angle));
}else
return angle;
}
function reduceAngle(angle) {
if(angle < Math.PI / 2) {
return angle;
}else{
angle = angle - (Math.PI / 2);
return reduceAngle (angle);
}
}
function updateAnimation(step) {
cx.clearRect(0, 0, 400, 400);
cx.lineWidth = 4;
cx.strokeRect(0, 0, 400, 400);
angle = checkAngle(angle);
x += Math.cos(angle) * step * 200;
y += Math.sin(angle) * step * 200;
cx.lineWidth = 2;
cx.beginPath();
cx.arc(x, y, 20, 0, 7);
cx.stroke();
}
</script>
答案 0 :(得分:2)
在处理非旋转框中的反射时,在反射时不需要处理角度。只需根据角度定义初始矢量。
var vector = {
x: speed * Math.cos(angle),
y: speed * Math.sin(angle)
};
然后,您只需分别检查x和y的边界,并反转每个轴的斜率值:
if (x - radius <= 0 || x + radius>= 400) {
vector.x = -vector.x; // reflect x
}
if (y - radius<= 0 || y + radius> 400) {
vector.y = -vector.y; // reflect y
}
您可以随时通过添加另一个带有delta角的矢量来调整角度。
如果您的反弹框不旋转0°,请检查this answer是否有矢量反射。
使用您的代码作为基础,这将实现如下:
var cx = document.querySelector("canvas").getContext("2d");
var lastTime = null;
var x, y;
// calculate an initial vector
var angle = 20 / 180 * Math.PI; // angle -> radians
var speed = 5;
var vector = {
x: speed * Math.cos(angle),
y: speed * Math.sin(angle)
};
x = y = 200;
function frame(time) {
if (lastTime != null)
updateAnimation(Math.min(100, time - lastTime) / 1000);
lastTime = time;
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
function checkAngle() {
var dlt = 10 + 2 + 4; //include radius and line-widths;
if (x - dlt <= 0 || x + dlt >= 400) {
vector.x = -vector.x; // reflect x
}
if (y - dlt <= 0 || y + dlt > 400) {
vector.y = -vector.y; // reflect y
}
}
function updateAnimation(step) {
cx.clearRect(0, 0, 400, 400);
cx.lineWidth = 4;
cx.strokeRect(0, 0, 400, 400);
x += vector.x; // use our vector
y += vector.y;
checkAngle(); // test for hits
cx.lineWidth = 2;
cx.beginPath();
cx.arc(x, y, 20, 0, 7);
cx.stroke();
}
<canvas width="400" height="400"></canvas>
答案 1 :(得分:1)
根据我在你的图纸和演示中所看到的情况来判断,角度是从错误的轴上取下来的。如果接近20度,你会期望球以180-20
度离开。相反,它正在做的是离开90+20
度。
虽然我无法在代码中找到导致此错误的确切位置,但我觉得我必须指出这一点,希望有人可以改进它。