- Home /
Why is my push rigidbody script not effected by mass?
I have this great script which allows a character controller to push rigidbodies around at a specified force. Anyone feel free to use this script for your purposes.
But it seems that the force pushing the rigidbodies does not take into account the mass of each rigidbody. So whether the rigidbody is a 2 kg cube or 1000 kg car the character controller still pushes it using the same force which obviously looks very unrealistic.
Is there a way to add the rigidbody mass into the push force calculation somehow?
I suppose it could be implemented using a tagging system; where the force is set to apply differently based on the tag of each rigidbody.
Here is the script:
// Script added to a player for it to be able to push rigidbodies around.
#pragma strict
#pragma implicit
#pragma downcast
// How hard the player can push
var LightpushPower = 0.5;
var HeavypushPower = 0.1;
// Which layers the player can push
// This is useful to make unpushable rigidbodies
var pushLayers : LayerMask = -1;
// pointer to the player so we can get values from it quickly
private var controller : CharacterController;
function Start () {
controller = GetComponent (CharacterController);
}
function OnControllerColliderHit (hit : ControllerColliderHit) {
if(hit.gameObject.tag == "enemy") {
var body : Rigidbody = hit.collider.attachedRigidbody;
// no rigidbody
if (body == null || body.isKinematic)
return;
// Only push rigidbodies in the right layers
var bodyLayerMask = 1 << body.gameObject.layer;
if ((bodyLayerMask & pushLayers.value) == 0)
return;
// We dont want to push objects below us
if (hit.moveDirection.y < -0.3)
return;
// Calculate push direction from move direction, we only push objects to the sides
// never up and down
var pushDir = Vector3 (hit.moveDirection.x, 0, hit.moveDirection.z);
body.velocity = pushDir * LightpushPower ;
}
}
Answer by ScriptGirl · Jan 18, 2012 at 12:58 PM
This is what the script should look like with hit.gameObject.tag == "enemy" used. Hope it helps!!
// Script added to a player for it to be able to push rigidbodies around.
#pragma strict
#pragma implicit
#pragma downcast
// How hard the player can push
var LightpushPower = 0.5;
var HeavypushPower = 0.1;
// Which layers the player can push
// This is useful to make unpushable rigidbodies
var pushLayers : LayerMask = -1;
// pointer to the player so we can get values from it quickly
private var controller : CharacterController;
function Start () {
controller = GetComponent (CharacterController);
}
function OnControllerColliderHit (hit : ControllerColliderHit) {
if(hit.gameObject.tag == "enemy") {
var body : Rigidbody = hit.collider.attachedRigidbody;
// no rigidbody
if (body == null || body.isKinematic)
return;
// Only push rigidbodies in the right layers
var bodyLayerMask = 1 << body.gameObject.layer;
if ((bodyLayerMask & pushLayers.value) == 0)
return;
// We dont want to push objects below us
if (hit.moveDirection.y < -0.3)
return;
// Calculate push direction from move direction, we only push objects to the sides
// never up and down
var pushDir = Vector3 (hit.moveDirection.x, 0, hit.moveDirection.z);
body.velocity = pushDir * LightpushPower ;
}
}
Thanks heaps. Ok, I've updated the script. That works great but it only uses one tag. I've tried editing it to use a second or multiple tags as well but keep getting errors about things being repeated. The only way I got it to work is by duplicating the script changing out the variable and tag, and then attaching the original and duplicate to the character controller.
There must a more optimized approach though. Any ideas how to get multiple tags to work in one script?
There is :D You need to move your if statement down and make one for each of the tags you have defined. $$anonymous$$ake sense?
Legend! THAT'S the advice I needed. Thanks so much. It works perfectly.
Quick note. For me to get this to work I had to say:
body.velocity = pushDir LightpushPower 100;
Not sure why I had to up it so much, but might help someone. AWESO$$anonymous$$E CODE!
Answer by syclamoth · Jan 18, 2012 at 06:42 AM
Have you looked at how your script actually manages the Rigidbody calculations? Specifically this line, the one which determines the rigidbody's resultant force:
body.velocity = pushDir * pushPower ;
Of course, rigidbody.velocity isn't affected by mass- only forces acting on the rigidbody are! In this, the rigidbody's velocity is being directly modified, so of course it doesn't take mass into account.
If you want to use actual forces, instead, use this line:
body.AddForce(pusDir * pushPower, ForceMode.Impulse);
This way, heavier bodies will move less than light ones.
Be warned- you may want to include some kind of system for limiting the resultant velocity- very light objects may get shot off into the distance otherwise!
Thanks for your response. I didn't actually understand how the script worked until you pointed it out, I'm still learning, but what you said has made things clearer now. I've tested what you suggested and it works.
I'm now wondering though if having actual forces being calculated for every rigidbody would be too expensive and unnecessary? Would it be better to create lets say 2 or 3 "pushPower" variables:
eg.
LightpushPower = 0.5
HeavypushPower = 0.2
And use a tagging system to detect which objects receive which pushPower in the OnControllerColliderHit function?
You could do that as well, but if the objects are rigidbodies there's really no difference performance-wise.
Sure, thanks for clearing that up.
So I've updated the code in the question and tried implementing a tagging system with 2 variables. I think this system will allow for easier control of exactly how much each object is pushed. I'm getting the following error though:
BCE0019: 'CompareTag' is not a member of 'UnityEngine.ControllerColliderHit'.
Since apparently CompareTag can't be used with ControllerColliderHit. Could you please advise how else I can use tagging, would be it be "if tag = variable"?
Thanks again
You need to use: hit.gameObject.tag == "enemy" in the if statement. And get rid of the second closing bracket. Hope that helps!!