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

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);
}

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.

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.

Related

Distance moved by XR-controller in Unity

I have been making a script in Unity that measures how far a player has moved in the real world using XRNodes like this for example with the right hand:
InputTracking.GetLocalPosition(XRNode.RightHand)
at the start of the movement and then comparing it to the end position
Now I would like to get the distance moved, even if the player moved around in a circle.
Is the a method to do this with XRNodes? Measuring total distance moved during play?
Yes, well, you could just simply sum it up every frame like
// Stores the overall moved distance
private float totalMovedDistance;
// flag to start and stop tracking
// Could also use a Coroutine if that fits you better
private bool track;
// Store position of last frame
private Vector3 lastPos;
public void BeginTrack()
{
// reset total value
totalMovedDistance = 0;
// store first position
lastPos = InputTracking.GetLocalPosition(XRNode.RightHand);
// start tracking
track = true;
}
public void EndTrack()
{
// stop tracking
track = false;
// whatever you want to do with the total distance now
Debug.Log($"Total moved distance in local space: {totalMovedDistance}", this);
}
private void Update()
{
// If not tracking do nothing
if(!track) return;
// get current controller position
var currentPos = InputTracking.GetLocalPosition(XRNode.RightHand);
// Get distance moved since last frame
var thisFrameDistance = Vector3.Distance(currentPos, lastPos);
// sum it up to the total value
totalMovedDistance += thisFrameDistance;
// update the last position
lastPos = currentPos;
}

GameObject is vibrating throughout the movement

I have a GameObject that takes position coordinates from a file. This GameObject moves with vibration rather than smoothly. (as if moving back and forth.)
Here is the code that provides the movement:
int counter = 0;
void Update()
{
var maxDistance = speed_* Time.deltaTime;
var oldPosition = transform.position;
var newPosition = Vector3.MoveTowards(transform.position, positions[counter], maxDistance);
var actualDistance = Vector3.Distance(newPosition, oldPosition);
var distanceRemainder = maxDistance - actualDistance;
if (distanceRemainder > 0.0001)
{
newPosition = Vector3.MoveTowards(newPosition, positions[counter], distanceRemainder);
counter++;
}
transform.localPosition = newPosition;
}
NOTE: The data read from the file is in the "positions" array (x,y,z coordinates).
When I lower the 300f value in the variable maxDistance, the vibration stops and the motion becomes more fluid. However, Gameobject speed is also slowing down. How can I ensure a fast and smooth movement?
SOLUTION:
While looking for a solution of the problem, I came across the this topic. It helped me learn the source of the problem.
I have observed that the GameObject is not vibrating in Scene view, it was moving smoothly. But the object seemed to be vibrating in GameView. The problem is not the moving object, it's the camera function I write to follow it.
The camera function that was written to follow the object has been updated and the problem has disappeared.
One can see more of the solution by going to Post #13 in the link above.
Thanks to everyone trying to help.
This is caused cause you are using your distanceRemainder as your maxDistanceDelta, which I think is incorrect, if you want a smooth movement, you should multiply it for the Time.deltaTime, try:
newPosition = Vector3.MoveTowards(newPosition, positions[counter], distanceRemainder*Time.deltaTime);
Or simply declare speed variable and do:
newPosition = Vector3.MoveTowards(newPosition, positions[counter], speed*Time.deltaTime);
I assume what you want is your object moving with a constant speed to the first position. Once it reaches it, move to the next one.
I would do it in a simple Coroutine which is better to understand and maintain than doing stuff in Update:
private void Start()
{
// todo assign positions
StartCoroutine(RunPositions());
}
private IEnumerator RunPositions()
{
foreach(var position in positions)
{
while(!Mathf.Approximately(Vector3.Distance(transform.position, position), 0))
{
var maxDistance = speed_* Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, positions[counter], maxDistance);
// render and continue in the next frame
yield return null;
}
}
}
If you are fine with a precision of 0.00001 you can also simply use
while(transform.position != position)
instead.

How to add a spawner on a side of moving camera in unity2D

