Javascript 大画布上的动画';可视区域';
问题的标题可能很模糊。基本上,想象一个在画布上构建的赛车游戏。该轨迹占用10000 x 10000像素的屏幕空间。但是,浏览器窗口为500 x 500像素。汽车应在浏览器中居中,10000 x 10000画布的“可视”区域将发生变化。否则,汽车就会在消失时驶离边缘 这种技术有名字吗Javascript 大画布上的动画';可视区域';,javascript,html5-canvas,Javascript,Html5 Canvas,问题的标题可能很模糊。基本上,想象一个在画布上构建的赛车游戏。该轨迹占用10000 x 10000像素的屏幕空间。但是,浏览器窗口为500 x 500像素。汽车应在浏览器中居中,10000 x 10000画布的“可视”区域将发生变化。否则,汽车就会在消失时驶离边缘 这种技术有名字吗 实现这一点的基本原则是什么?如果汽车应保持在相同的位置(相对于画布的位置),则不应移动汽车。相反,将背景图片/轨迹/贴图移到另一侧 让你的眼睛认为汽车向右移动可以通过将汽车向右移动或将地图向左移动来实现。第二个选项似
实现这一点的基本原则是什么?如果汽车应保持在相同的位置(相对于画布的位置),则不应移动汽车。相反,将背景图片/轨迹/贴图移到另一侧 让你的眼睛认为汽车向右移动可以通过将汽车向右移动或将地图向左移动来实现。第二个选项似乎是您想要的,因为汽车不会移动,而可视区域(即地图)会移动 这是一个从头开始的快速演示: 归根结底是改变地图的位置:
$("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();
});
如果您正在寻找一种在地图无法进一步移动时实际移动汽车的方法(因为您驾驶汽车靠近地图的一侧),那么您必须延长夹紧时间,并跟踪汽车移动的时间和距离:
我的第一个游戏是一个赛车游戏,我移动了背景而不是汽车,尽管我想现在我有理由这么做。。。我只是不太清楚 您需要了解一些技巧才能很好地实现这一目标
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();
};
如果你很聪明,你可以用它来创建多个不同大小的视口,图片中的图片,以及放大和缩小图片
演出
第二,正如我在代码中所评论的那样,您应该确保您的绘图代码知道您更大的“世界”的哪一部分是可见的,这样您就不会做很多工作来绘制不可见的东西
画布转换方法就是用来解决这类问题的。使用它们吧
*如果你的世界如此之大,以至于它的坐标无法容纳一个合适的整数,你可能会遇到问题。当你的世界超过十亿(10^9)或万亿(10^18)时,你大概会遇到这个问题任意维的像素,取决于整数是32位还是64位。如果你的世界不是用像素而是用“世界单位”来衡量的,那么当你的世界的总大小和最小特征尺度导致浮点不准确时,你会遇到问题。在这种情况下,你需要做额外的工作来跟踪事物……但你可能会我仍然想使用画布转换方法!我仍然不确定要问什么。你的意思是根据视口区域进行调整?此外,我无法想象1x10^8像素画布上的FPS效果会非常好。我想你不是想将汽车向右移动,而是想将地图向左移动。
// 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)
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();
};