Noticias

¡RECUERDA QUE SI ERES UN NUEVO USUARIO, DEBES PRESENTARTE PARA PODER PUBLICAR MENSAJES! | TENEMOS CANAL OFICIAL DE TELEGRAM: t.me/unity3dspain

Una ayudita con mi script?(nivel novato)

Iniciado por arkandius, Noviembre 21, 2016, 08:25:42 PM

Tema anterior - Siguiente tema
Noviembre 21, 2016, 08:25:42 PM Ultima modificación: Noviembre 21, 2016, 09:37:07 PM por arkandius
Buenas compañeros
Soy muy novato en programación, y más en C#. Necesito una pequeña ayudita. Me aparece un error de NullreferenceException (variable mal configurada) en mi código, el cual hace que al colisionar con una de mis herramientas, haga que ésta desaparezca, aumente en 1 el contador de la interfaz y reproduzca un sonido al recogerlo. EL tema está, que sólo me suma 1 en el contador al recoger la primera herramienta, el resto de herramientas no las contabiliza, sea en el orden que sea, de modo que le contador sigue en 1 aun habiendo recogido todas las herramientas. Me han comentado que debugee el código, pero cuando lo hago, si esque lo hago bien, no me aparece el error ni nada...

 
 
Os dejo el error y mi código! Y muchas gracias por vuestra ayuda!!
 
ERROR:

 
 



   
      NullReferenceException: Object reference not set to an instance of an object
Recoge_Herramientas+<OnTriggerEnter>c__Iterator0.MoveNext () (at Assets/Scripts/Recoge_Herramientas.cs:64)
UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) (at C:/buildslave/unity/build/Runtime/Export/Coroutines.cs:17)
   

[/quote]
 


 
 
CÓDIGO: 
 

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
 
public class Recoge_Herramientas : MonoBehaviour
{

public GameObject jugador;
public int herramientas_obtenidas;
public GameObject herramienta;
//Sonido
public AudioSource audio;
public AudioClip recogido;
private bool ispla***;
//Puntuación
private int contador;
public Text contadortext;
//Inicia el contador a 0
public void Start()
{
   contador = 0;
   SetContadorText();
}
 
//Recoge componente y pone ispla*** "audio" false.
public void Awake()
{
   audio = GetComponent<AudioSource> ();
   ispla*** = false;
   herramienta.SetActive (true);
}
//Función que establece en contadortext, el contenido de contador
void SetContadorText()
{
   contadortext.text = "Tools finded: " + contador.ToString ();
}
//Que pasa cuando colisiona con el game object
IEnumerator OnTriggerEnter(Collider hit)
{
   //Comprueba que tiene tag "player"
   if (hit.gameObject.tag == "Player")
   {
      //Si NO se ha reproducido, iniciarlo y colocar ispla*** = true
      if (!ispla***)
      {
         audio.Play();
         ispla*** = true;
      }
      GetComponent<Collider> ().enabled = false;
      GetComponent<MeshRenderer>().enabled = false;
      yield return new WaitForSecondsRealtime (audio.clip.length);
      //Destruye el objeto
      herramienta.GetComponent<MeshRenderer>().enabled = false;
      Destroy (herramienta, 1f);
      //Puntuación
      contador = contador+1;
      SetContadorText ();
   }
}
}

 
 

Hola, no me queda en claro si esto va en la herramienta o en el jugador, porque tenes public GameObject jugador y public GameObject herramienta. Vi mas o menos en detalle el codigo. Lo que te recomiendo en estos casos es crear un script recogedor, no un monton de scripts que esperen a ser recogidos, salvo que haya mas informacion en las "herramientas", pero si usas solo un tag no es necesario. Ponele "Player_recogedorDeHerramientas.cs" (por ejejmplo)
 
El nullreference se da siempre que estas tratando de acceder a algun componente y dicho componente no está (osea es nulo), pro ejemplo:
 

//MAL
if(objeto.GetComponent<BoxCollider>().size.x > 2)
  //hacer algo
 
 
//BIEN
  if(objeto.GetComponent<BoxCollider>()){
if(objeto.GetComponent<BoxCollider>().size.x > 2){
     //hacer algo
     }
  }

 
Claro que si tenes certeza de que algo tiene dicho componente no es necesario revisar si lo tiene, por ejemplo si arriba tenes un [RequiereComponent ...]
 
 
 
Si me permitis con respecto a la logica podes arrancar pensandolo de la siguiente manera (ademas para evitar estos problemas cuando empezas a complicar el codigo mas y mas):
 
- Podes tener una clase que lleve registro de lo que quieras, en este caso "contador" y darle metodos publicos que lo modifiquen:
 

