CreateJS / EaselJS

The Easel Javascript library provides a full, hierarchical display list, a core interaction model, and helper classes to make working with the HTML5 Canvas element much easier.
http://createjs.com/
MIT License
8.11k stars 1.97k forks source link

MovieClip performance issue #1048

Closed LiorZar closed 3 years ago

LiorZar commented 4 years ago

I'm using Adobe Animate HTML5 to create a board game to run on Smart TV (low-performance machine).

All my previous games were done using AS3. I quickly found there is no way to create a Sprite anymore (A movie clips with only 1 frame). After creating my board game (no code yet just elements) which is basically movie clips inside other movie clips. All single frame.

I checked the FPS on LG TV and so it is done from 60 to 20. On a static image. After research, I found that in the advance method in MovieClip class there is a constant check to update the frame. I added a change to check if the MovieClip class total frame is equal to 1 to change it the mode of the MovieClip to a single frame. This increases performance back to 60 FPS.

All MovieClips are created in independent mode, so once the move to the next frame the add the elements in that frame to the stage. if the MovieClip is only 1 frame this is redundant.

With Adobe Animate you cannot create an old as3 Sprite.

danzen commented 3 years ago

Hi @LiorZar - just looking into this and on our local version of CreateJS I have added totalFrames check in the advance() method like so:

if (this.paused || this.totalFrames <= 1) { return; }

Is that something like what you did?

Indeed, it appears as you say where the original CreateJS runs through a series of functions including _updateTimeline(), setPosition(), _updatePosition(), _updateTargetProps() and a bunch of tests within these. When we return if it is a single frame, it does not run through those functions and tests.

I am not sure what will happen if the frame does not advance with respect to the rest of CreateJS. For example, calling scripts. I added a script on the Adobe Animate timeline for the MovieClip and it ran it once in the original CreateJS and it ran it once in the modified CreateJS so that seems good. What about clips within clips? Or possibly clips within clips that were not made with Animate and have other modes set?

If others would like to try the change it is quite simple. Go to the advance() method of a MovieClip and adjust if (this.paused) { return; } to if (this.paused || this.totalFrames <= 1) { return; }

Or here is our test CreateJS: https://zimjs.org/cdn/1.3.3/createjs_doc_single.js

I will pass it along to some of our users and see if they will test it.

Cheers - and thanks for bringing up the issue.

LiorZar commented 3 years ago

wow, thanks for replying. this is my version c.advance = function(b) { var c = a.INDEPENDENT; if (this.mode === c) { for (var d = this, e = d.framerate; (d = d.parent) && null === e;) d.mode === c && (e = d. _framerate); if (this._framerate = e, !this.paused) { var f = null !== e && -1 !== e && null !== b ? b / (1e3 / e ) + this._t : 1, g = 0 | f; for (this._t = f - g; g--;) this._updateTimeline(this. _rawPosition + 1, !1) }

        if( 1 === this.totalFrames )
            this.mode = a.SINGLE_FRAME;
    }

}

I'm building a game that runs on televisions browsers which are slower (even than mobile) and this simple change increate FPS x3 times. In the original AS3 Animate, you can inherit from Sprite, the current version you can only inherit from MovieClip. In order to give an object an instance name is must be a MovieClip :(. In AS3 a Sprite is a MovieClip with a single frame. From my POV my code change go to the advance method only once and will not run it again. which makes it fast.

One more important thing (sorry for the long email) a standard scenario when using animate is to create a single frame MovieClip with all the assets you need in layers. give each one an instance name. (e.g in the main lobby, have login screen, signup screen, etc...) and in the lobby code remove all the screens that are not in use from the display list. instead of changing them to visible = false; if the MovieClip is not defined as a SINGLE_FRAME, you cannot remove things from the display list. the _updateTimeline will return everything you removed in the next frame

Again thanks a lot for replying Best regards Lior

On Fri, Aug 7, 2020 at 5:59 PM Dan Zen notifications@github.com wrote:

Hi @LiorZar https://github.com/LiorZar - just looking into this and on our local version of CreateJS I have added totalFrames check in the advance() method like so:

if (this.paused || this.totalFrames <= 1) { return; }

Is that something like what you did?

Indeed, it appears as you say where the original CreateJS runs through a series of functions including _updateTimeline(), setPosition(), _updatePosition(), _updateTargetProps() and a bunch of tests within these. When we return if it is a single frame, it does not run through those functions and tests.

I am not sure what will happen if the frame does not advance with respect to the rest of CreateJS. For example, calling scripts. I added a script on the Adobe Animate timeline for the MovieClip and it ran it once in the original CreateJS and it ran it once in the modified CreateJS so that seems good. What about clips within clips? Or possibly clips within clips that were not made with Animate and have other modes set?

