- Home /
Object shattering under a certain weight/force
Lets say I want to create a situation where a player has to walk on ice, or a glass panel. The glass panel/ice has a certain value of strength, and if the force applied to it is greater, it falls off/breaks. How would I go about this? I want it to shatter under "static" weight of a single heavy objects or multiple lighter ones, and also if someone threw a lighter object at it with great enough velocity.
To put it in pseudo:
if (sumOfAllForcesApplied > objectStrength){
Instantiate(destroyedVersion, transform.position, transform.rotation);
Destroy(gameObject);
}
Thanks in advance.
Hello @Utopian$$anonymous$$ing. I was reading about this a couple of weeks ago. I found this YouTube video very helpful. It's a bit long, but it is a detailed explanation. Give it a try. Link: https://www.youtube.com/watch?v=dA-$$anonymous$$PeZ0HV$$anonymous$$
Hope this helps :)
@tmalhassan Although it doesn't fully solve the "issue"(the sum of newtons from multiple objects), the video was very helpful in many ways. For example the thing with the AddExplosionForce was something I need somewhere else. So thank you:)
What do you mean by "The sum of newtons from multiple objects"? like multiple objects would hit the surface at the same time? and how does this part of your game work exactly? a detailed explanation would be helpful.
Check this asset, it may help.
https://www.assetstore.unity3d.com/en/#!/content/95438 CaronteFX
Tried using Collision.impulse ? This should account for not just the mass of the colliding objects, but also their velocity. If the impulse is high enough, shatter the object. Tested it, never$$anonymous$$d, I was wrong: impulse is zero when impact velocity is zero. (though it does seem to generate an impluse, for a frame or two, if I change the mass of one of the touching objects- which might be good enough)
Answer by shadowpuppet · Oct 31, 2017 at 01:30 PM
I suppose there is a way to do it with addForce and gravity and whatnot. But I would Forest Gump something together like this - which would be a pain if you have a LOT of possible objects, but I would just assign an integer (weight) to those possible objects. a rock could be 10, a sofa 150, a person 210 etc . etc. Have a trigger zone on the ice where if an object enters it adds that integer, if the weight exceeds breaking point
using UnityEngine;
using System.Collections;//code on the ice
public class iceBreaks : MonoBehaviour {
public static int weight = 0;//this will grow as objects enter the trigger zone
public int breakingWeight = 230;//whatever strength you want the ice to be
Animation ani;
void Start(){
ani = GetComponent<Animation>();
}
void Update(){
if( weight >= breakingWeight)
ani.Play ("iceBreaks");
}
}
}
______________________________________________________________________________________
//code can go on all objects just change the thisObjectsWeight
using UnityEngine;
using System.Collections;
public class objectWeight : MonoBehaviour {
MonoBehaviour weight;
public GameObject ice;
public int thisObjectsWeight = 15;
void Start (){
weight = ice.GetComponent<iceBreaks>();//this will access the static variable weight from ice script
}
void OnTriggerEnter (Collider other) {
if(other.tag == "ice")
iceBreaks.weight += thisObjectsWeight;
}
}
}
I was actually going to suggest this to him, until I read his new comment. It is actually much more complicated than this, but it is defiantly the way to start.
The rigidbody component has a value called "mass", is this the weight? if it's not, how it is different?
Could it be used here regardless by accessing it ins$$anonymous$$d of thisObjectsWeight ?
yes that would work. Just access the objects rigidbody mass ins$$anonymous$$d of assigning it a weight
//code can go on all objects just change the thisObjectsWeight
using UnityEngine;
using System.Collections;
public class objectWeight : $$anonymous$$onoBehaviour {
$$anonymous$$onoBehaviour weight;
public GameObject ice;
Rigidbody body;
void Start (){
body = GetComponent<Rigidbody>();//this will access the mass of the objects rigidbody
weight = ice.GetComponent<iceBreaks>();//this will access the static variable weight from ice script
}
void OnTriggerEnter (Collider other) {
if(other.tag == "ice")
iceBreaks.weight += body.mass;
}
}
}
@shadowpuppet I think I maybe can hack the code together using that code and the code on the video, provided to me by tmalhassan, to look something like this:
if(weightOnGlass + collision.relativeVelocity.magnitude > glassStrength){
Destroy(gameObject);
}
Or maybe I could use a variable somewhere called Force, which would be Velocity * $$anonymous$$ass and this variable is used ins$$anonymous$$d of collision.relativeVelocity.magnitude
though I get this feeling that this isn't quite the entirety of the solution, there's some tweaks to be made.
EDIT: m*v isn't force, it's momentum.. I told you I was rusty..
I think you need to tweak some more. Because how are you going to calculate the velocity if you're going to be dropping more than one object at a time (different objects with different velocities that collide at the same time)? But I guess you'll never know unless you try first, and we can definitely work from there.
or, skip adding that script to all objects that could possibly go on the ice and just have one on the ice script. You would need to tag all those possible objects with something like "heavy", but I don't know how to differentiate the different objects and get their specific mass. I mean whatever enters the trigger you need to get it's rigidbody.mass excluding all other objects tagged "heavy"
@shadowpuppet I think having the script on the ice/glass object is the way to go, now I just need a way to access the mass of any colliding object from the ice-script.
I've tried all sorts of things, and it appears that:
void OnCollisionEnter(Collision collision) {
Debug.Log(string.Format("$$anonymous$$ass = {0}",collision.rigidbody.mass ));
}
Gives me the mass value from a colliding object.
I have a script that accesses the mass of an object ( it's a boat that has one mass while running on water, and when it becomes airborne it seems to light so I increase the mass so it lands back in the water faster) and I do so by accessing the mass like in code below. onTriggerStay is a problem , I would think because it seems like it would keep adding the mass of the object unless you also destroy it. I think triggerenter to add the mass when object first enters and then resets on triggerStay. I have no clue how to add velocity. Sounds fun so I may actually play with this idea later
Rigidbody body;
Public GameObject objectOnIce = null;
public int weightOnIce = 0;
public int breakingPoint = 300;
void Start(){
body = objectOnIce.GetComponent<Rigidbody>();
}
void Update(){
if(weightOnIce>=breakingPoint)
Debug.Log ("ice breaks");// or whatever here
void OnTriggerEnter(Collider other){
if( other.tag == heavyItem)
{
objectOnIce = collider.name// really fuzzy on how to word this. but basically, the object with the tag heavyItem also has a name "sodaCan" and sodaCan becimes the objectOnIce variable
objectOnIce.body.mass += weightOnIce;
}
}
void OnTriggerStay(Collider other){
objectOnIce = null;//this resets the objectOnIce to null for the next object to enter the trigger zone
}
}
Answer by Glurth · Nov 01, 2017 at 05:49 PM
Had to play with this a bit after adding my comment above. I've only done limited testing on this, but seems to work as desired. Add this component to the rigid body that should break up.
This works with impacts at speed (smash), and with objects simply sitting on each other (but NOTE: in this case, the impulse is non-zero ONLY when the mass of one of the colliding rigid bodies changes.) Keep in mind; kenetic energy is mass times velocity SQUARED, so a change in the speed of impact will affect the "impulse" more than a similar change in mass (e.g. carefully placing a large brick on an ice cube with your hand, vs shooting the ice cube with a tiny bullet).
public class ShatterBody : MonoBehaviour {
public float breakingImpulse = 5.0f;
public bool alreadySmashed=false;
private void OnCollisionEnter(Collision collision)
{
if (alreadySmashed) return;
if (collision.impulse.magnitude > breakingImpulse)
{
Debug.Log("Smash! I'm breaking up!");
alreadySmashed = true;
}
}
private void OnCollisionStay(Collision collision)
{
if (alreadySmashed) return;
if (collision.impulse.magnitude > breakingImpulse)
{
string s = "Too heavy, I'm breaking up!";
if(collision.rigidbody.isKinematic)
s += "Under my own weight";
else
s += "under the weight of " + collision.rigidbody.gameObject.name;
Debug.Log(s);
alreadySmashed = true;
}
}
}
Answer by michi_b · Nov 11, 2017 at 03:52 AM
The answer obviously depends on how complex you want to get, so I'll just write what I guess I would do. In your ice plane case, i would simply assume that the strain on the structure equals the downwards force onto it (which is obviously not fully correct).
For resting objects, the gravitational downwards force is about 1 N per kg. Biggest problem for summing that up are stacked objects. You would have to maintain the network of rigid bodies that touch each other and apply their summed force to the plane.
For impacts/new collisions, the force is about their speed * their mass * the dot product of their movement direction and the down vector (since we are only concerned about downwards force). Apply that force over a short period of time, like 0.3s, and divide the force by that number (this number depends on softness of the object / flexibility of the plane)
Finally, make the plane shatter when the summed forces exceed a certain limit. I think that could give acceptable first results.
I have done something along those lines, though I used F=mg, meaning that the force is 9.81 * mass with stationary objects. (~10 N / kg)
The stacking part is something that I haven't managed to get around. I've been thinking that if I make a huge trigger box/volume, and everything within it gets added, but anything flying in that airspace would be added too, so I'd need to exclude those somehow. I have also been thinking about making each object keeping track what's on them, but that, like the network solution, is way beyond my scope of understanding how the engine works.
perhaps eli$$anonymous$$ate objects flying through the ice airspace by having as a condition to adding the objects weight that Y