在画布上进行位图环绕以进行无限滚动

时间:2013-11-28 10:45:56

标签: javascript canvas bitmap

我正在寻找一种在画布周围包裹位图图像的方法,以获得无限滚动效果。我正在看EaselJS但是干净的javascript代码也足够了。

现在我正在向左移动图像,当它到达某个标记时,它会自行重置。

来自actionscript,有一个选项可以将位图的像素“包裹”到另一侧,从而永远不会真正替换图像,而是将像素包裹在图像中。这是否可以在带有画布的javascript中使用?

我目前的代码:

this.update = function() {
    // super large graphic  
    _roadContainer.x -= 9;
    if(_roadContainer.x < -291) _roadContainer.x = 0;
}

3 个答案:

答案 0 :(得分:4)

从良好的风景图像开始。

enter image description here

使用context.scale(-1,1)水平翻转图像。

enter image description here

将翻转的图像合并到原始图像的右侧。

enter image description here

由于我们已完全镜像了图像,因此组合图像的最左侧和右侧完全相同。

因此,当我们平移组合图像并“用完图像”时,我们可以将组合图像的另一个副本添加到右侧,我们可以进行无限+无缝平移。

这是代码和小提琴:http://jsfiddle.net/m1erickson/ywDp5/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>

<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
</style>

<script>
$(function(){

    // thanks Paul Irish for this RAF fallback shim
    window.requestAnimFrame = (function(callback) {
      return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
      function(callback) {
        window.setTimeout(callback, 1000 / 60);
      };
    })();


    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

    var infiniteImage;
    var infiniteImageWidth;
    var img=document.createElement("img");
    img.onload=function(){

      // use a tempCanvas to create a horizontal mirror image
      // This makes the panning appear seamless when
      // transitioning to a new image on the right
      var tempCanvas=document.createElement("canvas");
      var tempCtx=tempCanvas.getContext("2d");
      tempCanvas.width=img.width*2;
      tempCanvas.height=img.height;
      tempCtx.drawImage(img,0,0);
      tempCtx.save();
      tempCtx.translate(tempCanvas.width,0);
      tempCtx.scale(-1,1);
      tempCtx.drawImage(img,0,0);
      tempCtx.restore();
      infiniteImageWidth=img.width*2;
      infiniteImage=document.createElement("img");
      infiniteImage.onload=function(){
          pan();
      }
      infiniteImage.src=tempCanvas.toDataURL();
    }
    img.crossOrigin="anonymous";
    img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/mountain.jpg";


    var fps = 60;
    var offsetLeft=0;
    function pan() {

        // increase the left offset
        offsetLeft+=1;
        if(offsetLeft>infiniteImageWidth){ offsetLeft=0; }

        ctx.drawImage(infiniteImage,-offsetLeft,0);
        ctx.drawImage(infiniteImage,infiniteImage.width-offsetLeft,0);

        setTimeout(function() {
            requestAnimFrame(pan);
        }, 1000 / fps);
    }

}); // end $(function(){});
</script>

</head>

<body>
    <canvas id="canvas" width=500 height=143></canvas><br>
</body>
</html>

答案 1 :(得分:2)

使用html5画布可以很容易地实现这一点 请看这里的drawImage规范:
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#drawing-images

drawImage有3种风格,第一种是图像的简单副本,第二种是允许缩放图像,第三种是你寻找的,它允许在一次调用中执行剪切。

你需要做什么:
- 让计数器从零移动到图像的宽度,然后再循环到零 - 每个帧,在画布上绘制最大的图像 - 如果画布的某些部分仍未绘制,则从零开始再次绘制图像以填充画布。

我做了一个小提琴,唯一重要的部分是动画功能(其他东西是我经常在我的小提琴中使用的工具)。
(Rq:我在这个例子中假设两个图像足以填满画布。)

http://jsfiddle.net/gamealchemist/5VJhp/

var startx = Math.round(startPos);
var clippedWidth = Math.min(landscape.width - startx, canvasWidth);

// fill left part of canvas with (clipped) image.
ctx.drawImage(landscape, startx, 0, clippedWidth, landscape.height,
0, 0, clippedWidth, landscape.height);

if (clippedWidth < canvasWidth) {
    // if we do not fill the canvas
    var remaining = canvasWidth - clippedWidth;
    ctx.drawImage(landscape, 0, 0, remaining, landscape.height,
    clippedWidth, 0, remaining, landscape.height);
}
// have the start position move and loop
startPos += dt * rotSpeed;
startPos %= landscape.width;

答案 2 :(得分:2)

回答我自己的问题:我找到了achieve this effect with EaselJS.的方法。这种方法的好处是你不必检查位图的位置。它将无限滚动 - 无需将位置重置为0。

诀窍是用bitmapfill填充形状。您可以将位图填充设置为无限重复。然后使用Matrix2D来确定bitmapfill的偏移量。由于它会自动重复,因此会产生滚动效果。

function.createRoad() {
    // road has a matrix, shape and image
    _m = new createjs.Matrix2D();
    // this gets the image from the preloader - but this can be any image
    _r = queue.getResult("road");
    // this creates a shape that will hold the repeating bitmap
     _roadshape = new createjs.Shape();
    // put the shape on the canvas
    addChild(_roadshape);
}
//
// the draw code gets repeatedly called, for example by requestanimationframe
//
function.drawRoad() {
    // var _speed = 4;
    _m.translate(-_speed, 0);
    _roadshape.graphics.clear().beginBitmapFill(_r, "repeat", _m).rect(0, 0, 900, 400);
}