Example #1
0
    void Apply()
    {
        var skeletonAnimation = GetComponent <SkeletonAnimation>();
        var skeleton          = skeletonAnimation.Skeleton;

        // STEP 0: PREPARE SKINS
        // Let's prepare a new skin to be our custom skin with equips/customizations.
        //We get a clone so our original skins are unaffected.
        customSkin = customSkin ?? new Skin("custom skin");
        // This requires that all customizations are done with skin placeholders defined in Spine.
        //customSkin = customSkin ?? skeleton.UnshareSkin(true, false, skeletonAnimation.AnimationState); // use this if you are not customizing on the default skin.
        var templateSkin = skeleton.Data.FindSkin(templateAttachmentsSkin);

        // STEP 1: "EQUIP" ITEMS USING SPRITES
        // STEP 1.1 Find the original/template attachment.
        // Step 1.2 Get a clone of the original/template attachment.
        // Step 1.3 Apply the Sprite image to the clone.
        // Step 1.4 Add the remapped clone to the new custom skin.

        for (int i = 0; i < AllReplacePairs.Count; i++)
        {
            SlotRegionPair Pair      = AllReplacePairs[i];
            int            slotIndex = skeleton.FindSlotIndex(Pair.Slot);
            // You can access GetAttachment and SetAttachment via string
            //, but caching the slotIndex is faster.
            Attachment templateAttachment = templateSkin.GetAttachment(slotIndex, Pair.Key); // STEP 1.1
            Attachment newAttachment      = templateAttachment.GetRemappedClone
                                                (Pair.newSprite, sourceMaterial);            // STEP 1.2 - 1.3

            if (newAttachment != null)
            {
                RegionAttachment ra = newAttachment as RegionAttachment;
                ra = (RegionAttachment)ra.Copy();
                float scale = 1f / Pair.newSprite.pixelsPerUnit;
                ra.Width  = ra.RegionWidth * scale;
                ra.Height = ra.RegionHeight * scale;

                customSkin.SetAttachment(slotIndex, Pair.Key, newAttachment);//STEP 1.4
            }
        }

        if (repack)
        {
            var repackedSkin = new Skin("repacked skin");
            repackedSkin.AddAttachments(skeleton.Data.DefaultSkin);                                                              // Include the "default" skin. (everything outside of skin placeholders)
            repackedSkin.AddAttachments(customSkin);                                                                             // Include your new custom skin.
            repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas); // Pack all the items in the skin.
            skeleton.SetSkin(repackedSkin);                                                                                      // Assign the repacked skin to your Skeleton.
            if (bbFollower != null)
            {
                bbFollower.Initialize(true);
            }
        }
        else
        {
            skeleton.SetSkin(customSkin); // Just use the custom skin directly.
        }

        skeleton.SetSlotsToSetupPose(); // Use the pose from setup pose.
        skeletonAnimation.Update(0);    // Use the pose in the currently active animation.

        Resources.UnloadUnusedAssets();
    }
