• RuntimesUnity
  • Spine的Skin换肤问题

  • Изменено

我在地图上创建了3个一模一样的Spine动画,我变化其中一个的手持武器,于是我调用了下面的方法,但是我发现我调用后,其他的spine也一起变了。这个有办法处理吗?

        /// <summary>
        /// spine的Slot中皮肤图片的修改
        /// </summary>
        /// <param name="skeleton"><see cref="Skeleton" /> 对象</param>
        /// <param name="skeletonDataAsset">spine中skeletonDataAsset对象</param>
        /// <param name="animationState">spine中AnimationState对象</param>
        /// <param name="slotName">槽位名字</param>
        /// <param name="findSpriteName">槽位下要替换的精灵的名字</param>
        /// <param name="sprite">更换的图片</param>
        /// <param name="skinLayerName">皮肤所在层</param>
       private static void SpinChangeSlotSkinSprite(Skeleton skeleton, SkeletonDataAsset skeletonDataAsset, Spine.AnimationState animationState, string slotName, string findSpriteName,  Sprite sprite, string skinLayerName)
        {
            Attachment cloneAttachment;
            var skeletonData = skeletonDataAsset.GetSkeletonData(true);
            var skin = skeletonData.FindSkin(skinLayerName);
            var slotData = skeletonData.FindSlot(slotName);
            Attachment templateAttachment = skin.GetAttachment(slotData.Index, findSpriteName);
            cloneAttachment = templateAttachment.GetRemappedClone(sprite, templateAttachment.GetMaterial());
            skin.SetAttachment(slotData.Index, slotName, cloneAttachment);
            skeleton.SetSkin(skin);
            skeleton.SetSlotsToSetupPose();
            animationState.Apply(skeleton);
        }
Related Discussions
...

