Jump to content
Sign in to follow this  
iRobb

Breve definición de mi Arquitectura

Recommended Posts

1.Definición de Object
Un Object es una class herededa de Mono que contiene una serie de funciones y propiedades virtuales básicas. Todo el resto hereda de esta clase base.
Cada Object es responsable de la inicialización/destrucción de sus Objects en jerarquía inferior.
No está permitido desactivar ninguno de los Objects mediante enabled/SetActive. Esto es debido a que un gameobject vuelve a llamar a las funciones Awake/Start/OnDestroy cuando esto ocurre y no son acciones deseables.

Todos los Objects contienen:
- Funciones virtuales de inicialización/destrucción específicas (start y destroy).
- Función virtual de enable que permite activar/desactivar los diferentes updates a través del Update Manager

2.Definición de los diferentes Objects (Managers, Controllers y Components)
- Un Manager inicializa y gestiona el flujo entre Controllers.
- Un Controller inicializa Managers y Components, la gestión de flujo entre Components y otros Managers y contiene lógica de proceso.
- Un Component inicializa otros Components además de contener lógica de proceso.

La diferencia entre un Controller y un Component es que el Controller permite la interacción entre diferentes Components a través de él. Si los Components son privados al Component no se requiere de un Controller.

3.Referencia entre Objects
- Todo Object únicamente puede tener una y solo una referencia a otro Object. Como referencia se entiende referenciado en el editor o a través de GetComponent. Si hay más de un Controller que requiere acceder a un Component, se creará un Manager que gestione el acceso único al Controller que contiene ese Component.
- Un Controller no puede acceder a otro Controller directamente. Debe hacerlo a través de su Manager.
- Un Controller puede acceder a cualquiera de los Managers que tenga en su jerarquía superior.
- Un Component no puede acceder directamente a otro Component que no se encuentre referenciado directamente. Debe hacerlo a través del Controller común. Si el Component pertenece a otro Controller ésto debe hacerse a través de un Manager. Esta circunstancia evidencia con total probabilidad un error de diseño.

Para acceder a otros Components a través del Controller común o un Controller que acceda a un Manager se utilizan events específicos.

4.Scene Manager (SM)
Gestiona la carga y descarga de scenes de manera async e inicializa el Main Manager que es buscado en tiempo real.

5.Main Manager (MM)
Este Object es único por scene e inicializa todos los Managers de jerarquía superior. Es llamado en la carga de la scene por el Scene Manager. Contiene un start y destroy con delays a base de coroutines para permitir una inicialización sin bloqueos y de gestión de estados.

6.Update Manager (UM)
El Update Manager es una class static y singleton. Permite el registro/deregistro de cualquier Object que tenga la interface iUpdatable en tiempo real.

7.Object Pool Manager (OPM)
Este Manager permite la gestión de pooling de Objects que tengan el interface iObjectPool. El Manager no es global o static sino que se permiten múltiples instancias de OPM's para que puedan incluso integrarse en prefabs. Permite mantener un mínimo/máximo de Objects en pool y llama a unas funciones específicas de spawn y despawn.

8.Audio Manager (AM)
Es una class singleton.
Contiene una referencia al Audio Mixer único y a un Scriptable Object (SO) que contiene diferentes funciones y métodos para la gestión de audio. Desde el cambio de volumen en db's, la reproducción de audio vía streaming, events de cambios de estado en un audio o de multiidioma. Todos los audio sources tienen asignado un canal en el Audio Mixer.

  • Like 2

Share this post


Link to post
Share on other sites

esta muy bien. todo bien organizado y separado.

mi "arquitectura" no es una arquitectura... sino que voy creando y poniendo cada pieza que necesecito conforme me hace falta... y si es necesario modifico otras piezas para que esa encaje.

si que hago algunos "controllers" o "managers" pero no para todo. y lo del pool de objetos antes solia hacerlos mas.... ultimamente no lo hago.... antes lo hacia para objetos que de otra manera estarian todo el reto instanciandose y destruyendose.... como por ejemplo disparos, explosiones, etc... cosas que se crea y se destruyen todo el rato.... y asi se supone que es menos trabajo para la CPU, porque en vez de crear un objeto usarlo y destruirlo, lo que haces es cojer un objeto ya existente (cojerlo del pool) ponerlo donde te hace falta, usarlo, y luego volver a ocultarlo o desactivarlo...  y asi le evitas al programa tener que crearlo cada vez....  pero ultimamente ya no lo hago... salvo en casos de objetos "grandes"... porejemplo tengo un generador de terrenos procedurales que tiene un manager que coje pedazos del terreno que se han quedado atras, los oculta, los modifica (a lo largo de varios frames, con una corrutina) y te los pone delante y los muestra para que el terreno continue y sea infinito... reaprobecha los mismos pedazos todo el rato... tiene tambien un pool de arboles y rocas para colocarlos (o no), si es necesario, donde sea necesario... 

lo he usado para varios proyectos, uno de ellos es de naves, hize una version alternativa para que en vez de ser un terreno infinito serian planetas esfericos...  pero las naves disparaban... muchos disparos....  pues porejemplo esos disparos no estan en un pool... se crea y se destruye cada uno de los disparos...

asi que se podria decir que no tengo un sistema. simplemente voy haciendo lo que me parece mejor cada vez... aunque eso no es muy bueno, a veces me da muchos quebraderos de cabeza por no haberlo organizado todo mejor desde el principio...

  • Like 1