Example #2
0
        void Apply()
        {
            var skeletonAnimation = GetComponent <SkeletonAnimation>();
            var skeleton          = skeletonAnimation.Skeleton;

            // STEP 0: PREPARE SKINS
            // Let's prepare a new skin to be our custom skin with equips/customizations. We get a clone so our original skins are unaffected.
            customSkin = customSkin ?? new Skin("custom skin");             // This requires that all customizations are done with skin placeholders defined in Spine.
            //customSkin = customSkin ?? skeleton.UnshareSkin(true, false, skeletonAnimation.AnimationState); // use this if you are not customizing on the default skin and don't plan to remove
            // Next let's
            var baseSkin = skeleton.Data.FindSkin(baseSkinName);

            // STEP 1: "EQUIP" ITEMS USING SPRITES
            // STEP 1.1 Find the original attachment.
            // Step 1.2 Get a clone of the original attachment.
            // Step 1.3 Apply the Sprite image to the clone.
            // Step 1.4 Add the remapped clone to the new custom skin.

            // Let's do this for the visor.
            int        visorSlotIndex = skeleton.FindSlotIndex(visorSlot);                            // You can access GetAttachment and SetAttachment via string, but caching the slotIndex is faster.
            Attachment baseAttachment = baseSkin.GetAttachment(visorSlotIndex, visorKey);             // STEP 1.1
            Attachment newAttachment  = baseAttachment.GetRemappedClone(visorSprite, sourceMaterial); // STEP 1.2 - 1.3

            customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment);                        // STEP 1.4

            // And now for the gun.
            int        gunSlotIndex = skeleton.FindSlotIndex(gunSlot);
            Attachment baseGun      = baseSkin.GetAttachment(gunSlotIndex, gunKey);        // STEP 1.1
            Attachment newGun       = baseGun.GetRemappedClone(gunSprite, sourceMaterial); // STEP 1.2 - 1.3

            if (newGun != null)
            {
                customSkin.SetAttachment(gunSlotIndex, gunKey, newGun);                             // STEP 1.4
            }
            // customSkin.RemoveAttachment(gunSlotIndex, gunKey); // To remove an item.
            // customSkin.Clear()
            // Use skin.Clear() To remove all customizations.
            // Customizations will fall back to the value in the default skin if it was defined there.
            // To prevent fallback from happening, make sure the key is not defined in the default skin.

            // STEP 3: APPLY AND CLEAN UP.
            // Recommended: REPACK THE CUSTOM SKIN TO MINIMIZE DRAW CALLS
            //              Repacking requires that you set all source textures/sprites/atlases to be Read/Write enabled in the inspector.
            //              Combine all the attachment sources into one skin. Usually this means the default skin and the custom skin.
            //              call Skin.GetRepackedSkin to get a cloned skin with cloned attachments that all use one texture.
            //				Under the hood, this relies on
            if (repack)
            {
                var repackedSkin = new Skin("repacked skin");
                repackedSkin.Append(skeleton.Data.DefaultSkin);
                repackedSkin.Append(customSkin);
                repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas);
                skeleton.SetSkin(repackedSkin);
                if (bbFollower != null)
                {
                    bbFollower.Initialize(true);
                }
            }
            else
            {
                skeleton.SetSkin(customSkin);
            }

            skeleton.SetSlotsToSetupPose();
            skeletonAnimation.Update(0);

            Resources.UnloadUnusedAssets();
        }
        public override void OnInspectorGUI()
        {
                        #if !NEW_PREFAB_SYSTEM
            bool isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
                        #else
            bool isInspectingPrefab = false;
                        #endif

            // Try to auto-assign SkeletonRenderer field.
            if (skeletonRenderer.objectReferenceValue == null)
            {
                var foundSkeletonRenderer = follower.GetComponentInParent <SkeletonRenderer>();
                if (foundSkeletonRenderer != null)
                {
                    Debug.Log("BoundingBoxFollower automatically assigned: " + foundSkeletonRenderer.gameObject.name);
                }
                else if (Event.current.type == EventType.Repaint)
                {
                    Debug.Log("No Spine GameObject detected. Make sure to set this GameObject as a child of the Spine GameObject; or set BoundingBoxFollower's 'Skeleton Renderer' field in the inspector.");
                }

                skeletonRenderer.objectReferenceValue = foundSkeletonRenderer;
                serializedObject.ApplyModifiedProperties();
            }

            var skeletonRendererValue = skeletonRenderer.objectReferenceValue as SkeletonRenderer;
            if (skeletonRendererValue != null && skeletonRendererValue.gameObject == follower.gameObject)
            {
                using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
                    EditorGUILayout.HelpBox("It's ideal to add BoundingBoxFollower to a separate child GameObject of the Spine GameObject.", MessageType.Warning);

                    if (GUILayout.Button(new GUIContent("Move BoundingBoxFollower to new GameObject", Icons.boundingBox), GUILayout.Height(50f)))
                    {
                        AddBoundingBoxFollowerChild(skeletonRendererValue, follower);
                        DestroyImmediate(follower);
                        return;
                    }
                }
                EditorGUILayout.Space();
            }

            EditorGUI.BeginChangeCheck();
            EditorGUILayout.PropertyField(skeletonRenderer);
            EditorGUILayout.PropertyField(slotName, new GUIContent("Slot"));
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
                                #if !NEW_PREFAB_SYSTEM
                if (!isInspectingPrefab)
                {
                    rebuildRequired = true;
                }
                                #endif
            }

            using (new SpineInspectorUtility.LabelWidthScope(150f)) {
                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(isTrigger);
                bool triggerChanged = EditorGUI.EndChangeCheck();

                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(clearStateOnDisable, new GUIContent(clearStateOnDisable.displayName, "Enable this if you are pooling your Spine GameObject"));
                bool clearStateChanged = EditorGUI.EndChangeCheck();

                if (clearStateChanged || triggerChanged)
                {
                    serializedObject.ApplyModifiedProperties();
                    if (triggerChanged)
                    {
                        foreach (var col in follower.colliderTable.Values)
                        {
                            col.isTrigger = isTrigger.boolValue;
                        }
                    }
                }
            }

            if (isInspectingPrefab)
            {
                follower.colliderTable.Clear();
                follower.nameTable.Clear();
                EditorGUILayout.HelpBox("BoundingBoxAttachments cannot be previewed in prefabs.", MessageType.Info);

                // How do you prevent components from being saved into the prefab? No such HideFlag. DontSaveInEditor | DontSaveInBuild does not work. DestroyImmediate does not work.
                var collider = follower.GetComponent <PolygonCollider2D>();
                if (collider != null)
                {
                    Debug.LogWarning("Found BoundingBoxFollower collider components in prefab. These are disposed and regenerated at runtime.");
                }
            }
            else
            {
                using (new SpineInspectorUtility.BoxScope()) {
                    if (debugIsExpanded = EditorGUILayout.Foldout(debugIsExpanded, "Debug Colliders"))
                    {
                        EditorGUI.indentLevel++;
                        EditorGUILayout.LabelField(string.Format("Attachment Names ({0} PolygonCollider2D)", follower.colliderTable.Count));
                        EditorGUI.BeginChangeCheck();
                        foreach (var kp in follower.nameTable)
                        {
                            string attachmentName = kp.Value;
                            var    collider       = follower.colliderTable[kp.Key];
                            bool   isPlaceholder  = attachmentName != kp.Key.Name;
                            collider.enabled = EditorGUILayout.ToggleLeft(new GUIContent(!isPlaceholder ? attachmentName : string.Format("{0} [{1}]", attachmentName, kp.Key.Name), isPlaceholder ? Icons.skinPlaceholder : Icons.boundingBox), collider.enabled);
                        }
                        sceneRepaintRequired |= EditorGUI.EndChangeCheck();
                        EditorGUI.indentLevel--;
                    }
                }
            }

            bool hasBoneFollower = follower.GetComponent <BoneFollower>() != null;
            if (!hasBoneFollower)
            {
                bool buttonDisabled = follower.Slot == null;
                using (new EditorGUI.DisabledGroupScope(buttonDisabled)) {
                    addBoneFollower |= SpineInspectorUtility.LargeCenteredButton(AddBoneFollowerLabel, true);
                    EditorGUILayout.Space();
                }
            }


            if (Event.current.type == EventType.Repaint)
            {
                if (addBoneFollower)
                {
                    var boneFollower = follower.gameObject.AddComponent <BoneFollower>();
                    boneFollower.skeletonRenderer = skeletonRendererValue;
                    boneFollower.SetBone(follower.Slot.Data.BoneData.Name);
                    addBoneFollower = false;
                }

                if (sceneRepaintRequired)
                {
                    SceneView.RepaintAll();
                    sceneRepaintRequired = false;
                }

                if (rebuildRequired)
                {
                    follower.Initialize();
                    rebuildRequired = false;
                }
            }
        }
        void Apply()
        {
            var skeletonAnimation = GetComponent <SkeletonAnimation>();
            var skeleton          = skeletonAnimation.Skeleton;

            // STEP 0: PREPARE SKINS
            // Let's prepare a new skin to be our custom skin with equips/customizations. We get a clone so our original skins are unaffected.
            customSkin = customSkin ?? new Skin("custom skin");             // This requires that all customizations are done with skin placeholders defined in Spine.
            //customSkin = customSkin ?? skeleton.UnshareSkin(true, false, skeletonAnimation.AnimationState); // use this if you are not customizing on the default skin.
            var templateSkin = skeleton.Data.FindSkin(templateAttachmentsSkin);

            // STEP 1: "EQUIP" ITEMS USING SPRITES
            // STEP 1.1 Find the original/template attachment.
            // Step 1.2 Get a clone of the original/template attachment.
            // Step 1.3 Apply the Sprite image to the clone.
            // Step 1.4 Add the remapped clone to the new custom skin.

            // Let's do this for the visor.
            int        visorSlotIndex     = skeleton.FindSlotIndex(visorSlot);                                // You can access GetAttachment and SetAttachment via string, but caching the slotIndex is faster.
            Attachment templateAttachment = templateSkin.GetAttachment(visorSlotIndex, visorKey);             // STEP 1.1
            Attachment newAttachment      = templateAttachment.GetRemappedClone(visorSprite, sourceMaterial); // STEP 1.2 - 1.3

            customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment);                                // STEP 1.4

            // And now for the gun.
            int        gunSlotIndex = skeleton.FindSlotIndex(gunSlot);
            Attachment templateGun  = templateSkin.GetAttachment(gunSlotIndex, gunKey);            // STEP 1.1
            Attachment newGun       = templateGun.GetRemappedClone(gunSprite, sourceMaterial);     // STEP 1.2 - 1.3

            if (newGun != null)
            {
                customSkin.SetAttachment(gunSlotIndex, gunKey, newGun);                             // STEP 1.4
            }
            // customSkin.RemoveAttachment(gunSlotIndex, gunKey); // To remove an item.
            // customSkin.Clear()
            // Use skin.Clear() To remove all customizations.
            // Customizations will fall back to the value in the default skin if it was defined there.
            // To prevent fallback from happening, make sure the key is not defined in the default skin.

            // STEP 3: APPLY AND CLEAN UP.
            // Recommended, preferably at level-load-time: REPACK THE CUSTOM SKIN TO MINIMIZE DRAW CALLS
            //              IMPORTANT NOTE: the GetRepackedSkin() operation is expensive - if multiple characters
            //              need to call it every few seconds the overhead will outweigh the draw call benefits.
            //
            //              Repacking requires that you set all source textures/sprites/atlases to be Read/Write enabled in the inspector.
            //              Combine all the attachment sources into one skin. Usually this means the default skin and the custom skin.
            //              call Skin.GetRepackedSkin to get a cloned skin with cloned attachments that all use one texture.
            if (repack)
            {
                var repackedSkin = new Skin("repacked skin");
                repackedSkin.AddAttachments(skeleton.Data.DefaultSkin);                                                              // Include the "default" skin. (everything outside of skin placeholders)
                repackedSkin.AddAttachments(customSkin);                                                                             // Include your new custom skin.
                repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas); // Pack all the items in the skin.
                skeleton.SetSkin(repackedSkin);                                                                                      // Assign the repacked skin to your Skeleton.
                if (bbFollower != null)
                {
                    bbFollower.Initialize(true);
                }
            }
            else
            {
                skeleton.SetSkin(customSkin);                 // Just use the custom skin directly.
            }

            skeleton.SetSlotsToSetupPose();          // Use the pose from setup pose.
            skeletonAnimation.Update(0);             // Use the pose in the currently active animation.

            Resources.UnloadUnusedAssets();
        }
