Sokuaisushi

  • 24 janv. 2023
  • Inscrit 19 août 2019
  • Harald a écrit

    [...]
    New 4.0 and 4.1-beta unitypackages are available for download here as usual:
    spine-unity Download
    Make sure to copy all 3 fadeout-related components and the example scene to your 3.8 project.

    I know this post is nearly a year old, but I'm having troubles using the RenderTexture example that you made Harald when I build to mobile devices.

    Specifically the alpha value is completely ignored when building to physical iOS and Android devices. I've confirmed that this is an issue with the example scene as well, and not our code, as the example scene displays properly on Desktop and in Play mode. However on iOS the Spine Boy renders properly, but doesn't fade out at all, and stays at an opacity of 1.0f, and then on Android the Spine Boy RenderTextures display nothing at all.

    Curiously if I manually set the RenderTexture's to "Sprites-Default" then the RenderTexture displays properly on iOS, including the opacity. However it still doesn't display at all on Android. If I then force the SkeletonRenderTexture script to find the "Spine/RenderQuad" shader to make a new material from, by setting the quadMaterial field in the inspector to "None", then it displays on both iOS and Android, but also ignores the RenderTexture's set opacity.

    I'm assuming that this is some issue with texture compression, or texture format, but haven't been able to get anything that works on Android properly, and the solution I found for iOS displays nothing at all on Android...

    Some help would be greatly appreciated.

    EDIT:

    I believe I found a workaround for now, as it seems to be related to using the Vulkan Unity Graphics API.

    If anyone is having the same problem as I am, in the Player Settings if you un-toggle Auto Graphics API, and either move OpenGLES3 to the top or remove Vulkan entirely, then the RenderTextures display as intended on Android, including their opacity.

    Then for it to display properly on both iOS and Android, simply change line #94 of the SkeletonRenderTexture from:

    quadMeshRenderer.material = new Material(Shader.Find("Spine/RenderQuad"));

    to

    quadMeshRenderer.material = new Material(Shader.Find("Sprites/Default"));

    After that the RenderTextures should display properly on both iOS and Android, including the RenderTexture's set opacity. (You might need to change/remove the "Quad Material" in the Inspector of your example scene, or your actual SkeletonRenderTexture objects for this fix to fully work for you.)

  • Sure, if Cocos2d-x v3.17.2 (and thus the Spine Cocos2d-x and C++ runtimes) are compiled into a DLL on Windows with Visual Studio then the following compiler error occurs:

    E0330    "spine::RTTI::RTTI(const spine::RTTI &obj)" (declared at line 50 of "[...]\cocos2d\cocos\editor-support\spine\RTTI.h") is inaccessible    [Project Name]    [...]\Classes\scenes\TitleScene.cpp [Line #]

    This is from adding a single line of code to TitleScene.cpp:

    spine::RTTI static_RTTI_Variable = spine::MeshAttachment::rtti;

    Some research shows it might not be possible to access statically defined variables (such as the RTTI types) from a DLL at all, which would be unfortunate.

    Anyways, I hope this helps you and thank you for your help!

  • My team and I are currently porting our game, Election Year Knockout, to Windows. We had to compile Cocos2d-x as a DLL in order to more easily utilize the framework on Windows, which means our Spine runtimes were also compiled to the same DLL.

    So far this hasn't been an issue aside from one thing; some very light RTTI checks when we color certain attachments. These static RTTI variables are inaccessible from outside the DLL as far as I can tell, since they are static in a dynamic library. It does give me a compile error when I attempt to do something like this:

    if(attachment->getRTTI().isExactly(spine::MeshAttachment::rtti)

    More specifically I've determined that the cause of the compile error is:

    spine::MeshAttachment::rtti

    I did notice that attachment->getRTTI() works as intended and we can even get the name of the RTTI from that returned getRTTI() call.

    So my question is if there is a way to get the static RTTI variables, or if you recommend we just do string comparisons in order to check the RTTI of a given attachment (note we iterate over all of the attachments of two spine objects at the start of every level).

    Edit:
    For further clarification this can be avoided by doing dynamic_cast to each Attachment type you need to access the member functions of, and then just doing a nullptr check before trying to use the casted variable. It is still curious as to the expected behavior of the static RTTI variables when building the spine runtimes as a DLL for Windows.

  • badlogic a écrit

    Yeah, a small Cocos2d-x project that actually tries to swap out the textures would be fantastic!

    Not a problem! Just give me a little time to create the project as we are preparing for a city fair this weekend to show off the game and have some changes that need to be done first.

  • badlogic a écrit

    In principal, AnimationState is stateless. However, timelines inside animations managed by AnimationState are not quite. The offender here is likely http://esotericsoftware.com/spine-api-reference#DeformTimeline, which keeps a reference to an attachment to be deformed by it.

    Would it be possible for you to whip up a small repro for this? We've had similar reports and I'd like a real world-ish thing I could try to use and improve the API with so this is more easily possible.

    I must've misunderstood the documentation. I understood AnimationState to be stateful, while AnimationStateData was stateless... If AnimationState is stateless, how should I go about maintaining the state from the old skeleton to the new skeleton?

    I will look into the DeformTimeline as well, thank you for the link!

    As for a small repro for this issue, it goes something like this:

    void PlayerNode::setGraphicsQuality(SettingsManager::GraphicsSettings quality)
    {
        bool isLowQuality = quality == SettingsManager::GraphicsSettings::LOW;
        float renderScale = SCALE_NORMAL; // 1.0f
    
    auto animationState = _spine->getState();
    
    spine::SkeletonAnimation* newSpine;
    
    if(isLowQuality) {
        renderScale = SCALE_PERFORMANCE; // 0.25f
        
        newSpine = spine::SkeletonAnimation::createWithJsonFile(SPINE_PATH("player_character.json"), SPINE_PATH("perf_player_character.atlas"), renderScale / Director::getInstance()->getContentScaleFactor());
    } else {
        newSpine = spine::SkeletonAnimation::createWithJsonFile(SPINE_PATH("player_character.json"), SPINE_PATH("player_character.atlas"), renderScale / Director::getInstance()->getContentScaleFactor());
    }
    
    newSpine->setToSetupPose();
    animationState->update(0);
    animationState->apply(*newSpine->getSkeleton());
    
    this->removeChild(_spine);
    
    _spine  = newSpine;
    
    // Add the new spine to our PlayerNode
    this->addChild(_spine);
    _spine->onEnter();
    
    // Register the event and completion listeners that the old skeleton used.
    _spine->setCompleteListener(CC_CALLBACK_1(PlayerNode::onSpineComplete, this));
    _spine->setEventListener(CC_CALLBACK_2(PlayerNode::onSpineEvent, this));
    }

    Here SettingsManager::GraphicsSettings is an enum class with only LOW and HIGH. The PlayerNode is an extension of the Cocos2d-x Node class which maintains a reference to it's spine::SkeletonAnimation, among other things pertaining to the player character.

    If you'd like me to create a small Cocos2d-x project to repro these issues too, I'd be more than happy to oblige!

    Thanks for your time badlogic!

  • In the project my team and I are currently working on we've seemingly ran into a huge roadblock.

    In order to support older and lower end devices we added a quality setting to our game, which the user can change during the fights in our game (it's a cross between PunchOut and a political parody). In order to do this I would've liked to just be able to swap out the atlas at run-time with a performance variant, however as far as I can see this isn't possible with the C++/Cocos2d-x runtimes. (If this is possible, could you please point me in the right direction for it. I've been scouring the internet for a solution to this for days now and haven't turned up anything useful.)

    To get around this we are disposing of the SkeletonAnimation object, and then creating a new one using the new texture atlas, this part works fine. But in order to maintain the state of the animation tracks before we dispose of the old skeleton we get a reference to the old skeleton's AnimationState, and try to apply this to the new skeleton...

    This is where the issue begins, while this code seemingly works and positions the new skeleton in the same position of the animation that the old skeleton was in, the animation does not continue from that point. Until we play a new animation track the new skeleton will forever be in that frozen pose... For the life of me I can't seem to figure out how to maintain the AnimationState from the old skeleton to the new skeleton, and have the animation continue from that point.

    So why is the skeleton frozen after using AnimationState->apply, and how do I get the skeleton to continue playing the animation from that point? Maintaining the AnimationState is vital for us because we use tons of TrackEntry's with their own lambda functions onTrackCompletion, independent of the animation itself but based on the state of the fighter, among other things.

    I might not be explaining myself or what we are trying to accomplish very well, and am most likely doing something wrong or unintended to achieve this. Any advice and suggestions to fix this system would be greatly appreciated, as I'd rather not have to tell the player that all graphics changes will take place in the next fight... Thank you for your time!

    TLDR; I get the AnimationState from a SkeletonAnimation object, create a new SkeletonAnimation object with the same JSON but a different atlas. I then use animationState->apply(*newSkeleton->getSkeleton()), which sets the new skeleton into the correct pose of the correct animation. The problem being that the new skeleton is frozen in that pose until we do newSkeleton->setAnimation(...).