I'm creating a 2D racing game in Unity2D and unsure how to approach on coding my spawner for objects e.g. power-up, rewards and obstacles ahead on the right side of my moving camera. The camera follows my vehicle and moves from left to right. Currently objects spawn in the game, but only spawn on a point and continue to spawn in the same point when the camera has scrolled way past. Apologies, if the answer was simple.
Here are the scripts I used:
coin.cs is attached to my coin prefab
public class coin : MonoBehaviour
{
public Camera mainCamera;
Rigidbody2D rb;
// Start is called before the first frame update
void Start()
{
mainCamera = GameObject.FindObjectOfType<Camera>();
rb = this.gameObject.GetComponent<Rigidbody2D>();
transform.position = new Vector2(mainCamera.pixelWidth / 32, getRandomHeight());
}
float getRandomHeight(){
return Random.Range(-(mainCamera.pixelHeight / 2) / 100, (mainCamera.pixelHeight / 2) / 100);
}
private void OnTriggerEnter(Collider coll){
if (coll.gameObject.tag == "Player"){
Destroy(this.gameObject);
}
}
// Update is called once per frame
void Update()
{}
}
and coinSpawner.cs is attached to a gameObject in the scene
public class coinSpawner : MonoBehaviour
{
float LastSpawnTime = -500f;
float NextSpawnTime = 3;
public Object CoinPrefab; // declare coinPrefab
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Time.time - LastSpawnTime > NextSpawnTime)
{
NextSpawnTime = Random.Range(3, 10);
LastSpawnTime = Time.time;
Instantiate(CoinPrefab);
}
}
Instantiate(CoinPrefab);
spawns this object without any information of position or parent object. This it will always be spawned at Scene root and 0,0,0.
Then this line
transform.position = new Vector2(mainCamera.pixelWidth / 32, getRandomHeight());
in coin always places it to the absolute position depending on your pixelWidth which doesn't change over time.
You are saying the Camera is moving so you should rather take it's transform.position into account.
You have basically two(three) ways to go here:
You can make the spawner GameObject a child of your Camera - so it is automatically moved along with it - and move it to the right to have the desired offset. Then simply spawn new objects at this GameObjects position. Then you can do it in coinSpawner:
Instantiate(CoinPrefab, transform.position, Quaternion.Identity);
Or get the Camera reference and use it's position + the desired offset either also only in coinSpawner like
// reference this already via the Inspector if possible
[SerializeField] Camera _camera;
// Otherwise get the reference on runtime
void Awake()
{
if(!_camera)_camera = Camera.main;
}
float getRandomHeight => Random.Range(-(_camera.pixelHeight / 2) / 100, (_camera.pixelHeight / 2) / 100;
and then do something like
Instantiate(CoinPrefab, new Vector2(_camera.transform.position.x + mainCamera.pixelWidth / 32, getRandomHeight()), Quaternion.Identity);
This would actually be more efficient since the entire coin script would be reduced to only the OnTriggerEnter part and not every coin would use FindObjectOfType and GetComponent when spawned.
Basically the same as above but sticking to your code structure simply do
transform.position = new Vector2(mainCamera.transform.position.x + mainCamera.pixelWidth / 32, getRandomHeight());
I wouldn't do it this way though due to efficiency as said.

Move an object in unity2D towards another clicked object

I have an object called 'Player' in my scene.
I also have multiple objects called 'Trees'.
Now I'd like whenever the user clicks on a 'Tree', the 'Player' to move slowly to that position (using Lerp or moveTowards) is both O.K for me.
Now I have 2 issues with this code:
I'd like this code to be generic
Whenever I click a tree object I'd like this to move the player towards that tree. I don't want to write up this script and attach it to each tree object.
Where should I put the script?
Currently I attach this code to every tree object.
How should I write it down so that it applies to every tree object
in the scene?
If another click is made while moving, cancel previous movement and start moving to new position
How should I write it so that if I click on another object while the
player is moving towards another object that was clicked, the players stops moving towards it's previous position, and starts
moving towards the new point.
I'm having some trouble adjusting to the new UnityScript thingy. I come strictly from a Javascript background and it really seems like the 2 of them are languages with very different semantics. So if someone answers this with code(which is what I would want:) ), I'd appreciate some verbose comments as well.
I currently do this:
var playerIsMoving = false;
Public playerObject: Gameobject; //I drag in the editor the player in this public var
function update(){
var thisTreePosition = transform.point; //this store the X pos of the tree
var playerPosition = player.transform.point;
if(playerIsMoving){
player.transform.position = Vector2.MoveTowards(playerPosition, thisTreePosition, step);
}
}
function OnMouseDown(){
playerIsMoving = true;
}
I'm writing this from home where I don't have Unity and I forgot the code syntax therefore expect the above code to have typos or issues, at work it works just fine, apart from being very crude and unsophisticated.
I would recommend you to put the movement Script on the player. And how abour using Raycast to the test whether you hit a tree?
http://docs.unity3d.com/ScriptReference/Physics.Raycast.html
Vector3 positionToWalkTo = new Vector3();
void Update() {
if (Input.GetMouseButtonDown(0)) {
RaycastHit hit;
Ray ray = new Ray(transform.position, direction);
if (Physics.Raycast(ray, out hit))
if (hit.gameObject.tag.Equals("tree")){
positionToWalkTo = hit.gameObject.transform.position;
}
}
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, positionToWalkTo, step);
}
To get something like this running, you should tag all the trees.
'JavaScript'
var target: Transform;
// Speed in units per sec.
var speed: float;
function Update () {
if (Input.GetMouseButtonDown(0)) {
var hit: RaycastHit;
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
// Raycasting is like shooting something into the given direction (ray) and hit is the object which got hit
if (Physics.Raycast(ray, hit)) {
if (hit.gameObject.tag = "tree")
target = hit.gameObject.transform.position; // Sets the new target position
}
}
// The step size is equal to speed times frame time.
var step = speed * Time.deltaTime;
// Move our position a step closer to the target.
transform.position = Vector3.MoveTowards(transform.position, target.position, step);
}
Okay, so I've done it myself (with some help from Freshchris's answer).
Here it is:
var target:Vector2;
var targetObject:GameObject;
var initialY:float;
var tolerance = 1;
var speed = 3;
var isMoving = false;
function Start(){
target = transform.position;
}
function Update () {
if (Input.GetMouseButtonDown(0)) {
var hit: RaycastHit2D = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero); //raycast the scene
// if we hit something
if (hit.collider != null) {
isMoving=true; //it should start moving
targetObject = hit.collider.gameObject; //the target object
target = hit.collider.gameObject.transform.position;
}
}
// The step size is equal to speed times frame time.
var step = speed * Time.deltaTime;
// if it should be moving - move it - and face the player to the correct direction
if (isMoving){
if(transform.position.x>target.x){
gameObject.transform.localScale.x = -0.7;
}else {
gameObject.transform.localScale.x = 0.7;
}
transform.position = Vector2.MoveTowards(transform.position, target, step);
}
// if it reached the target object by a specified tolerance, tell it to stop moving
if(isMoving){
if((transform.position.x < target.x+tolerance)&&(transform.position.x > target.x-tolerance)){
print("position reached"); //this is fired just once since isMoving is switched to false just one line below
print(targetObject);
isMoving=false;
}
}
}