Example #5
0
        void Apply()
        {
            var skeletonAnimation = GetComponent <SkeletonAnimation>();
            var skeleton          = skeletonAnimation.Skeleton;

            // STEP 0: PREPARE SKINS
            // Let's prepare a new skin to be our custom skin with equips/customizations. We get a clone so our original skins are unaffected.
            customSkin = customSkin ?? new Skin("custom skin");             // This requires that all customizations are done with skin placeholders defined in Spine.
            var templateSkin = skeleton.Data.FindSkin(templateAttachmentsSkin);

            // STEP 1: "EQUIP" ITEMS USING SPRITES
            // STEP 1.1 Find the original/template attachment.
            // Step 1.2 Get a clone of the original/template attachment.
            // Step 1.3 Apply the Sprite image to the clone.
            // Step 1.4 Add the remapped clone to the new custom skin.

            // Let's do this for the visor.
            int        visorSlotIndex     = skeleton.Data.FindSlot(visorSlot).Index;              // You can access GetAttachment and SetAttachment via string, but caching the slotIndex is faster.
            Attachment templateAttachment = templateSkin.GetAttachment(visorSlotIndex, visorKey); // STEP 1.1

            // Note: Each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true` creates
            // a cached Texture copy which can be cleared by calling AtlasUtilities.ClearCache() as done in the method below.
            Attachment newAttachment = templateAttachment.GetRemappedClone(visorSprite, sourceMaterial, pivotShiftsMeshUVCoords: false); // STEP 1.2 - 1.3

            customSkin.SetAttachment(visorSlotIndex, visorKey, newAttachment);                                                           // STEP 1.4

            // And now for the gun.
            int        gunSlotIndex = skeleton.Data.FindSlot(gunSlot).Index;
            Attachment templateGun  = templateSkin.GetAttachment(gunSlotIndex, gunKey);                                        // STEP 1.1
            Attachment newGun       = templateGun.GetRemappedClone(gunSprite, sourceMaterial, pivotShiftsMeshUVCoords: false); // STEP 1.2 - 1.3

            if (newGun != null)
            {
                customSkin.SetAttachment(gunSlotIndex, gunKey, newGun);                             // STEP 1.4
            }
            // customSkin.RemoveAttachment(gunSlotIndex, gunKey); // To remove an item.
            // customSkin.Clear()
            // Use skin.Clear() To remove all customizations.
            // Customizations will fall back to the value in the default skin if it was defined there.
            // To prevent fallback from happening, make sure the key is not defined in the default skin.

            // STEP 3: APPLY AND CLEAN UP.
            // Recommended, preferably at level-load-time: REPACK THE CUSTOM SKIN TO MINIMIZE DRAW CALLS
            //              IMPORTANT NOTE: the GetRepackedSkin() operation is expensive - if multiple characters
            //              need to call it every few seconds the overhead will outweigh the draw call benefits.
            //
            //              Repacking requires that you set all source textures/sprites/atlases to be Read/Write enabled in the inspector.
            //              Combine all the attachment sources into one skin. Usually this means the default skin and the custom skin.
            //              call Skin.GetRepackedSkin to get a cloned skin with cloned attachments that all use one texture.
            if (repack)
            {
                var repackedSkin = new Skin("repacked skin");
                repackedSkin.AddSkin(skeleton.Data.DefaultSkin);  // Include the "default" skin. (everything outside of skin placeholders)
                repackedSkin.AddSkin(customSkin);                 // Include your new custom skin.

                // Note: materials and textures returned by GetRepackedSkin() behave like 'new Texture2D()' and need to be destroyed
                if (runtimeMaterial)
                {
                    Destroy(runtimeMaterial);
                }
                if (runtimeAtlas)
                {
                    Destroy(runtimeAtlas);
                }
                repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas); // Pack all the items in the skin.
                skeleton.SetSkin(repackedSkin);                                                                                      // Assign the repacked skin to your Skeleton.
                if (bbFollower != null)
                {
                    bbFollower.Initialize(true);
                }
            }
            else
            {
                skeleton.SetSkin(customSkin);                 // Just use the custom skin directly.
            }

            skeleton.SetSlotsToSetupPose();          // Use the pose from setup pose.
            skeletonAnimation.Update(0);             // Use the pose in the currently active animation.

            // `GetRepackedSkin()` and each call to `GetRemappedClone()` with parameter `premultiplyAlpha` set to `true`
            // cache necessarily created Texture copies which can be cleared by calling AtlasUtilities.ClearCache().
            // You can optionally clear the textures cache after multiple repack operations.
            // Just be aware that while this cleanup frees up memory, it is also a costly operation
            // and will likely cause a spike in the framerate.
            AtlasUtilities.ClearCache();
            Resources.UnloadUnusedAssets();
        }