If others would like to try the change it is quite simple. Go to the advance() method of a MovieClip and adjust if (this.paused) { return; } to if (this.paused || this.totalFrames <= 1) { return; }

Or here is our test CreateJS: https://zimjs.org/cdn/1.3.3/createjs_doc_single.js

I will pass it along to some of our users and see if they will test it.

Cheers - and thanks for bringing up the issue.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/CreateJS/EaselJS/issues/1048#issuecomment-670559276, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABXRS7GTXYWDJILHIQKLRTTR7QJEPANCNFSM4NWXYC7A .

danzen commented 3 years ago

Hi @LiorZar I think you are working in the minified file and I am working in the non-minified file. Not a big deal, but just mentioning it. So... I can't tell for sure, is the only change you made to yours that you added the test if the totalFrames is 1 then make the clip SINGLE_FRAME? I adjusted my change to that as follows:

if (this.totalFrames == 1) this.mode = MovieClip.SINGLE_FRAME;

and then adjusted my earlier change from if (this.paused || this.totalFrames <= 1) { return; } to what it was before: if (this.paused) { return; }

When I run this version which can be found at https://zimjs.org/cdn/1.3.3/createjs_doc_single2.js then a simple moveclip on the stage works fine - but it does not call the frame script on the timeline of the MovieClip.

I am not sure if this is normal behaviour for a single frame clip - I would not think so. What are your thoughts? I just want to check to see if that was the only change you made before digging into it further.

danzen commented 3 years ago

In https://github.com/CreateJS/EaselJS/issues/1038 it is mentioned that there is an _off property that will stop the object from showing up in the timeline if it is set to false. Apparently visible does the same thing.

We are exploring there if toggling this directly in the addChild() and removeChild() would give the expected result and if there would be other issues if we did that.

LiorZar commented 3 years ago

it looks good, i don't understand why it will not call scripts on the first (and only) frame, at least once. it is done inside the updateTimeline? and the updateTimeline is called once. Maybe inside the updateTimeline there is another check of the movieclip mode (i see there is) this is not normal behavior it should be called at least once.

Thanks Lior

On Sat, Aug 8, 2020 at 7:37 PM Dan Zen notifications@github.com wrote:

Hi @LiorZar https://github.com/LiorZar I think you are working in the minified file and I am working in the non-minified file. Not a big deal, but just mentioning it. So... I can't tell for sure, is the only change you made to yours that you added the test if the totalFrames is 1 then make the clip SINGLE_FRAME? I adjusted my change to that as follows:

if (this.totalFrames == 1) this.mode = MovieClip.SINGLE_FRAME;

and then adjusted my earlier change from if (this.paused || this.totalFrames <= 1) { return; } to what it was before: if (this.paused) { return; }

When I run this version which can be found at https://zimjs.org/cdn/1.3.3/createjs_doc_single2.js then a simple moveclip on the stage works fine - but it does not call the frame script on the timeline of the MovieClip.

I am not sure if this is normal behaviour for a single frame clip - I would not think so. What are your thoughts? I just want to check to see if that was the only change you made before digging into it further.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/CreateJS/EaselJS/issues/1048#issuecomment-670948617, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABXRS7H6S25LJ4VSMPXOL2TR7V5NNANCNFSM4NWXYC7A .

danzen commented 3 years ago

Agreed - the script should be called at least once. Did you or could you try out the script here and confirm that it does not call the script in the timeline: https://zimjs.org/cdn/1.3.3/createjs_doc_single2.js

And while you are at it... could you test this and see if the following works for you to perform better on TV and still works with your clips: https://zimjs.org/cdn/1.3.3/createjs_doc_single.js

I am still waiting on others for the test - August is sometimes a quiet time ;-)

LiorZar commented 3 years ago

yes, but will have the answer on monday

On Sun, Aug 9, 2020 at 3:57 PM Dan Zen notifications@github.com wrote:

Agreed - the script should be called at least once. Did you or could you try out the script here and confirm that it does not call the script in the timeline: https://zimjs.org/cdn/1.3.3/createjs_doc_single2.js

And while you are at it... could you test this and see if the following works for you to perform better on TV and still works with your clips: https://zimjs.org/cdn/1.3.3/createjs_doc_single.js

I am still waiting on others for the test - August is sometimes a quiet time ;-)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/CreateJS/EaselJS/issues/1048#issuecomment-671048928, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABXRS7DG7TAWLFWDPBI6OTLR72MKVANCNFSM4NWXYC7A .

danzen commented 3 years ago

image

danzen commented 3 years ago

Have left this as the initial change. @LiorZar if you have any more news on this, please let us know. Am updating the main branch.

if (this.totalFrames <= 1) { return; }

Note - the if (this.paused) part was moved lower down by an earlier Grant adjust.

https://github.com/CreateJS/EaselJS/commit/4e6357408a78d74a15632ecb0fcfbd629e10bb0f