Unity 3D Aiuto tutorial unity "space"

Stato
Discussione chiusa ad ulteriori risposte.
L'errore e' sicuramente dovuto a uno script che cerca di usare un oggetto distrutto.

Non avendo bene idea di cosa venga distrutto, non posso dirti di piu'.

Esempio:
C#:
...

public GameObject test;

void Update()
{
   Debug.log(test.name);
}
...
Se l'oggeto la cui referenza e' (... non ho idea di come dirlo in italiano quindi storpio un verbo inglese xD) "storata" in test viene distrutto (con Destroy) dallo stesso script o da un altro, Unity cechera' di accedere ugualmente a test senza pero' trovarlo. Quest genera un eccezione che non e' altro che il messaggio di errore che hai letto.

Consiglio:
Evitare sempre di usare GetComponent<blabla>() oppure anche obj.transform in funzioni come Update/FixedUpdate. GetComponent grava molto sulle performance del gioco.
@Thomaspetri97 dai un occhiata allo scipt che ti ha scritto @murdercode, lui non usa il GetComponent in Update ma inizializza una variabile un unica volta per poi usarla in tutto lo script. Questa e' davvero un ottima abitudine da prendere alla svelta per evitare di sprecare ore nell'ottimizzazione del gioco.
 
  • Mi piace
Reazioni: murdercode

Thomaspetri97

Utente Bronze
5 Aprile 2016
14
1
0
32
Ciao a tutti, sto seguendo il tutorial sul sito di unity "Space" e sto riscontando un problema in quanto mi esce l'errore "MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it", nel tutorial 8 e non capisco il perchè, sapete aiutarmi. Grazie.

Questi sono gli script:

PlayerController

using UnityEngine;
using System.Collections;

[System.Serializable]
public class Boundary
{
public float xMin, xMax, zMin, zMax;
}


public class PlayerController : MonoBehaviour
{

public float speed;
public float tilt;
public Boundary boundary;

public GameObject shot;
public GameObject shotSpawn;
public float fireRate;

private float nextFire;

void Update()
{
if (Input.GetButton("Fire1") && Time.time > nextFire)
{


shot = Instantiate(shot) as GameObject;
nextFire = Time.time + fireRate;
//GameObject clone =
shot.transform.position = shotSpawn.transform.position;

}
}
void FixedUpdate()
{

float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");

Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);
GetComponent<Rigidbody>().velocity = movement * speed;

GetComponent<Rigidbody>().position = new Vector3
(
Mathf.Clamp(GetComponent<Rigidbody>().position.x, boundary.xMin, boundary.xMax), 0.0f, Mathf.Clamp(GetComponent<Rigidbody>().position.z, boundary.zMin, boundary.zMax)
);
GetComponent<Rigidbody>().rotation = Quaternion.Euler(0.0f, 0.0f, GetComponent<Rigidbody>().velocity.x * -tilt);
}

}

DestroyByBoundary


using UnityEngine;
using System.Collections;

public class DestroyByBoundary : MonoBehaviour
{

void OnTriggerExit(Collider other)
{
Destroy(other.gameObject,0.1f);
}
}
 
Ti posto direttamente il mio PlayerController finitissimo, quindi molte cose vanno avanti.

Codice:
using UnityEngine;
using System.Collections;

[System.Serializable]
public class Boundary
{
    public float xMin, xMax, zMin, zMax;
}

public class PlayerController : MonoBehaviour {

    // Declaration
    private Rigidbody rb;
    private AudioSource audioSource;
    public float speed;
    public float tilt;
    public Boundary boundary;

    public GameObject shot;
    public Transform shotSpawn;
    public float fireRate;
    public float nextFire;

    // Start function
    void Start()
    {
        rb = GetComponent<Rigidbody>(); // Access to Rigidbody
        audioSource = GetComponent<AudioSource>(); // Access and cache AudioClip elements
    }

