Unity Spain

Post Antiguos => General (Antiguo) => Mensaje iniciado por: lightbug en Noviembre 23, 2016, 11:58:47 PM

Título: Metodo para cargar datos ya guardados
Publicado por: lightbug en Noviembre 23, 2016, 11:58:47 PM
Hola, hace unos dias me esta quemando el coco lo siguiente:
 
Tengo dos escenas,
 
La primera es una interfaz general, contiene menu principal, nuevo perfil, opciones, etc (solo una camara basicamente con menus).
 
La segunda es el juego en si (tiene un Player con muchas funcionalidades), y tengo pensado que sea una sola escena entera.
 
De entrada (en la escena 1) tengo un objeto (con DontDestroyOnLoad) que instancia una clase que se llama Game (singleton) que tiene informacion del estado actual del juego (si esta en menu, en running, en pausa, en skills(para las habilidades), si hay que guardar o cargar ) y a su vez el mismo objeto tiene otra clase llamada GameData que contiene funcionalidad de datos y ademas una clase serializable de los datos a guardar (objeto1, skill1, skill2 , ... posx,posy y posz), esta misma clase serializa y deserializa los datos y los guarda o carga en un directorio que yo indique.
 

public class GameData : MonoBehaviour{
private int numeroPerfil;
private SerializableData data = new SerializableData ();
private bool loadingData;
public bool isLoading() { return loadingData; }

private void ResetData ()
{
   //...
}
 
private void LoadData ()
{
   //...
}
public void SaveData()   //llamado desde un checkpoint
{
   //...
}
 
public void Create_Load_Game(int profile)   //llamado desde menu
{      
   //...
}

}
 

 
Hasta ahora bien, cada uno por su parte funciona de maravilla. el problema esta en el metodo me parece, que no se en que momento GameData le debe pasar los datos al player, ya que cuando cargo la escena no se si todavia se cargó el Player, y me tira NullReference logico.
 

//
//
SceneManager.LoadScene (1 , LoadSceneMode.Single);
<--- No se si ya se cargó o no

 
 
 
Entonces dentro de GameData le invente esto:
 

void Update()
{
   if (loadingData) {
      print ("loading ...");
      if (!Player.GetInstance ())
         return;
      if (!Player.GetInstance ().GetTransform ())
         return;   
         
      if (!Player.GetInstance ().GetTransform ().GetComponent<Player_Skills> ())
         return;
      
            //En este punto me aseguro que lo player, transform del player y skills existen
             
      LoadData ();
      ResetData ();
      Game.state = Game.GameState.running;
      loadingData = false;
            
   }
}

 
Todavia tengo algunos problemas con algunas cosas que no se cargan bien pero lo demas funciona bastante bien, la pregunta es la siguiente:
 
Existe una forma menos complicada de hacer esto? Ademas el proceso de carga actual funciona asi, pongo todo como estaba y ni bien se cargo lo que quiero lo modifico en el acto, obviamente imperceptible al ojo humano, ahora digamos que aparezco delante de 25 floreros, destruyo 17 floreros, lo guardo. salgo y lo cargo, aparecen los 25 y le restan los 17 en el acto, mmm no me cierra.
 
Lo primero que se me ocurre es en los juegos comerciales que antes de que se cargue todo cada cosa parece estar en su lugar como debe ser y una vez listo aparece la escena, o es un truco sucio que hacen los desarrolladores y en si hacen lo que puse arriba.
 
Saludos y gracias de antemano
 
 
 
 
Título: Metodo para cargar datos ya guardados
Publicado por: iRobb en Noviembre 24, 2016, 02:01:56 AM
Después de LoadScene ya se ha cargado. Por otro lado, pon lo del Update después del LoadScene que estará en el Singleton. Recuerda que el update se llama 60 veces por segundo, es para actualizar, digamos objetos de pantalla siendo procesos los más rápido posibles.
 
Creo que te falta conocer el funcionamiento básico de Unity, como todos al empezar, el workflow interno que tiene. Pilla algún tutorial más para entenderlo.
Título: Metodo para cargar datos ya guardados
Publicado por: kingtrase en Noviembre 24, 2016, 02:10:15 AM
@lightbug (por que sabe lo que hace), si vieses su perfil mismamente este contesta a muchas preguntas del foro con acierto. por otro lado si miramos en el Update () la funcion solo se ejecuta 1 vez que es cuando bool loadingData esta en true y luego cambia a false, el planteamiento es bueno, y por ahora va en buen camino, lightbug mira a ver en la doc de unity si existe algun evento justo despues de cargar la escena, si creas un prefab en la escena, (no instanciarlo) me refiero a que carge con la escena ya de serie compilado. la primera funcion que carga despues de LoadScene es Awake() y luego Start() y bueno ya sabes. puedes seguir ese camino.
Título: Metodo para cargar datos ya guardados
Publicado por: lightbug en Noviembre 24, 2016, 02:10:32 AM
Hola, justamente no es asi como decis, despues de LoadScene todavia no se carga la escena y me da nullreference, , la unica forma es usando un flag en update, lo verifique con Debug.Log y estoy completamente seguro que es asi.
 
