检测画布的边缘并允许其离开

时间:2018-09-21 22:20:08

标签: javascript algorithm canvas

我有一个小游戏,玩家在画布上移动一个圆圈。我在检测画布的边缘时遇到问题,不允许玩家移动经过这些边缘,并允许用户从任何给定的边缘移开。

当前,玩家可以在大多数时间击中画布边缘并成功移动。但是,结合某些运动和沿边缘的碰撞,玩家将变得“卡住”。

如何创建简单的画布边缘碰撞检测并允许用户在事件发生后自由移动?

我的代码:

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height - 30;
var dx = 2;
var dy = -2;
var ballRadius = 10;
var rightPressed = false;
var leftPressed = false;
var upPressed = false;
var downPressed = false;

document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);

function keyDownHandler(e) {
  if (e.keyCode == 65) {
    rightPressed = true;
  }

  if (e.keyCode == 68) {
    leftPressed = true;
  }

  if (e.keyCode == 87) {
    upPressed = true;
  }

  if (e.keyCode == 83) {
    downPressed = true;
  }
}

function keyUpHandler(e) {
  if (e.keyCode == 65) {
    rightPressed = false;
  }

  if (e.keyCode == 68) {
    leftPressed = false;
  }

  if (e.keyCode == 87) {
    upPressed = false;
  }

  if (e.keyCode == 83) {
    downPressed = false;
  }
}

function drawBall() {
  ctx.beginPath();
  ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
  ctx.strokeStyle = "black";
  ctx.stroke();
  ctx.closePath();
}

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

  if (x + dx > canvas.width - ballRadius || x + dx < ballRadius - 3) {
    dx = -dx;
  }

  if (y + dy > canvas.height - ballRadius || y + dy < ballRadius - 3) {
    dy = -dy;
  }

  if (rightPressed) {
    x -= dx;
  }

  if (leftPressed) {
    x += dx;
  }

  if (upPressed) {
    y += dy;
  }

  if (downPressed) {
    y -= dy;
  }
}

setInterval(draw, 10);
<canvas id="myCanvas"></canvas>

3 个答案:

答案 0 :(得分:3)

好吧,我不得不承认那是很长时间了,因为我没有接触过存储在仓库中的旧库。拉克利(Luckley)我手头上有消息来源,因此看一看之后,我将介绍一种对我有用的方法,有关如何检测球形物体在墙壁上的粘菌

我想它会满足您的需求,不知道更好还是更坏的解决方案,但是行得通!让我们从定义如何表示每个球的数据开始,回想一下unix的朋友们,他说复杂性的一部分在数据结构中,因为它是整个算法的一部分...但是聊够了,转到问题..通过使用这种数据结构表示Ball

class Ball
{
    radio : number
    x : number
    y : number
}

This is a good way for representing balls in 2d worlds 这样您就可以这样绘制球了:

function draw (Graphics g)
{
    int r = ball.getRadio ();
    int diam = rad * 2;
    int px = (int) ball.getPx () - r;
    int py = (int) ball.getPy () - r;
    g.setColor (niceColor);

    g.fillArc (px,py,diameter,diameter,0,360); // Fills a circular or elliptical arc covering the specified rectangle 
}

//免责声明,我不太了解画布中图形例程的原语,但我认为您有足够的能力来画出所有这些。您得到了px,py,x,y,单选,直径。

无论如何,问题的答案都在这里,您可以在其中使用以下代码:

function isAHorizontalCollision (ball c,int width)
{
    return (c.x > width - c.radio || c.x < radio);
}

function isAVerticalCollision (ball c,int height)
{
    return (c.y > height - c.radio || c.y < radio);
}

//假设球可以移动的包围矩形在水平(0,width)和垂直(top,0)之间。

重要的是,只有在x值从左到右递增且y从上到下递减的情况下,才建议这样做。

