大画布如何拥有动画“可视区域”

时间:2011-12-05 15:59:49

标签: javascript html5-canvas

问题标题可能含糊不清。基本上,想象一下用帆布制作的赛车游戏。该轨道占用10,000 x 10,000像素的屏幕空间。但是,浏览器窗口为500 x 500像素。汽车应该在浏览器中居中,10,000 x 10,000画布的“可视”区域将会改变。否则汽车会在消失时从边缘驶出。

这种技术有名字吗?

实现这一目标的基本原则是什么?

3 个答案:

答案 0 :(得分:2)

如果汽车应该停留在相同的位置(相对于画布的位置),那么你不应该移动汽车。而是将背景图片/轨道/地图移动到另一侧

让您的眼睛认为汽车向右移动可以通过将汽车移动到右侧或移动地图来完成到。第二种选择似乎是你想要的,因为汽车不会移动,而可视区域(即地图)将会移动。

这是从头开始的快速演示:http://jsfiddle.net/vXsqM/

归结为反过来改变地图的位置:

$("body").on("keydown", function(e) {
    if(e.which === 37) pos.x += speed; // left key, so move map to the right
    if(e.which === 38) pos.y += speed;
    if(e.which === 39) pos.x -= speed;
    if(e.which === 40) pos.y -= speed;

    // make sure you can't move the map too far.
    // clamp does: if x < -250 return -250
    //             if x >    0 return    0
    //             else it's allowed, so just return x
    pos.x = clamp(pos.x, -250, 0);
    pos.y = clamp(pos.y, -250, 0);

    draw();
});

然后,您可以使用保存的位置绘制地图:

ctx.drawImage(img, pos.x, pos.y);

如果您正在寻找一种实际移动汽车的方法,当地图无法再移动时(因为您正在驾驶汽车靠近地图的一侧),那么您必须延长夹紧时间并且还要记录应该移动汽车的时间以及距离:http://jsfiddle.net/vXsqM/1/

                              // for x coordinate:
function clamp2(x, y, a, b) { // x = car x, y = map x, a = min map x, b = max map x
    return y > b ? -y : y < a ? a - y : x;
}

然后,夹紧位置变得有点复杂:

// calculate how much car should be moved
posCar.x = clamp2(posCar.x, posMap.x, -250, 0);
posCar.y = clamp2(posCar.y, posMap.y, -250, 0);

// also don't allow the car to be moved off the map
posCar.x = clamp(posCar.x, -100, 100);
posCar.y = clamp(posCar.y, -100, 100);

// calculate where the map should be drawn
posMapReal.x = clamp(posMap.x, -250, 0);
posMapReal.y = clamp(posMap.y, -250, 0);

// keep track of where the map virtually is, to calculate car position
posMap.x = clamp(posMap.x, -250 - 100, 0 + 100);
posMap.y = clamp(posMap.y, -250 - 100, 0 + 100);
// the 100 is because the car (circle in demo) has a radius of 25 and can
// be moved max 100 pixels to the left and right (it then hits the side)

答案 1 :(得分:2)

两件事:

画布转换方法

首先,canvas transformation methods(以及context.save()context.restore()是您的朋友,并将大大简化查看大型世界的一部分所需的数学计算。你使用这种方法,只需指定可见的世界部分和想要绘制的所有内容的世界坐标,就可以获得所需的行为。

这不是唯一的做事方式*但转换方法意味着正是为了解决这类问题。您可以使用它们,也可以通过手动跟踪应该绘制背景的位置等来重新发明它们。

这是一个如何使用它们的例子,改编自我的项目:

function(outer, inner, ctx, drawFunction) {
  //Save state so we can return to a clean transform matrix.
  ctx.save();

  //Clip so that we cannot draw outside of rectangle defined by `outer`
  ctx.beginPath();
  ctx.moveTo(outer.left, outer.top);
  ctx.lineTo(outer.right, outer.top);
  ctx.lineTo(outer.right, outer.bottom);
  ctx.lineTo(outer.left, outer.bottom);
  ctx.closePath();

  //draw a border before clipping so we can see our viewport
  ctx.stroke();
  ctx.clip();

  //transform the canvas so that the rectangle defined by `inner` fills the
  //rectangle defined by `outer`.
  var ratioWidth = (outer.right - outer.left) / (inner.right - inner.left);
  var ratioHeight = (outer.bottom - outer.top) / (inner.bottom - inner.top);
  ctx.translate(outer.left, outer.top);
  ctx.scale(ratioWidth, ratioHeight);
  ctx.translate(-inner.left, -inner.top);

  //here I assume that your drawing code is a function that takes the context
  //and draws your world into it.  For performance reasons, you should
  //probably pass `inner` as an argument too; if your draw function knows what
  //portion of the world it is drawing, it can ignore things outside of that
  //region.
  drawFunction(ctx);

  //go back to the previous canvas state.
  ctx.restore();

};

如果你很聪明,你可以使用它来创建不同大小的多个视口,画中画等,并放大和缩小内容。

效果

其次,正如我在代码中所评论的那样,你应该确保你的绘图代码知道你的更大的世界的哪一部分&#39;将是可见的,这样你就不会做很多工作来尝试绘制看不见的东西。

画布转换方法旨在解决这类问题。使用&#39; em!

*如果您的世界太大而其坐标无法放入适当的整数,您可能会遇到问题。当你的世界在任何维度上超过十亿(10 ^ 9)或长万亿(10 ^ 18)像素时,你会大致遇到这个问题,这取决于整数是32位还是64位。如果您的世界不是以像素为单位测量,而是以世界单位衡量,那么当您的世界总大小和最小特征尺度导致浮点不准确时,您就会遇到问题。在这种情况下,你需要做额外的工作来跟踪事情......但是你可能仍然想要使用画布转换方法!

答案 2 :(得分:1)

我的第一个游戏是一个赛车游戏,我移动背景而不是汽车,虽然我想现在我有理由这样做......我只是不知道更好。< / p>

为了实现这一目标,您需要了解一些技巧。

  1. 平铺背景。你需要用平铺的小块来制作你的轨道。要绘制10,000 x 10,000像素是100MPix图像,通常这样的图像将具有32位深度(4字节),这将最终在内存中为400MB。像PNG,JPEG这样的压缩对您有所帮助,因为这些压缩用于存储和传输图像。它们无法在没有解压缩的情况下渲染到画布上。

  2. 沿着您的轨道移动汽车。没有什么比在汽车下移动BG更糟糕了。如果你需要为你的游戏添加更多功能,比如AI汽车...现在他们将不得不沿着地图移动并实施汽车碰撞,你需要做一些不难但是奇怪的空间变换。

  3. 添加相机实体。相机需要具有位置和视口大小(这是画布的大小)。相机会决定你的比赛。这个实体会给你游戏中的速度感...你可以让相机晃动碰撞,如果你的游戏漂移,如果你的游戏相机可以滑动通过所需的位置,并回到汽车中心等当然最重要的是跟踪汽车。我能给你的一些简单的建议就是不把车放在相机的死角。把车稍稍放在后面你可以看到更多的东西在你面前。汽车移动越快,你应该越多地偏移相机。此外,您无法计算相机的位置,而是计算所需的位置,每帧慢慢地将当前相机位置移动到所需位置。

  4. 现在,当您拥有相机和大型平铺地图时,绘制平铺时,您必须减去相机位置。您还可以计算哪些图块不可见并跳过它们。这种技术可以让您使用更大的地图扩展您的游戏,或者您可以将地图流式传输到您未加载所有图块的地方,并提前加载背景(AJAX)即将看到的内容。