//clase Registro.cs (creas este archivo)
private int contador;
void Start()
{
contador = 0;
}
public void SumarContador()
{
contador++;
//Aca reproducir Sonido si lo deseas, entonces sos libre de destruir el objeto ni bien colisiona
}

 
y en el codigo encargado de modificar este valor, el jugador por ejemplo:
 

private Registro registro;
void Start()
{
registro = GameObject.Find("Registro").GetComponent<Registro>(); //Debes llamas al objeto que tiene el script Registro como "Registro"
}
// cuando se produce la colision en el OnTriggerEnter
void OnTriggerEnter(Collider col)
      {
         if(col.tag == "herramienta")
        {
      registro.SumarContador();
            Destroy(col.gameObject);
        }
      }
     

 
Salu2!

Si lo he entendido bien entonces, debería hacer el script en el jugador y no en las herramientas, y en lugar de buscar el tag Player, uno como "pickupobject", y tener un script de registro que se modifica desde el script del player no?
 
Si es así, creo que ya sé cómo debo hacerlo :3 Muchas graciaas!!!!

Claro exactamente, igual no es que haya un metodo correcto, yo tengo en algunos objetos scripts como el tuyo, por ejemplo cuando el player entra en un trigger "activador", o algo parecido, ya que el mismo trigger tiene informacion de que activar, con que delay, con que condicion, etc.
 
Lo que no entendi es porque usaste IEnumerator, se que se usa para corrutinas pero no se nada mas jaja. yo antes las usaba mucho, despues espece a temporizar todo y me olvide la verdad.

Noviembre 21, 2016, 09:39:33 PM #4 Ultima modificación: Noviembre 21, 2016, 09:44:42 PM por arkandius
Pues la verdad es que no tengo ni idea, es lo que hacía el hombre del curso que estoy haciendo 
 
Cómo crees que debería hacerlo??
 
Por cierto, debería hacer una variable publica para las herramientas/grupo de herramientas? o con el tag bastará?
 
Acabo de terminar de editar el código y me salta este error: 
 



   
      Assets/Scripts/Recoge_Herramientas.cs(34,14): error CS1624: The body of `Recoge_Herramientas.OnTriggerEnter(UnityEngine.Collider)' cannot be an iterator block because `void' is not an iterator interface type

       
   

[/quote]
 
 

El tag sirve justamente para eso, el motor tiene ese sistema de etiquetas, como tiene las layers para el tema de las fisicas y colisiones. Que las variables publicas sean realmente necesarias, por ejemplo al player lo podes buscar con el find o con otros metodos, no es necesario que lo busques cada vez que pones un script.
 
Lo de las herramientas depende, cuantos tipos de herramientas tenes? por ejemplo si cada herramienta tiene una particularidad podes usar mas tags, pero si tenes muchisimas herramientas distintas, cada una con algun atributo unico, usar muchos tags no es practico a nivel orden, pones un script, o un scriptableObject (es una base de datos, no asociada a ningun gameObject). Fijate los tags que trae unity, creo que son Player, mainCamera, y algunos otros mas, bien basicos.
 
 

Y tienes idea de porqué me sale el error ese? no me deja probar la escena al tener error de compilación

Cita de: arkandius date=1479763077Y tienes idea de porqué me sale el error ese? no me deja probar la escena al tener error de compilación
   


Ah pero es un error de compilacion, segun lo que te dice ahi tiene que ver con el OnTriggerEnter, proba poner como te puse arriba void OnTriggerEnter() a ver que pasa.
 
aca lo tenes es las referencias:
 
OntriggerEnter

Noviembre 21, 2016, 10:28:02 PM #8 Ultima modificación: Noviembre 21, 2016, 10:30:47 PM por arkandius
Esto es lo que tengo ahora

 
 

   void OnTriggerEnter(Collider hit)
{
   //Comprueba que tiene tag "PickUp"
   if (hit.gameObject.tag == "PickUp")
   {
      //Si NO se ha reproducido, iniciarlo y colocar ispla*** = true
      if (!ispla***)
      {
         audio.Play();
         ispla*** = true;
      }
      registro.SumarContador();
      Destroy (hit.gameObject);
      yield return new WaitForSecondsRealtime (audio.clip.length);
   }
}

 
 

Cita de: arkandius date=1479763682Esto es lo que tengo ahora

       
   
   

   void OnTriggerEnter(Collider hit)
{
   //Comprueba que tiene tag "PickUp"
   if (hit.gameObject.tag == "PickUp")
   {
      //Si NO se ha reproducido, iniciarlo y colocar ispla*** = true
      if (!ispla***)
      {
         audio.Play();
         ispla*** = true;
      }
      registro.SumarContador();
      Destroy (hit.gameObject);
      yield return new WaitForSecondsRealtime (audio.clip.length);
   }
}

   
       
   


asi no te deveria dar error, el otro error era por que tenias IEnumerator OnTriggerEnter (Collider hit), no puedes cambiar el tipo de funcion a tu parecer, ya que son funciones derivadas de MonoBehaviour.

