How can i make my script driven player and ai character interact with rigidbodys. So the player can push away boxes.
5 Answers
5The built-in CharacterController class has special status in the physics engine which means that it doesn't interact with other physics objects by default.
In order to be able to push objects around, you need to add a script, as described in the CharacterController class manual page. It gives this example:
// this script pushes all rigidbodies that the character touches
var pushPower = 2.0;
function OnControllerColliderHit (hit : ControllerColliderHit)
{
var body : Rigidbody = hit.collider.attachedRigidbody;
// no rigidbody
if (body == null || body.isKinematic) { 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);
// If you know how fast your character is trying to move,
// then you can also multiply the push velocity by that.
// Apply the push
body.velocity = pushDir * pushPower;
}
I use a modified version of the example. It’s more useful if you want to interact via physics, I personally think my solution makes more sense. This solution will apply force to the point of contact. This means that if you bump into the corner, the object will rotate, if you hit the top, it will tip over. It’s by no means absolutely perfect but it is better and still very simple.
The one also works with up and down so if you ever wanted to use a teeter totter you could. If you tried to simply enable downwards movement on the original script you won’t get the intended results. I put this right into the CharacterMotor script which Unity provides, it really works nicely and makes things fun.
// this script pushes all rigidbodies that the character touches
var pushPower = 2.0;
var weight = 6.0;
function OnControllerColliderHit (hit : ControllerColliderHit)
{
var body : Rigidbody = hit.collider.attachedRigidbody;
var force : Vector3;
// no rigidbody
if (body == null || body.isKinematic) { return; }
// We use gravity and weight to push things down, we use
// our velocity and push power to push things other directions
if (hit.moveDirection.y < -0.3) {
force = Vector3 (0, -0.5, 0) * movement.gravity * weight;
} else {
force = hit.controller.velocity * pushPower;
}
// Apply the push
body.AddForceAtPosition(force, hit.point);
}
I could be wrong but I believe it's in the default CharacterMotor script. If it's not use a number like "20" (my value) or "10" (the default) instead of "movement.Gravity".
– titegtnodIthanks so much for this piece of code. i hate to be lazy but this is absolutely perfect, lightweight, and very straightforward.
– dborgmanI had to fix this by changing hit.controller.velocity to hit.controller.velocity.magnitude * hit.normal * -1. The force being applied was not pointing the right direction some times, such as when the object the character was colliding with would resist the movement and make it move sideways.
The simpler, cleaner, less buggy solution is just simply:
function OnControllerColliderHit (hit : ControllerColliderHit) {
var body : Rigidbody = hit.collider.attachedRigidbody;
if (body != null && !body.isKinematic)
body.velocity += controller.velocity;
}
I added this script (C# version of above) to my CharacterController gameobject. using UnityEngine; using System.Collections; public class ControllerCollderHit : MonoBehaviour { void OnControllerColliderHit(ControllerColliderHit hit) { Rigidbody body = hit.collider.attachedRigidbody; if (body != null && !body.isKinematic) body.velocity += hit.controller.velocity; } }
– mtanuThis doesn't work at all, when my character hit rigidbody object, it's velocity immediately sets to zero vector, so that adding it's own velocity to hit rigidbody doesn't moving at all.
– modernator24I've recently come up with a funky solution to a similar problem: I had to go through a revolving door, pushing the blades of the door with my CharacterController. The revolving door was done with a (very very low poly) mesh collider and a RigidBody component held in place by a vertical hinge joint.
After I found out that a CharacterController isn't able to influence RigidBodies I created a new CapsuleCollider with the same size like the one my CharacterController used, attached a RigidBody component to it and wrote a very little script that always places this new CapsuleCollider at the same position that my CharacterController currently occupies. - That way the Capsule was pushing the doors like it would be pushed by the CharacterController itself. I then added a few lines of code to my script to switch off all physics on the CapsuleCollider at a certain distance from the door so that I could save the calculations for the physics when not needed.
That's probably not a good solution at all, but it worked perfectly and without any noticeable negative effect.
How do you intend on using the push action? It it just for non scripted objects or an object that will ‘use’ the gameobject/rigid for a purpose?
I'm also interested in this for future reference, how do you make it so they can only push certain objects, is that simply by naming a specific game object and if so what would that script look like... sorry, new to this whole scripting thing too. ;)
– anon48034950