Share this post


Link to post
Share on other sites

@Igor El problema de esta creando constátente objetos es la llamada y costo del recolector de basura. En PC no se nota en sesiones cortas, pero te diría que habrás el Administrador de Tareas y Dejes disparando tu juego unas 3 horas y verás como el consumo de RAM empieza a subir.

Por otro lado la implementación de un PoolObject no debería por que ser un cambio radical en tu Script. Simplemente cambiarias Instantiate por

 PoolObject<BulletBehaviour>["bullets"].GetObject();

------------------------------------

@iRobb Me parece una buena arquitectura, en lo particular la sección 2 y 3 nunca las entendí a pesar de querer implementarlas parece como un pseudo MVC, no digo que esté mal, solo digo que nunca entendí la aplicación en Unity, use y uso MVC para desarrollo de software en general.

El único consejo que te daría es sobre AudioManager, es importante que en cada juego definas los Mixer que vas a contener, por eso, dentro del manager deberías tener una lista con todos los mixer, por ejemplo FX, UI, SOUNDs, MUSIC ... etc..  y cuando llamas a

 AudioManager.Instance.PlayOnShot(MixerIndex, AudioManager.Instance.GetAudioClip("MiAudio"));

 

Share this post


Link to post
Share on other sites

Sí claro @francoe1. El Audio Component accede a las tracks y a las propiedades expuestas del mixer. Utilizo un nombre de identificación para cada track.

  • Like 1

Share this post


Link to post
Share on other sites
2 hours ago, francoe1 said:

@Igor El problema de esta creando constátente objetos es la llamada y costo del recolector de basura. En PC no se nota en sesiones cortas, pero te diría que habrás el Administrador de Tareas y Dejes disparando tu juego unas 3 horas y verás como el consumo de RAM empieza a subir.

Por otro lado la implementación de un PoolObject no debería por que ser un cambio radical en tu Script. Simplemente cambiarias Instantiate por


 PoolObject<BulletBehaviour>["bullets"].GetObject();

 

hola

mirare de realizar ese cambio... pero no son solo las balas... son un montos de FX... laseres y explosiones de varios tipos, chispas y hits... etc....  y puede ser una locura controlar todos.... tener un pool con un monton de todos los posibles efectos.... por esos obte por crearlos y destruirlos...

de todas formas yo entiendo que al cambiar de escena (loadScene) se vacia el recolector de basura y la ram, no?

porque en ese juego estas de media 5 minutos en cada escenario. entonces la ram se vacia al cambiar, no?

Share this post


Link to post
Share on other sites

Yo lo hago de manera explícita una vez se han inicializado todos los componentes de la scene y al descargar la scene.

  • Like 1

Share this post


Link to post
Share on other sites
2 hours ago, iRobb said:

Yo lo hago de manera explícita una vez se han inicializado todos los componentes de la scene y al descargar la scene.

como lo haces. me puedes poner un ejemplo?

Share this post


Link to post
Share on other sites

Por supuesto. Tengo estas dos simples funciones en el Scene Manager:

        private void memoryInfo(string process) {
            Debug.Log("memoryGC" + process);
            Debug.Log("memoryGC:RAMTotal " + cSystemIOMemory.RAMTotal);
            Debug.Log("memoryGC:RAMAlloc " + cSystemIOMemory.RAMAlloc);
        }

        public IEnumerator memoryGC(string process) {
            this.memoryInfo(process);
            yield return StartCoroutine(cSystemIOMemory.memoryGC());
            this.memoryInfo(process);
        }

Una vez se han inicializado todos los componentes desde el main, lo llamo así:

 

          this.StartCoroutine(this.sceneManager.memoryGC("_main:end"));


Y me dará lo que actualmente llevo ocupado y lo que se ha liberado.

cSystemIOMemory es una extensión y contiene ésto:

    public static class cSystemIOMemory {
        public static string RAMTotal {
            get { return (SystemInfo.systemMemorySize.ToString() + " MB"); }
        }

        public static string RAMAlloc {
            get { return ((Profiler.GetTotalAllocatedMemoryLong() / 1000000).ToString("0") + " MB"); }
        }

        public static IEnumerator memoryGC() {
            yield return Resources.UnloadUnusedAssets();
            GC.Collect();
        }

 

  • Like 2

Share this post


Link to post
Share on other sites

muchas gracias.

vi ayer que me habias contestado pero lo vi en el curro, y como llegue a casa tarde pues no me puse a mirar el codigo con detenimiento... ahora ya si.

entiendo que casi todo el codigo es solo para ver la memoria gastada y liberada...

para eliminar assets no usados usas "unloadUnusedAssets()".... y cuando esto ha acabado usas "GC.Collect" para eliminar la basura... supongo que es este ultimo el que libera la ram... es algo asi?

lo usas al iniciar una escena y al "terminarla"? (cuando vas a cargar otra)

he mirado lo de unloadUnusedAssers y pone que hay que tener cuidado con las variables estaticas o modificaciones hechas a assets en la memoria... 

Static variables are also examined.

This requires extra care for assets which have been modified in memory. 

 

gracias de nuevo

 

Edited by Igor

Share this post


Link to post
Share on other sites

Sí. Al inicializar todo después de cargar una scene y al descargar otra. Para asegurarme. No he tenido problemas y si un buen ritmo de liberación de memoria antes de empezar.

Share this post


Link to post
Share on other sites
Sign in to follow this  

×
×
  • Create New...