Animation not playing when "interval" too short

Hello friends,

Still working on my online card game, more and more players are switching from the legacy flash client to the brand new vuejs/babylonjs one, which is great, and soon - flash death sentence is for end of the year - the remaining majority will be forced to do so.

Here is my last issue, I managed to worked around it to fix million priority other ones, but since this is the remaining one :slight_smile:

I have some problems to illustrate it on a playground but if no other way then I’ll invest the required effort.

So, I have a function that is called every time one of the three other players is playing a card and I use it to animate the card like the player would take it out of his hand and throw it on the table. The information is coming asynchronously from a web socket. In the flash client, I was imposing a delay after the last player has played, to let other players see his card before he plays a new turn. Regular players were used to play ultra quickly.

What I saw with my new babylonjs client is that when players were playing too quickly, the animations of the cards were sometimes not played, and so no card would be displayed… the workaround I applied at this time was to discretely slow down the flash client :stuck_out_tongue:

So here is the function I am using, actually a new version where I really try to partition the different case as much as I can as I thought there might be some global variable left that would be overwritten by a second call of the function too close to the first one, but still not working… I invested sometimes in developing bots to play with beginners or in the middle of the night with sleepless players, so I use them for my tests… they have setInterval to make them wait before to play, and things start to getting bad from around 0.3s…