补充下: 我是通过这个方法直接调用的,所以说因为直接引用了Spine内部的skeletonDataAsset数据吗

   /// <summary>
    /// 修改spine中的slot中皮肤的精灵图片
    /// </summary>
    /// <param name="skeletonAnimation"><see cref="SkeletonAnimation" /> 对象</param>
    /// <param name="slotName">槽位名字</param>
    /// <param name="findSpriteName">槽位下要替换的精灵的名字</param>
    /// <param name="sprite">更换的图片</param>
    /// <param name="skinLayerName">皮肤所在层</param>
    public static void ChangeSlotSkinSprite(this SkeletonAnimation skeletonAnimation, string slotName, string findSpriteName, Sprite sprite, string skinLayerName)
    {
        SpinChangeSlotSkinSprite(skeletonAnimation.Skeleton, skeletonAnimation.skeletonDataAsset, skeletonAnimation.AnimationState, slotName, findSpriteName, sprite, skinLayerName);
    }
  • Harald ответили на это сообщение.

    yuanjiashun
    是的,如果您更改共享数据 (SkeletonData) 而不是实例数据 (Skeleton),它将影响所有实例。 请在 此处 查看 spine-unity 文档,并查看 spine-unity 运行时包附带的示例场景。

    有关一般设计概述,请参阅此处的文档页面:
    http://zh.esotericsoftware.com/spine-runtime-architecture#%E6%95%B0%E6%8D%AE%E5%AF%B9%E8%B1%A1
    https://zh.esotericsoftware.com/spine-api-reference#%E8%BF%90%E8%A1%8C%E6%97%B6%E7%B1%BB%E5%9B%BE


    Yes, if you change the shared data (SkeletonData) instead of the instance data (Skeleton) it will affect all instances. Please check out the spine-unity documentation here, and have a look at the example scenes that come with the spine-unity runtime package.

    See the documentation pages here for a general design overview:
    http://zh.esotericsoftware.com/spine-runtime-architecture#%E6%95%B0%E6%8D%AE%E5%AF%B9%E8%B1%A1
    https://zh.esotericsoftware.com/spine-api-reference#%E8%BF%90%E8%A1%8C%E6%97%B6%E7%B1%BB%E5%9B%BE


    改成了这个依然是一样的效果

    不幸的是,自动翻译未能正确翻译您的信息,结果太含糊了。 你能更详细地解释一下你在上面的信息中问的是什么吗?

    Unfortunately automatic translation failed to translate your message properly, the result was too ambiguous. Could you explain in more detail what you were asking in your message above?

    我在地图上创建了3个一模一样的Spine动画,我变化其中一个的手持武器,我通过调用修改skeletonAnimation.Skeleton.Data 中的实例数据,发现还是所有spine都发生了改变!

    skeletonAnimation.Skeleton.Data 正在再次访问共享的 SkeletonData 而不是实例属性。 名称中带有“数据”的所有内容都是共享数据,在所有骨架实例之间共享。 请在上方查看我的消息,您应该改用什么:
    https://esotericsoftware.com/forum/d/24021-spine的皮肤换肤问题/3


    skeletonAnimation.Skeleton.Data is accessing the shared SkeletonData again instead of instance properties. Everything with data in the name is shared data, shared amoung all skeleton instances. Please see my message above what you should use instead:
    https://esotericsoftware.com/forum/d/24021-spine的skin换肤问题/3

    12 дней спустя

    我的问题还是没有解决,因为我不知道如何写才可以让只修改实例的表现?不修改共享数据,我还有一个问题,我现在有个角色有40套衣服,这个spine,而且人还有可以修改的眼睛,眉毛,眼睛,耳坠,裤子,上衣,鞋子这些也有好多组装,这个你们有啥建议吗

    很遗憾听到以前的帖子没有帮助。 第一次发布的代码中有问题的行如下:

    var skin = skeletonData.FindSkin(skinLayerName);
    [...]
    skin.SetAttachment(slotData.Index, slotName, cloneAttachment);

    在这里修改 skeletonData 的皮肤。 相反,您应该按照 spine-unity 文档页面 此处:

    var mixAndMatchSkin = new Skin("custom-girl");
    mixAndMatchSkin.AddSkin(skeletonData.FindSkin("skin-base"));

    然后你可以将你想要的皮肤添加到 mixAndMatchSkin 中,并调用 mixAndMatchSkin.SetAttachment(slotData.Index, slotName, cloneAttachment);



    Sorry to hear that the previous postings did not help. The problematic lines in your code of the first posting is as follows:

    var skin = skeletonData.FindSkin(skinLayerName);
    [...]
    skin.SetAttachment(slotData.Index, slotName, cloneAttachment);

    Here you modify the skin of skeletonData. Instead you should create a new skin as described in the spine-unity documentation pages here:

    var mixAndMatchSkin = new Skin("custom-girl");
    mixAndMatchSkin.AddSkin(skeletonData.FindSkin("skin-base"));

    Then you can add your desired skins to the mixAndMatchSkin, and call mixAndMatchSkin.SetAttachment(slotData.Index, slotName, cloneAttachment);.

    6 дней спустя

    皮肤特别多的话,我的合图都在一个里面,这样加载spine的时候会把所有皮肤需要的合图都加到内存里面,这样会导致我的内存非常庞大,而我用到的只有1套皮肤!

    @yuanjiashun 不幸的是,机器翻译未能正确翻译您之前的帖子。 你能否更详细地描述你正在尝试做什么,你想要的结果是什么,以及你收到了什么?

    Unfortunately machine translation failed to translate your previous posting properly. Could you please describe in more detail and separate sentences what you are trying to do, what your desired outcome is, and what you are receiving instead?

    现在我有一个Spine角色,他有30套皮肤可以更换,每个皮肤里面都包含(头发,脸型,眼睛,眉毛,上衣,下衣服,鞋子)等部件,我在做spine的时候如果全部导出会导致所有皮肤都在一个合图里面,这样加载的时候会导致内存特别大,单独挂载图片又担心碎图太多,代码阅读性差,所以问下官方有啥好的建议?

    感谢您的附加信息。 一般来说,拥有一个大图集纹理还是拥有多个小纹理总是取决于您的用例。 大纹理的大小是多少,下载时间是否太长(如果您不下载它并将其与游戏可执行文件一起提供,下载时间无关紧要)? 或者大小是否超出了最低目标硬件的限制? 如果您不下载纹理或执行任何其他按需加载,如 Unity Addressables 或 Asset Bundles,所有纹理无论如何都会在关卡加载时立即加载(只要存在对纹理资产的任何间接引用,它们就会被加载), 所以当使用多个小纹理而不是单个大纹理时,它不会改变加载时间。

    他有30套皮肤可以更换,每个皮肤里面都包含(头发,脸型,眼睛,眉毛,上衣,下衣,鞋子)等部件

    不幸的是,关于 30 皮肤的机器翻译仍然有点模棱两可:每个皮肤是否只包含一个装备项目而没有其他东西? 比如黑发一张皮,棕发一张皮,蓝裤子一张皮,黑裤子一张皮? 或者一张皮肤是否包含多个项目,如头发、裤子、上衣等?

    如果每个设备项目只有一个皮肤,您可以使用皮肤 API 将皮肤添加到组合皮肤中,如 此处。 如果您想使用 Addressables 或 AssetBundles 或其他按需加载功能,则需要一些编码。 然后,您将从材料中删除对纹理的任何直接引用(例如,通过预构建步骤自动进行,然后在构建后再次恢复它)并按需下载纹理并将它们分配给各自的材料。 您可以查看此论坛帖子中的描述:
    翻译:

    如果您决定自己实现此功能而不是等待官方实现,我建议在设置和加载任何皮肤时添加一层间接层(例如,一个新的 SkinLoader 组件类)。 作为准备工作,您将从任何 SkeletonDataAsset 引用级联中删除除默认皮肤资产以外的所有资产。 然后您可以在 skinLoader.SetSkin(targetSkeletonAnimation, "skinname") 处设置您的皮肤,它首先检查它是否已加载,按需加载它并连接任何引用,然后调用 targetSkeletonAnimation.Skeleton.SetSkin(skinname)。 这样它应该是可行的,而不必修改 spine-unity 代码。

    然后,您可以按照 下面的文档 创建单个纹理并减少绘制调用。



    Thanks for the additional information. In general whether it's better to have one large atlas texture versus multiple small textures always depends on your use case. What is the size of the large texture, does it take too long to download (if you don't download it and ship it with the game executable, download time won't matter)? Or does the size exceed the limitations of your minimum target hardware? If you don't download the textures or perform any other on-demand loading like Unity Addressables or Asset Bundles, all textures are anyway loaded at once at level-load time (whenever any indirect reference to texture assets exists, they are loaded), so it does not change loading time when using multiple small textures instead of a single large texture.

    他有30套皮肤可以更换,每个皮肤里面都包含(头发,脸型,眼睛,眉毛,上衣,下衣服,鞋子)等部件

    Regarding 30 skins machine translation unfortunately still was a bit ambiguous: Does each skin only contain a single equipment item and nothing else? Like one skin for black hair, one skin for brown hair, one skin for blue trousers, one skin for black trousers? Or does a single skin contain multiple items like hair, trousers, tops, etc?

    If you have a single skin per equipment item, you would use the Skin API to add skins to a combined skin as documented here. If you want to use Addressables or AssetBundles or other on-demand loading functionality, there is a bit of coding required. You would then remove any direct references to textures from your materials (e.g. automatically via a pre-build step, then restore it in post-build again) and on-demand download the textures and assign them at their respective material. You can check out the description in this forum posting:
    Translation:

    If you decide to implement this feature yourself and not wait for the official implementation, I would recommend adding one layer of indirection (e.g. a new SkinLoader component class) around setting and loading any skin. As a preparation you would then remove all but the default skin's assets from any SkeletonDataAsset reference cascades. Then you would set your skin at skinLoader.SetSkin(targetSkeletonAnimation, "skinname") which first checks if it's loaded, loads it on demand and hooks up any references, and then calls targetSkeletonAnimation.Skeleton.SetSkin(skinname). This way it should be doable without having to modify the spine-unity code.

    You could then repack the combined skin as shown in the documentation immediately below to create a single texture and reduce draw calls.