CreateJS / EaselJS Strange Performance with certain size shapes
Asked Answered
W

2

7

I am currently developing a game, it uses a large tiled map, that can be dragged around, and moves quickly with your character.

I have created a simple version of the problem JSFiddle Example

Each tile is a Shape and is cached. All shapes go inside a container, the container is moved based on camera position.

I am noticing weird drops in fps at certain zoom levels. The zoom simply adjusts the size of the shapes.

If you adjust the zoom you will see what i mean.

Chrome

zoom 1 = good fps
zoom 3 = bad fps
zoom 5 = good fps

What would be the reason for this frame rate problem?

Note i have i posted this on the createjs community forum as well.
Community Question

Here is the code in the jsfiddle example

HTML

<canvas id="mainCanvas" width="500" height="500"></canvas>
<span id="fps-container"><span id="fps">Loading</span> FPS</span>

JS

/*
This is a very simple version of a larger app/game i am creating
uses a large map that is drawn in sectors (createjs shapes)
I have not figured out the best way to cache, because if i cache all at once, its a lot of overhead.

My main issue is the zoom levels, the zoom simply adjusts the sectorsize.
The problem with this is that there seems to be a wierd performance problem at certain zoom levels.

To test this out, adjust the camera zoom property. I do not recommend anything more that 6.
*/

//Generic Settings
var Settings = {
    block_size: 50,
    rows: 50,
    cols: 50
}

//Create Camera
var Camera = {
    /*

    HERE IS THE ZOOM PROBLEM

      Chrome
      zoom : 1 = good fps
      zoom : 2 - 4 = bad fps
      zoom : 5 - 6 = good fps again ... wtf

      Safari
      Zoom: 7 = Good fps

  */
    x: 0,
    y: 0,
    zoom:1
}

//Create Short Alias
var Stage = createjs.Stage;
var Ticker = createjs.Ticker;
var Container = createjs.Container;
var Graphics = createjs.Graphics;
var Shape = createjs.Shape;


//Full Screen Canvas
var canvas = document.getElementById("mainCanvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

//Create Stage
var mainStage = new Stage(canvas);
mainStage.snameToPixelsEnabled = true;
mainStage.autoClear = true;

//Start Ticker
Ticker.addListener(this);
Ticker.useRAF = true;
Ticker.setFPS(30);

//Create Container;
var mainContainer = new Container();
mainContainer.snapToPixel = true;

//Add Container to Stage
mainStage.addChild(mainContainer);


//Create Lots of Shapes
var size = Settings.block_size * Camera.zoom;

//For the purpose of demonstration, I am only creating a square
//My actual app has much more complex drawings
var graphics = new Graphics();
graphics.setStrokeStyle(1 * Camera.zoom, "round");
graphics.beginFill(Graphics.getRGB(230,230,230,0.5));
graphics.beginStroke(null);
graphics.rect(-10, -10, size+10, size+10);


var cols = Settings.cols;
var rows = Settings.rows;
for (var x = 0; x < cols; x++) {
    for (var y = 0; y < rows; y++) {

        var shape = new Shape(graphics);
        shape.x = x * size;
        shape.y = y * size;

        //Cache the shape, (the offset is to prevent the cache from chopping off complex shapes)
        var cache_offset = 10 * Camera.zoom;
        shape.cache(-cache_offset,-cache_offset, size + cache_offset, size + cache_offset);

        //Add shape to container
        mainContainer.addChild(shape);
    }
}

//Make map draggable
var lastX,lastY;

mainStage.onMouseDown = function(evt){
    lastX = evt.stageX;
    lastY = evt.stageY;
}

mainStage.onMouseMove = function(evt){
    if(lastX && lastY){
        var stageX = evt.stageX;
        var stageY = evt.stageY;
        var diffX = lastX - stageX;
        var diffY = lastY - stageY;
        lastX = stageX;
        lastY = stageY;
        Camera.x += diffX / Camera.zoom;
        Camera.y += diffY / Camera.zoom;
    }    
}

mainStage.onMouseUp = function(evt){
    lastX = null;
    lastY = null;
}

//Update the container position based on camera position and zoom
updatePosition = function(){
    mainContainer.x = -Camera.x * Camera.zoom;
    mainContainer.y = -Camera.y * Camera.zoom;
}


tick = function(){
    updatePosition();
    mainStage.update();
    var fps = document.getElementById('fps');
    fps.innerHTML = Ticker.getMeasuredFPS();
}
Whap answered 6/2, 2013 at 6:41 Comment(4)
+1 for a well-documented question, but I don't see the problem at all in Chrome 24 on Windows 7.Firebug
your "game" totally crashes firefox(latest,win7). You might want to test it on more than chrome.Jackofalltrades
Yeah sorry, the problem is very inconsistent. I will try and narrow it down further.Whap
[fixed example below].Whap
W
4

Solved.

I solved the issue by looping through each shape on tick, and applying a visible = false; if it is out of bounds Updated Fixed Example

//Update the container position based on camera position and zoom
updatePosition = function () {

    var floor = Math.floor;

    var min_x = 0 + Camera.x * Camera.zoom - size;
    var min_y = 0 + Camera.y * Camera.zoom - size;
    var max_x = Screen.width + Camera.x * Camera.zoom + size
    var max_y = Screen.height + Camera.y * Camera.zoom + size;



    mainContainer.x = -Camera.x * Camera.zoom;
    mainContainer.y = -Camera.y * Camera.zoom;

    var shape_count = mainContainer.getNumChildren() - 1;

    for (var i = 0; i <= shape_count; i++) {
        var shape = mainContainer.getChildAt(i);

        if(shape.x < min_x || shape.x > max_x){
            shape.visible = false;
        }
        else if(shape.y < min_y || shape.y > max_y){
           shape.visible = false; 
        }
        else {
            shape.visible = true;
        }

    }

}
Whap answered 6/2, 2013 at 21:5 Comment(0)
B
1

What I noticed is, that if the caching-square is smaller than a certain size the framerate drops, so what I did:

var cache_offset = 10 * Camera.zoom;
=>
var cache_offset = 10 * Camera.zoom + 77;

And I played around with that 77 a little, my initial thought was that the caching area has to be in the power of 2, but at zoom:3, adding 77 results in a caching-size of 364x364px and any size above that works fine as well for zoom:3, so I don't know why, but the size of the caching-rectangle somehow causes the framerate to drop.


And there's one typo(not really affecting this issue):

mainStage.snameToPixelsEnabled = true;
=>
mainStage.snapToPixelEnabled = true;

That brought up the framerate by about 2-3fps

Banting answered 7/2, 2013 at 0:18 Comment(1)
[+1] Thanks for the typo! Yeah it definitely is a size of the rectangle causes the drop. Appreciate the input , will play around with the cache sizing. Here is the updated version with that only caches when in view. jsfiddle.net/Bodman/28Jqa Still lags at moments.Whap

© 2022 - 2024 — McMap. All rights reserved.