• RuntimesBugs
  • Can't change skin in @pixijs/spine-pixi if `eventMode` is set

I have this function that sets random skin for object. it works on click on button (button is HTML element).

const setSkin = () => {
    const skin = new Skin('custom')
    skin.addSkin(skeletonData.findSkin('skin-base')!)

    groupedSkins.forEach((skinGroup: any) => {
      const skinName = skinGroup[getRandomInt(0, (skinGroup.length - 1))]
      skin.addSkin(skeletonData.findSkin(skinName)!)
    })

    spineObject!.skeleton.setSkin(skin)
    spineObject!.skeleton.setSlotsToSetupPose()
  }

Everything works ok. The next thing i want to do is to add interactivity to spineObject itself, make it animate on click for example.
Here is what i do:

spineObject.eventMode = 'dynamic'
spineObject.on('pointerdown', () => {
    spineObject.state.setAnimation(1, 'blink', false)
    spineObject.state.setAnimation(2, 'aware', false)
    spineObject.state.addEmptyAnimation(2, 0.2, 0)
  })

And it works too. But when i click on the button that calls setSkin i have an error in console:

Uncaught TypeError: Cannot read properties of undefined (reading 'batcher')
    at SpinePipe.updateRenderable (@pixi_spine-pixi.js?t=1721202700303&v=cef1a748:11956:34)
    at RenderGroup.updateRenderable (chunk-HF2HE6F3.js?v=cef1a748:3750:61)
    at updateRenderables (chunk-3STGYXCO.js?v=cef1a748:996:19)
    at RenderGroupSystem.render (chunk-3STGYXCO.js?v=cef1a748:960:9)
    at SystemRunner.emit (chunk-3STGYXCO.js?v=cef1a748:187:21)
    at WebGLRenderer.render (chunk-3STGYXCO.js?v=cef1a748:342:25)
    at _Application2.render (chunk-VHV5RU3V.js?v=cef1a748:6017:19)
    at TickerListener.emit (chunk-OWQFXLRL.js?v=cef1a748:233:18)
    at _Ticker2.update (chunk-OWQFXLRL.js?v=cef1a748:492:29)
    at _tick (chunk-OWQFXLRL.js?v=cef1a748:301:14)

It only happens when i add eventMode to spineObject. What am i doing wrong?

Runtime information

@pixi/spine-pixi: 2.0.2 (it's a port for Pixi v8 by Pixi team, it uses "@esotericsoftware/spine-core": "~4.2.45" under the hood).
pixi.js: 8.2.5

Related Discussions
...

The issue you're encountering seems to be related to the interaction between the eventMode property and the setSkin function in the @pixi/spine-pixi runtime. The error message indicates that there is a problem with the batcher property, which is likely related to the rendering pipeline of the spine object when the skin is changed.

Here are a few steps you can take to troubleshoot and potentially resolve the issue:

  1. Ensure Proper Initialization: Make sure that the spine object and its skeleton are properly initialized before setting the skin or adding interactivity.

  2. Check for Null References: Before setting the skin, ensure that all necessary properties and objects are not null or undefined. This includes the spineObject, skeletonData, and any skins you are trying to add.

  3. Update Renderable State: After setting the skin, you might need to update the renderable state of the spine object to ensure that it is correctly rendered with the new skin. This can be done by calling the update method on the spine object or forcing a re-render.

  4. Event Mode and Skin Change: Since the error occurs when eventMode is set, try temporarily disabling the event mode before changing the skin and re-enabling it afterward. This can help isolate whether the issue is directly related to the event mode.

Here is an updated version of your setSkin function with additional checks and steps:

const setSkin = () => {
  if (!spineObject || !skeletonData) {
    console.error('Spine object or skeleton data is not initialized.');
    return;
  }

  // Temporarily disable event mode
  const previousEventMode = spineObject.eventMode;
  spineObject.eventMode = 'none';

  const skin = new Skin('custom');
  const baseSkin = skeletonData.findSkin('skin-base');
  if (baseSkin) {
    skin.addSkin(baseSkin);
  } else {
    console.error('Base skin not found.');
  }

  groupedSkins.forEach((skinGroup) => {
    const skinName = skinGroup[getRandomInt(0, skinGroup.length - 1)];
    const foundSkin = skeletonData.findSkin(skinName);
    if (foundSkin) {
      skin.addSkin(foundSkin);
    } else {
      console.error(`Skin ${skinName} not found.`);
    }
  });

  spineObject.skeleton.setSkin(skin);
  spineObject.skeleton.setSlotsToSetupPose();

  // Re-enable event mode
  spineObject.eventMode = previousEventMode;

  // Force update renderable state
  spineObject.update(0);
};

Additionally, ensure that your event listener setup is correct:

spineObject.eventMode = 'dynamic';
spineObject.on('pointerdown', () => {
  spineObject.state.setAnimation(1, 'blink', false);
  spineObject.state.setAnimation(2, 'aware', false);
  spineObject.state.addEmptyAnimation(2, 0.2, 0);
});

If the issue persists, it might be worth checking if there are any known issues or updates related to the @pixi/spine-pixi runtime and the specific version of Pixi.js you are using. You can also consider reaching out to the maintainers of the @pixi/spine-pixi package for further assistance.

    Spinebot OMG, spineObject.update(0); made a trick! Everything works now. But why? Where can i read more about why it helped?

    In general, by calling state.update(0), you force the skeleton to re-evaluate its current state, ensuring that all attachments and constraints are correctly set according to the new skin.

    The crash might be related to the fact that some attachments are not yet set in the skeleton and Pixi is trying to render something that does not exist.