19 Replies Latest reply on Jun 14, 2018 10:40 AM by ClayUUID

    Accessing movieClip.children array Animate CC Canvas

    Viki-lynn Level 1

      Hello,

       

      I’m trying to make a reusable widget for our design team, and instead of the user having to put this.movieClipInstances in a array inside my logic, I’d like to sort through the children of my container movieClip using Easlejs myContainer.children and storing them dynamically. If I console.log myContainer.children, I get an array with all the children in the movie clip - Great! But if I try to get the length or try to get an index of container.children[0] it returns undefined.  I am so confused as to why this shows up but I’m unable to access it?

       

      On the stage I have a movieClip instance myContainer.

       

      In myContainer I have three movie clip instances test_01, test_02, test_03.

      (Inside my container movieClip)

      var c = this;

      var arrChildren = c.children;

       

      console.log(arrChildren); //returns array

      console.log(arrChildren.length); //returns 0

      console.log(arrChildren[0]); //returns undefined

       

      If I console.log arrChildren, I get:

       

      Array(3)

      0: lib.Symbol1{objects properties}

      1: lib.Symbol1{objects properties}

      2: lib.Symbol1{objects properties}

      length:3

      __proto__:Array(0)

       

      Does anyone know why I can’t loop through this array or access even it’s length?

       

      Any help from the community would be awesome. Thank you in advance!

        • 1. Re: Accessing movieClip.children array Animate CC Canvas
          JoãoCésar Adobe Community Professional & MVP

          Hi.

           

          I changed the size of your text because it was too small.

           

          About your question, it seems that in HTML5 (Canvas) documents, Movie Clips on stage are always accessible, you can console.log them, and so on, but their internal contents/timeline no. Not always.

           

          Run a test:

           

          Extend the layer with the content until the 2nd frame and also put the code in the second frame and see if you get the result you're expecting.

          • 2. Re: Accessing movieClip.children array Animate CC Canvas
            Viki-lynn Level 1

            You are awesome, that worked. I've been beating my head on my desk for a day so I thank you for your response 

             

            I changed nothing but extended the script to frame 2 (and added a stop of course) and I am able to access the children array as expected.

             

            Many thanks!

            • 3. Re: Accessing movieClip.children array Animate CC Canvas
              JoãoCésar Adobe Community Professional & MVP

              This is wonderful!

               

              You're welcome!

              • 4. Re: Accessing movieClip.children array Animate CC Canvas
                ClayUUID Adobe Community Professional

                If you want to keep your widget more code-driven, you don't have to add another timeline frame. To wait the duration of one frame using code, do this:

                 

                createjs.Ticker.on("tick", myInitFunction, this, true);

                function myInitFunction() {

                    // your initialization code...

                }

                 

                However, you don't even really need to wait an entire frame to make things work right. The problem you were experiencing happens because of execution order. CreateJS calls timeline code first, then child initialization code. If you could somehow shuffle your code to execute after all the child initialization, but before the next frame begins, it would work fine. And huzzah, you can!

                 

                setTimeout(myInitFunction.bind(this), 0);

                function myInitFunction() {

                    // your initialization code...

                }

                 

                Using setTimeout() with a delay of 0 basically yields execution to whatever else the browser has to do (in this case running the rest of the setup code and rendering the current frame), and schedules the function you give it to execute as soon as possible.

                javascript - Why is setTimeout(fn, 0) sometimes useful? - Stack Overflow

                javascript - What is setTimeout doing when set to 0 milliseconds? - Stack Overflow

                 

                If you stick console.log(this.currentFrame); in your init code, you'll see that the first variant executes on frame 1, but the second variant executes while still on frame 0. So it's probably the better option for getting your widget fully operational as quickly as possible.

                • 5. Re: Accessing movieClip.children array Animate CC Canvas
                  ClayUUID Adobe Community Professional

                  I'd just like to add some more information to the above post. While the setTimeout approach does work for safely executing initialization code in the same frame, it has the disadvantage that it executes after rendering. So any visual properties you've changed won't show up until the next stage update. However, it turns out the CreateJS API provides an even better approach. You can do this instead:

                   

                  stage.on("drawstart", myInitFunction, this, true);

                   

                  Every time the stage is updated, it fires two events-- "drawstart" before it starts drawing, and "drawend" when it's done. Hooking an event listener to "drawstart" allows executing setup code with fully initialized clips, but before anything is actually drawn for the current frame/tick. For example you can do this.my.deeply.nested.clip.stop(); in the event handler and it will work, without having to wait a frame.

                   

                  The reason to use on instead of addEventListener is because of the extra functionality on provides. The third argument specifies the scope that the event handler executes in (so you don't have to mess with bind), and the fourth argument specifies that the listener only executes once.

                  2 people found this helpful
                  • 6. Re: Accessing movieClip.children array Animate CC Canvas
                    Colin Holgate MVP & Adobe Community Professional

                    That's useful to know, thanks. Do you know where a tick listener falls in time? Like, does a tick listener function extend the current frame duration, in the way that exitframe would do in AS3 or Lingo? Even if tick is handled before draw starts, is there any drawback (pardon the pun) to using the drawstart approach instead of a tick listener?

                     

                    By the way, one worry is that drawstart would happen when everything is ready to draw. If you then change the state of something, will the new state be drawn, or the state before the change?

                     

                    I'll be trying it out anyway!

                    • 7. Re: Accessing movieClip.children array Animate CC Canvas
                      Colin Holgate MVP & Adobe Community Professional

                      Forget most of what I just said. It looks like the drawstart approach is a one time thing, not every frame. Maybe it's also when you change frames? But staying on one frame and using drawstart instead of tick, stops anything you were animating with code.

                      • 8. Re: Accessing movieClip.children array Animate CC Canvas
                        ClayUUID Adobe Community Professional

                        No, drawstart executes once per tick, regardless of whether the playhead is advancing. This will rapidly fill up the console:

                        this.stop();

                        stage.addEventListener("drawstart", function(){console.log("hello")});

                         

                        Regarding listenening for a tick event, as I noted in my older post, that delays code execution until the next frame (or frame render).

                        • 9. Re: Accessing movieClip.children array Animate CC Canvas
                          Colin Holgate MVP & Adobe Community Professional

                          Could I be using the 'this' or 'true' wrongly? Here you can see my normal line and the replacement line, and with the normal way I can flick some movieclips and over time they come to a halt. With drawstart they stop moving as soon as I release the mouse button:

                           

                          //stage.on("drawstart", inertia, this, true);
                          createjs.Ticker.addEventListener("tick", inertia);
                          • 10. Re: Accessing movieClip.children array Animate CC Canvas
                            ClayUUID Adobe Community Professional

                            Remember, passing true as the fourth argument says to only execute the listener once. That makes it useful for initialization code.

                             

                            The distinction between listening for tick vs drawstart appears to be... subtle. If you stick this in the first frame of a multi-frame timeline:

                            createjs.Ticker.on("tick", function(){console.log("Tick:"+this.currentFrame)}, this);

                            stage.on("drawstart", function(){console.log("Drawstart:"+this.currentFrame)}, this);

                             

                            You get:

                            Drawstart:0

                            Drawstart:1

                            Tick:1

                            Drawstart:2

                            Tick:2

                            Drawstart:3

                            Tick:3

                            etc...

                             

                            So drawstart appears to be guaranteed to fire within the same frame the listener is added.

                            • 11. Re: Accessing movieClip.children array Animate CC Canvas
                              JoãoCésar Adobe Community Professional & MVP

                              All of this information is really useful. I've unchecked my answer as the correct and marked Clay's.

                               

                              And I think it would be really useful if someone from the CreateJS team could stop by once in awhile here in the forums to give us insight about the application of these libraries inside of Animate CC.

                               

                              I know there is the official documentation but in my experience and seeing the doubts from the users that show up here, I feel that there are many details that could be clarified.

                               

                              Or the Animate Team could provide a online doc for this integration.

                              • 12. Re: Accessing movieClip.children array Animate CC Canvas
                                Colin Holgate MVP & Adobe Community Professional

                                I found this page:

                                 

                                https://createjs.com/docs/easeljs/classes/Stage.html#event_drawstart

                                 

                                and now realize that for my application, drawend is more useful. drawstart will solve the problem of talking to things and knowing that they are initialize, and what you do will show up even in the first redraw. But I was interested in something equivalent to enterframe.

                                 

                                The good thing about enterframe is that you are doing your time consuming things after the frame is drawn, and you have 1/framerate of a second of time to finish doing those things. exitframe will always extend the duration of the current frame, to be 1/framerate of a second, plus how long it takes for your code to run. Similarly, timerevents could happen at any time, and will very often extend the length of the current frame.

                                 

                                So, if I'm right (and I'll try to test it), using drawend to trigger when your time consuming things will happen could improve performance.

                                1 person found this helpful
                                • 13. Re: Accessing movieClip.children array Animate CC Canvas
                                  ClayUUID Adobe Community Professional

                                  I suspect using setTimeout with a delay of 0 would do what you want, since that will defer execution of your callback until CreateJS is done and waiting for the next tick.

                                   

                                  Hmm... although, scheduling that to execute on every frame could be tricky. Drawend probably would be easier.

                                  • 14. Re: Accessing movieClip.children array Animate CC Canvas
                                    Colin Holgate MVP & Adobe Community Professional

                                    I tried it anyway. All sorts of test of the other three ways of working ended up being much the same time to do a lot of complex tasks. But then I changed to looking at how far a complicated animation had advanced in the same time. With tick, drawstart, and drawend, the animation had advanced about 12 frames during the test. With setTimeout it advanced 50 frames.

                                     

                                    My conclusion is that behind the scenes CreateJS is doing a lot to keep regular timing, no matter what technique you're doing, and setTimeout is a way to defeat that.

                                    • 15. Re: Accessing movieClip.children array Animate CC Canvas
                                      albertd9194959 Level 3

                                      Interesting post !

                                      Colin, Clay, Joao, have you looked deeply into the animate JS final output file?

                                       

                                      From a glance, the load order/queuing of code within the final animate may be influencing this ?

                                       

                                      The lib is processes from the get go, so you can at any time call anything from the library directly.

                                      Then, the rest of the content, as animate uses a timeline approach, is loaded as separate functions as dictated by your placement in the timeline on your stage.

                                       

                                      Adding to that, if you have 1 frame with code, and a movie clip, it looks like the timeline functions are processed first, then the stage items. Layer order with regards to the code seems to be ignored, its always loaded first, even if the code layer is at the bottom.

                                       

                                      Which falls in line with the recommend" placing code on the second frame, not the first" to ensure all the visual elements have been loaded that many people here have said ?

                                       

                                      But, not sure if this is the case, haven't had time to look deeply into it.

                                       

                                      Regards,

                                      • 16. Re: Accessing movieClip.children array Animate CC Canvas
                                        Colin Holgate MVP & Adobe Community Professional

                                        My usual approach is to have the symbols I want to talk to be on a given frame, and then have the code that talks to them be on the next frame. Then I'm sure they are around. Clay's drawstart idea is a away to do that on the same frame.

                                         

                                        My other way of working is to put the code needed to set up a symbol in the first frame of that symbol. This is sometimes the only realistic way to do some things. For example, I have animations where the animated character needs to be customized on the fly, based on selections the user had made previously. Like, they had chosen a certain head type, different shirts, hat, eyewear, and so on. In each of those I might have something like (this would be the hat symbol):

                                         

                                        this.gotoAndStop(window.hatnumber);

                                         

                                        Previously window.hatnumber has been set to be the variation of the hat that the user wanted. In the hat symbol would be as many frames as there are hats, and when the user chose a hat it would have been (for JavaScript), 0-n (n being one less than the number of hats).

                                         

                                        The good thing about this approach is both that the timeline of the symbol does exist at the time that I this.gotoAndStop(window.hatnumber);, but more importantly it doesn't matter how deep in the hierarchy the symbol is. If I did the same thing from the main timeline I might have something like:

                                         

                                        this.character1.head.hat.gotoAndStop(this.hatnumber);

                                         

                                        That's fine if the character is at the main timeline, but what if I put it into an animated scene, that is inside another holder symbol. The depth to the hat could get to be:

                                         

                                        this.scene.room1.character1.head.hat.gotoAndStop(this.hatnumber);

                                         

                                        It's not worth the hassle!

                                        1 person found this helpful
                                        • 17. Re: Accessing movieClip.children array Animate CC Canvas
                                          Scott Bower Level 1

                                          I just wanted to complement you for mentioning Lingo . And that this is one of the best flash posts in years. I am coming back to the IDE after years of frustration with React and everything else post 2010. This is gold.

                                          • 18. Re: Accessing movieClip.children array Animate CC Canvas
                                            Colin Holgate MVP & Adobe Community Professional

                                            Before I was well known for working in Flash Pro, I was famous for working in Director.. Quite a few Director engineers went on to work on Flash Pro, which is why, for example, Flash 8 gained some of the imaging code that was already in Director. Another thing that was added to ActionScript was exitframe.

                                             

                                            For a long time Director didn't have enterframe, and so it did suffer from the problem of complex code causing the frame to last longer than it should. I guess exitframe is useful for jumping to another part of the timeline, knowing that the current frame has been shown for long enough. But for getting lengthy code to run, enterfame is good in both tools, because it runs while the current frame is being displayed.

                                            • 19. Re: Accessing movieClip.children array Animate CC Canvas
                                              ClayUUID Adobe Community Professional

                                              https://forums.adobe.com/people/Colin+Holgate  wrote

                                               

                                              I tried it anyway. All sorts of test of the other three ways of working ended up being much the same time to do a lot of complex tasks. But then I changed to looking at how far a complicated animation had advanced in the same time. With tick, drawstart, and drawend, the animation had advanced about 12 frames during the test. With setTimeout it advanced 50 frames.

                                              If I'm understanding the experiment you're describing correctly, this result makes perfect sense. Tick, drawstart, and drawend events will never fire any faster than the CreateJS frame rate. setTimeout with an interval of 0, on the other hand, will execute its callback as frequently as possible, continuously pushing itself onto the browser event queue. Probably not a great idea for a continuous animation, since this could easily blow up CPU utilization and yield an uneven frame rate.