• Runtimes
  • Spine-TS - Need help with rendering and animating in multiple skeletons (post 2)

Hi,

Hi,

I'm following a demo code in getting Spine-TS runtime to work with my project. I'll put the original demo code and the one I localized for myself below as a pastebin link. As what the title says, I'm trying to get more than one skeleton to draw on the screen. My setup is there's one <canvas> in the html (that's what the code below refers to). Right now, what happens is, if run:

vnX.spinexLoad('character01', 'character01', 'images/spines/')

It works fine. I have a code that destroys it too, and running it again is fine. However, if I run the above, then after I see the spine character animating on screen, and run the following to get another character there:

vnX.spinexLoad('character02', 'character02', 'images/spines/')

It looks as if character02 just replaced character01 on screen. I checked the spinexRender() function and have it spit out the spinekey passed to it, it's showing both character01 and character02, meaning the spinexRender() is running both of them. So how would I go about displaying the 2 animating characters on the same canvas (if that's possible)?

Related Discussions
...

Note: Sorry, I deleted the first post because I was encountering errors while editing the content.

Phew, that's 500 lines of code I can't debug 🙂

From what I gather, you are re-creating the webgl rendering context, shaders, batcher, renderer, and asset manager every time you load a new spine skeleton. You want a single instance of each to render multiple skeletons.

I strongly suggest you have a look at the samples that use the SpineCanvas class:
https://github.com/EsotericSoftware/spine-runtimes/blob/4.1/spine-ts/spine-webgl/example/barebones.html

    Mario

    Ok. Do I need the canvas to be separate for each skeleton as well?

    Depends on your use case. If all skeletons should "live" next to each other on the page, one canvas is what you want.

    • تم التحرير

    Ok, I think I got the bare demo to work:

    let gl = spctx.gl;
    let spnow = Date.now() / 1000;
    let delta = spnow - lastFrameTime;
    lastFrameTime = spnow;
    
    // Update the MVP matrix to adjust for canvas size changes
    spresize();
    
    gl.clearColor(0, 0, 0, 0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    
    // Apply the animation state based on the delta time.
    let skeleton = spskeletons['character01']['Binary'].skeleton;
    let state = spskeletons['character01']['Binary'].state;
    let bounds = spskeletons['character01']['Binary'].bounds;
    let premultipliedAlpha = spskeletons['character01']['Binary'].premultipliedAlpha;
    state.update(delta);
    state.apply(skeleton);
    skeleton.updateWorldTransform();
    
    let skeleton2 = spskeletons['character02']['Binary'].skeleton;
    let state2 = spskeletons['character02']['Binary'].state;
    let bounds2 = spskeletons['character02']['Binary'].bounds;
    let premultipliedAlpha2 = spskeletons['character02']['Binary'].premultipliedAlpha;
    
    skeleton2.getRootBone().x = 200;
    state2.update(delta);
    state2.apply(skeleton2);
    skeleton2.updateWorldTransform();
    
    // Bind the shader and set the texture and model-view-projection matrix.
    spshader.bind();
    spshader.setUniformi(spinex.Shader.SAMPLER, 0);
    spshader.setUniform4x4f(spinex.Shader.MVP_MATRIX, spmvp.values);
    
    // Start the batch and tell the SkeletonRenderer to render the active skeleton.
    spbatcher.begin(spshader);
    
    spskeletonRenderer.premultipliedAlpha = premultipliedAlpha;
    spskeletonRenderer.draw(spbatcher, skeleton);
    spskeletonRenderer.draw(spbatcher, skeleton2);
    spbatcher.end();
    
    spshader.unbind();
    
    requestAnimationFrame(sprender);
    
    }

    Hi Mario,

    I'm trying to get the demo with the class to work with multiple skeletons. So basically, I was able to call this in the console and randomizing the skeleton's x and y values to see if I will see multiple skeletons being placed into thecanvas:

    new spinex.SpineCanvas(document.getElementById("spcanvas"), {
    app: new App()
    })

    Unfortunately, it had the same effect of being replaced just like the first attempt.

    In the code above which I said I got the demo to work, I eventually got it to work as intended, but the context, shaders, batcher, renderer, and asset manager are shared instead of creating a new xxx for each character. In the renderer, I got rid of the parameter and just needed to run it once and it'll run continuously, but this time it takes an array of list of spine characters and run in the ff loop section:

    
    for (var count = 0; count < charArr.length; count++) {
    
        skeleton = spskeletons[charArr[count]]['Binary'].skeleton;
        state = spskeletons[charArr[count]]['Binary'].state;
        bounds = spskeletons[charArr[count]]['Binary'].bounds;
        premultipliedAlpha = spskeletons[charArr[count]]['Binary'].premultipliedAlpha;
        state.update(delta);
        state.apply(skeleton);
        skeleton.updateWorldTransform();
    
        spskeletonRenderer.premultipliedAlpha = premultipliedAlpha;
        spskeletonRenderer.draw(spbatcher, skeleton);
    
    }

    As I said in my previous reply, you WANT to share the shaders, batcher, renderer, and asset manager! Why do you not want to share them? You can not render to the same canvas if you do not share them.

    Mario You want a single instance of each to render multiple skeletons.

    I thought you meant single instance of each one (webgl rendering context, shaders, batcher, renderer, and asset manager...)

    Well, all is good!