希望我的打字稿一样的代码很适合解释。我在Java中有很多源文件。如果需要更多。 (例如两个圆圈之间的碰撞)。

如果您有时间i would recommend to check this out,那里的功能非常强大。

答案 1 :(得分:1)

您使用所有布尔变量使事情有些复杂...
只需将dxdy设为您的速度即可将它们设置为0来停止。

看起来也像您一样,将键的方向反转为直线:

if (x + dx > canvas.width - ballRadius || x + dx < ballRadius - 3) {
  dx = -dx;
}

if (y + dy > canvas.height - ballRadius || y + dy < ballRadius - 3) {
  dy = -dy;
}

当这些条件为真时,向上现在是向下而向右是左边,不确定这是否是您的预期行为,当它起作用时,看起来好像球从边缘弹起,但是从那一点上,键被倒转了...我将其从修复程序中删除。

这是我的方法,我添加了一些数学乐趣来使您的播放器动起来:

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
var dx = 0;
var dy = 0;
var ballRadius = 10;

document.addEventListener("keydown", keyDownHandler, false);
document.addEventListener("keyup", keyUpHandler, false);

function keyDownHandler(e) {
  if (e.keyCode == 65) dx = -2
  if (e.keyCode == 68) dx = 2
  if (e.keyCode == 87) dy = -2
  if (e.keyCode == 83) dy = 2
}

function keyUpHandler(e) {
  if (e.keyCode == 65) dx = 0
  if (e.keyCode == 68) dx = 0
  if (e.keyCode == 87) dy = 0
  if (e.keyCode == 83) dy = 0
}

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

  var fx = x + dx
  var fy = y + dy
  if (ballRadius < fx && fx < canvas.width - ballRadius) x = fx;
  if (ballRadius < fy && fy < canvas.height - ballRadius) y = fy;
}

setInterval(draw, 10);

var hr = ballRadius / 2 - 1
var pi2 = Math.PI * 2
var i = 0

function drawBall() {
  ctx.beginPath();
  ctx.arc(x, y, ballRadius, 0, pi2);
  ctx.strokeStyle = "black";
  ctx.stroke();

  // draw some small moving circles inside
  ctx.beginPath();
  ctx.fillStyle = "red";
  ctx.arc(x + hr * Math.sin(i), y + hr * Math.cos(i), hr, 0, pi2);
  ctx.fill();
  ctx.beginPath();
  ctx.fillStyle = "blue";
  ctx.arc(x - hr * Math.sin(i), y - hr * Math.cos(i), hr, 0, pi2);
  ctx.fill();
  ctx.closePath();
  i += 0.1 + Math.abs(dx)/15 + Math.abs(dy)/15
}
<canvas id="myCanvas" style="border:1px solid #000000;"></canvas>

答案 2 :(得分:0)

感谢你们两个回答了我的问题的帮助。由于你们两个,我得以成功找到解决方案。

最初,我使用它来确定画布的边缘,并相应地调整方向:

if (x + dx > canvas.width - ballRadius || x + dx < ballRadius - 3) {
    dx = -dx;
}

if (y + dy > canvas.height - ballRadius || y + dy < ballRadius - 3) {
    dy = -dy;
}

但是,正如所指出的那样,它会反转运动方向,从而使它对于我的预期目的基本上毫无用处。不仅如此,画布的所有4面都在彼此略有不同的庄园中起作用。

使用来自其他答案的反馈,这是我现在正在使用的解决方案,效果很好:

if (x + dx > canvas.width - ballRadius) {
    var fx = x - dx;
    x = fx;
} 

if (x + dx < ballRadius) {
    var fx = x + dx;
    x = fx;
}

if (y + dy > canvas.height - ballRadius) {
    var fy = y + dy;
    y = fy;
}

if (y + dy < ballRadius) {
    var fy = y - dy;
    y = fy;
}

这样,我可以成功检测到所有四个侧面,停止用户接触时的运动,并允许玩家从画布的侧面移开。