Hey everyone. I’m using a level I made with the ragdoll/player that came with Unity to try to make the guy go flying upon being hit by a flying ball. I think the scripting he came with to control whether he is a ragdoll or a player should work for this situation, but he does not react when the ball hits him. The ball has a collider though so I think it should work. Any suggestions?
Which script are you talking about?
The CharacterAndRagdoll.js script?
Does the ball you are throwing at him have a rigidbody? The script was written so that only other rigidbodies will turn him into a ragdoll.
Thanks - making the sphere a rigidbody worked perfectly. Now how would I simulate an explosion on the person? I don’t care about how the actual explosion part looks - that’s a particle thing, but I’m not sure how I would make something like that where the forces would work in the correct way.
Also, sometimes the “bullet” passes through the character, and obviously for a game based on health based on collisions, that’s not a great thing. Is there any way to fix this without just making the bullet bigger?
One last question - is there any way to make the ragdoll really fly when something hits him? I guess I could lower the mass of all his different body parts… I’ll try that and get back to you.
Also, thanks in advance for any assistance anyone can give regarding these topics. Sorry for being such a noob.
Unity’s a great program as well. When my trial ends in a day or two, I’m definitely going to buy it. Thanks again.
I guess what it seems like is that there is no way to make him actually respond to the bullet’s push on him, since the bullet is moving fast enough that he is not yet a ragdoll before it’s past him. Is there a way to fix that?
Usually bullets wouldn’t be implement using rigidbody spheres, the only time you would use rigidbody spheres for weapons is probably grenades. Even missiles would better be approximated with boxes or capsules.
Usually what you do is cast a ray instead.
If you did hit something, you can use the raycast hit structure’s impact point.
From that point you simply apply forces to all sorrounding rigidbodies.
See the example in /Users/Shared/Unity/Examples/Script Tutorial/Assets/Fire Projectile Explosion.unity and especially the script Explosion.js in the same folder.
Basically you have to modify the Explosion.js script to
- Go through all nearby colliders and turn any CharacterAndRagdoll’s into Ragdolls.
- Then apply forces to all their rigidbodies
/// When the projectile collides with an object it destroys itself and replaces itself with an explosion.
/// When explosion game object is activated, this script is executed.
/// This script applies a force to all nearby colliders!
// Variables declared with var are visible in the inspector and can be edited there.
var explosionRadius = 5.0;
var explosionPower = 10.0;
function Start()
{
// Find all nearby colliders
colliders = Physics.OverlapSphere (transform.position, explosionRadius);
// Turn nearby characters into ragdolls
for (var hit in colliders) {
var ragdoll : CharacterAndRagdoll = hit.GetComponent(CharacterAndRagdoll);
if (ragdoll)
ragdoll.SetRagdollEnabled(true);
}
// Find all nearby colliders
colliders = Physics.OverlapSphere (transform.position, explosionRadius);
// Apply a force to all surrounding rigid bodies.
for (var hit in colliders) {
if (hit.rigidbody)
{
// We use a coroutine here because we want to apply force not only for one frame but several!
// This gives a nicer explosion effect.
// A coroutine can always be paused and resumed by giving special yield instructions
// Coroutines don't use threads and have minimal performance overhead.
StartCoroutine ("ApplyForce", hit.rigidbody);
}
}
}
function ApplyForce (body : Rigidbody)
{
time = 0.5;
// Apply the force smoothly over time!
// Check if the rigid body we apply force to is still alive.
// In a real game situation it might have been hit by and explosion and was destroyed.
while (time > 0 body)
{
explosionPosition = transform.position;
bodyPosition = body.transform.position;
offset = bodyPosition - explosionPosition;
direction = offset.normalized;
// It looks a lot cooler if explosions have more upwards force throwing things into the air!
direction.y += 2;
direction = direction.normalized;
// We apply the force based on the distance.
// Percentage will be in the range 0...1
// Where 0 means no force applied. And 1 means apply full force.
rangePercentage = (explosionRadius - offset.magnitude) / explosionRadius;
rangePercentage = Mathf.Clamp01 (rangePercentage);
power = rangePercentage * explosionPower * time;
force = direction * power;
body.AddForceAtPosition (force, explosionPosition);
// Yields until the next fixed update frame.
// Forces always need to be applied at fixed frame rate!
yield new WaitForFixedUpdate ();
time -= Time.deltaTime;
}
}
When implementing explosions, it is usually a very good pattern to
- Make a game object which has the explosion script attached
- Possibly add some particle system as a child to it in the hierarchy
- Make a prefab out of the explosion game object
This way, when you cast your ray and you hit something, you only have to instantiate the prefab at the right position in the scene and everything will just work.
Thanks a lot! That’s very helpful and also obviously much better than my solution! It works great, and your notes are very helpful. Next time I’ll be able to figure out a solution to my proble. Thanks again.
I get an error on the script when it runs:
System.MissingMethodException: Cannot find method SetRagdollEnabled.
I know it has the function in CharacterAndRagdoll, and I checked to make sure the syntax was right, but it still didn’t work. Case sensitivity isn’t an issue… I don’t know what the problem is. I wish I knew a little more about JavaScript.
As another question, I now know how bullets are done, but with rockets, it would be a totally different thing, right? The trend isn’t somehow moving a rocket model along a Ray, is it? It would seem logical to make it a collider and not a rigidbody, and when it collides, treat it like a grenade exploding.
You could try using static typing in the line where you call GetComponent(CharacterAndRagdoll); That way you will get more error messages at compile time when something is wrong. Actually, i looked over the script and i had a bug where i wrote GetComponent(Rigidbody) instead of CharacterAndRagdoll.
I updated the script, so it should be fine now.
Usually i also make rockets with rigidbodies. Just turn off gravity for rockets.
Give them drag, so that they have a maximum speed and then add a lot of force forward every frame. You can use the constant force component for that.
That does the right thing for the grenade now. When it runs, it throws the guy in generally the same direction all the time, though. I know modifying this is in the “direction” part, but I can’t find any methods for finding the direction between objects using Vector3’s. Also, I can’t figure out how to destroy my objects once they are used/dead.
Possibly you are not instantiating the explosion at the right position?
Look at the explosion object in the the scene when playing.
Just subtract the other target object’s position from the current one:
var dir = transform.position - other_transform.position;
(Replacing other_transform with the transform of the other object.)
So if I wanted to have a ray create a force on the rigidbody it hits, I could use a statement something like:
var dir = transform.position - rigidbody_to_add_force_to.position;
dir = dir.normalized;
dir.y += 2;
rigidbody_to_add_force_to.AddForce(dir);
Another thing I wondered about was if I wanted my bullet to have a “trail,” but my bullet is merely a ray, how could I do a particle system that does a kind of spiraling thing, as if it were the vapor following the grooves on the bullet? If there is no object to attach the system to, it seems like I shouldn’t be able to do something like this.
Lerp a dummy object’s position from the ray’s origin to the hit point and attach your particles to that.
If I wanted to lerp an empty from the ray’s origin to the hit point, what would the third argument be? I’ve never used anything that “lerped” before and I can’t figure out exactly what the syntax guide definition means.
Thanks for the help.
The third argument is how much to lerp, between 0 and 1 if I recall.
There is a question I asked about rotation here:
http://forum.otee.dk/viewtopic.php?t=1237
And nicholas was kind enough to explain how it works to me, and it uses Lerp. It might be useful to you.
-Jeremy
Sure, in a Vector3.Lerp the third argument is the transition, or interpolation, from one vector to another and it works on a scale from 0 to 1. So for the bullet tracer 0 would be at the ray’s origin and 1 would be where the ray hits… and 0.5 would be halfway along that path. Since you want your bullet to move really fast you could set a variable that increases to 1 in only a few steps…
var x = x + 0.2;
bullet.position = Vector3.Lerp(rayOrigin, rayHit, x);
And I believe if you want your bullet to have a consistent velocity using this method you’d do…
var x = x + (1/rayHit.distance * 0.2);
But you’d crank up “0.2” to something quite a bit higher. Thinking out loud on that one so I’m not sure it works right. But the gist of it is there.
HTH
Wouldn’t you want to multiply your value by Time.deltaTime to keep it consistant? I remember nicholas telling me that for my rotation question.
//str is the var for the lerp amount, Mathf.Min makes sure we don't exceed 1.
str = Mathf.Min (strength * Time.deltaTime, 1);
Not sure if if applies here.
-Jeremy
That seems like it should apply here as well - that’s how David JJ did the constant velocity stuff in the racing tutorial.