user1270217
user1270217

Reputation: 131

MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it (ERROR)

I have a problem that iv been trying to figure out for a couple of says and i cant seem to pin point the cause of it! I have created a first person shooter that consists of a few enemies on a small map. I have two scenes (the main menu and the game level). When my player dies it is takes to the main menu from which you can choose to play the game again. This then reloads the level again. The first time the game is run it runs without any problems. However when i doe and press the play game button again it returns to me a message which states the following "MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it." from the code below I can only see two types which are of GameObject. I have tried to remove the muzzleFlash to see if that is the issue however it makes no difference. I have unticked all the static boxes as i read that this may be the cause of the problem but this did not resolve the problem. this script below is attached to an enemy, I have a PlayerShot script attached to the FPS. Please could someone help?

// speed of the AI player
public var speed:int = 5;

// speed the ai player rotates by
public var rotationSpeed:int = 3;

// the waypoints
public var waypoints:Transform[];

// current waypoint id
private var waypointId:int = 0;

// the player
public var player:GameObject;

// firing toggle
private var firing:boolean = false;

// the Mesh Renderer of the Muzzle Flash GameObject
private var muzzleFlashAgent:GameObject;


/**
    Start
*/
function Start() 
{
    // retrieve the player
    player = GameObject.Find("First Person Controller");

    // retrieve the muzzle flash
    muzzleFlashAgent = GameObject.Find("muzzleFlashAgent");

    // disable the muzzle flash renderer
    muzzleFlashAgent.active = false;
}

/**
    Patrol around the waypoints
*/
function Patrol()
{
    // if no waypoints have been assigned
    if (waypoints.Length == 0) 
    {
        print("You need to assign some waypoints within the Inspector");
        return;
    }

    // if distance to waypoint is less than 2 metres then start heading toward next waypoint
    if (Vector3.Distance(waypoints[waypointId].position, transform.position) < 2)
    {
        // increase waypoint id
        waypointId++;

        // make sure new waypointId isn't greater than number of waypoints
        // if it is then set waypointId to 0 to head towards first waypoint again
        if (waypointId >= waypoints.Length) waypointId = 0;
    }

    // move towards the current waypointId's position
    MoveTowards(waypoints[waypointId].position);
}

/**
    Move towards the targetPosition
*/
function MoveTowards(targetPosition:Vector3)
{
    // calculate the direction
    var direction:Vector3 = targetPosition - transform.position;

    // rotate over time to face the target rotation - Quaternion.LookRotation(direction)
    transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);

    // set the x and z axis of rotation to 0 so the soldier stands upright (otherwise equals REALLY bad leaning)
    transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);

    // use the CharacterController Component's SimpleMove(...) function
    // multiply the soldiers forward vector by the speed to move the AI
    GetComponent (CharacterController).SimpleMove(transform.forward * speed);

    // play the walking animation
    animation.Play("walk");
}


/**
    Update
*/
function Update()
{
    // calculate the distance to the player
    var distanceToPlayer:int = Vector3.Distance(transform.position, player.transform.position);

    // calculate vector direction to the player
    var directionToPlayer:Vector3 = transform.position - player.transform.position;

    // calculate the angle between AI forward vector and direction toward player
    // we use Mathf.Abs to store the absolute value (i.e. always positive)
    var angle:int = Mathf.Abs(Vector3.Angle(transform.forward, directionToPlayer));

    // if player is within 30m and angle is greater than 130 (IN FRONT) then begin chasing the player
    if (distanceToPlayer < 30 && angle > 130)
    {
        // move towards the players position
        MoveTowards(player.transform.position);

        // if not firing then start firing!
        if (!firing) Fire();
    }
    // if player is within 5m and BEHIND then begin chasing
    else if (distanceToPlayer < 5 && angle < 130)
    {
        // move towards the players position
        MoveTowards(player.transform.position);

        // if not firing then start firing!
        if (!firing) Fire();
    }
    else
    {
        // patrol
        Patrol(); 

        // stop firing
        firing = false;
    }
}

/**
    Fire at the player
*/
function Fire()
{
    // toggle firing on
    firing = true;

    // check if still firing
    while (firing)
    {
        // hit variable for RayCasting
        var hit:RaycastHit;

        // range of weapon
        var range:int = 30;

        // fire the ray from our position of our muzzle flash, forwards "range" metres and store whatever is detected in the variable "hit"
        if (Physics.Raycast(muzzleFlashAgent.transform.position, transform.forward, hit, range)) 
        {
            // draw a line in the scene so we can see what's going on
            Debug.DrawLine (muzzleFlashAgent.transform.position, hit.point);

            // if we hit the player
            if (hit.transform.name == "First Person Controller")
            {
                // inform the player that they have been shot
                player.GetComponent(PlayerShot).Shot();  

                // play gunshot sound
                audio.PlayOneShot(audio.clip);


                // show muzzle flash for X seconds
                muzzleFlashAgent.active = true;
                yield WaitForSeconds(0.05);
                muzzleFlashAgent.active = false; 

                // wait a second or two before firing again
                yield WaitForSeconds(Random.Range(1.0, 2.0));
            }
        }

        // wait till next frame to test again
        yield;
    }
}

this is the PlayerShot which destroys the gameobject.

// the sound to play when the player is shot
public var shotSound:AudioClip;



// the number of lives
public var lives:int = 3;


/**
    Player has been shot
*/
function Shot () 
{
    // play the shot audio clip
    audio.PlayOneShot(shotSound);

    // reduce lives
    lives--;

    // reload the level if no lives left
    if (lives == 0)
    {
        // destroy the crosshair
        Destroy(GetComponent(CrossHair));


        // add the camera fade (black by default)
        iTween.CameraFadeAdd();

        // fade the transparency to 1 over 1 second and reload scene once complete
        iTween.CameraFadeTo(iTween.Hash("amount", 1, "time", 1, "oncomplete", "ReloadScene", "oncompletetarget", gameObject));
    }
}


/**
    Reload the scene
*/ 
function ReloadScene()
{
    // reload scene
    Application.LoadLevel("MainMenu");
}

The script attached to the enemy along with the BasicAI is the SoldierShot Script which destroys the gameobject. below is the script.

public var ragdoll:GameObject;

/**
    Function called to kill the soldier
*/
function Shot()
{
    // instantiate the ragdoll at this transform's position and rotation
    Instantiate(ragdoll, transform.position, transform.rotation);

    Destroy(GetComponent(BasicAI));
    // destroy the animated soldier gameobject
    Destroy(gameObject);

}

Upvotes: 1

Views: 13933

Answers (2)

Roberto
Roberto

Reputation: 11953

It seems that you keep a reference to the destroyed GameObject (or am I wrong?).

As opposed to what happens in common C# (and probably javascript) programs that when you have a reference to an object, it will never be garbage collected, in Unity if you destroy the object all your references to it will go to null.

Upvotes: 3

Xav
Xav

Reputation: 147

Easy fix, you could delete the gameObject in the "Game Level" and instantiate your soldier on the fly with:

var instance : GameObject = Instantiate(Resources.Load("Soldier"));

You just need to make a Resources folder in your project folder and put the prefab for your solder into it.

Upvotes: 1

Related Questions