In Unity3d using the FPS Controller, how can I keep a constant player speed when auto-walk forward using transform.forward?

Using Unity3d First Person Controller, I want the player to move forward automatically in the direction the camera is looking at. It should behave the same as using the arrow keys, except I keep the arrow up key "pressed". I have this working in the script below, however the player slows down as he rotates the first-person camera away from the 0 degrees on the y-axis. When looking towards the 0 degrees on the y-axis, player speed is normal again.
How can I modify the script below so that the player always moves at a constant speed, no matter the camera rotation?
I set this script on the First Person Controller parent node:
public var head : GameObject;
private var motor : CharacterMotor;
// Use this for initialization
function Awake () {
motor = GetComponent(CharacterMotor);
}
// Update is called once per frame
function Update () {
// Retrieve a forward direction based on camera rotation
var directionVector = transform.forward;
directionVector.y = 0;
directionVector.Normalize();
// Apply the direction to the CharacterMotor
motor.inputMoveDirection = transform.rotation * directionVector;
motor.inputJump = Input.GetButton("Jump");
}
// Require a character controller to be attached to the same game object
#script RequireComponent (CharacterMotor)
#script AddComponentMenu ("Character/FPS Input Controller")
Multiply your movement for Time.deltaTime This time is the time between frames.
Example copy from http://docs.unity3d.com/ScriptReference/Time-deltaTime.html
function Update () {
// Move the object 10 meters per second!
var translation : float = Time.deltaTime * 10;
transform.Translate (0, 0, translation);
}