unity no carga sus assets en el update por alguna razon utiliza otro camino, la instruccion es de LoadScene solo le da el aviso que la cargue. Igual lo del update me dispara dos print("loading..."), nada, muy rapido es.
 
Por otro lado use tambien OnLevelLoaded (o algo asi) en el Player y funciono pero me quedo un poco desprolijo
Título: Metodo para cargar datos ya guardados
Publicado por: iRobb en Noviembre 24, 2016, 02:11:57 AM
No creo que poner eso en el Update sea correcto, sobretodo sabiendo que después de la carga ya está la scene.
 
Yo creo que @lightbug es buen coder, pero la falta lo que todos al principio de meterse en Unity.
 
Voy a mirar como lo tengo yo hecho, que mi memoria no da para tanto y lo pongo.
 
Esta es mi función "core" de carga de scenes:   
 

    private IEnumerator _loadAppScene(string sceneName) {
            this.gcDestroy();
            Resources.UnloadUnusedAssets();
            ///////////////
      SceneManager.LoadScene(sceneName, LoadSceneMode.Single);
            Scene s = SceneManager.GetSceneByName(sceneName);
            while (s.isLoaded == false) {
                yield return null;
            }
            SceneManager.SetActiveScene(s);
      /////////////////
        }

 
Entre los comments lo que necesitas. Si la llamas con "yield return StartCor.... bla bla", después de esa línea la scene estará cargada.
Título: Metodo para cargar datos ya guardados
Publicado por: lightbug en Noviembre 24, 2016, 02:18:31 AM
iRobb A unity me meti en 2011 no te preocupes por eso ;) y el flag ese justamente esta para eso, el update ese vive dos ciclos y muere, hasta que reinicie el juego, osea, mas barato que eso no se puede jaja
 
La pregunta del millon del topic es si hay otro metodo o ustedes han usado algun otro metodo mas prolijo, que no sea como el ejemplo que di de los floreros.
 
 
Título: Metodo para cargar datos ya guardados
Publicado por: kingtrase en Noviembre 24, 2016, 02:18:52 AM
Piensa que el quiere saber cuando "loadingData" esta en true y ejecutar el codigo, eso lo haces en un bucle, y no hay mejor bucle que Update(). lo recomendable seria luego destruir ese objeto con ese script para que no siga llamando a Update()

SceneManager.LoadScene(sceneName, LoadSceneMode.Single);
            Scene s = SceneManager.GetSceneByName(sceneName);
            while (s.isLoaded == false) {
                yield return null;
            }
            SceneManager.SetActiveScene(s);

 
 
 
creo que es la respuesta xD
 
por que se acoplan los comentarios?? no mola nada
 
 
Título: Metodo para cargar datos ya guardados
Publicado por: lightbug en Noviembre 24, 2016, 02:23:46 AM
Cita de: kingtrase date=1479950332lo recomendable seria luego destruir ese objeto con ese script para que no siga llamando a Update()
   
   
       
   


Exacto, eso lo pense, pero el objeto es el responsable de Guardar cuando se llega a un CheckPoint jaja, lo unico se podria separarlos, pero tampoco funcionaria porque desde el juego podria volver al menu principal y cargar otro perfil (y no estaria ahi)
 



   
       
   
   

Scene s = SceneManager.GetSceneByName(sceneName);
            while (s.isLoaded == false) {
                yield return null;
            }
            SceneManager.SetActiveScene(s);

   
       
   

[/quote]
 
Ah usar un yield no lo pense asi, lo voy a probar y te digo
Título: Metodo para cargar datos ya guardados
Publicado por: iRobb en Noviembre 24, 2016, 02:31:39 AM
Entonces lo tienes mal diseñado. Esa función que tengo está en una clase singleton y el núcleo del juego hereda de esa clase.
 
A esa función no se la llama directamente, ya que hay una previa en la misma clase que es protected que gestiona las colas de scenes, sino que se llama a la gestora de colas (para ir atrás por ejemplo) y al terminar la llamada estoy en otra scene, pero la línea de código desde la cual se ha llamado se ejecuta después de la carga.
Título: Metodo para cargar datos ya guardados
Publicado por: lightbug en Noviembre 24, 2016, 02:39:07 AM
Cita de: iRobb date=1479951099Entonces lo tienes mal diseñado. Esa función que tengo está en una clase singleton y el núcleo del juego hereda de esa clase.
   
   
      A esa función no se la llama directamente, ya que hay una previa en la misma clase que es protected que gestiona las colas de scenes, sino que se llama a la gestora de colas (para ir atrás por ejemplo) y al terminar la llamada estoy en otra scene, pero la línea de código desde la cual se ha llamado se ejecuta después de la carga.
   