    void Update()
    {
        if (Input.GetButton ("Fire1") && Time.time > nextFire) { // Check for SPACE Button
            nextFire = Time.time + fireRate;
            //GameObject clone =
            Instantiate(shot, shotSpawn.position, shotSpawn.rotation); // as GameObject // Create a Instance for Shot GameObject
            audioSource.Play();
        }

    }

    void FixedUpdate()
    {
        // Grab inputs from the player
        float moveHorizontal = Input.GetAxis ("Horizontal");
        float moveVertical = Input.GetAxis ("Vertical");

        // Declare movement variable as a Vector3
        Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);

        // Add a force to Rigidbody
        rb.velocity = movement * speed;

        rb.position = new Vector3 (
            Mathf.Clamp (rb.position.x, boundary.xMin, boundary.xMax),
            0.0f,
            Mathf.Clamp (rb.position.z, boundary.zMin, boundary.zMax)
        );

        //Till the Ship
        rb.rotation = Quaternion.Euler(0.0f, 0.0f, rb.velocity.x * -tilt);

    }
}
 
L'errore e' sicuramente dovuto a uno script che cerca di usare un oggetto distrutto.

Non avendo bene idea di cosa venga distrutto, non posso dirti di piu'.

Esempio:
C#:
...

public GameObject test;

void Update()
{
   Debug.log(test.name);
}
...
Se l'oggeto la cui referenza e' (... non ho idea di come dirlo in italiano quindi storpio un verbo inglese xD) "storata" in test viene distrutto (con Destroy) dallo stesso script o da un altro, Unity cechera' di accedere ugualmente a test senza pero' trovarlo. Quest genera un eccezione che non e' altro che il messaggio di errore che hai letto.

Consiglio:
Evitare sempre di usare GetComponent<blabla>() oppure anche obj.transform in funzioni come Update/FixedUpdate. GetComponent grava molto sulle performance del gioco.
@Thomaspetri97 dai un occhiata allo scipt che ti ha scritto @murdercode, lui non usa il GetComponent in Update ma inizializza una variabile un unica volta per poi usarla in tutto lo script. Questa e' davvero un ottima abitudine da prendere alla svelta per evitare di sprecare ore nell'ottimizzazione del gioco.
innanzi tutto grazie, ciò che mi provoca quell'errore è il boundary che l'ho dovuto mettere come trigger, io avvio il gioco inizio a sparare e va tutto bene, smetto e poi sparando di nuovo ed esce quell'errore (esso servirebbe ad eliminare i cloni del bolt).
 

Allegati

  • Boundary.PNG
    Boundary.PNG
    497.1 KB · Visualizzazioni: 30
innanzi tutto grazie, ciò che mi provoca quell'errore è il boundary che l'ho dovuto mettere come trigger, io avvio il gioco inizio a sparare e va tutto bene, smetto e poi sparando di nuovo ed esce quell'errore (esso servirebbe ad eliminare i cloni del bolt).

Prova un codice del genere per distruggere gli oggetti:
C#:
void OnTriggerExit(Collider other)
{
   if(other.gameObject != null) // controlla che l oggetto esista ancora prima di distruggerlo
     Destroy(other.gameObject,0.1f);
   else
     Debug.Log("L'oggetto non esiste"); // se non esite allora ti avvisa che hai provato a distruggere un oggetto inesistente
}

Per quanto riguarda il codice di @murdercode non me lo fa utilizzare perchè mi dice "MissingReferenceException: The variable shotSpawn of PlayerController doesn't exist anymore."

Hai provato ad assegnare dall'inspector la variabile:
C#:
    public Transform shotSpawn;

Se si verificano altri errori puoi postare lo screen dell'intera console? oppure copiare e incollare anche lo stack di chiamate ripostato nel quadrato inferiore della console, s e' vuoto basta che clicchi su un errore e ti dovrebbe mostrare del testo.
 
Prova un codice del genere per distruggere gli oggetti:
C#:
void OnTriggerExit(Collider other)
{
   if(other.gameObject != null) // controlla che l oggetto esista ancora prima di distruggerlo
     Destroy(other.gameObject,0.1f);
   else
     Debug.Log("L'oggetto non esiste"); // se non esite allora ti avvisa che hai provato a distruggere un oggetto inesistente
}