Just tell me if it would help I put somewhere the Card object too and already a big thanks!

      playCardOther: function(player, cardNumber){
         
            //remove the potential atout bubble
            if(this.bubbleAtout!=null){
                this.bubbleAtout.dispose();
                this.bubbleAtout=null;
            }

            if(this.annonceShowed)
                this.clearAnnonce();

            switch(player){
                case 2:{    let _this = this;

                            let card = new Card(this,cardNumber,"cardTest",this.scene, this.cardWidth, this.cardHeight, this.versoMat);
                            this.shadowGenerator.addShadowCaster(card.mesh);

                            let maxFrame=30;
                            this.cardP2=card;

                            card.mesh.rotation.x= Math.PI/5;
                            card.mesh.rotation.y= -Math.PI/2;
                            card.mesh.rotation.z= -Math.PI/2;

                            card.mesh.position.x=2.15;
                            card.mesh.position.y=4.35;
                            card.mesh.position.z=1;

                            let moveOnTable = new BABYLON.Animation(
                                "moveOnTable",
                                "position",
                                90,
                                BABYLON.Animation.ANIMATIONTYPE_VECTOR3,
                                BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
                            );

                            let rotation = new BABYLON.Animation(
                                "rotation",
                                "rotation",
                                90,
                                BABYLON.Animation.ANIMATIONTYPE_VECTOR3,
                                BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
                            );

                            let easingFunction = new BABYLON.CubicEase();

                            // For each easing function, you can choose between EASEIN (default), EASEOUT, EASEINOUT
                            easingFunction.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEIN);
                            moveOnTable.setEasingFunction(easingFunction);
                            rotation.setEasingFunction(easingFunction);

                            let keysMove =[];
                            keysMove.push({
                                frame: 0,
                                value: new BABYLON.Vector3(card.mesh.position.x, card.mesh.position.y, card.mesh.position.z)
                            });
                            keysMove.push({
                                frame: maxFrame,
                                value:new BABYLON.Vector3(1.6, 0.11, 1)
                            });
                            moveOnTable.setKeys(keysMove);

                            let keysRot=[];
                            keysRot.push({
                                frame: 0,
                                value: new BABYLON.Vector3(card.mesh.rotation.x, card.mesh.rotation.y, card.mesh.rotation.z)
                            });
                            keysRot.push({
                                frame: maxFrame,
                                value: new BABYLON.Vector3(Math.PI / 2, card.mesh.rotation.y, 0)
                            });
                            rotation.setKeys(keysRot);

                            this.scene.beginDirectAnimation(card.mesh, [moveOnTable, rotation], 0, maxFrame, false, 1.0,
                                function () {
                                    if(_this.nextDonne){
                                        setTimeout(_this.pointArdoise, 1000, _this.nextDonne);
                                        _this.nextDonne=false;
                                    }
                                    console.log("P2,_this.showingAnnonce:"+_this.showingAnnonce+", _this.nextDonne:"+_this.nextDonne);
                                    switch(_this.showingAnnonce){
                                        case 1: _this.chibre.showAnnonce(true);
                                            _this.showingAnnonce =0;
                                            break;
                                        case 2: _this.chibre.showAnnonce(false);
                                            _this.showingAnnonce =0;
                                            break;
                                    }
                                    if(card.value%9<4){
                                        _this.updateWritingPlane(_this.writingPlaneP2,card.value%9+6);
                                        _this.writingPlaneP2.isVisible=true;
                                    }
                                }
                            );
                            break;
                        }

                case 3:{    let _this = this;

                            let card = new Card(this,cardNumber,"cardTest",this.scene, this.cardWidth, this.cardHeight, this.versoMat);
                            this.shadowGenerator.addShadowCaster(card.mesh);

                            let maxFrame=30;
                            this.cardP3=card;

                            card.mesh.rotation.x= Math.PI/5;
                            card.mesh.rotation.y= Math.PI;
                            card.mesh.rotation.z= -Math.PI/2;

                            card.mesh.position.x=0.2;
                            card.mesh.position.y=4.35;
                            card.mesh.position.z=3.15;

                            let moveOnTable = new BABYLON.Animation(
                                "moveOnTable",
                                "position",
                                90,
                                BABYLON.Animation.ANIMATIONTYPE_VECTOR3,
                                BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
                            );

                            let rotation = new BABYLON.Animation(
                                "rotation",
                                "rotation",
                                90,
                                BABYLON.Animation.ANIMATIONTYPE_VECTOR3,
                                BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
                            );

                            let easingFunction = new BABYLON.CubicEase();

                            // For each easing function, you can choose between EASEIN (default), EASEOUT, EASEINOUT
                            easingFunction.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEIN);
                            moveOnTable.setEasingFunction(easingFunction);
                            rotation.setEasingFunction(easingFunction);

                            let keysMove =[];
                            keysMove.push({
                                frame: 0,
                                value: new BABYLON.Vector3(card.mesh.position.x, card.mesh.position.y, card.mesh.position.z)
                            });
                            keysMove.push({
                                frame: maxFrame,
                                value:new BABYLON.Vector3(0, 0.11, 2.6)
                            });
                            moveOnTable.setKeys(keysMove);

                            let keysRot=[];
                            keysRot.push({
                                frame: 0,
                                value: new BABYLON.Vector3(card.mesh.rotation.x, card.mesh.rotation.y, card.mesh.rotation.z)
                            });
                            keysRot.push({
                                frame: maxFrame,
                                value: new BABYLON.Vector3(Math.PI / 2, card.mesh.rotation.y, 0)
                            });
                            rotation.setKeys(keysRot);

                            this.scene.beginDirectAnimation(card.mesh, [moveOnTable, rotation], 0, maxFrame, false, 1.0,
                                function () {
                                    if(_this.nextDonne){
                                        setTimeout(_this.pointArdoise, 1000, _this.nextDonne);
                                        _this.nextDonne=false;
                                    }
                                    console.log("P2,_this.showingAnnonce:"+_this.showingAnnonce+", _this.nextDonne:"+_this.nextDonne);
                                    switch(_this.showingAnnonce){
                                        case 1: _this.chibre.showAnnonce(true);
                                            _this.showingAnnonce =0;
                                            break;
                                        case 2: _this.chibre.showAnnonce(false);
                                            _this.showingAnnonce =0;
                                            break;
                                    }
                                    if(card.value%9<4){
                                        _this.updateWritingPlane(_this.writingPlaneP3,card.value%9+6);
                                        _this.writingPlaneP3.isVisible=true;
                                    }
                                }
                            );
                            break;
                        }

                case 4: {   let _this = this;

                            let card = new Card(this,cardNumber,"cardTest",this.scene, this.cardWidth, this.cardHeight, this.versoMat);
                            this.shadowGenerator.addShadowCaster(card.mesh);

                            let maxFrame=30;
                            this.cardP4=card;

                            card.mesh.rotation.x= Math.PI/5;
                            card.mesh.rotation.y= Math.PI/2;
                            card.mesh.rotation.z= -Math.PI/2;

                            card.mesh.position.x=-2.15;
                            card.mesh.position.y=4.35;
                            card.mesh.position.z=1;

                            let moveOnTable = new BABYLON.Animation(
                                "moveOnTable",
                                "position",
                                90,
                                BABYLON.Animation.ANIMATIONTYPE_VECTOR3,
                                BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
                            );

                            let rotation = new BABYLON.Animation(
                                "rotation",
                                "rotation",
                                90,
                                BABYLON.Animation.ANIMATIONTYPE_VECTOR3,
                                BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE
                            );

                            let easingFunction = new BABYLON.CubicEase();

                            // For each easing function, you can choose between EASEIN (default), EASEOUT, EASEINOUT
                            easingFunction.setEasingMode(BABYLON.EasingFunction.EASINGMODE_EASEIN);
                            moveOnTable.setEasingFunction(easingFunction);
                            rotation.setEasingFunction(easingFunction);

                            let keysMove =[];
                            keysMove.push({
                                frame: 0,
                                value: new BABYLON.Vector3(card.mesh.position.x, card.mesh.position.y, card.mesh.position.z)
                            });
                            keysMove.push({
                                frame: maxFrame,
                                value:new BABYLON.Vector3(-1.6, 0.11, 1)
                            });
                            moveOnTable.setKeys(keysMove);

                            let keysRot=[];
                            keysRot.push({
                                frame: 0,
                                value: new BABYLON.Vector3(card.mesh.rotation.x, card.mesh.rotation.y, card.mesh.rotation.z)
                            });
                            keysRot.push({
                                frame: maxFrame,
                                value: new BABYLON.Vector3(Math.PI / 2, card.mesh.rotation.y, 0)
                            });
                            rotation.setKeys(keysRot);

                            this.scene.beginDirectAnimation(card.mesh, [moveOnTable, rotation], 0, maxFrame, false, 1.0,
                                function () {
                                    if(_this.nextDonne){
                                        setTimeout(_this.pointArdoise, 1000, _this.nextDonne);
                                        _this.nextDonne=false;
                                    }
                                    console.log("P2,_this.showingAnnonce:"+_this.showingAnnonce+", _this.nextDonne:"+_this.nextDonne);
                                    switch(_this.showingAnnonce){
                                        case 1: _this.chibre.showAnnonce(true);
                                                _this.showingAnnonce =0;
                                                break;
                                        case 2: _this.chibre.showAnnonce(false);
                                                _this.showingAnnonce =0;
                                                break;
                                    }
                                    if(card.value%9<4){
                                        _this.updateWritingPlane(_this.writingPlaneP4,card.value%9+6);
                                        _this.writingPlaneP4.isVisible=true;
                                    }
                                }
                            );
                            break;
                        }

            }
        }

A playground would be amazing and I bet @msDestiny14 would be glad to help :slight_smile:

Yes I’d love a playground of this and I’d be happy to take a look shortly.

So… here is the playground https://www.babylonjs-playground.com/#J0ZJDX#10 but useless actually as I cannot reproduce my issue :slight_smile:

I’ll have to look elsewhere I think but a little question before, this playground is not fully representing the game where a lot of high quality assets are preloaded with several of them used in the same time to texture game props… could the issue be linked to a lack of browser resources during a peak moment ?

Okay, we can close this one, my bad :slight_smile:

@Fenryll I had a similar issue recently but on investigation my timings were much smaller and fell under the threshold supported by HTML5 complaint browsers i.e. 4ms. In my use case I switched to a deltaTime calculation, which is what I should have been using all along.

But looking at your code I don’t think this is your issue :slight_smile:

thanks :slight_smile:
Doing the playground made me realize I had to go look somewhere else, and finally, it is the animation that is cleaning the table, simulating the winner taking the cards, that is disposing the card meshes at the end that could conflict with next turn player cards, when really played quick, and dispose them too…

3 Likes