Seguramente este ligeramente diseñado ya que el juego completo esta casi terminado, pero cuando quise poner menus y manejo de scenes me choque contra un pared jaja. Ahora mismo parece funcionar muy bien, pero quiero pulir todo lo que se pueda.
 
Interesante algo asi queria hacer, una especie de clase "core" como decis vos encargada de gestionar absolutamente todo.
Título: Metodo para cargar datos ya guardados
Publicado por: iRobb en Noviembre 24, 2016, 02:46:32 AM
Realmente mi arquitectura es: 
 
- AppCore. Una clase core que el juego deriva para todos los apartados generales, siendo multi-scene (singleton)
 
- SceneCore. Una clase core con apartados propios por scene. De aquí el juego deriva otra y es una por scene (no singleton)
 
Básicamente contienen muchas funciones protected y virtual para ser override en las clases finales. Al conocerse la estructura de las clases, cada vez que se carga una scene el AppCore busca y llama a las funciones de inicialización de SceneCore.
 
Para el intercambio de información "inter-scene" hay una clase que acepta múltiples tipos de datos dentro de AppCore. Esta se guarda al salir SceneCore y se llama al entrar a la nueva SceneCore para que recoja datos propios del juego.
Título: Metodo para cargar datos ya guardados
Publicado por: lightbug en Noviembre 24, 2016, 02:52:29 AM
Cita de: iRobb date=1479951992Realmente mi arquitectura es: 
   
   
      - AppCore. Una clase core que el juego deriva para todos los apartados generales, siendo multi-scene (singleton)
   
   
      - SceneCore. Una clase core con apartados propios por scene. De aquí el juego deriva otra y es una por scene (no singleton)
   
   
      Básicamente contienen muchas funciones protected y virtual para ser override en las clases finales. Al conocerse la estructura de las clases, cada vez que se carga una scene el AppCore busca y llama a las funciones de inicialización de SceneCore.
   
   
      Para el intercambio de información "inter-scene" hay una clase que acepta múltiples tipos de datos dentro de AppCore. Esta se guarda al salir SceneCore y se llama al entrar a la nueva SceneCore para que recoja datos propios del juego.
   


Muy bueno  !  voy a analizarlo y ver como lo puedo extrapolar en mi proyecto (y en futuros proyectos)
 
Como es el formato de tu AppCore? del objeto que tiene la instancia de la clase? Es como mi objeto que tiene la clase Game? osea un GameObject que sobrevive a todo cambio de escena?
Título: Metodo para cargar datos ya guardados
Publicado por: iRobb en Noviembre 24, 2016, 02:59:25 AM
Te cuento. Una de las cosas que más fastidia es no probar las scenes de manera independientemente, sino tener que pasar por todas ellas para llegar a la que te interesa. Para dos scenes no es un problema, pero si tienes 10 en árbol es un problema. Entonces la appCore es singleton y DontDestroyOnLoad, pero está replicada en todas las scenes. El Awake de la appCore va guardando su número de instancias. Cuando llega a 0 llama al destructor del SceneCore y se destruye a sí misma, sino destruye a la AppCore que encuentra en la scene y llama a la SceneCore de la scene para empezar el proceso.
 
De este modo se puede cargar cada scene de manera independiente y realizar el testeo unitario sin pasar por todos los pasos.
Título: Metodo para cargar datos ya guardados
Publicado por: lightbug en Noviembre 24, 2016, 03:05:32 AM
Ah si se lo que es eso porque tuve problemas con lo mismo, yo hice un scipt InitGame que creaba el juego (singleton) independientemente de la escena, lo probe con tres y funciono , era algo asi:
 

using UnityEngine;
using System.Collections;
public class InitGame : MonoBehaviour {
public bool DebugGameplay = false;
void Awake () {
   if (!(Game)FindObjectOfType (typeof(Game))) {
      GameObject gameMaster = new GameObject ("Game");
      gameMaster.AddComponent<Game> ();
      if(!DebugGameplay){
         Game.state = Game.GameState.menu;
      }else{
         Game.state = Game.GameState.running;
      }
   }
}   
}

 
Lo hice a las apuradas pero para debug servia en otras escenas que no eran la inicial
Título: Metodo para cargar datos ya guardados
Publicado por: iRobb en Noviembre 24, 2016, 03:13:14 AM
Bueno, tu lo añades sino lo tienes. Yo sencillamente lo creo persistente en la scene y lo elimino si vengo de otra. El resultado es el mismo.
 
El dejarlo persistente tiene una ventaja y es si quieres cambiar parámetros del objeto en el editor para el testeo unitario.
Título: Metodo para cargar datos ya guardados
Publicado por: lightbug en Noviembre 24, 2016, 03:14:17 AM
Cita de: iRobb date=1479953594Bueno, tu lo añades sino lo tienes. Yo sencillamente lo creo persistente en la scene y lo elimino si vengo de otra. El resultado es el mismo.
   
   
      El dejarlo persistente tiene una ventaja y es si quieres cambiar parámetros del objeto en el editor para el testeo unitario.
   


Excelente, voy a ver eso Gracias!