• Runtimes
  • Spine player animation loop

warmanw

If you don't set any animation at the beginning, the player won't play anything.
Set a default animation, or invoke player.play() in the success callback.

Related Discussions
...

Thanks for your help Davide you already saved my day, however I want the player to start without playing anything and only when I press a key it should play an animation once. but pressing key wont respond unless I click on player which starts animation which I dotn want.

if (!player) return; This isn't doing anything. You set the player before even adding the listener, so it's always set.

As Davide said, you aren't setting an animation in success, so the player isn't playing. Call play(). Also don't indent your code inside a script like a psychopath.

<script>
var player = new spine.SpinePlayer("player-container", {
	jsonUrl: "gifts.json",
	atlasUrl: "gifts.atlas",
	showControls: true,
	skin: "bluff",
	backgroundColor: "000000",
	defaultMix: 0,
	premultipliedAlpha: true,
	success: function (player) {
		player.setViewport("base");
		player.play();
	},
});

document.addEventListener("keydown", function (event) {
	let currentAnimation = player.animationState.getCurrent(0)?.animation?.name;
	if (currentAnimation !== "base") {
		 player.animationState.setAnimation(0, "base", false);
	} else {
		 let randomIndex = Math.floor(Math.random() * 6) + 1;
		 player.animationState.setAnimation(randomIndex, "meta_" + randomIndex, false);
	}
});
</script>

If I call play on success, the player continuously loops an animation. What I want is for the player to remain in a ready state without playing any animation, so when I press a key, it plays the corresponding animation

Also why does it play animation in a loop none of my setAnimation() call animation in loop

Nate

The problem is that if player.play() is called when you don't pass an animation in the config, the player will select the first animation stored in the skeleton data and play it. We should probably change that.

I think we can trick the current behavior though. Do not call player.play() on the success callback, try to call it inside the keydown callback like this:

document.addEventListener("keydown", function (event) {
	if (player.paused) {
		player.play();
		player.skeleton.setToSetupPose();
	}
	let currentAnimation = player.animationState.getCurrent(0)?.animation?.name;
	if (currentAnimation !== "base") {
		 player.animationState.setAnimation(0, "base", false);
	} else {
		 let randomIndex = Math.floor(Math.random() * 6) + 1;
		 player.animationState.setAnimation(randomIndex, "meta_" + randomIndex, false);
	}
});

    Still I wonder why setViewport sets the animation.

    It is a bit odd to want to "play" when there is no animation. To play means the animation is applied and updateWorldTransform is done. When there is no animation, it's not necessary. Maybe we should just check if there are any animations and if there are, we apply and updateWorldTransform. Then the concept of play/pause would exist only for the player to stop animations. It would be "playing" by default.

    Davide That works, @Davide! Just a small thing—right now, the keydown event plays an animation on its track as expected, but play() plays the first animation in a loop.

      warmanw

      I've looked now into the logic of your page.

      As far as I understood, the logic you want is to play:

      • for the first key pressed, the base animation. This one will be execute only at the first key press.
      • for the next key presses, a random meta_N animation

      The problem now is that the base animation is the first animation stored in the skeleton data, so the play() function actually selects it as the animation for track 0.
      Then, the if checks if the animation on track 0 is base and with the current code that condition is always false. So we never call the player.animationState.setAnimation(0, "base", false);.

      So, just move the code introduced yesterday into the if like this:

      document.addEventListener("keydown", function (event) {
      	let currentAnimation = player.animationState.getCurrent(0)?.animation?.name;
      	if (currentAnimation !== "base") {
      		if (player.paused) {
      			player.play();
      			player.skeleton.setToSetupPose();
      		}
      		player.animationState.setAnimation(0, "base", false);
      	} else {
      		let randomIndex = Math.floor(Math.random() * 6) + 1;
      		player.animationState.setAnimation(randomIndex, "meta_" + randomIndex, false);
      	}
      });

      Thanks! that worked, its not looping now.

      Please also clarify this question: why at the first when animation is playing we see the content slides. the reason is viewport is not set? or mixing with setup pose?

        warmanw

        Yes, you should set your desired viewport on success.
        You could also set viewport: { transitionTime: 0 } as player settings.