Disable Ragdoll #C - Timer before disable.
So I am a beginning coder who has been writing in Javascript up until this point, but what I am doing now is creating a short script that disables the ragdoll effect after the enemy has died. I am using a custom method that is a part of the asset pack we are using - Paragon AI (I think now called Tactical Shooter AI or something).
I have followed the instructions of the author who told me how I could go about disabling the effect via turning off the colliders of the object and setting the rigidbody to kinematic which works; however the enemy just freezes as soon as they die so they are not dropping to the ground. So I figure I need a short timer that runs through before the rest of the code, so that the bodies have time to hit the ground before the ragdolls are disabled.
Here's my code.
using UnityEngine;
using System.Collections;
public class disableRagdoll : MonoBehaviour {
Collider[] rigColliders;
Rigidbody[] rigRigidbodies;
void Start (){
rigColliders = GetComponentsInChildren<Collider>();
rigRigidbodies = GetComponentsInChildren<Rigidbody>();
}
public void OnAIDeath()
{
//wait 2-3 seconds.
foreach (Collider col in rigColliders){
col.enabled = false;
}
foreach (Rigidbody rb in rigRigidbodies){
rb.isKinematic = true;
}
}
}
I have commented where I think the timer should go, is anyone able to help me out?
I found where in the pack the Ragdoll is turned on during death, so I have tried adding the disable bit after it and still not working. This is from the packs HealthScript.
void $$anonymous$$illAI()
{
//Check if we've done this before
if(this.enabled)
{
int i;
//Enable the ragdoll
for(i = 0; i < rigidbodies.Length; i++)
{
rigidbodies[i].is$$anonymous$$inematic = false;
}
for(i = 0; i < collidersToEnable.Length; i++)
{
collidersToEnable[i].enabled = true;
}
Invoke ("StopRagdoll", 3f);
//Disable scripts
if(rotateToAimGunScript)
rotateToAimGunScript.enabled = false;
if(animator)
animator.enabled = false;
if(gunScript)
{
gunScript.enabled = false;
}
this.enabled = false;
}
}
void DisableRagdoll ()
{
int i;
for (i = 0; i < rigidbodies.Length; i++)
{
rigidbodies[i].is$$anonymous$$inematic = true;
}
for(i = 0; i < collidersToEnable.Length; i++)
{
collidersToEnable[i].enabled = false;
}
}
}
}
Just picked up on the obvious mistake there, that was left over from me testing the old method. I have also discovered the problem with this method which is pretty much the same as the first problem I had. The $$anonymous$$illAI runs every frame, therefor gets stuck on the Invoke line.
So this is where the BaseScript is sending messages calling the OnAiDeath function.
public float timeUntilBodyIsDestroyedAfterDeath = 60;
//$$anonymous$$ill AI///////////////////////////////////////////////////////////
public void $$anonymous$$illAI()
{
//Check if we can actually do this, to stop errors in wierd edge cases
if(this.enabled)
{
if (combatBehaviour)
combatBehaviour.$$anonymous$$illBehaviour();
if (idleBehaviour)
idleBehaviour.$$anonymous$$illBehaviour();
//Call method on other scripts on this object, in case extra stuff needs to be done when the AI dies.
gameObject.Send$$anonymous$$essage("OnAIDeath", Send$$anonymous$$essageOptions.DontRequireReceiver);
GameObject.Destroy(animationScript.myAIBodyTransform.gameObject, timeUntilBodyIsDestroyedAfterDeath);
GameObject.Destroy(gameObject);
}
}
Answer by JigneshKoradiya · Apr 11, 2016 at 06:12 AM
public void OnAIDeath()
{
//wait 2-3 seconds.
foreach (Collider col in rigColliders){
col.enabled = false;
}
Invoke("StopBody",2.0f);
}
void StopBody()
{
foreach (Rigidbody rb in rigRigidbodies)
{
rb.isKinematic = true;
}
}
set second as per your requirement in invoke method
Invoke method, of course! Thank you very much for your speedy reply.
Sorry I thought it was working but then I realised that the Invoke is not actually working, anything within the StopBody method is not called for some reason.
This is what I have now.
public class disableRagdoll : $$anonymous$$onoBehaviour {
Collider[] rigColliders;
Rigidbody[] rigRigidbodies;
void Start (){
rigColliders = GetComponentsInChildren<Collider>();
rigRigidbodies = GetComponentsInChildren<Rigidbody>();
}
public void OnAIDeath()
{
foreach (Rigidbody rb in rigRigidbodies){
rb.is$$anonymous$$inematic = true;
}
//wait 2-3 seconds.
Invoke("StopRagdoll",2.0f);
}
void StopRagdoll(){
foreach (Collider col in rigColliders){
col.enabled = false;
}
}
}
I swapped around the colliders and rigidbody functions just for testing purposes. So anything in the StopRagdoll method does not get called.
Answer by Sarrixx · Apr 11, 2016 at 12:09 PM
So I have figured out that any script that uses the OnAIDeath method will only run the code in that method before the object destroys itself. So for example I tried calling a Coroutine from the OnAIDeath method and it does not seem to run the code in the Coroutine.
So this is where I am at now, still with no success.
public class disableRagdoll : MonoBehaviour {
Collider[] rigColliders;
Rigidbody[] rigRigidbodies;
public float ragdollTime;
void Start (){
rigColliders = GetComponentsInChildren<Collider>();
rigRigidbodies = GetComponentsInChildren<Rigidbody>();
}
public void OnAIDeath()
{
StartCoroutine(StopRagdoll());
}
IEnumerator StopRagdoll (){
yield return new WaitForSeconds(ragdollTime);
foreach (Rigidbody rb in rigRigidbodies) {
rb.isKinematic = true;
}
foreach (Collider col in rigColliders){
col.enabled = false;
}
}
}
So I have made some slight progress, I figured that in the Base Script of Paragon is a method called $$anonymous$$illAI() which basically sends the OnAIDeath message and then destroys the object. So what was happening is that when the Invoke was being called, the object was being destroyed before the pause timer before the disable ragdoll was being turned off. So I commented out the last line where it destroys the object and moved it over to my script.
//$$anonymous$$ill AI///////////////////////////////////////////////////////////
public void $$anonymous$$illAI()
{
//Check if we can actually do this, to stop errors in wierd edge cases
if(this.enabled)
{
if (combatBehaviour)
combatBehaviour.$$anonymous$$illBehaviour();
if (idleBehaviour)
idleBehaviour.$$anonymous$$illBehaviour();
//Call method on other scripts on this object, in case extra stuff needs to be done when the AI dies.
gameObject.Send$$anonymous$$essage("OnAIDeath", Send$$anonymous$$essageOptions.DontRequireReceiver);
GameObject.Destroy(animationScript.myAIBodyTransform.gameObject, timeUntilBodyIsDestroyedAfterDeath);
//GameObject.Destroy(gameObject);
}
}
So this is what my code looks like now -
public class disableRagdoll : $$anonymous$$onoBehaviour {
Collider[] rigColliders;
Rigidbody[] rigRigidbodies;
public float ragdollTime;
bool canCall = true;
void Start (){
rigColliders = GetComponentsInChildren<Collider>();
rigRigidbodies = GetComponentsInChildren<Rigidbody>();
}
public void OnAIDeath()
{
Debug.Log ("test");
if (canCall) {
Invoke("StopRagdoll", ragdollTime);
canCall = false;
}
}
void StopRagdoll (){
Debug.Log ("test2");
foreach (Rigidbody rb in rigRigidbodies) {
rb.is$$anonymous$$inematic = true;
}
foreach (Collider col in rigColliders){
col.enabled = false;
}
GameObject.Destroy(gameObject);
}
}
Whats happening now though is that when the enemy dies for the period where the Invoke is pausing before disabling the ragdoll, the enemy slides along the ground. But the ragdoll does turn off after that period.
So what I am wondering now, is would there be a relatively simple way of creating a script that you attach to each piece of the rig that would disable the ragdoll for each individual collider after they have hit the ground and completely stopped moving? $$anonymous$$aybe with raycasting or something?
Your answer
Follow this Question
Related Questions
Need help with making disappearing platforms. Error CS1525 1 Answer
HH:MM:SS game clock with modifiable start time error 1 Answer
Timer float not evaluating correctly when I check if it's less than another number 3 Answers
2D active ragdoll holding object 1 Answer
Timer only goes for .02 seconds 1 Answer