KonvaJS / HTML5 canvas 无限循环 tilemap。设置相机位置

KonvaJS / HTML5 canvas infinite looping tilemap. Setting camera position

我正在尝试创建一个基于主 'grid' 的无限循环 canvas。此处按比例缩小 fiddle,网格位于视口的中心。

JS Fiddle here

在 fiddle 中,我的主要彩色方块网格位于中心,我希望它们在各个方向上无限平铺。显然这在现实中是不可能的,所以我想通过根据滚动方向重新绘制网格来给人一种无限的错觉。

我发现了一些好文章: https://developer.mozilla.org/en-US/docs/Games/Techniques/Tilemaps/Square_tilemaps_implementation:_Scrolling_maps

https://gamedev.stackexchange.com/questions/71583/html5-dynamic-canvas-grid-for-scrolling-a-big-map

最好的方法似乎是获取拖动方向,然后将相机重置到该点,这样图层在主 canvas 视口下滚动,这意味着相机永远无法到达边缘主视口 canvas。

我一直致力于为鼠标拖动添加一些事件侦听器:

Fiddle with mouse events

 var bMouseDown = false;
    var oPreviousCoords = {
        'x': 0,
        'y': 0
    }
    var oDelta;
    var oEndCoords;
    var newLayerTop;


    $(document).on('mousedown', function (oEvent) {
        bMouseDown = true;
        oPreviousCoords = {
            'x': oEvent.pageX,
            'y': oEvent.pageY
        }
    });

    $(document).on('mouseup', function (oEvent) {
        bMouseDown = false;

        oPreviousCoords = {
            'x': oEvent.pageX,
            'y': oEvent.pageY
        }


        oEndCoords = oDelta


        if(oEndCoords.y < -300){


            if(newLayerTop){
                newLayerTop.destroy();
            }

            layerCurentPosition = layer.position();

            newLayerTop = layer.clone();
            newLayerTop.position({
                x:  layerCurentPosition.x,
                y:  layerCurentPosition.y -1960
            });


            stage.add(newLayerTop)

            stage.batchDraw();



        }

    });

    $(document).on('mousemove', function (oEvent) {


        if (!bMouseDown) {
            return;
        }

        oDelta = {
            'x': oPreviousCoords.x - oEvent.pageX,
            'y': oPreviousCoords.y - oEvent.pageY
        }


    });

但我不能可靠地算出每个方向的坐标,然后如何重置相机位置。

根据需要 "infinite" canvas 我建议不要使用滚动并使 canvas 与用户视口一样大。然后你可以模拟相机并且在每次移动时,你需要在 canvas 上绘制一个新的网格。你只需要仔细计算网格的位置即可。

const stage = new Konva.Stage({
  container: 'container',
  width: window.innerWidth,
  height: window.innerHeight,
  draggable: true
});

const layer = new Konva.Layer();
stage.add(layer);


const WIDTH = 100;
const HEIGHT = 100;

const grid = [
  ['red', 'yellow'],
  ['green', 'blue']
];

function checkShapes() {
  const startX = Math.floor((-stage.x() - stage.width()) / WIDTH) * WIDTH;
  const endX = Math.floor((-stage.x() + stage.width() * 2) / WIDTH) * WIDTH;
  
  const startY = Math.floor((-stage.y() - stage.height()) / HEIGHT) * HEIGHT;
  const endY = Math.floor((-stage.y() + stage.height() * 2) / HEIGHT) * HEIGHT;
 
  
  for(var x = startX; x < endX; x += WIDTH) {
    for(var y = startY; y < endY; y += HEIGHT) {
      const indexX = Math.abs(x / WIDTH) % grid.length;
      const indexY = Math.abs(y / HEIGHT) % grid[0].length;
      layer.add(new Konva.Rect({
        x,
        y,
        width: WIDTH,
        height: HEIGHT,
        fill: grid[indexX][indexY]
      }))
    }
  }
}


checkShapes();
layer.draw();

stage.on('dragend', () => {
  layer.destroyChildren();
  checkShapes();
  layer.draw();
})
  <script src="https://unpkg.com/konva@^2/konva.min.js"></script>
  <div id="container"></div>

如果您需要滚动,您可以在舞台上收听 wheel 事件并向所需方向移动。