····>Desarrollando un videojuegos online-arcade para Android.


····>Programador en:C,C#,VB.net,PHP,HTML5,SQL,JS,Ruby.


····>Trabajando en: Desarrollo de paginas web y bushistudios.


                    ๑۩۞۩๑_(▀▄)KINGTRASE(▄▀)_๑۩۞۩๑ 



 
 
No entiendo, entonces debo tener col en vez de hit ? Pero aún teniendo el void me da error, os paso los dos scripts a ver...porque no entiendo nada...
 
 
 
El Registro.cs
 

using UnityEngine;
using System.Collections;
public class Registro : MonoBehaviour {
private int contador;
// Use this for initialization
void Start ()
{
   contador = 0;
}
public void SumarContador()
{
   contador++;
}
}

 
 
 
Recoge_Herramientas implementado en el player con tag player, las herramientas están con el tag PickUp
 

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Recoge_Herramientas : MonoBehaviour
{
public GameObject jugador;
//Sonido
public AudioSource audio;
public AudioClip recogido;
private bool ispla***;
//Puntuación
private Registro registro;
//Recoge componente y pone ispla*** "audio" false.
public void Awake()
{
   audio = GetComponent<AudioSource> ();
   ispla*** = false;
}
public void Start()
{
   registro = GameObject.Find("Registro").GetComponent<Registro>(); //Debes llamar al objeto que tiene el script Registro como "Registro"
}
   
//Que pasa cuando colisiona con el game object
void OnTriggerEnter(Collider col)
{
   //Comprueba que tiene tag "PickUp"
   if (col.gameObject.tag == "PickUp")
   {
      //Si NO se ha reproducido, iniciarlo y colocar ispla*** = true
      if (!ispla***)
      {
         audio.Play();
         ispla*** = true;
      }
      registro.SumarContador();
      Destroy (col.gameObject);
      yield return new WaitForSecondsRealtime (audio.clip.length);
   }
}
}

 
 
 
 

vale, el error te da al ejecutar el juego o cuando se compila el script, creo que te dar error por que siempre compruebas el tag de col, pero nunca compruebas si col es null, da igual col o hit, pon esnto en el if de OnTrigger->
 
if (col != null && col.gameObject.tag == "PickUp")

····>Desarrollando un videojuegos online-arcade para Android.


····>Programador en:C,C#,VB.net,PHP,HTML5,SQL,JS,Ruby.


····>Trabajando en: Desarrollo de paginas web y bushistudios.


                    ๑۩۞۩๑_(▀▄)KINGTRASE(▄▀)_๑۩۞۩๑ 



col es el collider que definis en OnTriggerEnter puede ser del nombre que quieras. LA misma IDE te dice donde y porque tenes un error, ayudaria si pones la linea donde esta. Estas usando mono (la default de unity)?

Noviembre 21, 2016, 11:07:58 PM #13 Ultima modificación: Noviembre 21, 2016, 11:08:51 PM por arkandius
Cita de: kingtrase date=1479765709vale, el error te da al ejecutar el juego o cuando se compila el script, creo que te dar error por que siempre compruebas el tag de col, pero nunca compruebas si col es null, da igual col o hit, pon esnto en el if de OnTrigger->
   
   
      if (col != null && col.gameObject.tag == "PickUp")
   


Nein, me sigue saltando el mismo error. :( Es error de compilación, no puedo darle a play.
 
Cita de: lightbug date=1479765744col es el collider que definis en OnTriggerEnter puede ser del nombre que quieras. LA misma IDE te dice donde y porque tenes un error, ayudaria si pones la linea donde esta. Estas usando mono (la default de unity)?
   


Ya he citado el error, es todo lo que dice, en otros errores si me salía la línea, pero en éste simplemente pone esto: 
 



   
      Assets/Scripts/Recoge_Herramientas.cs(34,14): error CS1624: The body of `Recoge_Herramientas.OnTriggerEnter(UnityEngine.Collider)' cannot be an iterator block because `void' is not an iterator interface type
   

[/quote]
 
Sisí estoy usando el monodevelop de unity, aunque tengo el notepad++

solo tienes ese error?, creo que tienes algun otro error y no compila, por eso ese error sigue saliendo, ya que la ultima lectura de unity fue esa, tienes mas errores?
 
ese error ya lo hemos solucionado, cambiando IEnumerator por void en el OnTriggerEnter.

····>Desarrollando un videojuegos online-arcade para Android.


····>Programador en:C,C#,VB.net,PHP,HTML5,SQL,JS,Ruby.


····>Trabajando en: Desarrollo de paginas web y bushistudios.


                    ๑۩۞۩๑_(▀▄)KINGTRASE(▄▀)_๑۩۞۩๑ 



Etiquetas: