CreateJS/EaselJS Странная производительность с фигурами определенного размера

В настоящее время я разрабатываю игру, в ней используется большая мозаичная карта, которую можно перетаскивать, и она быстро перемещается вместе с вашим персонажем.

Я создал простую версию задачи Пример JSFiddle

Каждая плитка представляет собой фигуру и кэшируется. Все фигуры находятся внутри контейнера, контейнер перемещается в зависимости от положения камеры.

Я замечаю странные падения частоты кадров при определенных уровнях масштабирования. Масштаб просто регулирует размер фигур.

Если вы отрегулируете масштаб, вы поймете, что я имею в виду.

Хром

зум 1 = хороший fps
зум 3 = плохой fps
зум 5 = хороший fps

В чем может быть причина этой проблемы с частотой кадров?

Обратите внимание, что я также опубликовал это на форуме сообщества createjs.
Вопрос сообщества

Вот код в примере jsfiddle

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();
}

person Bodman    schedule 06.02.2013    source источник
comment
+1 за хорошо документированный вопрос, но я вообще не вижу проблемы в Chrome 24 в Windows 7.   -  person Tim Medora    schedule 06.02.2013
comment
ваша игра полностью вылетает из firefox (последняя версия, win7). Возможно, вы захотите протестировать его не только на хроме.   -  person mpm    schedule 06.02.2013
comment
Да, извините, проблема очень противоречивая. Я постараюсь сузить его еще больше.   -  person Bodman    schedule 06.02.2013
comment
[исправленный пример ниже].   -  person Bodman    schedule 25.03.2013


Ответы (2)


Решено.

Я решил эту проблему, перебирая каждую фигуру в цикле и применяя visible = false;, если она выходит за пределы Обновлено Исправлено Пример

//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;
        }

    }

}
person Bodman    schedule 06.02.2013

Что я заметил, так это то, что если площадь кэширования меньше определенного размера, частота кадров падает, поэтому я сделал следующее:

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

И я немного поиграл с этим 77, моя первоначальная мысль заключалась в том, что область кэширования должна быть в степени 2, но при zoom:3, adding 77 получается размер кэширования 364x364px и любой размер выше, который также отлично работает для zoom:3, так что я не знаю почему, но размер прямоугольника кэширования каким-то образом приводит к падению частоты кадров.


И есть одна опечатка (на самом деле не влияющая на эту проблему):

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

Это увеличило частоту кадров примерно на 2-3 кадра в секунду.

person olsn    schedule 07.02.2013
comment
[+1] Спасибо за опечатку! Да, это определенно размер прямоугольника, вызывающий падение. Оцените ввод, поиграйте с размером кеша. Вот обновленная версия, которая кэширует только при просмотре. jsfiddle.net/Bodman/28Jqa Все еще иногда отстает. - person Bodman; 07.02.2013