Search Issue Tracker

By Design

Votes

0

Found in

2017.4.0f1

2018.2.20f1

2018.3.0a1

2019.1.0a1

2019.2.0a1

Issue ID

1117255

Regression

No

Sprite.OverridePhysicsShape raises an error when using it in Editor Mode

2D

-

Repro Steps:
1. Open attached "UnityBug.zip" project
2. Press on the "TrollRuntSprites" Spritesheet in the Project view
3. In the Inspector context menu, select "Set Physics Shape For All Sprites"
4. Observe the Console error tab

Expected Behavior: All the Sprite physics in the Spritesheet are overridden and set to be identical to the first sprite
Actual Behavior: The error is raised that the use of Sprite.OverridePhysicsShape is not allowed

Reproducible with: 2017.4.18f1, 2018.3.2f1, 2019.1.0a14, 2019.2.0a1

  1. Resolution Note:

    Sprite.OverridePhysicsShape can only be used in Edit Mode when importing the Sprite, for example when post processing a Sprite through AssetPostprocessor.OnPostprocessSprites(Texture2D, Sprite[]). The changes done in Sprite.OverridePhysicsShape only update the physics shape for the Sprite asset and will be lost when the Texture Importer is reimported and regenerates the Sprite assets.

    Instead, you will need to update the actual physics shape inside the Texture Importer in order to have the behavior you want. Here is an example script which can do this:

    using System.Collections.Generic;
    using System.Linq;
    using UnityEditor;
    using UnityEditor.Experimental.U2D;
    using UnityEngine;

    public class SetPhysicsShapeForAllSpritesTool : Editor {

    private Vector2Int pivot;
    private bool normalized;

    [MenuItem("CONTEXT/TextureImporter/Set Physics Shape For All Sprites")]
    public static void ShowSetPhysicsShapeForAllSpritesWindow() {

    // Overwrite physics shape for each sprite in the spritesheet
    Sprite[] sprites = (Selection.activeObject as Texture2D).GetSprites();
    if (sprites.IsNullOrEmpty()) {
    return;
    }

    string path = AssetDatabase.GetAssetPath(Selection.activeObject);
    TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter;
    var spritePhysicsShapeImporter = new SpritePhysicsShapeImporter(importer);
    List<Vector2[]> copyShapes = spritePhysicsShapeImporter.GetPhysicsShape(0);
    for (int i = 0; i < sprites.Length; ++i) {
    spritePhysicsShapeImporter.SetPhysicsShape(i, copyShapes);
    }

    // Save the changes made to the importer and refresh the database
    spritePhysicsShapeImporter.Save();
    }
    }

    public class SpritePhysicsShapeImporter
    {
    private TextureImporter m_TI;
    private SerializedObject m_TISerialized;

    public SpritePhysicsShapeImporter(TextureImporter ti)
    {
    m_TI = ti;
    m_TISerialized = new SerializedObject(m_TI);
    }

    public List<Vector2[]> GetPhysicsShape(int index)
    {
    var physicsShapeProperty = GetPhysicsShapeProperty(index);
    var physicsShape = new List<Vector2[]>();
    for (int j = 0; j < physicsShapeProperty.arraySize; ++j)
    {
    SerializedProperty physicsShapePathSP = physicsShapeProperty.GetArrayElementAtIndex(j);
    var o = new Vector2[physicsShapePathSP.arraySize];
    for (int k = 0; k < physicsShapePathSP.arraySize; ++k)
    {
    o[k] = physicsShapePathSP.GetArrayElementAtIndex(k).vector2Value;
    }
    physicsShape.Add(o);
    }
    return physicsShape;
    }

    public void SetPhysicsShape(int index, List<Vector2[]> data)
    {
    var physicsShapeProperty = GetPhysicsShapeProperty(index);
    physicsShapeProperty.ClearArray();
    for (int j = 0; j < data.Count; ++j)
    {
    physicsShapeProperty.InsertArrayElementAtIndex(j);
    var o = data[j];
    SerializedProperty outlinePathSP = physicsShapeProperty.GetArrayElementAtIndex(j);
    outlinePathSP.ClearArray();
    for (int k = 0; k < o.Length; ++k)
    {
    outlinePathSP.InsertArrayElementAtIndex(k);
    outlinePathSP.GetArrayElementAtIndex(k).vector2Value = o[k];
    }
    }
    m_TISerialized.ApplyModifiedPropertiesWithoutUndo();
    }

    public void Save()
    {
    AssetDatabase.ForceReserializeAssets(new string[] { m_TI.assetPath }, ForceReserializeAssetsOptions.ReserializeMetadata);
    m_TI.SaveAndReimport();
    }

    private SerializedProperty GetPhysicsShapeProperty(int index)
    {
    if (m_TI.spriteImportMode == SpriteImportMode.Multiple)
    {
    var spriteSheetSP = m_TISerialized.FindProperty("m_SpriteSheet.m_Sprites");
    if (index < spriteSheetSP.arraySize)
    {
    var element = spriteSheetSP.GetArrayElementAtIndex(index);
    return element.FindPropertyRelative("m_PhysicsShape");
    }
    }
    return m_TISerialized.FindProperty("m_SpriteSheet.m_PhysicsShape");
    }
    }

Comments (5)

  1. ohin

    Jan 17, 2021 18:30

    I also wanted to set physics shape from the script when importing spritesheet. Ended up here. Using the code from resolution works, however I don't like the usage of reflection.
    This should really be reconsidered.

  2. SunnysideGames

    Aug 19, 2020 07:44

    Ok so thanks to the code in the resolution note I managed to put together a script to easily copy / paste sprite physics shape to multiple selected sprites:

    Screenshot and code:
    https://forum.unity.com/threads/same-custom-physic-shape.761795/#post-6218889

  3. Yemnefer

    Jul 31, 2020 20:49

    You should use the AssetDatabase.

    string path = AssetDatabase.GetAssetPath (Selection.activeObject);
    Sprite[] sprites = AssetDatabase.LoadAllAssetsAtPath (path)
    .OfType<Sprite> ().ToArray ();
    if (sprites.Length == 0)
    return;

    for textures not only inside the Resources folder.

  4. ExNinja

    Oct 17, 2019 15:39

    These lines do not work in version 2019.2:
    Sprite[] sprites = (Selection.activeObject as Texture2D).GetSprites();
    if (sprites.IsNullOrEmpty()) {
    return;
    }

    They can be replaced by these lines IF the selection is in the Resources folder:
    Texture2D tex = Selection.activeObject as Texture2D;
    Sprite[] sprites = Resources.LoadAll<Sprite>(tex.name);
    if (sprites.Length == 0) return;

  5. ExNinja

    Oct 17, 2019 15:18

    Regardless of whether this is by design, it is still very problematic that it does not work. Please consider re-opening this bug so that we can modify physics shapes of sprites in code.

Add comment

Log in to post comment

All about bugs

View bugs we have successfully reproduced, and vote for the bugs you want to see fixed most urgently.