Search Unity

Destructible 2D ☄️ Dynamic Sprite Destruction

Discussion in 'Assets and Asset Store' started by Darkcoder, May 29, 2014.

  1. Toastbyte

    Toastbyte

    Joined:
    Sep 1, 2016
    Posts:
    54
    Hi there @Darkcoder

    I wanted to ask how to manually update the damaged alpha texture of a sprite shape. The Polygon2D colliders are up to date with how it should look like, but the texture is not:

    upload_2022-12-22_23-22-2.png

    Thanks in advance
     
  2. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,412
    The current destruction state is stored in the D2dDestructibleSprite component's AlphaData setting which is a 2D array of AlphaWidth * AlphaHeight size. If you manually modify this then you must call the NotifyRebuilt() method after, which will update the visual destruction texture, and colliders.
     
    Toastbyte likes this.
  3. Leyren

    Leyren

    Joined:
    Mar 23, 2016
    Posts:
    29
    Hey, thanks for the package, it's really helpful and offers a lot of features. One tiny thing I noticed with the D2dDestroyer:
    1. The shrinking logic is using the configured fade value instead of shrink value:
      Code (CSharp):
      1. finalScale *= Life / FadeDuration
    2. The shrinking is not clamped to a multiplier of 1. E.g. if Life = 1 and Shrinking (or currently Fading) duration is 0.1, it would start at a scale of 10. (On fading, it would wait for 0.9s before starting, but on shrink that's not the case)
     
  4. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,412
    Thanks for pointing this out, this will be fixed in the next version!
     
  5. Westy661

    Westy661

    Joined:
    Sep 13, 2015
    Posts:
    14
    Hello! Thanks for the cool asset, i like it very much.
    However i have a problem i hope you can help with :).

    So i have an arrow, which is a projectile in my game. It gets force applied to it, and in an
    OnCollisionEnter2D method i check for some internal gameplay code, and if the arrow didnt hit a player i call
    D2dFracturer.Fracture() on it.
    The problem is, that the fractures then hit something (via the OnCollusionEnter2D) again and again spawning countless number of other fractures, which slows the game down to a halt.

    So the question: Is there a way to exclude nested fractures (fractured parts fracturing). I know there is damage and multipliers, but im looking for a one liner for visual candy.

    Question2: What to do if i want to reuse the fractured asset? (Like a player which got a limb cut off). Do i have to manually disable the original object, instantiate the sprite representation, and fracture that?
     
    Last edited: Jan 6, 2023
  6. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,412
    1 - If your custom fracturing script is on your arrow, I'm not sure why each fractured part would then fracture each other. They don't have your script on, right? If it's the arrow that keeps hitting the fractured pieces, then you could check the destructible object's AlphaRatio value before fracturing (e.g. 1 means it hasn't been damaged yet, and lower values like 0.5 means it's half damaged).

    2 - I'm not sure I understand the question. Do you mean you want to prevent the player object/script/etc from being duplicated when it gets fractured or sliced (i.e. so you only ever have one player in your scene)? If so, you could use the fixture system and attach it to the head or somewhere, and put your player script on that. The fixture will only ever be attached to one destructible object even after splitting/fracture, so it can prevent duplication. Just keep in mind if you destroy the pixel the fixture is on, the fixture will be destroyed.
     
  7. Toastbyte

    Toastbyte

    Joined:
    Sep 1, 2016
    Posts:
    54
    Hello @Darkcoder
    Thanks for this incredible asset and your helpful answers in the forum!

    I have a very specific question. Hopefully you can help me.

    In the end of the Search() function of D2dSplitter.cs:
    I want to take all information from an island, add this information to another island (basically have 2 islands in 1) and finally delete the old island from the list.
    This is because later during TrySplit(), I don't want the old island to be split. Instead, the old island should be treated just like the first island in the islands[] list, which triggers "isLast = true" in SplitNext() of D2dDestructible.cs.

    Another way to explain this: I want specific islands to not be considered during the splitting process (as if splitting ) and came up with the idea of combining all the islands that should not be split into one "cluster" of islands. This cluster of islands -being in just one entry in the islands[] list- would then trigger the isLast = true boolean and not be considered during splitting.

    Here is what I tried doing, however it does not work as expected and I'm not sure if I'm completely missing something. I would really appreciate your input!!!

    Code (CSharp):
    1. //1. Scan for islands that should not be considered when splitting
    2. //(all islands marked as .isGround = true should not be considered when splitting)
    3.  
    4. //List that stores all indexes of the .isGround marked islands in islands[] list
    5. List<int> indexesOfMarkedIslands = new List<int>();
    6.  
    7. for(int i = 0; i < islands.Count; i++)
    8. {
    9.     if (islands[i].isGround)
    10.     {
    11.         indexesOfMarkedIslands.Add(i);
    12.     }
    13. }
    14.  
    15. //2. Add all information from the marked island to another island. Repeat for every marked island.
    16. //Here, I chose the first marked island as the "cluster" that should contain the information of all added islands: islands[indexesOfMarkedIslands[0]].
    17.  
    18. for (int i = 1; i < indexesOfMarkedIslands.Count; i++)
    19. {
    20.     for(int a = 0; a < islands[indexesOfMarkedIslands[i]].Lines.Count; a++)
    21.     {
    22.         islands[indexesOfMarkedIslands[0]]
    23.             .Lines.Add(islands[indexesOfMarkedIslands[i]].Lines[a]);
    24.     }
    25. }
    26.  
    27. //3. Finally, delete all islands that were transfered in step 2 to islands[indexesOfMarkedIslands[0]], since they are not needed anymore and should not be considered during the splitting process.
    28. for(int i = 1; i < indexesOfMarkedIslands.Count; i++)
    29. {
    30.     islands.Remove(islands[indexesOfMarkedIslands[i]]);
    31. }
    Or is there maybe a better way of ignoring certain islands during the splitting process?
     
    Last edited: Jan 7, 2023
  8. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,412
    Islands contain more than just the Lines list, you must also update the Count (pixel count), and MinX/MaxY/MinY/MaxY (pixel boundary) values, otherwise the split islands won't generate correctly.

    You can see lines 301-305 of D2dSplitter::Search for how this is done when adding new lines to an island.

    As long as the final island list has unique lines and the correct count + boundary then splitting should work with any kind of island modifications you perform.

    Also, keep in mind the order of the islands will be more or less scanline order, so combining the islands based on their list index may not be so useful. You might want to check their Count or boundary center or something, but it depends on what you're trying to do.
     
    Toastbyte likes this.
  9. elvin0272

    elvin0272

    Joined:
    Feb 16, 2021
    Posts:
    13
    Hello. I use D2DRequirements and Alpha Ratio from 0 to 1. For some reason, sometimes the method is called 2 times. I need to make the method called only 1 time. How can I do this?
     
  10. elvin0272

    elvin0272

    Joined:
    Feb 16, 2021
    Posts:
    13
    Hello @Darkcoder . Is this forum being checked? My deadlines are burning. I never figured it out. Where else can I write? Do you have a discord channel or telegram?
     
  11. elvin0272

    elvin0272

    Joined:
    Feb 16, 2021
    Posts:
    13
    My problem has not been solved. How can I turn to the event for cutting sprite and impose my method on it ONCE. Is this asset no longer supported?
     
  12. singlarijul24

    singlarijul24

    Joined:
    Jan 4, 2023
    Posts:
    1
    Hey! I just imported this asset and I am having issues with the d2d splitter thing. I want to slice the objects and i was just testing to see if simple slicing works with a sprite circle in my game scene, but for some reason it doesnt. The demo scene with the asset works fine, i created a new scene and tested it works fine.
    I added circle sprite and then made it d2d splitter component, added a drag to slice game object as well. is there anything i am missing?
     
  13. alahaboba

    alahaboba

    Joined:
    Dec 30, 2022
    Posts:
    2
    Hello, in order to heal sprite, it must be damaged first. How can I just make a sprite completely damaged when start the game. I read the comment about same problem, but it is in 2017, not sure that can help much. Many thanks
     
  14. jarbleswestlington_unity

    jarbleswestlington_unity

    Joined:
    Dec 6, 2017
    Posts:
    32
    I've run into a problem and was wondering if you had a suggestion. I have a project where all of a sudden the collider child of a gameobject with a d2d polygon is invisible, and clicking on the collider child freezes my editor with no error. I tried reimporting the d2d asset, but the project seems to still be corrupted. Any ideas?
     
  15. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,412
    Sorry for the late reply.

    The D2dRequirements component stores an internal 'met' value, which changes based on your requirement settings. If this met value changes to true then the OnRequirementsMet event is invoked. Since this met value is by default false, if your initial requirements are true, then when you start your game it will immediately fire the event. So perhaps this causes unexpected behavior in your game? If so, you can enable the inspector debug mode and enable met in edit mode. I can't see how it would get called twice though. You could add a breakpoint to the met value change code and debug it to see when and why it's changing.


    I'm not sure I understand the issue. If you can prepare a really simple demo scene and send it to me then I can test it.


    The heal feature heals toward the 'HealSnapshot' you specify, so you should configure your healed sprite first, make a snapshot of it, and then replace your D2dDestructibleSprite's Shape with a destroyed version of your sprite. Keep in mind the sprite must be the same size as the non-destroyed version so the heal snapshot resolution is the same.


    If it's just one object then can you rebuild it? If it's too complex then you could try turning it into a prefab and see if that fixes it. If not, maybe enabling the debug inspector or removing the inspector tab allows you to select it? If not, you could try putting it in an empty scene and deleting the child by manually editing the scene file with a text editor.
     
  16. alahaboba

    alahaboba

    Joined:
    Dec 30, 2022
    Posts:
    2
    why my destructible sprite dont have alpha count although it display normal on my game, i meant everything work perfectly like it can be damaged but the alpha count always 0 here is the image
     

    Attached Files:

  17. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,412
    Does this issue occur in the editor? Or only in a build? On a specific device?
     
  18. jarbleswestlington_unity

    jarbleswestlington_unity

    Joined:
    Dec 6, 2017
    Posts:
    32
    Is there any reason a d2d object is fracturing like this? With correct collisions but weirdly segmented and duplicate portions of its sprite? I changed very little from the shatter demo.

    upload_2023-4-28_15-2-48.png
     
  19. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,412
    Is your sprite part of an atlas? If so, could you try without an atlas? If not, could you send me a private message or email with a unitypackage of this sprite + a demo scene with it configured for destruction.
     
  20. jarbleswestlington_unity

    jarbleswestlington_unity

    Joined:
    Dec 6, 2017
    Posts:
    32
    Perfect, resolved. Last question: When an object fractures, is there a way to set its pivot closer to the center of the collision? The default pivot seems to be that of the original gameobject:
    upload_2023-5-1_10-54-37.png
     
    Darkcoder likes this.
  21. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,412
    It might be possible, but I'm out of town for the next week so I can't say for sure. I'll look into it after I get back.
     
  22. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,412
    I had a quick look into this and it seems like it would be fairly difficult to implement.

    In terms of physics this doesn't matter because Rigidbody2D objects rotate about their own pivot based on the colliders, so this would only matter for custom rotation or scaling, in which case you would have to do the same as the physics system and base your rotation/scaling on the center of the destructible object. You could directly read the Rigidbody2D's centerOfMass for this. If you don't have one then you can call your D2dDestructibleSprite component's AlphaToLocalMatrix.MultiplyPoint(new Vector2(0.5f, 0.5f)) method, where xy of the returned vector is the center in local space.
     
  23. jarbleswestlington_unity

    jarbleswestlington_unity

    Joined:
    Dec 6, 2017
    Posts:
    32
    So the reason I asked is that when I use torque on a rigidbody 2D, it seems each fractured piece will simulate rotating around the pivot. Is this unusual behavior, and/or do you happen to have any suggestions as to a fix?

     
  24. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,412
    Sorry for the late reply.

    I've attached a demo scene showing that Rigidbody2D torque is applied to the center of mass, so it doesn't matter where the pivot point is. Just click the object to fracture it, and you will see each part rotates around its center, even though all objects have the same actual pivot.

    Not sure what's going on in your video. Do you have some kind of custom rotation script that uses the Transform's rotation? If so, you must use the Rigidbody2D's centerOfMass to both translate and rotate your object around this axis rather than relying on the Transform's origin.
     

    Attached Files:

  25. jarbleswestlington_unity

    jarbleswestlington_unity

    Joined:
    Dec 6, 2017
    Posts:
    32
    Nope, just a simple add torque 2D impulse. I have a splitter and a fracturer attached. It looks like the center of mass of each piece is being set incorrectly somehow. When I manually the center of mass to the bounds center of the collider2D, it is still incorrect somehow. I'm going to keep testing things
     
    Last edited: Jun 14, 2023
  26. Humusk

    Humusk

    Joined:
    Jan 8, 2021
    Posts:
    6
    Hi!

    I want to buy the asset but I have a question first about how splitting objects work.

    In the documentation it says:

    When a destructible sprite splits in half using the D2dSplitter component, it will be cloned/instantiated to make the other side, and D2dSplitter will automatically separate the destruction data between the two destructible sprites.

    My question is about how the data is separated, specially the mass of objects. If I split an object in half is the mass going to be half for each object?

    I need that to happen to be able to correctly implement the mechanic I want.

    Thanks!
     
  27. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,412
    If your destructible object uses the D2dPolygonCollider component and your Rigidbody2D has UseAutoMass enabled, then all separated parts will be given mass based on the area of the colliders. If you don't enable UseAutoMass, then you can add the D2dCalculateMass component, which will override the Rigidbody2D Mass setting based on the amount of solid pixels remaining in the current part of the destructible object.
     
  28. TibiTibith

    TibiTibith

    Joined:
    Mar 8, 2015
    Posts:
    29
    Just wanted to say this asset is incredible and that I've fixed the issues I've been telling you about in the emails, Carlos (I was incorrectly creating a sprite from a texture with wrong default settings and assigning it to my Shape and then firing Rebuild().) All good now!


     
    Darkcoder likes this.
  29. kentaruu97

    kentaruu97

    Joined:
    Nov 15, 2022
    Posts:
    1
    Hi @Darkcoder, I created a game using this package and used the D2D Repeat Stamp Object to destroy the target Object. It worked perfectly on normal Android devices, except the Samsung Galaxy A14, it's very laggy and has a dropped framerate. I tried to optimize the object as much as I could, with the Adaptive Performance Android package installed, but it's not helping at all.
    Can you find me away to fix this problem?
     
  30. nguyenhoangphuongofficial

    nguyenhoangphuongofficial

    Joined:
    Jul 5, 2021
    Posts:
    6
    I wanna to ask how to use your plugin to clip a custom object on a terrain like that:
     
  31. blaher

    blaher

    Joined:
    Oct 21, 2013
    Posts:
    80
    Thanks for the quick email response regarding adding the needed D2D code to custom shaders (and your amazing Space Game Toolkit).

    What I would really love to see is D2D shader integration on the fly somehow? It isn't a big deal for a simple shader to manually add the needed D2D properties/frag code -- but adding the needed code for frag/surface to the HDRP/Lit shader... not so easy...
     
  32. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,412
    I don't have this device so I can't say for sure. If it works fine on most other devices then maybe this device just has a very weak CPU. All destruction is implemented on the CPU, and D2dRepeatStamp applies destruction every 'Delay' seconds, so you could increase this if possible. If you've already optimized all scripts to the max then there's not much else you can do except make your destructible objects smaller, or perhaps split them up, or remove features from them like the splitter if you use it.


    I'm not sure what you mean by clip a custom object. If you mean a custom shape, then you can achieve this using the stamp settings. For example, the D2dTapToStamp component allows you to set a 'StampShape', which can be any texture like an outline of your wooden beam.


    This would be nice, but making an auto shader upgrader to make these changes is incredibly difficult.
     
  33. blaher

    blaher

    Joined:
    Oct 21, 2013
    Posts:
    80
    Do you know a reasonably repeatable process for adding the needed D2D bits to shadergraph shaders? I notice a "compile and view code" option for a shadergraph... and seeing "compiling x/5300 variants" I punted on waiting...
     
  34. Dimension_B

    Dimension_B

    Joined:
    Oct 22, 2022
    Posts:
    1
    Thanks for your great assets@Darkcoder.
    I'm trying to create a customed sprite by mesh,using OverrideGeometry.But after adding D2dDestructibleSprite,my sprite renderer just show nothing.And if calling rebuild, the sprite becomes a rectangle,ignoring overrideGeometry.
    Is it possible to use customed sprite created by mesh(in runtime,allowing customed shaped in game)?

    Code (CSharp):
    1. spriteR = gameObject.GetComponent<SpriteRenderer>();
    2.  
    3. // Create a blank Texture and Sprite to override later on.
    4. var texture2D = new Texture2D(640, 640);
    5. spriteR.sprite = Sprite.Create(texture2D, new Rect(0, 0, texture2D.width, texture2D.height),
    6.     new Vector2(0.5f,0.5f), 100);
    7.  
    8. Mesh mesh = GetComponent<PolygonCollider2D>().CreateMesh(false, false);
    9. Vector2[] vertices2D = new Vector2[mesh.vertices.Length];
    10. float scale = transform.localScale.x;
    11. for (int i = 0; i < vertices2D.Length; i++)
    12.     vertices2D[i] = (mesh.vertices[i] - transform.position) * 100+new Vector3(320,320);
    13. ushort[] triangles = new ushort[mesh.triangles.Length];
    14. for (int i = 0; i < triangles.Length; i++)
    15.     triangles[i] = (ushort)mesh.triangles[i];
    16. Destroy(GetComponent<PolygonCollider2D>());
    17.  
    18. spriteR.sprite.OverrideGeometry(vertices2D, triangles);
    19. D2dDestructibleSprite d2dSr =  gameObject.AddComponent<D2dDestructibleSprite>();
    20. d2dSr.Rebuild();
    upload_2024-2-5_17-25-17.png
     
  35. Darkcoder

    Darkcoder

    Joined:
    Apr 13, 2011
    Posts:
    3,412
    The D2dDestructibleSprite component already uses OverrideGeometry (line 319) to clip out the destroyed border regions. This is especially useful when using splitting to avoid overdraw. If you need some custom geometry then you could try commenting out this line, or modifying the code.
     
    Dimension_B likes this.
  36. dmitriyl

    dmitriyl

    Joined:
    Oct 14, 2015
    Posts:
    5
    Wazap,

    I'm using Splitable objects with Fixtures (from demo scene 13 break off) to drop some loot Item when Fixture is destroyed.

    But I found that "D2D Fixture group"."On all Detached" can be called multiple times:
    - when object hasn't been split and pixel underneath the Fixture was destroyed (OK scenario)
    - when object is split then its Fixture can be Re-attached to newly Split (Cloned) part of object (most probably this is done here Destructible2D.D2dFixture.TryFixTo), so "On all Detached" is called on Original object (because its Fixture was moved to newly split part and original object lost all its fixtures). Then "On all Detached" may be called once more or multiple times again during further splitting scenarios until Fixture is actually destroyed.

    Any suggestion how to precisely detect when Fixture is actually destroyed?
     
  37. dmitriyl

    dmitriyl

    Joined:
    Oct 14, 2015
    Posts:
    5
    For now added event into D2dFixture

    Code (CSharp):
    1.    
    2.  
    3. // in D2dFixture class:
    4.  
    5. public UnityEvent OnDestroyed { get { if (onDestroyed == null) onDestroyed = new UnityEvent(); return onDestroyed; } } [SerializeField] public UnityEvent onDestroyed;
    6.  
    7. // ...
    8.  
    9. private void DestroyFixture() {
    10.       try {
    11.         onDestroyed?.Invoke();
    12.       } catch (Exception e) {
    13.         Debug.LogException(e);
    14.       }
    15.             CwHelper.Destroy(gameObject);
    16.         }
    17.  
    18. // in stage generator
    19.  
    20.       var fixture = rock.GetComponentInChildren<D2dFixture>();
    21.       fixture.OnDestroyed.AddListener(() => {
    22.         // spawn item
    23.       });
    24.  
    25.  
    26.  
    27.  
     
  38. starfoxy

    starfoxy

    Joined:
    Apr 24, 2016
    Posts:
    184
    Anyone know of a way to explode a sprite into even squares or is it all random-looking fragment pieces?
     
  39. RequiemOfTheSun

    RequiemOfTheSun

    Joined:
    Sep 16, 2012
    Posts:
    4
    Is there a good way to fracture all the layers of a object built like the fish in the pierce demo?

    I've got two destructible layers then a skeleton. I'd like everything to held together until the skeleton fractures and have that fracture split off with all the above layers still attached to their piece of the skeleton.

    More detail, I'm creating destructible vehicles with D2D sprites buried down in the children of the object. I don't want to prematurely split off my engines or anything so it's just taking sprite impacts until the vehicle is so damaged and dies then I'd like to ragdoll the vehicle by fracturing it and letting the bits all fly around.

    Edit:
    Other point, I just got to save / loading this, I see D2dSnapshotData Load function is empty. This will be really nice to have once it's in. I'll fill out the function as best I can and hope for no issues but mentioning just because I was going oh sweet everything I need is right here, followed by, aw dang.

    Hands down the most useful and exciting asset I've bought btw. Great work!
     
    Last edited: Mar 12, 2024
  40. _DARKER_

    _DARKER_

    Joined:
    Oct 14, 2020
    Posts:
    1
    Hello, I selected the recently updated "Used by composite" option, but when I add a composite collider and switch to play mode, the composite collider is removed. Is this the correct behavior? If so, how should I use composite collider?
     
  41. thong381998

    thong381998

    Joined:
    Oct 17, 2022
    Posts:
    1
    Hello @Darkcoder, thanks for great asset. I have a scenario:
    Let's say I have a land that can be destructible, and a bomb that cause an explosion (with custom predefined shape). The explosion damage only an area of the land and I want that area to be fractured into pieces. Can I do that with D2D?. I know how to fracture using the D2DFracturer, but dont know how to split the explosion area from the land. Can the D2DSplitter do that?

    Thanks!