question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Rats! WebGL hit a snag when creating (and destroying) many AnimatedSprites during app lifetime

See original GitHub issue

I am creating new AnimatedSprites on pointerdown event (and deleting them on next pointerdown event) over the course if application lifetime. At some point around 20 clicks, the app crashes with an error: Rats! webGl crashed. At that point no error is displayed in console. Crash happens on a mobile device, and would probably also happen on desktop, if someone perform plenty of clicks. You can anticipate the crash. Few clicks before the final crash, animations become really stuttering.

Code that is repeatedly used is below. I also include live example at http://forwardingsolutions.club/. Can someone please point out what am I doing wrong?

 function setupNextSpritesAnimation(){
        setupNextAnimation();
        console.log("next color: "+nextColor);
        switch (nextColor) {
            case "red":
                var newLoader = new PIXI.loaders.Loader()
                .add('nextSprite', '/assets/sprite/red.png.png')
                .load(function (loader, resources){
                    var interval = setInterval(function(){
                        if (!isAnimating){
                            clearInterval(interval);
                            createNewAnimatedSprite(resources,newLoader);
                        }
                    },50);

                });

                break;
            case "aqua":
                var newLoader = new PIXI.loaders.Loader()
                .add('nextSprite', '/assets/sprite/aqua.png.png')
                .load(function (loader, resources){
                    var interval = setInterval(function(){
                        if (!isAnimating){
                            clearInterval(interval);
                            createNewAnimatedSprite(resources,newLoader);
                        }
                    },50);
                });
                break;            
            case "green":
                var newLoader = new PIXI.loaders.Loader()
                .add('nextSprite', '/assets/sprite/blue.png.png')
                .load(function (loader, resources){
                    var interval = setInterval(function(){
                        if (!isAnimating){
                            clearInterval(interval);
                            createNewAnimatedSprite(resources,newLoader);
                        }
                    },50);
                });
                break;            
            case "purple":
                var newLoader = new PIXI.loaders.Loader()
                .add('nextSprite', '/assets/sprite/purple.png.png')
                .load(function (loader, resources){
                    var interval = setInterval(function(){
                        if (!isAnimating){
                            clearInterval(interval);
                            createNewAnimatedSprite(resources,newLoader);
                        }
                    },50);
                });
                break;   
                         }
    }
 

    function createNewAnimatedSprite(resources,newLoader){
        var tmpSprite = new PIXI.extras.AnimatedSprite(setupFrames(resources["nextSprite"].texture.baseTexture));
        app.stage.addChild(tmpSprite);
        spritesArray.push(tmpSprite);
        setupNextSprites(tmpSprite);

        app.renderer.plugins.prepare.upload(tmpSprite, function(){
            console.log("updoaded now");
            canRunNext = true;
            newLoader.reset();
            //console.log("kill");
            delete tmpSprite;

        });
    }
 

    function setupNextSprites(nextSprite){
        nextSprite.x = app.renderer.width / 2;
        nextSprite.y = app.renderer.height / 2;
        nextSprite.anchor.set(0.5);
        nextSprite.loop = false;
        nextSprite.animationSpeed = 0.5; 
        nextSprite.visible = false;
        nextSprite.onComplete = function (){
            console.log("animation finished");
            isAnimating = false;
        };
    }


    function setupNextAnimation(){
        var randomNumber = getRandomInt(0,3);
        switch (randomNumber) {
            case 0:
                nextColor = "red";
                break;
            case 1:
                nextColor = "aqua";
                break;            
            case 2:
                nextColor = "green";
                break;            
            case 3:
                nextColor = "purple";
                break;   
                            }  
    }
 

 

    app.stage.on("pointerdown", function () {
        if (firstRun && !isAnimating) {
            firstRun = false;
            isAnimating = true;
            currentSprite.gotoAndPlay(0);
        }else{ 
            if (canRunNext && !isAnimating){
                isAnimating=true;

                if (currentSprite.visible){
                    currentSprite.visible = false;
                    currentSprite.destroy(true);
                }
                spritesArray[spritesArray.length-1].visible = true;
                spritesArray[spritesArray.length-1].gotoAndPlay(0);

                app.stage.removeChild(spritesArray[spritesArray.length-2]);
               spritesArray[spritesArray.length-2].destroy({ children:true, texture:true, baseTexture:true});

                canRunNext = false;
                setupNextSpritesAnimation();

            }
        }
    });


function setupSpritesAnimation(){
//created currentSprite just once at the start of app
spritesArray.push(currentSprite);
}

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:10 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
englercjcommented, Jun 9, 2017

You need to call loader.reset() when you are done with it. The loader is made to have resources added, load them, and be done. If you call reset it goes back to step one (clearing the .resources property of the things previously loaded). This is how you can resuse a single loader instance for all loading done in your app, just call .reset() when you plan to use it again. The only reason you would ever need to create multiple instances of the loader is if you want different middleware on different loaders. Otherwise just use one and .reset().

This is similar to how you call destroy on sprites when you are done with them.

0reactions
lock[bot]commented, Jul 15, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Rats! WebGL hit a snag when creating (and destroying) many ...
I am creating new AnimatedSprites on pointerdown event (and deleting them on next pointerdown event) over the course if application lifetime ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found