0
\$\begingroup\$

Problem and Requirements

I'm putting together a simple game that will involve an overworld map consisting of 12px x 12px square terrain tiles. These maps may be as large as 500x500 in size (so 250k tiles). I would like the player to be able to drag their way around this map quickly and easily, much like you can in Lords Mobile or other similar mobile games.

It would be preferable if the user could easily zoom in and out. I will also be placing interactive 'nodes' of various sorts on this map.

Technologies and Stats

Languages:

  • Lucee backend to generate these maps
  • HTML and JQuery for display
  • I'm willing to use other Javascript libraries, but would prefer not to have to learn some whole new framework unless absolutely necessary.

Devices:

  • Game will be designed primarily for mobile devices, but should run in any browser on any device.
  • Due to mobile support, resources will be limited.
  • I will likely create an Android app made up of a splash screen and a webview. My Java skills are lacking (and I dislike Java) so I really don't want a Java based solution.

Map Stats:

  • Maps are expected to be between 200x200 and 500x500.
  • They may need to be larger, possibly in excess of 1200x1200. So I would like a scaleable approach.

Possible/Rejected Solutions

The obvious first thought was to create a large container div, and an < img > for each tile absolutely positioned within that container. However, a quarter of a million img tags, each with events attached, is insane, so I rejected this almost as soon as I thought of it. I tested it anyway on my gaming PC just in case and memory usage shot through the roof and there was significant lag. This would be completely impractical on a phone or other mobile device.

So then I thought that since the world map won't really ever change, maybe I could create one large image, and just pickup where the player taps via the click event properties and calculate the tile from that. However, for a 500x500 map of 12x12 tiles, that would be a 6000x6000 image (36 megapixel). Again, I would be concerned about a mobile device handling that, especially with hundreds of 'nodes' and other 'stuff' dropped on top of it.

