7

I'm trying to create an infinite looping canvas based on a main 'grid'. Scaled down fiddle here with the grid in the centre of the viewport.

JS Fiddle here

In the fiddle I have my main grid of coloured squares in the centre, I want them tiled infinitely in all directions. Obviously this isn't realistically possible, so I want to give the illusion of infinite by just redrawing the grids based on the scroll direction.

I found some good articles: 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

And the best route seems to be to get the drag direction and then reset camera to that point, so the layers scroll under the main canvas viewport, thus meaning the camera can never reach the edge of the main viewport canvas.

I've worked on adding some event listeners for mouse drags :

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
        }


    });

But I can't reliably work out the co-ordinates for each direction and then how to reset the camera position.

Kiksy
  • 1,272
  • 5
  • 20
  • 43
  • A few warnings about the initial JS Findle: last_position in line 1 is never used; missing semicolon in lines 24, 37, 43, 187; unnecessary semicolon in line 47. – Tiago Martins Peres Dec 07 '18 at 19:56
  • Neither fiddle is working for me. Both just show blank pages. Console shows warnings like `Konva warning: Can not change width of layer`. – Old Pro Dec 07 '18 at 23:36
  • 1
    Neither fiddle is working for me too. I just see a blank page. – AmerllicA Dec 09 '18 at 21:23
  • 1
    Fiddle is not working for me too. I just see a blank page. – Chinmoy Samanta Dec 10 '18 at 07:29
  • This fiddle: https://jsfiddle.net/kiksy/dvn2wyh5/25/ is working, you may need to scroll to see the squares however. – Kiksy Dec 12 '18 at 14:21
  • I've updated the mouse event fiddle to reduce the canvas size so the squares can be seen. https://jsfiddle.net/kiksy/025fp49w/8/ – Kiksy Dec 12 '18 at 14:28

1 Answers1

12

As you need "infinite" canvas I suggest to not use scrolling and make canvas as large as user viewport. Then you can emulate camera and on every move, you need to draw a new grid on the canvas. You just need to carefully calculate the position of the grid.

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>

If you need scrolling you can listen wheel event on stage and move into desired direction.

lavrton
  • 18,973
  • 4
  • 30
  • 63
  • Thanks, this isn't infinte however. The desire result is that the squares would keep looping, making it impossible to reach the edge, top bottom, left or right. – Kiksy Dec 12 '18 at 14:19
  • The logic is explained a bit here, https://gamedev.stackexchange.com/questions/71583/html5-dynamic-canvas-grid-for-scrolling-a-big-map but I'm looking for a infinite looping tile map. – Kiksy Dec 12 '18 at 14:26
  • Sorry, just realised that works! I was scrolling not dragging. – Kiksy Dec 12 '18 at 14:29
  • Good, that it helps. You can add scrolling manually. Listen to `wheel` event and change position of the stage in it. – lavrton Dec 12 '18 at 15:08
  • Still tearing my hair out with this one. Trying to get text to stay in the correct place. Heres a cut down fiddle with what I mean: https://jsfiddle.net/kiksy/jqo2h3dx/2/ The text doesn't stay in the boxes, I don't really understand why as the X Y are the same as the rectangle on redraw? – Kiksy Dec 19 '18 at 17:20