Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Jelly Sprites - Soft body sprite physics system

Discussion in 'Assets and Asset Store' started by mrsquare, Dec 5, 2013.

  1. vonchor

    vonchor

    Joined:
    Jun 30, 2009
    Posts:
    249
    Ran into an issue with 2DTK: I needed an animated sprite, that is, I want to use the TK2D Sprite Animator component. I tried attaching that to a "Toolkit 2D Jelly Sprite" and got the following error:

    Code (csharp):
    1. Sprite not found attached to tk2dSpriteAnimator.
    2. UnityEngine.Debug:LogError(Object)
    3. tk2dSpriteAnimator:get_Sprite() (at Assets/TK2DROOT/tk2d/Code/Sprites/tk2dSpriteAnimator.cs:137)
    4. tk2dSpriteAnimator:OnEnable() (at Assets/TK2DROOT/tk2d/Code/Sprites/tk2dSpriteAnimator.cs:116)
    Basically, the animator can't find the sprite. Looking at your tk2dJellySprite.cs it seems the issue is that that class isn't based off of BaseSprite - seems like you're just making a wrapper. Works ok for a static sprite but not if you want an animation.

    I'm going to try to see if I can find a workaround... or am I doing something wrong?
     
  2. tobln

    tobln

    Joined:
    Jul 5, 2013
    Posts:
    5
    hello mrsquare, thx for the improvements. there seems to be a problem when the used Unity Sprite has an Packing Tag set. I couldn't really find a way to solve it for now i will leave it out of the atlas but maybe you could take a look :)

    and again, great plugin
     
  3. kilik128

    kilik128

    Joined:
    Jul 15, 2013
    Posts:
    909
    it's possible to use for deform only ? manualy
     
  4. Mr_Mendel

    Mr_Mendel

    Joined:
    Dec 31, 2013
    Posts:
    19
    Hi when using I get quite a lot of spiking coming out the the sprites especially when they fall off things?

    As seen here.

    $Test.png
     
  5. Mr_Mendel

    Mr_Mendel

    Joined:
    Dec 31, 2013
    Posts:
    19
    Changed some settings and fixed it.
     
  6. Mr_Mendel

    Mr_Mendel

    Joined:
    Dec 31, 2013
    Posts:
    19
    Hi,
    In my game I need to return the sprite back to an old position and get rid of any force applied. As there is a List of references is there any easy way to access all of them?

    I thought about adding a copy and reset code to it but thought there might be an easier way.


    Edit - Worked it all out works great now thanks!


    Thx
    Mike
     
    Last edited: Feb 11, 2014
  7. armanigt

    armanigt

    Joined:
    Feb 10, 2014
    Posts:
    2
    i am trying to start of my jelly sprite rotated, but it seems to always revert back to 0 rotation when i run the scene - is this a bug?
     
  8. JAMiller

    JAMiller

    Joined:
    Apr 2, 2009
    Posts:
    78
    I came here to ask the same thing, specifically: I am hoping I can JellySprotes on the XZ Plane, is this possible?
     
  9. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    Hi all,

    Sorry, yeah, tk2DJellySprite isn't a subclass of tk2DSprite, it just uses a 2D Toolkit sprite collection for the texture. The idea was to have a nice generic base JellySprite class, and then have the UnityJellySprite/tk2DJellySprite classes to just control how the initial texture acquisition is done.

    I helped out somebody a few weeks back with animating a Jelly Sprite - you should be able to change the texture dynamically by doing something like this:

    Code (csharp):
    1.  
    2. jellySprite.m_SpriteId = newAnimationFrameID;
    3. jellySprite.ReInitMaterial();
    4. jellySprite.UpdateTextureCoords();
    5.  
    so if you're happy rolling your own little animation frame manager class then you should be able to get it animating fairly easily.

    I'll definitely have a look at adding proper support though, it'd be nice to be able to associate animation data with a Jelly Sprite and have it automatically manage animating between frames.

    That is a bug, yep - sorry, will take a look at a fix for that tonight.

    Cool - thanks for letting me know, will take a look :)

    Possibly - can you expand on that a bit? So rather than being springy, the bodies would just stay still once they got squashed?
     
    Last edited: Feb 11, 2014
  10. Mr_Mendel

    Mr_Mendel

    Joined:
    Dec 31, 2013
    Posts:
    19
    Hi,
    Is there any easy way to set the position of the sprite. Your system is great but as now I cannot use simple commands to move the object etc.. I added a copy location restore location code.

    Thx Mike
     
  11. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,286
    Amazing software :)

    Is there any news on the rotation reset problem, my camera is always at 90 degrees and sprites keep auto rotating to 0

    Is there a quick fix, like some lines of code we could add and fix it ?
     
  12. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    This has now been fixed in the latest update - just download v.1.18 from the asset store :)

    If you want to manually move the sprites, you need to move the Jelly Sprite reference points (ie. the physics bodies that the Jelly Sprite uses to collide with things) - the visible mesh will then also move to the correct position.

    This will do the trick:

    Code (csharp):
    1.  
    2. void MoveJellySpriteToPosition(JellySprite jellySprite, Vector3 position, bool resetVelocity)
    3. {
    4.     Vector3 offset = position - jellySprite.CentralPoint.GameObject.transform.position;
    5.  
    6.     foreach(JellySprite.ReferencePoint referencePoint in jellySprite.ReferencePoints)
    7.     {
    8.         if(!referencePoint.IsDummy)
    9.         {
    10.             referencePoint.GameObject.transform.position = referencePoint.GameObject.transform.position + offset;
    11.  
    12.             if(resetVelocity)
    13.             {
    14.                 if(referencePoint.Body2D)
    15.                 {
    16.                     referencePoint.Body2D.angularVelocity = 0.0f;
    17.                     referencePoint.Body2D.velocity = Vector2.zero;
    18.                 }
    19.                 else if(referencePoint.Body3D)
    20.                 {
    21.                     referencePoint.Body3D.angularVelocity = Vector3.zero;
    22.                     referencePoint.Body3D.velocity = Vector3.zero;
    23.                 }
    24.             }
    25.         }
    26.     }
    27. }
    28.  
     
    Last edited: Feb 12, 2014
  13. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,286

    Unfortunalty i have done some modifications in the demo scenes, is there a specific file or files i should change to make it work ?

    I would download in a empty project and then insert only the needed files for example in order to control the changes
     
  14. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    Sure - just make these changes to Start() in JellySprite.cs (hope this notation makes sense! just insert the bits marked by ROTATION FIX and place them at the same point in your file :))

    Code (csharp):
    1.  
    2.     /// <summary>
    3.     /// Start this instance.
    4.     /// </summary>
    5.     void Start()
    6.     {
    7.         if(IsSpriteValid())
    8.         {
    9.             ....
    10.  
    11.             if(Application.isPlaying)
    12.             {
    13.                 // START ROTATION FIX
    14.                 Vector3 spriteAngle = this.transform.eulerAngles;
    15.                 this.transform.eulerAngles = Vector3.zero;
    16.                 // END ROTATION FIX
    17.  
    18.                 ...
    19.  
    20.                 CalculateInitialOffsets();
    21.                 InitMass();
    22.                 CalculateWeightingValues();
    23.                 SetupCollisions();
    24.  
    25.                 m_ReferencePointOffsets = new Vector3[m_ReferencePoints.Count];
    26.  
    27.                 // START ROTATION FIX
    28.                 foreach(ReferencePoint referencePoint in m_ReferencePoints)
    29.                 {
    30.                     if(!referencePoint.IsDummy)
    31.                     {
    32.                         Vector3 referencePointPosition = referencePoint.GameObject.transform.position;
    33.                         Vector3 centralPointPosition = this.transform.position;
    34.                         referencePoint.GameObject.transform.position = centralPointPosition + (Quaternion.Euler(spriteAngle) * (referencePointPosition - centralPointPosition));
    35.                     }
    36.                 }
    37.  
    38.                 m_CentralPoint.GameObject.transform.eulerAngles = spriteAngle;
    39.                 // END ROTATION FIX
    40.             }
    41.         }
    42.     }
    43.  
     
  15. nasos_333

    nasos_333

    Joined:
    Feb 13, 2013
    Posts:
    13,286
    Thanks :), that is much easier, doing mass upgrade in anything in my project gives me a headacke :)

    BTW, did i mention that your system is amazing ? :), i am sure will make a hell of a difference in my project, really really cool job

    EDIT: Is there a way to tell the sprites to hop to another direction ? Now they are propery rotated by they jump along the line of the previous 0 degrees rotation, is there a way to align that motion too ?

    EDIT2: Just noticed there is a BlobBehaviour.cs attached to blobs :), i guess i will modify this one

    EDIT3: I cant seem to be able to remove the axis motion constraint, is it integraded in the main blob code ? I see the contraint in the Reference Points, where are those created in code ?

    EDIT4: Ok, did it, i had to introduce a vector3 Addforce and lock the X axis in the main code, now it is easy :)
     
    Last edited: Feb 12, 2014
  16. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    So a few people have asked whether it is possible to animate a Jelly Sprite in a similar way to how you would animate a regular Unity sprite. I'm still searching for a nice' way of doing this, but the documentation on the sprite animator is quite sparse. In the meantime though, you can very easily do something like this:

    - Add a Jelly Sprite to your scene
    - Add an animated Unity Sprite to your scene
    - Create a new script called JellySpriteAnimator.cs (code below) and attach it to the Unity Sprite.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class JellySpriteAnimator : MonoBehaviour
    5. {
    6.     public UnityJellySprite jellySprite;
    7.     SpriteRenderer spriteRenderer;
    8.    
    9.     void Start ()
    10.     {
    11.         spriteRenderer = this.GetComponent<SpriteRenderer>();
    12.     }
    13.  
    14.     void Update ()
    15.     {
    16.         if(jellySprite  spriteRenderer)
    17.         {
    18.             // If the sprite has changed...
    19.             if(jellySprite.m_Sprite != spriteRenderer.sprite)
    20.             {
    21.                 // Update the Jelly Sprite with the new sprite frame
    22.                 jellySprite.m_Sprite = spriteRenderer.sprite;
    23.                 jellySprite.ReInitMaterial();
    24.                 jellySprite.UpdateTextureCoords();
    25.             }
    26.         }
    27.     }
    28. }
    29.  
    - In the inspector, link the Jelly Sprite to the JellySpriteAnimator script.

    And that's it! The Unity sprite acts as a sort of control object, and will automatically update the Jelly Sprite to use whatever sprite frame it is currently displaying :) You'll just need to move the Unity sprite somewhere off-screen so you can't see it.

    (oh, and make sure that all animation frames have exactly the same dimensions or else you'll run into issues)
     
  17. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    I just downloaded your plugin and it looks fantastic. I noticed an issue, which isn't necessarily your fault as it is a bug the latest version of Unity 4.3 seems to have. I spoke with 2DToolkit about the same issue here at the very bottom of the forum post:

    http://2dtoolkit.com/forum/index.php/topic,3114.msg17077.html#msg17077

    In your script JellySpriteEditor.cs file for the SortingLayer popup in the editor you use a check to get all the SortingLayerNames into an array to show them in the editor. This is fine, except there seems to be a bug where Unity returns the Default sorting layer as a blank string "", instead of "Default" sometimes, which cause the user to never be able to set the SortingLayer to Default on the Jelly Sprites. The solution or "temporary hack", which I discussed with 2D Toolkit is to add in this code at the top of the function SortingLayerNamePopup:

    Code (csharp):
    1.  
    2. string[] names = GetSortingLayerNames();
    3.        
    4. //BEGIN MY MODIFIED CODE
    5. //If value is not in the array set it to Default
    6. string finalValueToUse = value;
    7. int hasValueInArray = System.Array.IndexOf(names, finalValueToUse);
    8.  
    9. if(hasValueInArray == -1)
    10. {
    11.     finalValueToUse = "Default";
    12. }
    13. //END MY MODIFIED CODE
    Then from there everywhere you have the value variable replace it with finalValueToUse:

    Code (csharp):
    1. return EditorGUILayout.TextField(label, finalValueToUse);
    2.  
    3. if (names[i] == finalValueToUse)
    This is just a minor bug, which hopefully Unity will fix soon, but I thought I'd point that out to you to help make your already great product as annoyance free as possible for now. Thanks.
     
  18. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    Ah, awesome, thanks for the tip! Hadn't noticed that - I'll take a look tomorrow and can hopefully roll out a little update at some point over the weekend :)
     
  19. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    No problem. I saw in your setup video that we have to set the soft body on a layer that can't collide with itself due to an issue with Unity not having the ability to not collide with themselves in 2D. I was wondering if there was any progress on this issue, or if it was fixed? Your soft body system is so nice and great to work with we'd love to have more than one soft body jelly sprite in our scene at once without a having a layer for every one of them.

    Thanks for the great plugin.
     
  20. JAMiller

    JAMiller

    Joined:
    Apr 2, 2009
    Posts:
    78
    I'm loving JellySprites!

    I do have two issues I haven't figured out yet, any advice would be greatly appreciated:

    1. Looking for a way to make a JellySprite seem deflated or softer at runtime. I tried setting some of the spring stiffness through m_Stiffness, etc. but they did not see to have any effect. The only one that seemed to work was m_GravityScale, which made it look flattened/deflated, but also makes it fall faster.

    2. How can I rotate a JellySprite? I notice on page 1 it says there is rotation support, but I haven't found the way to do it. I've tried rotating actual JellySprite's transform. and the central body with no real results (yes lo. Body2D AddTorque works to do flips and spinning, but what if I want to rotate towards a specific angle over time? For example roll upside down 180 when dead.

    Any help would be greatly appreciated!
     
  21. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    Nope, not yet I'm afraid :( I'm keeping tabs on the bug (http://feedback.unity3d.com/suggest...tal-for-proper-one-way-platformers-in-unity2d) as I want to get it fixed ASAP, but there hasn't been any response from Unity yet as far as I can tell.

    Spring stiffness is definitely the value to alter if you want to make them look deflated. If you're trying to adjust the stiffness via code, you'll need to call this after setting the new value:

    Code (csharp):
    1.  
    2. jellySprite.UpdateJoints();
    3. jellySprite.WakeUp();
    4.  
    otherwise the changes won't have any effect.

    I suspect that you need to rotate the central body but also rotate all the reference points around the central body in order to make the rotation 'stick'. Try something like this:

    Code (csharp):
    1.  
    2. // Work out the amount you want to rotate by
    3. Vector3 angleChange = new Vector3(0.0f, 0.0f, 200.0f * Time.deltaTime);
    4.  
    5. // Rotate the central body by the required amount
    6. jellySprite.CentralPoint.GameObject.transform.localEulerAngles = jellySprite.CentralPoint.GameObject.transform.localEulerAngles + angleChange;
    7.  
    8. // Now go through all the reference points and orbit them around the central body by the required amount
    9. foreach(JellySprite.ReferencePoint referencePoint in jellySprite.ReferencePoints)
    10. {
    11.     if(!referencePoint.IsDummy)
    12.     {
    13.         Vector3 referencePointPosition = referencePoint.GameObject.transform.position;
    14.         Vector3 centralPointPosition = this.transform.position;
    15.         referencePoint.GameObject.transform.position = centralPointPosition + (Quaternion.Euler(angleChange) * (referencePointPosition - centralPointPosition));
    16.     }
    17. }
    18.  
    Just trying that in the demo scene and it seems to do the trick :) I'll add that in as a helper function for the next update.
     
    Last edited: Mar 1, 2014
  22. JAMiller

    JAMiller

    Joined:
    Apr 2, 2009
    Posts:
    78
    Thanks for the reply!

    Changing stiffness then using UpdateJoints and WakeUp did the trick!

    However, I tried your rotating code and it didn't seem to effect any sprites when using 2D Physics mode. When unchecking 2D I noticed it seemed to work, but so far in 2D, no rotation. Could I be configuring it wrong?

    Looking forward to all future updates on JellySprites, a helper function for rotating would be great!
     
  23. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    Thats weird - yeah, I only tested in 3D mode. I'll give it a try in 2D and see if I can work out whats up :)
     
  24. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    Seems okay for me in 2D mode - I've basically added this function to JellySprite.cs:

    Code (csharp):
    1.  
    2. /// <summary>
    3. /// Rotate the whole jelly sprite by the given angle
    4. /// </summary>
    5. public void Rotate(float angleChange)
    6. {
    7.     Vector3 eulerAngleChange = new Vector3(0.0f, 0.0f, angleChange);
    8.  
    9.     // Rotate the central body by the required amount  
    10.     CentralPoint.GameObject.transform.localEulerAngles = CentralPoint.GameObject.transform.localEulerAngles + eulerAngleChange;
    11.        
    12.     // Now go through all the reference points and orbit them around the central body by the required amount
    13.     foreach(ReferencePoint referencePoint in ReferencePoints)          
    14.     {          
    15.         if(!referencePoint.IsDummy)        
    16.         {              
    17.             Vector3 referencePointPosition = referencePoint.GameObject.transform.position;             
    18.             Vector3 centralPointPosition = this.transform.position;            
    19.             referencePoint.GameObject.transform.position = centralPointPosition + (Quaternion.Euler(eulerAngleChange) * (referencePointPosition - centralPointPosition));              
    20.         }          
    21.     }
    22. }
    23.  
    then I've replaced the code in the Update function of BlobBehaviour.cs with this:

    Code (csharp):
    1.  
    2. void Update ()
    3. {
    4.     m_JellySprite.Rotate(200 * Time.deltaTime);
    5. }
    6.  
    and then in the demo scene
    - Change the kinematic RigidBody/BoxCollider components on the 'Floor' object to be a kinematic RigidBody2D/BoxCollider2D,
    - Set all the Jelly Sprites to 2D mode.


    It might possibly not be working on your Jelly Sprites if you don't have 'Lock Rotation' enabled? The pink blob in the demo is using the 'Triangle' layout with free rotation and gets stuck after about 180 degrees as, presumably, rotating the bodies is pushing the top reference point into the Floor collider and the physics system is just resolving it back out again. If that's the case, you could try just temporarily enabling rotation lock for the period that you want to be manually rotating the Jelly Sprite, and then turn it off again afterwards.

    Code (csharp):
    1.  
    2. jellySprite.m_LockRotation = true;
    3. jellySprite.UpdateRotationLock();
    4.  
     
  25. JAMiller

    JAMiller

    Joined:
    Apr 2, 2009
    Posts:
    78
    Hello, thanks again for your replies! I just figured out it was a the Attach Neighbors (at least in 2D mode) was causing it not rotate and always be upright.... after turning off attach neighbors all teh rotation seems free finally! Thanks, I will keep going at it and try your suggestions.
     
  26. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    For people stumbling into this thread looking for a 3D Jelly Sprites-style system, here's a little sneak peek of Jelly Mesh, which should (hopefully) be out within the next week or so on the Asset Store:

    Webplayer Demo

    $JellyMeshScreenshot1.png

    One sentence pitch: It's Jelly Sprites but with 3D meshes :)

    Obviously there is a certain amount of shared tech between the two projects (which I'm not trying to disguise, what with the similar name/branding etc.), but I hope that people won't begrudge me too much for releasing it as a separate asset. It's mainly because I don't want to increase the price of Jelly Sprites (I think it's currently sitting at a pretty good point in terms of value vs. features), and I don't expect there to be too much crossover as people aren't generally going to be needing both a 3D and a 2D version simultaneously.

    *edit* Wow, that was quick - approved already :)

    https://www.assetstore.unity3d.com/#/content/15685
     
    Last edited: Mar 4, 2014
  27. OzDave

    OzDave

    Joined:
    May 19, 2008
    Posts:
    144
    I have my eye on this one ( 2d sprites ).
    Is there a video on the triangular setup "rig"..?
    I am keen as mustard, but want to keep the complexity down for low spec mobile usage.
     
  28. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    Hey, no video specifically for that, but happy to answer any questions on here :)

    The triangle version is super simple - there's basically just a central physics body and then three physics bodies for the three corners of the triangle. So a total of 4 bodies, and three joints - shouldn't be too taxing at all for a mobile device. If you're running on mobile. then you probably also want to keep the vertex density of the sprite quite low too (theres a slider in the inspector to let you control that on a per-Jelly Sprite basis) - having a low density means that the deformation might not be quite as smooth, but the CPU cost is lower as the code doesn't need to iterate over so many vertices (for each one there is an associated CPU cost as it needs to do some maths work out the new position based on the positions of the physics bodies).
     
  29. OzDave

    OzDave

    Joined:
    May 19, 2008
    Posts:
    144
    Hello mrsquare,

    Thankyou kindly for that information, it will help greatly. I need to look at the mesh one now as well.
     
  30. JJones

    JJones

    Joined:
    Feb 27, 2013
    Posts:
    5
    I'm trying to limit the velocity of the JellySprite, but neither Playmaker or my attempts at code recognizes the rigidbody. I know every collider must have it's own, but how do I address the "main" rigidbody? I'm not a skilled programmer, but the simple code I found and try to add is under. Thanks!

    public float maxSpeed = 200f;//Replace with your max speed

    void FixedUpdate()
    {
    if(rigidbody.velocity.magnitude > maxSpeed)
    {
    rigidbody.velocity = rigidbody.velocity.normalized * maxSpeed;
    }
    }
     
  31. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    Heya,

    Jelly Sprites are slightly different from normal gameObjects because they are made up of multiple rigid bodies - the main Jelly Sprite gameObject doesn't actually have a rigidBody of its own. If you want to limit the velocity, the best way is probably to grab the central rigid body from the Jelly Sprite (the one that all the other rigid bodies are attached to) and limit the velocity of that.

    If you create a new C# script called LimitJellySpriteVelocity and add this code, I think that should do the trick. Let me know if there are any compile errors - I'm not at my Unity machine just now so can't test it myself, but I think it should all be good :)

    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. // LimitJellySpriteVelocity Behaviour - Use to limit the velocity of a Jelly Sprite
    5. [RequireComponent (typeof (JellySprite))]
    6. public class LimitJellySpriteVelocity : MonoBehaviour
    7. {
    8.     //Replace with your max speed
    9.     public float maxSpeed = 200.0f;
    10.    
    11.     // Jelly Sprite component
    12.     JellySprite jellySprite;
    13.  
    14.     void Start()
    15.     {
    16.         // Cache the Jelly Sprite component to avoid having to fetch it each frame
    17.         jellySprite = GetComponent<JellySprite>();
    18.     }
    19.  
    20.     void FixedUpdate()
    21.     {
    22.         // If the Jelly Sprite is valid and has a central point...
    23.         if(jellySprite != null  jellySprite.CentralPoint != null)
    24.         {      
    25.             // ...and we're in 2D mode...
    26.             if(jellySprite.CentralPoint.Body2D)
    27.             {
    28.                 //...and the central point's velocity is greater than the max speed value...
    29.                 if(jellySprite.CentralPoint.Body2D.velocity.magnitude > maxSpeed)
    30.                 {
    31.                     //...then limit the velocity of the 2D rigid body
    32.                     jellySprite.CentralPoint.Body2D.velocity = jellySprite.CentralPoint.Body2D.velocity.normalized * maxSpeed;
    33.                 }                        
    34.             }
    35.             // ...otherwise if we're in 3D mode...
    36.             else if(jellySprite.CentralPoint.Body3D)
    37.             {
    38.                 //...and the central point's velocity is greater than the max speed value...
    39.                 if(jellySprite.CentralPoint.Body3D.velocity.magnitude > maxSpeed)
    40.                 {
    41.                     //...then limit the velocity of the 3D rigid body
    42.                     jellySprite.CentralPoint.Body3D.velocity = jellySprite.CentralPoint.Body3D.velocity.normalized * maxSpeed;
    43.                 }      
    44.             }
    45.         }
    46.     }
    47. }
    48.  
     
    Last edited: Mar 31, 2014
  32. JJones

    JJones

    Joined:
    Feb 27, 2013
    Posts:
    5
    Thank you very much for the code, but Unity doesn't seem to recognize the operator?

    Also, would it be possible to get a quick example in C# on how to recognize and start something after a collision/triggering? I'm trying to add force when my JellySprite hits a wall (which has the tag "wall"). Thanks a lot!
     
  33. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    Apologies - 22nd line should have been:

    Code (csharp):
    1.  
    2. if(jellySprite != null  jellySprite.CentralPoint != null)
    3.  
    I've updated the original reply to reflect that. For detecting a collision, attach this script to the Jelly Sprite:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class JellyDetectCollision : MonoBehaviour
    6. {
    7.     public LayerMask validLayers = -1;
    8.     public float minCollisionRepeatTime = 0.0f;
    9.     JellySprite jellySprite;
    10.     float lastCollisionTime;
    11.  
    12.     /// <summary>
    13.     /// Awake this instance.
    14.     /// </summary>
    15.     void Awake ()
    16.     {
    17.         jellySprite = GetComponent<JellySprite>();     
    18.     }
    19.  
    20.     /// <summary>
    21.     /// Raises the jelly collision enter event for 3D collisions.
    22.     /// </summary>
    23.     void OnJellyCollisionEnter(JellySprite.JellyCollision jellyCollision)
    24.     {
    25.         if(Time.time >= lastCollisionTime + minCollisionRepeatTime)
    26.         {
    27.             // Check if the colliding object's layer matches the layerMask
    28.             if((1 << jellyCollision.Collision.collider.gameObject.layer  validLayers) != 0)
    29.             {
    30.                 Debug.Log("Collision Detected with " + jellyCollision.Collision.gameObject.name +  " at " + jellyCollision.Collision.contacts[0].point);
    31.                 lastCollisionTime = Time.time;
    32.             }
    33.         }      
    34.     }
    35.  
    36.     /// <summary>
    37.     /// Raises the jelly collision enter event for 2D collisions.
    38.     /// </summary>
    39.     void OnJellyCollisionEnter2D(JellySprite.JellyCollision2D jellyCollision)
    40.     {
    41.         if(Time.time >= lastCollisionTime + minCollisionRepeatTime)
    42.         {
    43.             // Check if the colliding object's layer matches the layerMask
    44.             if((1 << jellyCollision.Collision2D.gameObject.layer  validLayers) != 0)
    45.             {
    46.                 Debug.Log("Collision Detected with " + jellyCollision.Collision2D.gameObject.name + " at " + jellyCollision.Collision2D.contacts[0].point);
    47.                 lastCollisionTime = Time.time;
    48.             }
    49.         }
    50.     }
    51.  
    52.     /// <summary>
    53.     /// Raises the jelly trigger enter event for 3D triggers.
    54.     /// </summary>
    55.     void OnJellyTriggerEnter(JellySprite.JellyCollider jellyCollider)
    56.     {
    57.         if(Time.time >= lastCollisionTime + minCollisionRepeatTime)
    58.         {
    59.             // Check if the colliding object's layer matches the layerMask
    60.             if((1 << jellyCollider.Collider.gameObject.layer  validLayers) != 0)
    61.             {
    62.                 Debug.Log("Trigger hit - " + jellyCollider.Collider.gameObject.name);
    63.                 lastCollisionTime = Time.time;
    64.             }
    65.         }
    66.     }
    67.    
    68.     /// <summary>
    69.     /// Raises the jelly trigger enter event for 2D triggers.
    70.     /// </summary>
    71.     void OnJellyTriggerEnter2D(JellySprite.JellyCollider2D jellyCollider)
    72.     {
    73.         if(Time.time >= lastCollisionTime + minCollisionRepeatTime)
    74.         {
    75.             // Check if the colliding object's layer matches the layerMask
    76.             if((1 << jellyCollider.Collider2D.gameObject.layer  validLayers) != 0)
    77.             {
    78.                 Debug.Log("Trigger hit - " + jellyCollider.Collider2D.gameObject.name);
    79.                 lastCollisionTime = Time.time;
    80.             }
    81.         }
    82.     }
    83. }
    84.  
    And just add your own custom code instead of the calls to Debug.Log. As with any other physics collision, there are separate function calls for 2D vs 3D collisions, and also different ones for collisions vs. triggers, so make sure you use the correct one :)

    *edit* Also added the ability to specify a min repeat time, as requested later in the thread
     
    Last edited: Apr 1, 2014
  34. JJones

    JJones

    Joined:
    Feb 27, 2013
    Posts:
    5
    Thanks a lot!

    One more question comes to my mind: What is the best way to pause/un-pause a Jelly Sprite? Like, if I want it to stop in mid-air (for example, from the press of a button), and then from the same button let it continue like nothing had happened? I'd only want the Jelly Sprite to be paused, while the rest of the game goes on. I tried to de-activate the JellySprite script while running, which did freeze the main sprite, but it still made all the generated colliders run off, so it didn't seem to be a good way.
     
  35. JJones

    JJones

    Joined:
    Feb 27, 2013
    Posts:
    5
    One more observation that came up, as adding force to a jelly sprite based on contact has proven a bit tricky. Because of the nature of the jelly sprite, it seems many of the colliders it consists of might collide with an object at the same time. So if you send an addForce based on contact, you might get the force x2 or even x3, because it fires off for every collider. Is there a way to limit this, to only one registered hit during x time for the whole jellysprite, for example?
     
  36. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    Yep, that's pretty easy - to pause them, you basically just need to loop over the Jelly Sprite's reference points, store their velocity and angular velocity, and then set the physics body to be kinematic. When unpausing, you just do the reverse - set the body to be non-kinematic, and then reinstate the saved velocities. I've attached a script below - if you attach this to a Jelly Sprite, you can just call Pause() and Unpause() and it should do it all for you :)

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. /// <summary>
    6. /// Helper class to allow you to pause and unpause a Jelly Sprite
    7. /// </summary>
    8. [RequireComponent(typeof(JellySprite))]
    9. public class JellyPause : MonoBehaviour
    10. {
    11.     JellySprite jellySprite;
    12.     Vector3[] velocity;
    13.     Vector3[] angularVelocity;
    14.     bool isPaused = false;
    15.  
    16.     /// <summary>
    17.     /// Awake this instance.
    18.     /// </summary>
    19.     void Awake ()
    20.     {
    21.         // Cache the Jelly Sprite to avoid having to fetch it each time
    22.         jellySprite = GetComponent<JellySprite>();
    23.     }
    24.    
    25.     /// <summary>
    26.     /// Pause this instance.
    27.     /// </summary>
    28.     public void Pause()
    29.     {
    30.         // If we're not already paused...
    31.         if(!isPaused)
    32.         {
    33.             // ...first create our arrays to save the rigid body velocities into, if we haven't already...
    34.             if(velocity == null)
    35.             {
    36.                 velocity = new Vector3[jellySprite.ReferencePoints.Count];
    37.             }
    38.            
    39.             if(angularVelocity == null)
    40.             {
    41.                 angularVelocity = new Vector3[jellySprite.ReferencePoints.Count];
    42.             }
    43.  
    44.             // ...now for each reference point...
    45.             for(int loop = 0; loop < jellySprite.ReferencePoints.Count; loop++)
    46.             {
    47.                 JellySprite.ReferencePoint referencePoint = jellySprite.ReferencePoints[loop];
    48.  
    49.                 //...if this is a valid reference point...
    50.                 if(!referencePoint.IsDummy)
    51.                 {
    52.                     //...if we're in 2D mode...
    53.                     if(referencePoint.Body2D != null)
    54.                     {
    55.                         //...store the velocity and angular velocity...
    56.                         velocity[loop] = new Vector3(referencePoint.Body2D.velocity.x, referencePoint.Body2D.velocity.y, 0);
    57.                         angularVelocity[loop] = new Vector3(0, 0, referencePoint.Body2D.angularVelocity);
    58.  
    59.                         //...and freeze the rigid body.
    60.                         referencePoint.Body2D.velocity = Vector2.zero;
    61.                         referencePoint.Body2D.angularVelocity = 0.0f;
    62.                         referencePoint.Body2D.isKinematic = true;
    63.                     }
    64.                     //...if we're in 3D mode...
    65.                     else if(referencePoint.Body3D != null)
    66.                     {
    67.                         //...store the velocity and angular velocity...
    68.                         velocity[loop] = referencePoint.Body3D.velocity;
    69.                         angularVelocity[loop] = referencePoint.Body3D.angularVelocity;
    70.  
    71.                         //...and freeze the rigid body.
    72.                         referencePoint.Body3D.velocity = Vector3.zero;
    73.                         referencePoint.Body3D.angularVelocity = Vector3.zero;
    74.                         referencePoint.Body3D.isKinematic = true;
    75.                     }
    76.                 }
    77.             }
    78.  
    79.             isPaused = true;
    80.         }
    81.     }
    82.  
    83.     /// <summary>
    84.     /// Unpause this instance.
    85.     /// </summary>
    86.     public void Unpause()
    87.     {
    88.         // If we are already paused...
    89.         if(isPaused)
    90.         {
    91.             // ...for each reference point...
    92.             for(int loop = 0; loop < jellySprite.ReferencePoints.Count; loop++)
    93.             {
    94.                 JellySprite.ReferencePoint referencePoint = jellySprite.ReferencePoints[loop];
    95.  
    96.                 //...if this is a valid reference point...
    97.                 if(!referencePoint.IsDummy)
    98.                 {
    99.                     //...if we're in 2D mode...
    100.                     if(referencePoint.Body2D != null)
    101.                     {
    102.                         //...set the body to non-kinematic and restore the saved velocities.
    103.                         referencePoint.Body2D.isKinematic = false;
    104.                         referencePoint.Body2D.velocity = velocity[loop];
    105.                         referencePoint.Body2D.angularVelocity = angularVelocity[loop].z;
    106.                     }
    107.                     //...if we're in 3D mode...
    108.                     else if(referencePoint.Body3D != null)
    109.                     {              
    110.                         //...set the body to non-kinematic and restore the saved velocities.
    111.                         referencePoint.Body3D.isKinematic = false;
    112.                         referencePoint.Body3D.velocity = velocity[loop];
    113.                         referencePoint.Body3D.angularVelocity = angularVelocity[loop];
    114.                     }
    115.                 }
    116.             }
    117.  
    118.             isPaused = false;
    119.         }
    120.     }
    121. }
    122.  
     
  37. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    Yep, that's correct - you'll get collision reports for each collider. I've updated the collision detection code in my earlier post to allow you to specify a 'Min Collision Repeat Time' value (measured in seconds), so the code will ignore multiple collisions within that time frame
     
  38. jgalvezpa

    jgalvezpa

    Joined:
    Dec 27, 2012
    Posts:
    36
  39. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    Hey - not really, I'm afraid. Sprite Slicer can only be used to cut physics-enabled sprites in half along a given vector, whereas the game in that video appears to be using some sort of destructible terrain system to carve out holes in 2D objects.

    You probably need something like this instead:

    http://u3d.as/content/axis3d/destroy2d/5Xe

    (n.b, I haven't use that asset, but it looks like it would let you create a similar sort of effect)
     
  40. Alan-Ward

    Alan-Ward

    Joined:
    Aug 26, 2012
    Posts:
    84
    Hi mrsquare - thanks for an excellent asset. I'm using 2D jelly sprites to create free-floating blob/bubble type sprites which is working extremely well - but I have a couple of questions...

    Is there a reason why Drag and Angular Drag are exposed in the inspector for 3D jelly sprites but not 2D? I've added the required code in to expose these values myself - but I just wanted to check if there is a good reason why I shouldn't? Something fundamental that I'm missing?

    Secondly, I was just wondering if it's possible to limit the amount of 'squish' a sprite can take (outside of increasing the spring stiffness) - i.e. limit the range the springs can travel so that sprites can't get overly squashed, only squishy up to a point... ?
     
  41. Greg-Bassett

    Greg-Bassett

    Joined:
    Jul 28, 2009
    Posts:
    628
    Hi, thanks for a great asset, and also the great support on this forum, I have used the JellyDetectCollision snippet above and it works great added to my JellyMesh detecting collisions with walls etc.

    But how can I add a force to my JellyMesh to send it bouncing off the object (e.g wall) its collided with.

    I want my JellyMesh to continually bounce around inside a walled area without losing its velocity, and I want it to hit the wall and bounce off at the opposite angle to that which it hit the wall.

    Imagine a pool table and you strike a ball around the table and it bounces off the cushions, thats the behaviour I am after, but the ball never stops it has a constant speed.

    Thanks in advance!
     
  42. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    Hey - um, I'm not sure actually! I seem to remember that they weren't exposed variables on rigidBody2Ds when I was originally writing the code - perhaps they got patched in after the original 4.3 release? Or alternatively it might just be me being stupid :) No reason for them not to be in the Jelly Sprites inspector window, so feel free to add them in yourself. I'll submit an update to fix that ASAP.

    There's no built in functionality at the moment, I'm afraid - you'd presumably need to add a little script to the Jelly Sprite reference points that would enforce a minimum distance from the central point, and move the points back along the point->centre vector when they got too close.

    Alternatively, once the Jelly Sprite has been created, you could maybe try modifying the reference point layers so that reference points are able to collide with the central point (by default they're all on the same layer and so can pass through it) - that way the central point would act as a sort of physical barrier, and the sprite wouldn't be able to be squashed more than the radius of the central point.
     
  43. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    Hi Greg,

    Somebody contacted me trying to do a similar thing a while back - the squishy nature of the Jelly Sprite bodies means that they're not ideally suited to conserving momentum, so its hard to get them to naturally bounce off objects like that, even when you completely eliminate friction, damping etc.

    The best approach that we found was to just completely disable gravity, and then create a script that constantly applies a force in a particular direction to the central point of Jelly Sprite. You can then use something like the JellyDetectCollision script to listen out for when the central point collides with a wall, and then reverse the direction of the the force that is getting applied, causing it to bounce off in the opposite direction.
     
  44. Greg-Bassett

    Greg-Bassett

    Joined:
    Jul 28, 2009
    Posts:
    628
    Thanks mrsquare,

    I have things almost working, but getting odd things happening with artefacts, so tweaking settings etc.

    How would I find the current vector of the JellySprite when it hits a wall, and then how would I reverse that direction? my 3D maths is not good...
     
  45. Greg-Bassett

    Greg-Bassett

    Joined:
    Jul 28, 2009
    Posts:
    628
    I tried this which almost works, but sometimes the JellyMesh will keep hitting the wall in the same direction instead of bouncing off... I think thats because I am not reversing the direction?

    Code (csharp):
    1.     void OnJellyCollisionEnter(JellySprite.JellyCollision jellyCollision)
    2.        
    3.     {
    4.        
    5.         if(Time.time >= lastCollisionTime + minCollisionRepeatTime)
    6.            
    7.         {
    8.            
    9.              // Check if the colliding object's layer matches the layerMask
    10.            
    11.             if((1 << jellyCollision.Collision.collider.gameObject.layer  validLayers) != 0)
    12.                
    13.             {
    14.                
    15.                 Debug.Log("Collision Detected with " + jellyCollision.Collision.gameObject.name +  " at " + jellyCollision.Collision.contacts[0].point);
    16.  
    17.  
    18.                 Vector2 jumpVector = Vector2.zero;
    19.                 jumpVector.x = jellySprite.CentralPoint.GameObject.rigidbody.velocity.x; //   UnityEngine.Random.Range(m_MinJumpVector.x, m_MaxJumpVector.x);
    20.                 jumpVector.y = jellySprite.CentralPoint.GameObject.rigidbody.velocity.y; //   UnityEngine.Random.Range(m_MinJumpVector.y, m_MaxJumpVector.y);
    21.                 jumpVector.Normalize();                
    22.                 jellySprite.AddForce(jumpVector * 6000);
    23.                
    24.                            
    25.                 lastCollisionTime = Time.time;
    26.                
    27.             }
    28.            
    29.         }        
    30.        
    31.     }
    32.  
    33.  

     
    Last edited: Apr 12, 2014
  46. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    Hey - that looks good, you just need to multiply the vector by -1 to reverse it :)

    Code (csharp):
    1.  
    2. ...
    3. jumpVector.Normalize();                
    4. jumpVector *= -1.0f;
    5. ...
    6.  
     
  47. Greg-Bassett

    Greg-Bassett

    Joined:
    Jul 28, 2009
    Posts:
    628
    Hi mrsquare,

    I am making excellent progress with my latest game using Jelly Sprites, so many thanks for answering my previous posts, and for producing such a great Asset.

    I have been studying the Blob Eyes script as I want to be able to change the main Sprite displayed via code, however I see that in the demo scene the Eyes gameobject uses the Unity Sprite Renderer and not the Mesh Renderer like the Jelly Sprites themselves.

    I also noticed that you have not made the Sprite variable available as m_Sprite in the Jelly Sprite script in the same way you have all the other parameters, such as Sprite Scale etc...

    Is there any reason for this?

    Do you have a suggestion as how best to access the Sprite parameter of the Jelly Sprite so I can set it to another sprite image in code?

    Thanks in advance!
     
  48. Greg-Bassett

    Greg-Bassett

    Joined:
    Jul 28, 2009
    Posts:
    628
    Worked it out myself, I was referencing my Jelly Sprites as type JellySprite and not UnityJellySprite, now I can access .m_Sprite, and once set via code call ReInitMaterial() to refresh with new sprite.

    Cool! :)
     
  49. mrsquare

    mrsquare

    Joined:
    Oct 25, 2013
    Posts:
    281
    Cool, glad you got it sorted :)
     
  50. dumbat

    dumbat

    Joined:
    Apr 24, 2014
    Posts:
    11
    Embarrassingly I followed the tutorial video and my JellySprite goes nowhere.

    On adding the JellySprite, "Use 2D physics" is not checked (unlike in the vid). So I set it to be checked. But when I Play the scene, the JellySprite doesn't move. It falls if I add a Rigidbody 2D component (though this isn't done in the vid), but it will fall right through any Rigidbody 2D Box Collider sprite I place below it. What am I missing?