So I thought maybe I could just build a container div at the full 6000x6000 size, and then load terrain tiles just for the 30-40 terrains within (and surrounding) the viewport. As the user tries to scroll I could dynamically generate the other img tags based on data either from an AJAX call or an array that holds all of the terrain data (if it's not too resource intensive). This seems overly complex, though, and I'd prefer a simpler solution, especially if this is going to lead to any sort of lag.

Question

How do other HTML/Javascript based games handle this sort of large scale overworld map? I can try to muddle through this myself, but this must be a very common need and I'm sure there are great solutions already out there.

\$\endgroup\$
  • \$\begingroup\$ Sounds like you're on the right track with breaking your map into smaller chunks and only loading/rendering those immediately surrounding the player's view. That's how most games with large worlds work. Have you run into any specific difficulties making this work the way you want? \$\endgroup\$ – DMGregory Dec 15 '18 at 23:05
  • \$\begingroup\$ @DMGregory Thanks. Honestly, I haven't gotten too deep into it. I sat down to try and realized that I could think of at least 3 different ways to approach it, with more probably incoming if I sat and thought a little more. So I was hoping to get more information on best practices to choose which one to go with, or if that's even the best technique to use. I was hoping there was something simpler to go with. \$\endgroup\$ – Nicholas Dec 16 '18 at 0:05
1
\$\begingroup\$

Well, Jay's answer was technically correct, and gave me a good starting point. So +1 to him for that. However, I wanted to take the time to post a fuller answer for others who happen across this question, now that I've figured out some basics.

The Various Attempts

First, I wanted to talk about the other possibilities I explored:

  • First I tried using CFML to create the HTML code on the server and write it out to the browser, as described in the question. For a 200x200 tile map it took over 20 seconds to load and render on a PC. This was obviously unworkable.

  • Then I tried stitching the tiles together into one large image, as described above. As a PNG its filesize was 62MB. I didn't bother going any further here.

I settled on the idea of loading only a small portion of the total map at a time, since the user can only see a few tiles anyway, and all of my following attempts built on that approach.

  • For my first partial success, I tried having JS pull a list of all local tiles (within 10 tiles of the viewing position) from the database in array format, which took a few hundred ms. Then I looped through that, looked to see if a tile was drawn for those coordinates yet, and wrote an img tag out to a container div if not. This processed in a few hundred ms too. However, after 40+ tiles were loaded the 'draggable' animation became very choppy on mobile, and after a 1000 or so the same happened on PC. Even a 200x200 map would contain 40k tiles, so this code was set aside as a backup.

  • Next I explored a very similar approach, except that instead of writing img files into a div I drew the images out to a canvas element. This worked exceptionally well; not only did it load and run faster than the last attempt, but the choppiness went away completely. Regardless of how many tiles I drew into the canvas, it dragged as a whole with perfect smoothness. Much closer!

  • However, each time the canvas was dragged and I had to go out to the server for more tile data, I incurred another 500+ ms hit. This was bothersome, not to mention the server strain caused by all those requests. So I decided to try loading the whole array of tile data at the start, now that everything else was running smoothly. To my surprise, even my phone didn't hesitate at loading a full 200x200 array into memory. That allowed me to cut out the ajax call completely and just to on-demand draws to the canvas based on in-memory data. Sweet!

By the end of the night I had a scrollable map, that loaded into a phone without hesitation, with smooth animation, just waiting for interactive elements to be dropped on top.

Final Working Example

My actual code has a number of dependencies, but here is a rudimentary example. It still needs some work, but demonstrates the basic principles in a functional script:

<head>
    <!DOCTYPE html>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">

    <script     src="https://code.jquery.com/jquery-3.3.1.min.js"
                integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
                crossorigin="anonymous"></script>
    <script     src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"
                integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU="
                crossorigin="anonymous"></script>
    <script src="/JS/jquery.ui.touch-punch.min.js" type="text/javascript"></script>
    <script src="/JS/utilityFunctions.js" type="text/javascript"></script>
</head>

<style>
    #mapContainer   {width:500px; height:500px; overflow:hidden;}
    #mapCanvas      {width:2500px; height:2500px;}
    .terrainTile    {width:50; height:50; position:absolute;}
</style>

<div id="mapContainer">
    <canvas id="mapCanvas" width="2500" height="2500">

    </canvas>
</div>

<script>
    var realmSize       = 50;       // Total number of tiles on each axis
    var divSize         = 2500;     // Total canvas size in pixels: realmSize * tileSize
    var containerSize   = 500;      // Size of the viewable area
    var tileSize        = 50;       // Size of each tile
    var curPosX         = 3;        // Default current position
    var curPosY         = 3;
    var minDragXY       = 0 - (divSize - containerSize);    // The furthest we can drag the canvas (so it's edge lines up with the container's edge)
    var loadTileDelta   = 5;        // How far in any direction to load onto the canvas
    var terrainImgArr   = [];

    // First we load the images we want to use for the tiles.  I named mine to correspond to the terrain ID in my database for now.
    for (x=1; x<=13; x++) {  
        terrainImgArr[x] = new Image(tileSize, tileSize);
        terrainImgArr[x].src = '/imgs/' + x + '.png';
    }

    // Create a three dimensional JS array of realmSize x realmSize x 2.  For any given x,y position, this will hold the terrain ID value in one cell and whether it's been drawn to the screen yet in the other.
    var mapTerrain  = ThreeDimensionalArray(realmSize, realmSize, 2);

    function mapLoad() {
        // This function does an ajax call to go out and get the data from my database.  I copied and pasted the response here so anyone viewing this can have a working demo...
        var mapData = "1,1,12|1,2,12|1,3,12|1,4,12|1,5,12|1,6,12|1,7,12|1,8,6|1,9,6|1,10,6|1,11,12|1,12,12|1,13,12|1,14,6|1,15,6|1,16,1|1,17,1|1,18,1|1,19,1|1,20,2|1,21,2|1,22,2|1,23,12|1,24,13|1,25,13|1,26,12|1,27,3|1,28,3|1,29,1|1,30,1|1,31,1|1,32,8|1,33,1|1,34,1|1,35,1|1,36,1|1,37,1|1,38,1|1,39,1|1,40,1|1,41,1|1,42,2|1,43,2|1,44,2|1,45,2|1,46,2|1,47,2|1,48,2|1,49,2|1,50,2|2,1,12|2,2,12|2,3,12|2,4,12|2,5,12|2,6,12|2,7,6|2,8,6|2,9,6|2,10,6|2,11,6|2,12,6|2,13,6|2,14,6|2,15,1|2,16,1|2,17,1|2,18,1|2,19,1|2,20,2|2,21,2|2,22,2|2,23,12|2,24,12|2,25,12|2,26,12|2,27,3|2,28,3|2,29,3|2,30,1|2,31,8|2,32,8|2,33,8|2,34,1|2,35,1|2,36,1|2,37,1|2,38,1|2,39,1|2,40,1|2,41,1|2,42,1|2,43,2|2,44,2|2,45,2|2,46,2|2,47,2|2,48,2|2,49,2|2,50,2|3,1,6|3,2,6|3,3,6|3,4,2|3,5,2|3,6,6|3,7,6|3,8,6|3,9,6|3,10,6|3,11,6|3,12,6|3,13,6|3,14,6|3,15,1|3,16,1|3,17,1|3,18,1|3,19,1|3,20,2|3,21,2|3,22,2|3,23,2|3,24,12|3,25,12|3,26,6|3,27,3|3,28,3|3,29,3|3,30,8|3,31,8|3,32,8|3,33,8|3,34,8|3,35,1|3,36,1|3,37,1|3,38,1|3,39,1|3,40,3|3,41,3|3,42,3|3,43,1|3,44,2|3,45,2|3,46,2|3,47,2|3,48,2|3,49,2|3,50,2|4,1,6|4,2,6|4,3,2|4,4,2|4,5,2|4,6,2|4,7,6|4,8,6|4,9,6|4,10,6|4,11,6|4,12,6|4,13,6|4,14,2|4,15,1|4,16,1|4,17,1|4,18,1|4,19,1|4,20,2|4,21,2|4,22,2|4,23,2|4,24,12|4,25,12|4,26,6|4,27,3|4,28,3|4,29,3|4,30,8|4,31,8|4,32,8|4,33,8|4,34,8|4,35,1|4,36,1|4,37,1|4,38,1|4,39,1|4,40,3|4,41,3|4,42,3|4,43,1|4,44,2|4,45,2|4,46,2|4,47,2|4,48,2|4,49,2|4,50,2|5,1,6|5,2,2|5,3,1|5,4,1|5,5,1|5,6,1|5,7,1|5,8,6|5,9,6|5,10,6|5,11,1|5,12,2|5,13,2|5,14,2|5,15,1|5,16,1|5,17,1|5,18,1|5,19,1|5,20,1|5,21,2|5,22,2|5,23,2|5,24,6|5,25,6|5,26,2|5,27,1|5,28,3|5,29,3|5,30,8|5,31,8|5,32,8|5,33,8|5,34,8|5,35,1|5,36,1|5,37,1|5,38,1|5,39,1|5,40,3|5,41,3|5,42,1|5,43,1|5,44,2|5,45,2|5,46,2|5,47,2|5,48,2|5,49,2|5,50,2|6,1,6|6,2,2|6,3,1|6,4,1|6,5,1|6,6,1|6,7,1|6,8,1|6,9,1|6,10,1|6,11,2|6,12,2|6,13,2|6,14,2|6,15,2|6,16,1|6,17,1|6,18,1|6,19,1|6,20,1|6,21,2|6,22,2|6,23,2|6,24,2|6,25,2|6,26,2|6,27,1|6,28,1|6,29,1|6,30,1|6,31,1|6,32,8|6,33,8|6,34,8|6,35,1|6,36,1|6,37,2|6,38,2|6,39,2|6,40,1|6,41,1|6,42,1|6,43,1|6,44,2|6,45,2|6,46,2|6,47,2|6,48,2|6,49,2|6,50,2|7,1,6|7,2,1|7,3,1|7,4,1|7,5,1|7,6,1|7,7,1|7,8,1|7,9,1|7,10,2|7,11,2|7,12,2|7,13,2|7,14,2|7,15,6|7,16,6|7,17,1|7,18,1|7,19,1|7,20,1|7,21,1|7,22,2|7,23,2|7,24,2|7,25,2|7,26,1|7,27,1|7,28,1|7,29,1|7,30,1|7,31,1|7,32,1|7,33,8|7,34,8|7,35,1|7,36,1|7,37,2|7,38,2|7,39,2|7,40,2|7,41,1|7,42,1|7,43,1|7,44,2|7,45,2|7,46,2|7,47,2|7,48,2|7,49,2|7,50,2|8,1,6|8,2,1|8,3,1|8,4,8|8,5,8|8,6,1|8,7,1|8,8,1|8,9,2|8,10,2|8,11,2|8,12,2|8,13,2|8,14,6|8,15,6|8,16,6|8,17,6|8,18,1|8,19,1|8,20,1|8,21,1|8,22,2|8,23,2|8,24,2|8,25,1|8,26,1|8,27,1|8,28,1|8,29,1|8,30,1|8,31,1|8,32,1|8,33,8|8,34,8|8,35,1|8,36,1|8,37,2|8,38,2|8,39,2|8,40,2|8,41,1|8,42,1|8,43,1|8,44,2|8,45,2|8,46,2|8,47,2|8,48,2|8,49,2|8,50,2|9,1,6|9,2,1|9,3,1|9,4,8|9,5,8|9,6,1|9,7,1|9,8,1|9,9,2|9,10,2|9,11,6|9,12,6|9,13,6|9,14,6|9,15,6|9,16,6|9,17,6|9,18,1|9,19,1|9,20,1|9,21,1|9,22,2|9,23,2|9,24,2|9,25,2|9,26,2|9,27,2|9,28,2|9,29,2|9,30,2|9,31,1|9,32,1|9,33,1|9,34,8|9,35,1|9,36,1|9,37,2|9,38,2|9,39,2|9,40,2|9,41,1|9,42,1|9,43,1|9,44,2|9,45,2|9,46,2|9,47,2|9,48,2|9,49,2|9,50,2|10,1,6|10,2,1|10,3,1|10,4,8|10,5,8|10,6,1|10,7,1|10,8,1|10,9,2|10,10,2|10,11,2|10,12,6|10,13,6|10,14,6|10,15,6|10,16,6|10,17,6|10,18,1|10,19,1|10,20,1|10,21,2|10,22,2|10,23,2|10,24,2|10,25,2|10,26,2|10,27,2|10,28,2|10,29,2|10,30,2|10,31,2|10,32,1|10,33,1|10,34,1|10,35,1|10,36,1|10,37,1|10,38,2|10,39,2|10,40,2|10,41,3|10,42,1|10,43,1|10,44,2|10,45,2|10,46,2|10,47,2|10,48,2|10,49,2|10,50,2|11,1,6|11,2,1|11,3,1|11,4,1|11,5,8|11,6,1|11,7,1|11,8,1|11,9,2|11,10,2|11,11,2|11,12,2|11,13,2|11,14,6|11,15,6|11,16,6|11,17,6|11,18,1|11,19,1|11,20,2|11,21,2|11,22,2|11,23,2|11,24,2|11,25,2|11,26,2|11,27,2|11,28,2|11,29,2|11,30,2|11,31,2|11,32,1|11,33,1|11,34,1|11,35,1|11,36,1|11,37,1|11,38,2|11,39,2|11,40,2|11,41,1|11,42,1|11,43,2|11,44,2|11,45,2|11,46,2|11,47,2|11,48,2|11,49,2|11,50,2|12,1,6|12,2,6|12,3,1|12,4,1|12,5,8|12,6,1|12,7,1|12,8,1|12,9,2|12,10,2|12,11,2|12,12,1|12,13,1|12,14,1|12,15,1|12,16,6|12,17,6|12,18,1|12,19,2|12,20,2|12,21,2|12,22,2|12,23,2|12,24,2|12,25,2|12,26,2|12,27,2|12,28,2|12,29,2|12,30,2|12,31,2|12,32,1|12,33,1|12,34,8|12,35,8|12,36,1|12,37,1|12,38,2|12,39,2|12,40,2|12,41,2|12,42,2|12,43,2|12,44,2|12,45,2|12,46,2|12,47,2|12,48,2|12,49,2|12,50,2|13,1,6|13,2,6|13,3,1|13,4,1|13,5,8|13,6,8|13,7,1|13,8,1|13,9,1|13,10,1|13,11,1|13,12,1|13,13,1|13,14,1|13,15,1|13,16,2|13,17,2|13,18,2|13,19,2|13,20,2|13,21,2|13,22,2|13,23,2|13,24,2|13,25,3|13,26,3|13,27,2|13,28,2|13,29,2|13,30,2|13,31,2|13,32,1|13,33,1|13,34,8|13,35,8|13,36,1|13,37,1|13,38,1|13,39,2|13,40,2|13,41,2|13,42,2|13,43,2|13,44,2|13,45,2|13,46,2|13,47,2|13,48,2|13,49,1|13,50,2|14,1,6|14,2,6|14,3,1|14,4,1|14,5,8|14,6,8|14,7,1|14,8,1|14,9,1|14,10,1|14,11,1|14,12,1|14,13,1|14,14,1|14,15,1|14,16,2|14,17,2|14,18,2|14,19,2|14,20,2|14,21,2|14,22,2|14,23,2|14,24,3|14,25,3|14,26,3|14,27,2|14,28,2|14,29,2|14,30,2|14,31,1|14,32,1|14,33,8|14,34,8|14,35,8|14,36,1|14,37,1|14,38,1|14,39,2|14,40,2|14,41,2|14,42,2|14,43,2|14,44,2|14,45,2|14,46,2|14,47,2|14,48,1|14,49,1|14,50,1|15,1,6|15,2,6|15,3,6|15,4,1|15,5,8|15,6,8|15,7,8|15,8,1|15,9,1|15,10,1|15,11,1|15,12,1|15,13,1|15,14,1|15,15,1|15,16,2|15,17,2|15,18,2|15,19,2|15,20,2|15,21,2|15,22,2|15,23,2|15,24,2|15,25,3|15,26,2|15,27,2|15,28,2|15,29,2|15,30,2|15,31,1|15,32,1|15,33,8|15,34,8|15,35,8|15,36,1|15,37,1|15,38,1|15,39,2|15,40,2|15,41,2|15,42,2|15,43,2|15,44,2|15,45,2|15,46,2|15,47,1|15,48,1|15,49,1|15,50,1|16,1,6|16,2,6|16,3,6|16,4,1|16,5,1|16,6,8|16,7,8|16,8,1|16,9,1|16,10,1|16,11,1|16,12,1|16,13,1|16,14,1|16,15,2|16,16,2|16,17,2|16,18,2|16,19,2|16,20,2|16,21,2|16,22,2|16,23,2|16,24,2|16,25,2|16,26,2|16,27,2|16,28,2|16,29,2|16,30,2|16,31,1|16,32,1|16,33,8|16,34,8|16,35,1|16,36,1|16,37,1|16,38,1|16,39,2|16,40,2|16,41,2|16,42,2|16,43,2|16,44,2|16,45,2|16,46,2|16,47,2|16,48,1|16,49,1|16,50,1|17,1,6|17,2,6|17,3,6|17,4,1|17,5,1|17,6,1|17,7,1|17,8,1|17,9,1|17,10,1|17,11,1|17,12,1|17,13,1|17,14,1|17,15,2|17,16,2|17,17,2|17,18,2|17,19,2|17,20,2|17,21,2|17,22,2|17,23,2|17,24,2|17,25,2|17,26,2|17,27,2|17,28,2|17,29,2|17,30,1|17,31,1|17,32,8|17,33,8|17,34,8|17,35,1|17,36,1|17,37,1|17,38,2|17,39,2|17,40,2|17,41,2|17,42,2|17,43,2|17,44,2|17,45,2|17,46,2|17,47,2|17,48,1|17,49,1|17,50,1|18,1,6|18,2,6|18,3,6|18,4,1|18,5,1|18,6,1|18,7,1|18,8,1|18,9,1|18,10,1|18,11,1|18,12,1|18,13,1|18,14,1|18,15,2|18,16,2|18,17,2|18,18,2|18,19,2|18,20,2|18,21,2|18,22,2|18,23,2|18,24,2|18,25,2|18,26,2|18,27,2|18,28,2|18,29,2|18,30,1|18,31,1|18,32,8|18,33,8|18,34,1|18,35,1|18,36,1|18,37,1|18,38,2|18,39,2|18,40,2|18,41,2|18,42,2|18,43,2|18,44,2|18,45,2|18,46,2|18,47,2|18,48,1|18,49,1|18,50,1|19,1,6|19,2,6|19,3,6|19,4,1|19,5,1|19,6,1|19,7,1|19,8,1|19,9,1|19,10,1|19,11,1|19,12,1|19,13,1|19,14,1|19,15,2|19,16,2|19,17,2|19,18,2|19,19,2|19,20,6|19,21,6|19,22,6|19,23,2|19,24,2|19,25,2|19,26,2|19,27,2|19,28,2|19,29,2|19,30,1|19,31,1|19,32,1|19,33,8|19,34,1|19,35,1|19,36,1|19,37,1|19,38,2|19,39,2|19,40,2|19,41,2|19,42,2|19,43,2|19,44,2|19,45,2|19,46,2|19,47,2|19,48,1|19,49,1|19,50,1|20,1,12|20,2,6|20,3,6|20,4,1|20,5,1|20,6,1|20,7,1|20,8,1|20,9,1|20,10,1|20,11,1|20,12,1|20,13,1|20,14,1|20,15,2|20,16,2|20,17,2|20,18,2|20,19,2|20,20,6|20,21,6|20,22,6|20,23,2|20,24,2|20,25,2|20,26,2|20,27,2|20,28,2|20,29,2|20,30,1|20,31,1|20,32,1|20,33,1|20,34,1|20,35,1|20,36,1|20,37,2|20,38,2|20,39,2|20,40,2|20,41,2|20,42,2|20,43,2|20,44,2|20,45,2|20,46,2|20,47,2|20,48,1|20,49,1|20,50,1|21,1,12|21,2,6|21,3,2|21,4,1|21,5,1|21,6,1|21,7,1|21,8,1|21,9,1|21,10,1|21,11,1|21,12,1|21,13,1|21,14,2|21,15,2|21,16,2|21,17,2|21,18,2|21,19,2|21,20,2|21,21,6|21,22,6|21,23,2|21,24,2|21,25,2|21,26,2|21,27,2|21,28,2|21,29,2|21,30,1|21,31,1|21,32,1|21,33,1|21,34,1|21,35,1|21,36,1|21,37,2|21,38,2|21,39,2|21,40,2|21,41,2|21,42,2|21,43,2|21,44,2|21,45,2|21,46,2|21,47,2|21,48,2|21,49,2|21,50,1|22,1,6|22,2,6|22,3,1|22,4,1|22,5,1|22,6,1|22,7,1|22,8,1|22,9,1|22,10,1|22,11,1|22,12,1|22,13,1|22,14,1|22,15,2|22,16,2|22,17,2|22,18,2|22,19,2|22,20,2|22,21,2|22,22,2|22,23,2|22,24,2|22,25,2|22,26,2|22,27,2|22,28,2|22,29,2|22,30,1|22,31,1|22,32,1|22,33,1|22,34,1|22,35,1|22,36,2|22,37,2|22,38,2|22,39,2|22,40,2|22,41,2|22,42,2|22,43,2|22,44,2|22,45,2|22,46,2|22,47,2|22,48,2|22,49,1|22,50,3|23,1,6|23,2,6|23,3,1|23,4,1|23,5,1|23,6,1|23,7,1|23,8,1|23,9,1|23,10,1|23,11,1|23,12,1|23,13,1|23,14,1|23,15,2|23,16,2|23,17,2|23,18,2|23,19,2|23,20,2|23,21,2|23,22,2|23,23,2|23,24,2|23,25,2|23,26,2|23,27,2|23,28,2|23,29,1|23,30,1|23,31,1|23,32,1|23,33,1|23,34,1|23,35,2|23,36,2|23,37,2|23,38,2|23,39,2|23,40,2|23,41,2|23,42,2|23,43,2|23,44,2|23,45,2|23,46,2|23,47,2|23,48,2|23,49,3|23,50,3|24,1,6|24,2,2|24,3,1|24,4,1|24,5,1|24,6,1|24,7,1|24,8,1|24,9,2|24,10,1|24,11,1|24,12,6|24,13,6|24,14,1|24,15,2|24,16,2|24,17,2|24,18,2|24,19,2|24,20,2|24,21,1|24,22,1|24,23,1|24,24,2|24,25,2|24,26,1|24,27,1|24,28,1|24,29,1|24,30,2|24,31,2|24,32,2|24,33,1|24,34,2|24,35,2|24,36,2|24,37,2|24,38,2|24,39,2|24,40,2|24,41,2|24,42,2|24,43,2|24,44,2|24,45,2|24,46,2|24,47,2|24,48,2|24,49,3|24,50,3|25,1,6|25,2,2|25,3,1|25,4,1|25,5,1|25,6,1|25,7,1|25,8,2|25,9,2|25,10,1|25,11,1|25,12,6|25,13,6|25,14,1|25,15,1|25,16,2|25,17,2|25,18,2|25,19,1|25,20,1|25,21,1|25,22,1|25,23,1|25,24,1|25,25,1|25,26,1|25,27,1|25,28,1|25,29,1|25,30,2|25,31,2|25,32,2|25,33,2|25,34,2|25,35,2|25,36,2|25,37,2|25,38,2|25,39,2|25,40,2|25,41,2|25,42,2|25,43,2|25,44,2|25,45,2|25,46,2|25,47,2|25,48,2|25,49,3|25,50,3|26,1,6|26,2,2|26,3,2|26,4,1|26,5,1|26,6,1|26,7,1|26,8,2|26,9,1|26,10,1|26,11,6|26,12,6|26,13,1|26,14,1|26,15,1|26,16,1|26,17,1|26,18,1|26,19,1|26,20,1|26,21,1|26,22,1|26,23,1|26,24,1|26,25,1|26,26,1|26,27,1|26,28,1|26,29,1|26,30,2|26,31,2|26,32,2|26,33,2|26,34,2|26,35,2|26,36,2|26,37,2|26,38,2|26,39,2|26,40,2|26,41,2|26,42,2|26,43,2|26,44,2|26,45,2|26,46,2|26,47,2|26,48,3|26,49,3|26,50,3|27,1,6|27,2,6|27,3,1|27,4,1|27,5,1|27,6,1|27,7,1|27,8,1|27,9,1|27,10,1|27,11,6|27,12,1|27,13,8|27,14,1|27,15,1|27,16,1|27,17,1|27,18,1|27,19,1|27,20,1|27,21,1|27,22,1|27,23,1|27,24,1|27,25,1|27,26,1|27,27,1|27,28,1|27,29,2|27,30,2|27,31,2|27,32,2|27,33,2|27,34,3|27,35,2|27,36,2|27,37,2|27,38,2|27,39,2|27,40,2|27,41,2|27,42,2|27,43,2|27,44,2|27,45,2|27,46,2|27,47,2|27,48,3|27,49,3|27,50,3|28,1,6|28,2,6|28,3,1|28,4,1|28,5,1|28,6,1|28,7,1|28,8,1|28,9,1|28,10,1|28,11,1|28,12,1|28,13,8|28,14,1|28,15,1|28,16,1|28,17,1|28,18,1|28,19,1|28,20,1|28,21,1|28,22,1|28,23,1|28,24,1|28,25,1|28,26,1|28,27,1|28,28,1|28,29,2|28,30,2|28,31,2|28,32,2|28,33,3|28,34,3|28,35,2|28,36,2|28,37,2|28,38,2|28,39,2|28,40,2|28,41,2|28,42,2|28,43,2|28,44,2|28,45,2|28,46,2|28,47,2|28,48,3|28,49,3|28,50,3|29,1,6|29,2,6|29,3,1|29,4,1|29,5,1|29,6,1|29,7,1|29,8,1|29,9,1|29,10,1|29,11,1|29,12,1|29,13,8|29,14,8|29,15,1|29,16,1|29,17,1|29,18,3|29,19,3|29,20,1|29,21,1|29,22,1|29,23,1|29,24,1|29,25,1|29,26,1|29,27,1|29,28,1|29,29,2|29,30,2|29,31,2|29,32,2|29,33,3|29,34,3|29,35,2|29,36,2|29,37,2|29,38,2|29,39,2|29,40,2|29,41,2|29,42,2|29,43,2|29,44,2|29,45,2|29,46,2|29,47,2|29,48,3|29,49,3|29,50,3|30,1,6|30,2,6|30,3,1|30,4,1|30,5,1|30,6,1|30,7,1|30,8,1|30,9,6|30,10,6|30,11,1|30,12,1|30,13,8|30,14,8|30,15,8|30,16,1|30,17,1|30,18,1|30,19,3|30,20,1|30,21,1|30,22,2|30,23,1|30,24,1|30,25,1|30,26,1|30,27,1|30,28,1|30,29,2|30,30,2|30,31,2|30,32,2|30,33,3|30,34,3|30,35,2|30,36,2|30,37,2|30,38,2|30,39,2|30,40,2|30,41,2|30,42,2|30,43,2|30,44,2|30,45,2|30,46,2|30,47,2|30,48,3|30,49,3|30,50,3|31,1,6|31,2,6|31,3,8|31,4,8|31,5,8|31,6,8|31,7,1|31,8,1|31,9,1|31,10,1|31,11,1|31,12,1|31,13,1|31,14,8|31,15,8|31,16,1|31,17,1|31,18,1|31,19,1|31,20,1|31,21,1|31,22,2|31,23,1|31,24,1|31,25,1|31,26,1|31,27,1|31,28,1|31,29,2|31,30,2|31,31,2|31,32,2|31,33,3|31,34,3|31,35,2|31,36,2|31,37,2|31,38,2|31,39,2|31,40,2|31,41,2|31,42,2|31,43,2|31,44,1|31,45,1|31,46,2|31,47,2|31,48,3|31,49,3|31,50,3|32,1,6|32,2,6|32,3,8|32,4,8|32,5,8|32,6,8|32,7,8|32,8,8|32,9,1|32,10,1|32,11,1|32,12,1|32,13,1|32,14,8|32,15,8|32,16,1|32,17,1|32,18,1|32,19,1|32,20,1|32,21,1|32,22,1|32,23,1|32,24,1|32,25,1|32,26,1|32,27,1|32,28,1|32,29,2|32,30,2|32,31,2|32,32,2|32,33,3|32,34,3|32,35,2|32,36,2|32,37,2|32,38,2|32,39,2|32,40,2|32,41,2|32,42,2|32,43,2|32,44,1|32,45,1|32,46,2|32,47,2|32,48,2|32,49,2|32,50,3|33,1,6|33,2,6|33,3,6|33,4,8|33,5,8|33,6,8|33,7,8|33,8,1|33,9,1|33,10,1|33,11,1|33,12,1|33,13,1|33,14,1|33,15,8|33,16,1|33,17,1|33,18,1|33,19,1|33,20,1|33,21,1|33,22,1|33,23,1|33,24,1|33,25,1|33,26,1|33,27,1|33,28,1|33,29,2|33,30,2|33,31,2|33,32,2|33,33,2|33,34,2|33,35,2|33,36,2|33,37,2|33,38,2|33,39,2|33,40,2|33,41,2|33,42,2|33,43,2|33,44,2|33,45,1|33,46,2|33,47,2|33,48,2|33,49,2|33,50,2|34,1,6|34,2,6|34,3,6|34,4,6|34,5,8|34,6,1|34,7,1|34,8,1|34,9,1|34,10,1|34,11,1|34,12,1|34,13,1|34,14,1|34,15,1|34,16,1|34,17,1|34,18,1|34,19,1|34,20,1|34,21,1|34,22,1|34,23,1|34,24,1|34,25,1|34,26,1|34,27,1|34,28,1|34,29,1|34,30,2|34,31,2|34,32,2|34,33,2|34,34,2|34,35,2|34,36,2|34,37,2|34,38,2|34,39,2|34,40,2|34,41,2|34,42,2|34,43,2|34,44,2|34,45,2|34,46,2|34,47,2|34,48,2|34,49,2|34,50,2|35,1,6|35,2,6|35,3,6|35,4,6|35,5,6|35,6,1|35,7,1|35,8,1|35,9,1|35,10,1|35,11,1|35,12,1|35,13,1|35,14,1|35,15,1|35,16,1|35,17,1|35,18,1|35,19,1|35,20,1|35,21,1|35,22,1|35,23,1|35,24,1|35,25,1|35,26,1|35,27,1|35,28,1|35,29,1|35,30,2|35,31,2|35,32,2|35,33,2|35,34,2|35,35,2|35,36,2|35,37,2|35,38,2|35,39,2|35,40,2|35,41,2|35,42,2|35,43,2|35,44,2|35,45,2|35,46,2|35,47,2|35,48,2|35,49,2|35,50,2|36,1,6|36,2,6|36,3,6|36,4,6|36,5,6|36,6,1|36,7,2|36,8,2|36,9,2|36,10,2|36,11,1|36,12,1|36,13,1|36,14,1|36,15,1|36,16,1|36,17,1|36,18,1|36,19,1|36,20,1|36,21,1|36,22,1|36,23,1|36,24,1|36,25,1|36,26,1|36,27,1|36,28,1|36,29,1|36,30,2|36,31,2|36,32,2|36,33,2|36,34,2|36,35,2|36,36,2|36,37,2|36,38,2|36,39,2|36,40,2|36,41,2|36,42,2|36,43,2|36,44,2|36,45,2|36,46,2|36,47,2|36,48,2|36,49,2|36,50,2|37,1,6|37,2,6|37,3,6|37,4,6|37,5,6|37,6,1|37,7,2|37,8,2|37,9,2|37,10,2|37,11,2|37,12,1|37,13,1|37,14,1|37,15,1|37,16,1|37,17,1|37,18,1|37,19,1|37,20,1|37,21,1|37,22,1|37,23,1|37,24,1|37,25,1|37,26,1|37,27,1|37,28,1|37,29,1|37,30,2|37,31,2|37,32,2|37,33,2|37,34,2|37,35,2|37,36,2|37,37,2|37,38,2|37,39,2|37,40,2|37,41,2|37,42,2|37,43,2|37,44,2|37,45,2|37,46,2|37,47,2|37,48,2|37,49,2|37,50,2|38,1,6|38,2,6|38,3,2|38,4,2|38,5,1|38,6,2|38,7,2|38,8,2|38,9,2|38,10,2|38,11,2|38,12,1|38,13,1|38,14,1|38,15,1|38,16,1|38,17,1|38,18,1|38,19,1|38,20,2|38,21,1|38,22,1|38,23,1|38,24,1|38,25,1|38,26,1|38,27,1|38,28,1|38,29,1|38,30,2|38,31,2|38,32,2|38,33,2|38,34,2|38,35,2|38,36,2|38,37,2|38,38,2|38,39,2|38,40,2|38,41,2|38,42,2|38,43,2|38,44,2|38,45,2|38,46,2|38,47,2|38,48,2|38,49,2|38,50,2|39,1,12|39,2,2|39,3,2|39,4,2|39,5,1|39,6,2|39,7,2|39,8,2|39,9,2|39,10,2|39,11,2|39,12,1|39,13,1|39,14,1|39,15,1|39,16,1|39,17,1|39,18,2|39,19,2|39,20,2|39,21,2|39,22,1|39,23,1|39,24,1|39,25,1|39,26,1|39,27,1|39,28,1|39,29,1|39,30,2|39,31,2|39,32,2|39,33,2|39,34,2|39,35,2|39,36,2|39,37,2|39,38,2|39,39,2|39,40,2|39,41,2|39,42,2|39,43,2|39,44,2|39,45,2|39,46,2|39,47,2|39,48,2|39,49,2|39,50,2|40,1,12|40,2,2|40,3,2|40,4,2|40,5,1|40,6,1|40,7,2|40,8,2|40,9,2|40,10,2|40,11,2|40,12,1|40,13,1|40,14,1|40,15,1|40,16,1|40,17,2|40,18,2|40,19,2|40,20,2|40,21,2|40,22,1|40,23,1|40,24,1|40,25,1|40,26,1|40,27,1|40,28,1|40,29,1|40,30,2|40,31,2|40,32,2|40,33,2|40,34,2|40,35,2|40,36,2|40,37,2|40,38,2|40,39,2|40,40,2|40,41,2|40,42,2|40,43,2|40,44,2|40,45,2|40,46,2|40,47,2|40,48,2|40,49,2|40,50,2|41,1,12|41,2,2|41,3,2|41,4,1|41,5,1|41,6,1|41,7,2|41,8,2|41,9,2|41,10,2|41,11,2|41,12,1|41,13,1|41,14,1|41,15,1|41,16,1|41,17,2|41,18,2|41,19,2|41,20,2|41,21,2|41,22,1|41,23,1|41,24,1|41,25,1|41,26,1|41,27,1|41,28,1|41,29,2|41,30,2|41,31,2|41,32,2|41,33,2|41,34,2|41,35,2|41,36,2|41,37,2|41,38,2|41,39,2|41,40,2|41,41,2|41,42,2|41,43,2|41,44,2|41,45,2|41,46,2|41,47,2|41,48,2|41,49,2|41,50,2|42,1,6|42,2,6|42,3,2|42,4,1|42,5,1|42,6,1|42,7,1|42,8,2|42,9,2|42,10,2|42,11,2|42,12,1|42,13,1|42,14,1|42,15,1|42,16,1|42,17,2|42,18,2|42,19,2|42,20,2|42,21,1|42,22,1|42,23,1|42,24,1|42,25,1|42,26,1|42,27,1|42,28,2|42,29,2|42,30,2|42,31,2|42,32,2|42,33,2|42,34,2|42,35,2|42,36,2|42,37,2|42,38,2|42,39,2|42,40,2|42,41,2|42,42,2|42,43,2|42,44,2|42,45,2|42,46,2|42,47,2|42,48,2|42,49,2|42,50,2|43,1,6|43,2,6|43,3,6|43,4,6|43,5,1|43,6,6|43,7,6|43,8,2|43,9,2|43,10,2|43,11,2|43,12,1|43,13,1|43,14,1|43,15,1|43,16,1|43,17,2|43,18,2|43,19,2|43,20,2|43,21,1|43,22,1|43,23,1|43,24,1|43,25,1|43,26,1|43,27,2|43,28,2|43,29,2|43,30,2|43,31,2|43,32,2|43,33,2|43,34,2|43,35,2|43,36,2|43,37,2|43,38,2|43,39,2|43,40,2|43,41,2|43,42,2|43,43,2|43,44,2|43,45,2|43,46,2|43,47,2|43,48,2|43,49,2|43,50,2|44,1,6|44,2,6|44,3,6|44,4,6|44,5,6|44,6,1|44,7,1|44,8,1|44,9,2|44,10,2|44,11,2|44,12,1|44,13,1|44,14,1|44,15,1|44,16,1|44,17,2|44,18,2|44,19,2|44,20,2|44,21,1|44,22,1|44,23,1|44,24,1|44,25,1|44,26,1|44,27,2|44,28,2|44,29,2|44,30,2|44,31,2|44,32,2|44,33,2|44,34,2|44,35,2|44,36,2|44,37,2|44,38,2|44,39,2|44,40,2|44,41,2|44,42,2|44,43,2|44,44,2|44,45,2|44,46,2|44,47,2|44,48,2|44,49,2|44,50,2|45,1,6|45,2,6|45,3,6|45,4,6|45,5,6|45,6,1|45,7,1|45,8,1|45,9,2|45,10,2|45,11,2|45,12,1|45,13,1|45,14,1|45,15,1|45,16,1|45,17,2|45,18,2|45,19,2|45,20,2|45,21,1|45,22,1|45,23,1|45,24,1|45,25,1|45,26,2|45,27,2|45,28,2|45,29,2|45,30,2|45,31,2|45,32,2|45,33,2|45,34,2|45,35,2|45,36,2|45,37,2|45,38,2|45,39,2|45,40,2|45,41,2|45,42,2|45,43,2|45,44,2|45,45,2|45,46,2|45,47,2|45,48,2|45,49,2|45,50,2|46,1,6|46,2,6|46,3,6|46,4,6|46,5,6|46,6,1|46,7,1|46,8,1|46,9,2|46,10,2|46,11,2|46,12,1|46,13,1|46,14,1|46,15,1|46,16,2|46,17,2|46,18,2|46,19,2|46,20,2|46,21,1|46,22,1|46,23,1|46,24,1|46,25,2|46,26,2|46,27,2|46,28,2|46,29,2|46,30,2|46,31,2|46,32,2|46,33,2|46,34,2|46,35,2|46,36,2|46,37,2|46,38,2|46,39,2|46,40,2|46,41,2|46,42,2|46,43,2|46,44,2|46,45,2|46,46,2|46,47,2|46,48,2|46,49,2|46,50,2|47,1,6|47,2,6|47,3,6|47,4,6|47,5,6|47,6,1|47,7,1|47,8,1|47,9,2|47,10,2|47,11,2|47,12,1|47,13,1|47,14,1|47,15,1|47,16,2|47,17,2|47,18,2|47,19,2|47,20,2|47,21,2|47,22,1|47,23,1|47,24,1|47,25,1|47,26,2|47,27,2|47,28,2|47,29,2|47,30,2|47,31,2|47,32,2|47,33,2|47,34,2|47,35,2|47,36,2|47,37,2|47,38,2|47,39,2|47,40,2|47,41,2|47,42,2|47,43,2|47,44,2|47,45,2|47,46,2|47,47,2|47,48,2|47,49,2|47,50,2|48,1,6|48,2,6|48,3,6|48,4,6|48,5,1|48,6,1|48,7,1|48,8,1|48,9,2|48,10,2|48,11,2|48,12,2|48,13,1|48,14,1|48,15,2|48,16,2|48,17,2|48,18,2|48,19,2|48,20,2|48,21,2|48,22,1|48,23,6|48,24,6|48,25,6|48,26,2|48,27,2|48,28,2|48,29,2|48,30,2|48,31,2|48,32,2|48,33,2|48,34,2|48,35,2|48,36,2|48,37,2|48,38,2|48,39,2|48,40,2|48,41,2|48,42,2|48,43,2|48,44,2|48,45,2|48,46,2|48,47,2|48,48,2|48,49,2|48,50,2|49,1,6|49,2,6|49,3,6|49,4,6|49,5,1|49,6,1|49,7,1|49,8,1|49,9,2|49,10,2|49,11,2|49,12,2|49,13,2|49,14,2|49,15,2|49,16,2|49,17,2|49,18,2|49,19,2|49,20,2|49,21,2|49,22,1|49,23,6|49,24,1|49,25,1|49,26,1|49,27,2|49,28,2|49,29,2|49,30,2|49,31,2|49,32,2|49,33,2|49,34,2|49,35,2|49,36,2|49,37,2|49,38,2|49,39,2|49,40,2|49,41,2|49,42,2|49,43,2|49,44,2|49,45,2|49,46,2|49,47,2|49,48,2|49,49,2|49,50,2|50,1,6|50,2,6|50,3,6|50,4,6|50,5,1|50,6,1|50,7,1|50,8,2|50,9,2|50,10,2|50,11,2|50,12,2|50,13,2|50,14,2|50,15,2|50,16,2|50,17,2|50,18,2|50,19,2|50,20,2|50,21,1|50,22,1|50,23,1|50,24,1|50,25,1|50,26,1|50,27,1|50,28,2|50,29,2|50,30,2|50,31,2|50,32,2|50,33,2|50,34,2|50,35,2|50,36,2|50,37,2|50,38,2|50,39,2|50,40,2|50,41,2|50,42,1|50,43,1|50,44,1|50,45,2|50,46,2|50,47,2|50,48,2|50,49,2|50,50,2";
        var zoneArr     = mapData.split("|");
        for (z=0; z<zoneArr.length; z++) {
            thisZone    = zoneArr[z].split(",");
            thisX       = thisZone[0];
            thisY       = thisZone[1];
            thisZ       = thisZone[2];
            mapTerrain[thisX][thisY][1] = thisZ;
            mapTerrain[thisX][thisY][2] = false;
        }

        mapRedraw(loadTileDelta*3);  // On initial draw, fill out 3 times as much area as normal.
    }

    function mapRedraw(thisLoadTileDelta) {
        // We'll call this function every time the canvas is dragged to draw any tiles that haven't been drawn yet.  We could just draw them all, but that causes serious performance issues on mobile once the realmSize is over 100 or so.

        // Calculate start and end positions for our tile loading loops
        thisXMin        = parseInt(curPosX - thisLoadTileDelta);
        if (thisXMin < 1) {
            thisXMin    = 1;
        }
        thisXMax        = parseInt(thisXMin + (thisLoadTileDelta*2));
        if (thisXMax > realmSize) {
            thisXMax    = realmSize;
            thisXMin    = parseInt(thisXMax - (thisLoadTileDelta*2));
        }

        thisYMin        = parseInt(curPosY - thisLoadTileDelta);
        if (thisYMin < 1) {
            thisYMin    = 1;
        }
        thisYMax        = parseInt(thisYMin + (thisLoadTileDelta*2));
        if (thisYMax > realmSize) {
            thisYMax    = realmSize;
            thisYMin    = parseInt(thisYMax - (thisLoadTileDelta*2));
        }

        // Slap our canvas context into a variable for easier access
        var thisCanvas = document.getElementById("mapCanvas");
        var canvasContext = thisCanvas.getContext("2d");
        for (x=thisXMin; x<=thisXMax; x++) {
            for (y=thisYMin; y<=thisYMax; y++) {
                // Check to see if we've drawn this tile yet.  If not, draw it.
                if (mapTerrain[x][y][2] == false) {
                    mapTerrain[x][y][2] = true;  // Mark the tile as drawn
                    xLoc                = (x - 1) * tileSize;  // Determine positioning in pixels
                    yLoc                = (y - 1) * tileSize;
                    canvasContext.drawImage(terrainImgArr[mapTerrain[x][y][1]], xLoc, yLoc, tileSize, tileSize);
                }
            }
        }
    }

    // Now we use jQuery to make the canvas draggable, essentially moving our "viewing window" (the containerDiv) around the map
    $("#mapCanvas").draggable({
        stop: function() {
            // If the user continues to scroll they can move off the map and end up in whitespace, which is never good.  So we set some limits here, and snap the user back if they tried to go too far in any direction.

            divLeft = parseInt($("#mapCanvas").css("left"));
            divTop  = parseInt($("#mapCanvas").css("top"));

            if (divLeft < minDragXY) {
                $("#mapCanvas").animate({left: minDragXY + "px"}, 150)
                divLeft = minDragXY;
            } else if (divLeft > 0) {
                $("#mapCanvas").animate({left: "0px"}, 150)
                divLeft = 0;
            }

            if (divTop < minDragXY) {
                $("#mapCanvas").animate({top: minDragXY + "px"}, 150)
                divTop  = minDragXY;
            } else if (divTop > 0) {
                $("#mapCanvas").animate({top: "0px"}, 150)
                divTop  = 0;
            }

            // After our containment checks are done, we update the curPos variables then call the map redraw function again.  That function will key off of the new curPos and load any tiles necessary.
            curPosX = (Math.abs(divLeft) + (containerSize/2)) / tileSize;
            curPosY = (Math.abs(divTop) + (containerSize/2)) / tileSize;
            mapRedraw(loadTileDelta);
        }
    });

    mapLoad();  // Kick off the whole process here.  This would ultimately end up in an onload handler...
</script>
\$\endgroup\$
0
\$\begingroup\$

What you are looking for is the HTML5 canvas element. From w3schools:

The HTML <canvas> element is used to draw graphics on a web page.

\$\endgroup\$
  • 2
    \$\begingroup\$ This is a first step in a useful direction. To be even more helpful, it would be best to try to explain how one would use a canvas element to achieve this outcome. \$\endgroup\$ – DMGregory Dec 16 '18 at 1:22
  • \$\begingroup\$ That's true but I was feeling lazy. The w3schools link has instruction on how to draw an image and it's a short leap from that to drawing a tile set. Also, this should help gamedev.stackexchange.com/questions/25318/…. Listing how every other browser game implements overworld maps would be off topic here. \$\endgroup\$ – Jay Dec 16 '18 at 2:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.