2

I'm an engineer and we are currently porting our Red5 + Flash game into a Node.js + Easeljs html5 application.

Basicly: it's a board game, not an rpg. The layer system means we have multiple canvasses, based on functionally. For example there is a static background stage, with images. There is a layer for just the timers.

At default, all canvas size is 1920x1080, if needed we downscale to fit to the resolution.

The first approach used kinetic.js, but the performance fallen when the game got complex. Then we switched to easel, because it's abstraction level is lower, so we can decide how to implement some more function, not just use the provided robust one.

I was optimistic, but now it's starting to show slowness again, that's why I want to look deeper inside and do fine performance tuning. (Of course everything is fine in Chrome, Firefox is the problem, but the game must run smoothly on all modern browser).

The main layer (stage) is the map, contains ~30 containers, in each there is a complex custom shape, ~10 images. The containers are listening to mouse events, like mouseover, out, click. Currently, for example on mouseover I refill the shape with gradient.

Somehow, when I use cache, like the way in the tuts the performance get even worse, so I assume I'm messing up something.

I collected some advanced questions:

  1. In the described situation when can I use cache and how? I've already tried cache on init, cacheUpdate after fill with other color or gradient, then stage.update(). No impact.

  2. If I have a static, never changing stage cache doesn't make sense on that layer, right?

  3. What stage.update() exactly do? Triggering the full layer redraw? The doc mentions some kind of intelligent if changed then redraw effect.

  4. If I want to refill a custom shape with new color or gradient I have to completely redraw its graphics, not just use a setFill method, right?

  5. In easel there is no possibility to redraw just a container for example, so how can I manage to not update the whole stage, but just the one container that changed? I thought I can achieve this with caching, cache all containers the just update the one that changed, but this way didn't work at all for me.

  6. Does it make sense to cache bitmap images? If there are custom shapes and images in a container what is better? Cache the container or just the shape in container.

    I found a strange bug, or at least an interesting clue. My canvas layers totally overlapping. On the inferior layers the mouseover listening is working well, but the click isn't on the very same container/object.

  7. How can I produce a click event propagation to overlapped layers those have click listeners? I've tried it with simple DOM, jquery, but the event objects were far away from what canvas listeners wanted to get.

In brief, methods and props I've already played with bare success when tried tuning: cache(), updateCache(), update(), mouseEnabled, snapToPixel, clear(), autoClear, enableMouseOver, useRAF, setFPS().

Any answer, suggestion, starting point appreciated.

UPDATE:

This free board game is a strategy game, so you are facing a world map, with ~30 territories. The custom shapes are the territories and a container holds a territory shape and the icons that should be over the territory. This container overlapping is minimal.

An example mouse event is a hover effect. The player navigate over the territory shape then the shape is getting recolored, resized, etc and a bubble showing up with details about the place.

Basically, maximum amount of 1-3 container could change at once (except the init phase -> all at this time). Not just the animations and recoloring slow in FF, but the listener delay is high too.

I wrote a change handler, so I only stage.update() up on tick the modified stages and the stages where an animation is running (tweenjs).

In my first approach I put every image to the container that could be needed at least once during the game, so I only set visible flags on images (not vectors).

Community
  • 1
  • 1
Tyborrex
  • 141
  • 2
  • 8
  • It would help us if you could briefly describe your game (maybe a url to an online version for us to look at). In particular, How many of the 30 containers require redrawing on a typical loop of your game—and also which objects in the containers require redrawing. Are the objects in the containers actually bitmaps or are they vector drawings—or a mix. How are the 30 containers laid out on your 1920x1080 board. Are containers overlapping such that redraw of container A impairs container B. BTW, don’t cache bitmaps—it’s easier for Easel to blit directly from the bitmap object. – markE Feb 28 '13 at 22:04
  • First of all, thank you for helping. The site is not ready, so the game is developed locally, but I will edit the question with the detailed container informations. The images are bitmaps. – Tyborrex Mar 01 '13 at 02:07

2 Answers2

0

Regarding caching: There are some strange caching-issues, somehow the performance can drop with certain sizes of the caching rectangle: CreateJS / EaselJS Strange Performance with certain size shapes

(2) Depending on how often you call stage.update();

(3)

Each time the update method is called, the stage will tick any descendants exposing a tick method (ex. BitmapAnimation) and render its entire display list to the canvas. Any parameters passed to update will be passed on to any onTick handlers.

=> Afaik it rerenders everything if not cached

(4) Yes.

(5) No. (I don't know of any)

(6) If the content's of the container don't change often, I'd cache the whole container, otherwise the container will be reconstructed every frame.

I have a question though: Why do you use multiple canvases? How many do you use? I could imagine that using multiple canvases might slow down the game.

How many sprites do you use in total?

Community
  • 1
  • 1
olsn
  • 16,644
  • 6
  • 59
  • 65
  • 1
    Thank you for your contribution! The number of the layers is 6-8. I started using multiple canvases because I thought the stage.update() will be a heavy one, so when I designed I splited the elements by funcionality, for example the timer layer doesn't need mosue listener, so I can disable it, but it have to be updated in every second. There are no sprites, the animations are driven by tweenjs. They are just simple size, alpha, position manipulation effects. Not all, but one of the containers changing constantly, based on the user. – Tyborrex Mar 01 '13 at 02:44
  • By your words I should cache the containers and just rerender the affected one, the cache it again. I also tried this possibility, but had no success however I could miss out sthg, therefore I will try it again. – Tyborrex Mar 01 '13 at 02:44
  • I have experienced similar drops in performance in Firefox while everything is super smooth on any webkit browser (Chrome, Safari, iOS...) even on just one canvas - but still it could be worth a try to test all canvases individually and completely remove the other canvases. – olsn Mar 01 '13 at 16:07
  • Maybe you can remove some canvases and use DIVs instead? I could imagine that a timer for example could have a better performance when rendering the text in a div with a background-image or so than using a canvas. – olsn Mar 01 '13 at 16:09
0

2: if your layer or stage doesn't change, don't call stage.update() for that layer (so it doesn't gets rerendered, gives me a much lower cpu!) For example, keep a global "stagechanged" variable and set this to true when something has changed:

createjs.Ticker.addEventListener("tick",
    function() {
        if (stagechanged)
        {
            stagechanged = false;
            stage.update();
        }
    });

(or do you already use this, as stated in your "update"?)

4: I found a way to update for example the fill color :)

contaier1.shape1.graphics._fillInstructions[0].params[1] = '#FFFFFF';

(use chrome debugger to look at the _fillInstructions array to see which array position contains your color)

5: I found a way to just paint one container :)

        //manual draw 1 component (!)
        var a = stage.canvas.getContext("2d");
        a.save();
        container1.updateContext(a);  //set position(x,y) on context
        container1.draw(a);
        a.restore();
André
  • 8,920
  • 1
  • 24
  • 24