Robert
Robert

Reputation: 31

How can I keep my canvas fast when creating a large map?

I'm trying to create a game with HTML5 and a canvas. At the moment I am using the KineticJS library.

The things I have working so far are zooming in and out, dragging from a layer within the stage, and dragging from some objects. This all works nice and fast.

However, the game also needs a landscape, where people can build houses, grainfields etc. Also there need to be some trees and other details. This all makes the canvas very full.

So to test, I made a canvas layer of 10000 x 10000 pixels and made it in 100 x 100 tiles of 100 x 100 px. Just this took so much time it didn't even load.

So I tried it with less tiles (25 x 25) and this does load, but when I try to zoom, drag the stage or drag an object, it is very, very slow and it all needs to contain many more objects.

So the main question is: Can anyone consult me of which method I can use best for the above story? Is a canvas the correct option, or are there other (and better) options?

Upvotes: 0

Views: 914

Answers (2)

Robert
Robert

Reputation: 31

I found a perfect solution!

I'm going to combine canvas with some regular HTML like div. I have made this, it makes a field from 15000x15000 px within this div i make 225 new divs which will contain the canvas objects. Every canvas object will have a size from 100x100 px.

The total loading time is about 4 seconds, and I will build the zooming, dragging with just some javascript and divs.

<!DOCTYPE HTML>
<html>
<head>

    <style>
        body,html {
            margin: 0px;
            padding: 0px;
        }
        #container{
            width: 15000px;
            height: 15000px;
        }
        .canvas{
            float: left;
            margin: 0px;
            padding: 0px;
            height: 1000px;
            width: 1000px;
        }
    </style>

    <script src="/js/jquery.js"></script>
    <script src="/js/kinetic.js"></script>

</head>
<body>
<div id="zoomer" style="position: absolute;"></div>
<div id="container">
    <?php for ($x = 1;$x<=15;$x++){?>
        <?php for ($y = 1;$y<=15;$y++){?>
            <div class="canvas" id="blok<?php echo $x;?>-<?php echo $y;?>"></div>
        <?php } ?>
    <?php } ?>
</div>
<script>
    var bk = {};
    $.each($(".canvas"),function(){

        var id = this.id;
        bk[id] = new Kinetic.Stage({
            container: this.id,
            width: 1000,
            height: 1000
        });

        var ly = new Kinetic.Layer();

        for(x = 0;x<10;x++){
            for(y = 0;y<10;y++){
                var r = Math.random();
                var g = Math.random();
                var b = Math.random();

                var tile = new Kinetic.Rect({
                    width: 100,
                    height: 100,
                    x: x * 100,
                    y: y * 100,
                    fill: "rgb("+ parseInt(255*r) +","+ parseInt(255*g) +","+ parseInt(255*b) +")"
                });
                ly.add(tile);
            }

        }
        ly.draw();

        bk[id].add(ly);

    });

</script>
</body>
</html>

Anyway, thanks for the effort!

Upvotes: 2

Jarrod
Jarrod

Reputation: 9465

A 10,000 x 10,000px map is waaay to large.

Conceptually, this is fine. The trick is not to hold-in-memory/draw the whole thing! ie, even if your map is that large you'll only ever draw/update the tiles/objects for the 500 x 500px, or whatever your viewport is, around your character.

See this post, and Simon's answer to achieve this.

And here is the example jsFiddle (full credit to Simon Sarris) associated with the answer.

Upvotes: 2

Related Questions