Hai provato ad assegnare dall'inspector la variabile:
C#:
    public Transform shotSpawn;

Se si verificano altri errori puoi postare lo screen dell'intera console? oppure copiare e incollare anche lo stack di chiamate ripostato nel quadrato inferiore della console, s e' vuoto basta che clicchi su un errore e ti dovrebbe mostrare del testo.
 

Allegati

  • Console.PNG
    Console.PNG
    59.7 KB · Visualizzazioni: 35
Ecco la soluzione:
C#:
    void Update()
    {
        if (Input.GetButton("Fire1") && Time.time > nextFire)
        {
            GameObject bullet = Instantiate(shot) as GameObject; // l'errore era in questa riga (spiegazione sotto)
            if (bullet == null)
                Debug.Log("Shot is null");
         
            nextFire = Time.time + fireRate;
            //GameObject clone =
            bullet.transform.position = shotSpawn.transform.position;       
        }
    }

Praticamente nel tuo codice tu scrivi:
C#:
shot = Instantiate(shot) as GameObject;
questa istruzione cosa va a fare: crea un istanza di shot (il tuo prefab), e ne salva la referenza in shot (sovrascrivendo cio che c'e gia dentro), la seconda volta che instantiate viene chiamto, l'oggetto spawnato non e' piu' un clone del prefab, ma un clone del clone. Se smettti di sparare per un po, il clone la cui referenza e' in shot viene distrutto e quindi non puoi piu' crearne dei nuovi.
Il missing reference exception ti indica solo che il tuo clone e' stato distrutto (spiegazione precendete) e quindi non puoi piu' crearne un altro.

La soluzione e' semplice basta assegnare l'oggetto spawnato a una nuova variabile, in modo tale non non perdere la "referenza" al prefab.
 
Ecco la soluzione:
C#:
    void Update()
    {
        if (Input.GetButton("Fire1") && Time.time > nextFire)
        {
            GameObject bullet = Instantiate(shot) as GameObject; // l'errore era in questa riga (spiegazione sotto)
            if (bullet == null)
                Debug.Log("Shot is null");
        
            nextFire = Time.time + fireRate;
            //GameObject clone =
            bullet.transform.position = shotSpawn.transform.position;      
        }
    }

Praticamente nel tuo codice tu scrivi:
C#:
shot = Instantiate(shot) as GameObject;
questa istruzione cosa va a fare: crea un istanza di shot (il tuo prefab), e ne salva la referenza in shot (sovrascrivendo cio che c'e gia dentro), la seconda volta che instantiate viene chiamto, l'oggetto spawnato non e' piu' un clone del prefab, ma un clone del clone. Se smettti di sparare per un po, il clone la cui referenza e' in shot viene distrutto e quindi non puoi piu' crearne dei nuovi.
Il missing reference exception ti indica solo che il tuo clone e' stato distrutto (spiegazione precendete) e quindi non puoi piu' crearne un altro.

La soluzione e' semplice basta assegnare l'oggetto spawnato a una nuova variabile, in modo tale non non perdere la "referenza" al prefab.
Grazie.
 
Ecco la soluzione:
C#:
    void Update()
    {
        if (Input.GetButton("Fire1") && Time.time > nextFire)
        {
            GameObject bullet = Instantiate(shot) as GameObject; // l'errore era in questa riga (spiegazione sotto)
            if (bullet == null)
                Debug.Log("Shot is null");
      
            nextFire = Time.time + fireRate;
            //GameObject clone =
            bullet.transform.position = shotSpawn.transform.position;    
        }
    }

Praticamente nel tuo codice tu scrivi:
C#:
shot = Instantiate(shot) as GameObject;
questa istruzione cosa va a fare: crea un istanza di shot (il tuo prefab), e ne salva la referenza in shot (sovrascrivendo cio che c'e gia dentro), la seconda volta che instantiate viene chiamto, l'oggetto spawnato non e' piu' un clone del prefab, ma un clone del clone. Se smettti di sparare per un po, il clone la cui referenza e' in shot viene distrutto e quindi non puoi piu' crearne dei nuovi.
Il missing reference exception ti indica solo che il tuo clone e' stato distrutto (spiegazione precendete) e quindi non puoi piu' crearne un altro.

La soluzione e' semplice basta assegnare l'oggetto spawnato a una nuova variabile, in modo tale non non perdere la "referenza" al prefab.
Per non aprire una nuova discussione sullo stesso progetto continuo qui. ho aggiunto gli asteroidi che spawnano in automatico e funziona tutto ma da quando ho inserito lo score nel momento in cui il proiettile colpisce l'asteroide si blocca ed esce l'errore
NullReferenceException: Object reference not set to an instance of an object
DestroyByContact.OnTriggerEnter (UnityEngine.Collider other). grazie.

-GameController

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class GameController : MonoBehaviour
{
public GameObject hazard;
public Vector3 spawnValues;
public int hazardCount;
public float spawnWait;
public float startWait;
public float waveWait;

//Score variables
public GUIText scoreText;
private int score;

void Start()
{
score = 0;
UpdateScore();
StartCoroutine(SpawnWaves());
}

IEnumerator SpawnWaves()
{
yield return new WaitForSeconds(startWait);
while (true)
{
for (int i = 0; i < hazardCount; i++)
{
Vector3 spawnPosition = new Vector3(Random.Range(-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z);
Quaternion spawnRotation = Quaternion.identity;
Instantiate(hazard, spawnPosition, spawnRotation);
yield return new WaitForSeconds(spawnWait);
}
yield return new WaitForSeconds(waveWait);
}
}

public void AddScore (int newScoreValue)
{
score += newScoreValue;
UpdateScore();
}

void UpdateScore ()
{
scoreText.text = "Score: " + score;
}
}

-DestroyByContact

using UnityEngine;
using System.Collections;

public class DestroyByContact : MonoBehaviour
{

public GameObject explosion;
public GameObject playerExplosion;
public int ScoreValue;
private GameController gameController;

void start ()
{


GameObject gameControllerObject = GameObject.FindGameObjectWithTag("GameController");
if (gameControllerObject != null) //Replace gameController with gameControllerObject
{
gameController = gameControllerObject.GetComponent<GameController>();
}
if (gameController == null)
{
Debug.Log("Cannot find 'GameController' script!");
}
}

void OnTriggerEnter(Collider other)
{
if (other.tag == "Boundary")
{
return;
}

Instantiate(explosion, transform.position, transform.rotation);

if (other.tag == "Player")
{
Instantiate(playerExplosion, other.transform.position, other.transform.rotation);
Destroy(gameObject);
}
gameController.AddScore(ScoreValue);
Destroy(other.gameObject);
Destroy(gameObject);
Destroy(transform.parent.gameObject);


}
}
 

Allegati

  • Score.PNG
    Score.PNG
    638.3 KB · Visualizzazioni: 20
Destroy(gameObject);
Destroy(transform.parent.gameObject);
Con queste due istruzioni distruggi l'oggetto su cui si trova lo script stesso e l'istruzione dopo non viene mai eseguita!

Hai controllato che ci siano tutte le "referenze" ai vari oggetti?
Mi puoi allegare lo stack di chiamate dell'errore cosi da capire meglio cosa succede?
 
Eccolo qui l'errore. Questa funzione start non viene chiamata da Unity perche ha la lettera "s" minuscola mentre l'engine cerca quella con la maiuscola.
Per sistemare cambia in:
Codice:
void Start ()
//nel file DestroyByContact.cs
grazie, da cosa puo' dipendere che il contatore score non viene aumentato quando vengono distrutti gli asteroidi ? (Nel DestroyByContact gli ho assegnato un valore di 10)
 
Riguardo lo score...
Assegna ad una variabile globale(int o float, dipende da come vuoi impostare lo score) scoreAdding il valore 10, dopodiché crei un'altra variabile globale numerica scoreValue con valore 0.
Ad ogni contatto(Più che alla distruzione, meglio se lo assegni all'entrata della collisione-sempre se non stai usando raycast),
Codice:
scoreValue += scoreAdding;

Senza lo script è un po' difficile aiutarti, però così funziona al 100%
 
Riguardo lo score...
Assegna ad una variabile globale(int o float, dipende da come vuoi impostare lo score) scoreAdding il valore 10, dopodiché crei un'altra variabile globale numerica scoreValue con valore 0.
Ad ogni contatto(Più che alla distruzione, meglio se lo assegni all'entrata della collisione-sempre se non stai usando raycast),
Codice:
scoreValue += scoreAdding;

Senza lo script è un po' difficile aiutarti, però così funziona al 100%
Ho caricato l'intero progetto sul drive, lo puoi trovare nella pagina 2 e li ci sono gli script.
 
Riguardo lo score...
Assegna ad una variabile globale(int o float, dipende da come vuoi impostare lo score) scoreAdding il valore 10, dopodiché crei un'altra variabile globale numerica scoreValue con valore 0.
Ad ogni contatto(Più che alla distruzione, meglio se lo assegni all'entrata della collisione-sempre se non stai usando raycast),
Codice:
scoreValue += scoreAdding;

Senza lo script è un po' difficile aiutarti, però così funziona al 100%
gli script sono:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class GameController : MonoBehaviour
{
public GameObject hazard;
public Vector3 spawnValues;
public int hazardCount;
public float spawnWait;
public float startWait;
public float waveWait;

//Score variables
public GUIText scoreText;
private int score;

void Start()
{
score = 0;
UpdateScore();
StartCoroutine(SpawnWaves());
}

IEnumerator SpawnWaves()
{
yield return new WaitForSeconds(startWait);
while (true)
{
for (int i = 0; i < hazardCount; i++)
{
Vector3 spawnPosition = new Vector3(Random.Range(-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z);
Quaternion spawnRotation = Quaternion.identity;
Instantiate(hazard, spawnPosition, spawnRotation);
yield return new WaitForSeconds(spawnWait);
}
yield return new WaitForSeconds(waveWait);
}
}

public void AddScore (int newScoreValue)
{
score += newScoreValue;
UpdateScore();
}

void UpdateScore ()
{
scoreText.text = "Score: " + score;
}
}


using UnityEngine;
using System.Collections;

public class DestroyByContact : MonoBehaviour
{

public GameObject explosion;
public GameObject playerExplosion;
public int ScoreValue;

private GameController gameController;

void start ()
{
ScoreValue = 0;

GameObject gameControllerObject = GameObject.FindGameObjectWithTag("GameController");
if (gameControllerObject != null) //Replace gameController with gameControllerObject
{
gameController = gameControllerObject.GetComponent<GameController>();
}
if (gameController == null)
{
Debug.Log("Cannot find 'GameController' script!");
}
}

void OnTriggerEnter(Collider other)
{
if (other.tag == "Boundary")
{
return;
}

Instantiate(explosion, transform.position, transform.rotation);

if (other.tag == "Player")
{
Instantiate(playerExplosion, other.transform.position, other.transform.rotation);
Destroy(gameObject);
}
gameController.AddScore(ScoreValue);
Destroy(other.gameObject);
Destroy(gameObject);
Destroy(transform.parent.gameObject);


}
}
 
Riguardo lo score...
Assegna ad una variabile globale(int o float, dipende da come vuoi impostare lo score) scoreAdding il valore 10, dopodiché crei un'altra variabile globale numerica scoreValue con valore 0.
Ad ogni contatto(Più che alla distruzione, meglio se lo assegni all'entrata della collisione-sempre se non stai usando raycast),
Codice:
scoreValue += scoreAdding;

Senza lo script è un po' difficile aiutarti, però così funziona al 100%
cosa devo modificare nel mio script? grazie.
 
Stato
Discussione chiusa ad ulteriori risposte.