Jump to content
Sign in to follow this  
TheShopKeeper

Ayuda para optimizar código

Recommended Posts

Saludos por acá, soy algo nuevo en esto, y estoy practicando para ir dominando poco a poco el C#. Pero mientras estaba haciendo un código me surgió una duda.

 

Lo que sucede es que estoy haciendo como una especie de reproductor de música y entonces según la canción que esté tocando le pido que cargue una imagen para el fondo. Lo que me gustaría saber es si el código se podría optimizar más, para ir aprendiendo y ver como quedaría de una manera más profesional, porque me parece que en el modo que lo hice estoy consumiendo recursos en vano.


 

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

public class MusicPlayer : MonoBehaviour
{
    private int index = 0;

    public Image Wallpaper;


    // Use this for initialization
    void Start()
    {

    }
    

    // Update is called once per frame
    void Update()
    {

        // WALLPAPER CHECK
        switch (index % songs.Length)
        {
            case 0:
                Wallpaper.sprite = Resources.Load<Sprite>("Images/wallpaper_0");
                break;
            case 1:
                Wallpaper.sprite = Resources.Load<Sprite>("Images/wallpaper_1");
                break;
            case 2:
                Wallpaper.sprite = Resources.Load<Sprite>("Images/wallpaper_2");
                break;
        }

    }

}

 

La cuestión es que creo que de este metodo estoy cargando "la misma imagen" una y otra y otra vez. O sea gastando memoria cargando el recurso una y otra vez.

¿Alguna recomendación que me puedan brindar?

Si conociera la forma me gustaría de alguna manera "Cargar" todos los fondos una primera vez y luego solo decirle que cuando suene "X" canción se reemplace la imagen. Pero bueno, lo dejo a criterio de ustedes que tienen más experiencia. Saludos

Share this post


Link to post
Share on other sites

Lo mas sencillo es crear una variable publica en la clase,

public Sprite[] Sprites[];

Agregar los sprites arrastrando al script y modificar los valores desde Update,  

 void Update () {

        Wallpaper.sprite = Sprites[index % songs.Length];

    }

 

  • Like 1

Share this post


Link to post
Share on other sites
5 hours ago, AlterKZero said:

La cuestión es que creo que de este metodo estoy cargando "la misma imagen" una y otra y otra vez. O sea gastando memoria cargando el recurso una y otra vez.

¿Alguna recomendación que me puedan brindar?

 

si, al estar el "switch" dentro del "Update" esta haciendo que se ejecute todo el rato esa parte de codigo... esto esta bastante mal...

no se como haces para elegir una cancion u otra, pero lo suyo seria hacer que cargase la imagen solo al iniciar...

cuando eliges la cancion, o cuando la mandas sonar... no se como funcionara eso ya que este script solo carga la imagen... 

  • Like 1

Share this post


Link to post
Share on other sites
On 8/21/2018 at 8:48 PM, AlterKZero said:

La cuestión es que creo que de este metodo estoy cargando "la misma imagen" una y otra y otra vez. O sea gastando memoria cargando el recurso una y otra vez.

Claro, dos cosas no solo la misma imagen una y otra vez sino que si no fuera una y otra vez ponele cada vez que cambias o no de tema estás recargando la imagen, menos intenso pero aun así haciendo cosas innecesarias, podes cargar todo al comienzo y listo.

On 8/21/2018 at 8:48 PM, AlterKZero said:

¿Alguna recomendación que me puedan brindar?

Bueno lo que ya te dijeron arriba y no hacer todo en Update. En gral si queres tocarlo un poco podés separar las cosas, osea: reproductor = monobehaviour ... recurso = tu "Track" . Por Track me refiero al conjunto AudioClip , Imagen, Descripción, Nombre, Artista, etc todo esta info puede estar en una clase generica de C#. En tu reproductor podes tener una lista de Tracks, todo algo así:

[System.Serializable]
public class Track
{
	public string title;
	public string artist;
	public string year;
	public string duration;
	public AudioClip clip;
	// ...
}

public class AudioPlayer : MonoBehaviour {

	[SerializeField]
	List<Track> m_trackList = new List<Track>();

	...

      
      public void PlayTrack(Track target)
      { 
      	audioSource.Stop();
      	audioSource.clip = target.clip;
      	audioSource.Play();
      }
		
}

 

 

  • Like 1

Share this post


Link to post
Share on other sites

Muchas gracias @lightbug @B-£otus @Igor @kaito , seguí sus aclaraciones y me gustó bastante la idea de @kaito al final creé una variable pública y cargué las imágenes arrastrándolos al script y luego con el update los cambiaba.

El código me quedó algo así:

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

public class MusicPlayer : MonoBehaviour {

    public AudioClip[] songs;
    private AudioSource player;
    private int index = 0;
    private Text title, timer;
    private Animator animator;

    public Image Wallpaper;
    public Sprite[] Wallpapers;
 

    // START!!!
    void Start () {
        player = GetComponent<AudioSource>();
        player.clip = songs[index];

        title = transform.Find("Texts-----------/TitleMusic").gameObject.GetComponent<Text>();
        title.text = player.clip.name;

        timer = transform.Find("Texts-----------/Time").gameObject.GetComponent<Text>();

        animator = transform.Find("Logo").gameObject.GetComponent<Animator>();
        animator.enabled = false;

        
    }

    //PLAY
    public void Play()
    {
        if (CheckNullSong()) return;

        if (!player.isPlaying)
        {
            player.Play();
            animator.enabled = true;

            CancelInvoke("Next");
            Invoke("Next", player.clip.length - player.time + 1f);
        }
        else
        {
            player.Pause();
            animator.enabled = false;
            CancelInvoke("Next");
        }

        Invoke("Next", player.clip.length + 1f);

    }

    //STOP
    public void Stop()
    {
        player.Stop();
        animator.enabled = false;
        CancelInvoke("Next");
    }

    //NEXT
    public void Next()
    {
        player.clip = songs[++index % songs.Length];
        if (CheckNullSong()) return;
        player.Play();
        animator.enabled = true;

        title.text = player.clip.name;

        CancelInvoke("Next");
        Invoke("Next", player.clip.length + 1f);
    }

    //PREV
    public void Prev()
    {
        if (--index < 0) index = songs.Length - 1;
        player.clip = songs[index % songs.Length];
        if (CheckNullSong()) return;
        player.Play();
        animator.enabled = true;

        title.text = player.clip.name;

        CancelInvoke("Next");
        Invoke("Next", player.clip.length + 1f);
    }

    
	
	// UPDATE!!
	void Update () {
        int minutes = (int) player.time / 60;
        int seconds = (int)player.time % 60;

        timer.text = minutes.ToString("00") + ":" + seconds.ToString("00");

        // WALLPAPER CHECK
        Wallpaper.sprite = Wallpapers[index % songs.Length];

    }



    bool CheckNullSong()
    {
        if (player.clip == null)
        {
            Debug.Log("Null Song");
            title.text = "Song not found";
            animator.enabled = false;
            CancelInvoke("Next");
            Invoke("Next", 3f);
            return true;
        }
        return false;
    }
}

¿Creen que hay algo que haya hecho mal o que pueda seguir optimizando? Me gustaría aprender a hacer las cosas lo mejor posible, pero no es como ir a google y decirle "Como optimizar mi codigo de tal cosa".

 

Aunque tengo una duda que me gustaría conocer para variar.

En este caso nadamás tengo 9 canciones, porque es algo sencillo y arrastrar 9 imágenes no me cuesta trabajo, pero si hubieran sido no se unas 50 canciones.

¿No hay alguna forma por script de "Cargar" y dejarlas almacenadas en la memoria como si fuera una Caché, para luego decirle que quiero mostrar la imagen? Como ejemplo esos típicos juegos que cargan todos los resources al comienzo del juego y ya luego no vez más el cartel de "Cargando"?

Saludos y gracias por las respuestas anteriores.

¿Creen que hay algo que haya hecho mal o que pueda seguir optimizando? Me gustaría aprender a hacer las cosas lo mejor posible, pero no es como ir a google y decirle "Como optimizar mi codigo de tal cosa".

 

Aunque tengo una duda que me gustaría conocer para variar.

En este caso nadamás tengo 9 canciones, porque es algo sencillo y arrastrar 9 imágenes no me cuesta trabajo, pero si hubieran sido no se unas 50 canciones.

¿No hay alguna forma por script de "Cargar" y dejarlas almacenadas en la memoria como si fuera una Caché, para luego decirle que quiero mostrar la imagen? Como ejemplo esos típicos juegos que cargan todos los resources al comienzo del juego y ya luego no vez más el cartel de "Cargando"?

Saludos y gracias por las respuestas anteriores.

Share this post


Link to post
Share on other sites

creo que el wallpaper lo deverias cambiar en "play" en "prev" y en "next" que son las que cambian la cancion... en vez de en "Update"

  • Like 2

Share this post


Link to post
Share on other sites
15 hours ago, AlterKZero said:

Muchas gracias @lightbug @B-£otus @Igor @kaito , seguí sus aclaraciones y me gustó bastante la idea de @kaito al final creé una variable pública y cargué las imágenes arrastrándolos al script y luego con el update los cambiaba.

Coincido con @Igor eso no deberías hacerlo en Update, por más que la referencia de la imagen ya la tengas (un "gran" problema resuelto) hacerlo cuadro a cuadro no se justifica, es decir siempre que puedas evitar un update (mismo para el resto de los mensajes cuadro a cuadro) hacelo. Viendo el código si tenes que usar el update si o si (por lo del tiempo) igual no estaría mal sacar lo del wallpaper.

 

15 hours ago, AlterKZero said:

¿No hay alguna forma por script de "Cargar" y dejarlas almacenadas en la memoria como si fuera una Caché, para luego decirle que quiero mostrar la imagen? Como ejemplo esos típicos juegos que cargan todos los resources al comienzo del juego y ya luego no vez más el cartel de "Cargando"?

Es lo mismo que estas haciendo ahora, al arrastrar al inspector tus imagenes estas cargandolas al iniciar el play, pasa igual que poner Resoruces.Load en Awake(no se si exactamente igual pero parecido al ojo humano), luego segun convenga se iran presentando de la manera que sea, pero es basicamente lo mismo, distinto a antes que estabas cargando en Update una y otra vez.

Personalmente yo nunca pondría imagenes en el inspector, como decís todo se empieza a desmoronar cuando tenes varias y no tenemos ganas de trabajar, así que tendría algún criterio como por ej:

Dream Theater/Images and Words/Images and Words.png y quizas quiero reproducir-> Dream Theater/Images and Words/Surrounded.mp3, entonces presento la imagen relacionada al directorio, quizás imponga que tenga el mismo nombre de la carpeta, quizas que sea la primera que salga (probablemente esta), igual así funcionaba winamp o aimp o el reproductor de windows creo, buscan la primer imagen que se les aparezca en el directorio. Las imagenes relacionadas a los albums se cargan al comienzo, aca podés usar cualquier criterio de carga  (cargar hasta 1 MB, hasta 1 GB , etc) no es necesario cargar quizas las imagenes de los 2 millones de albums que tengas, si cae fuera del bloque se cargara un bloque enterio nuevo más, igual que como funciona una cache real. EN resumen cada vez que le doy Play a un tema (Surrounded.mp3) se cargará su imagen asociada (Images and Words.png), lo mismo para el resto de la informacion que contenga el mismo mp3, creo que podés extraer del archivo esa clase de cosas como año, duración, interprete, etc.

Saludos

  • Like 1

Share this post


Link to post
Share on other sites

@Igor @lightbug me alegra que me pudieran iluminar por esta parte, no había pensado de esa manera, siempre que pueda hacer las cosas sin utilizar el update sería lo ideal.

Tengo una duda que no me he puesto a investigar mucho de ella, pero la dejo caer por si acaso tienen experiencia hacerca de ello. En este caso todos los sprites, fondos y etc están en elementos separados, o sea, los fondos para las canciones son, wallpaper_1.png, wallpaper_2.png y así sucesivamente.

Según tengo entendido (no estoy seguro) el uso de "Atlas" permite una reducción de consumo de memoria, ahora, en el caso mío, ¿si yo creo una imagen de 2048x2048 y pusiera todos los "wallpapers" en esa imagen, consumiría menos que con cada fondo en archivos separados?

Saludos y gracias una vez más.

Share this post


Link to post
Share on other sites

La verdad no se del consumo de memoria, si te referís a consumir menos todas juntas vs todas las individuales juntas quizás puedas beneficiarte en algo si haces compresión a un solo archivo con todos los datos, en vez de a muchos archivos separados, la verdad no lo se.

Tengo entendido que crear una atlas implica cargar más cosas en memoria, pero procesarlas más rápido. Es beneficioso a la hora de renderizar esa imagen ya que el recurso donde el proceso debe tomar la información es uno solo y ya está en memoria, lo procesaría más rápido que tener que andar cargando y renderizando muchas imagenes separadas todo el tiempo. (Un sprite en multiple funciona algo así, un mini atlas). Fijate que se ve mucho con imagenes pequeñas/medianas valiendose de dos puntos, 1- su frecuencia de uso , 2 - su tamaño, si se requieren en todo momento (alta frecuencia) -> Joya , si se pueden llegar a requerir de vez en cuando pero son pequeñas y no molestan -> Joya. Fijate que pasa si lo hacés con cientos de wallpapers 4k, el consumo (utilización) de memoria se te escaparía, estarías usando muchisima memoria solamente para esto (>5GB con cientos de 4k, en crudo) cuando quizás la frecuencia de uso entre todos no lo sea tan alta y ni te convenga hacerlo (preferible cargarlo cada vez que los necesites).

Si tenés dudas y de paso lo verificás (nunca metí mano en esto) fijate el profiler, la parte de memoria y la parte de "time" del update (para ver cuanto tardó en completar el frame), hacé un script que cambie cada X cuadros (o de uno en uno) entre todas las imagenes del atlas versus imagenes separadas.

Saludos

  • Like 1

Share this post


Link to post
Share on other sites

Ahh el profiler, cada vez que veo las gráficas esas les cojo un poco de miedo. Gracias por la aclaración @lightbug

Disculpa que haga otra pregunta una vez más, pero es que soy nuevo en este mundo y aparecen dudas a por montones. El estilo del reproductor toma algo así:

https://ibb.co/jRevA9
 

Entonces, la imagen del medio (la del esqueleto), se mueve si la música está reproduciéndose a través de una animación que le hice. Pero que sucede, hay veces que la canción suena algo bajito o incluso en unos segundos no suena, y se ve esa imagen moviendose, que es algo extraño porque la imagen intenta transmitir un ritmo. Por lo que pude notar en el inspector Unity es capaz de ver la "Onda" o no se como llamarle a esto:

https://ibb.co/hgJoV9

¿No existe alguna manera que en vez de mover la imagen del centro por una animación, lo haga según el nivel de la onda (por la amplificación de la misma, no me se el nombre de esto)?. Algo así como los espectros del Windows Media Player que cuando la música es fuerte sale muchos efectos y si la música es algo suave los efectos son más pacíficos

 

Share this post


Link to post
Share on other sites
7 hours ago, AlterKZero said:

¿No existe alguna manera que en vez de mover la imagen del centro por una animación, lo haga según el nivel de la onda (por la amplificación de la misma, no me se el nombre de esto)?. Algo así como los espectros del Windows Media Player que cuando la música es fuerte sale muchos efectos y si la música es algo suave los efectos son más pacíficos

Sí, he visto hace mucho algunos tutoriales al respecto, pero no se hacerlo, es cuestión de investigar, podés simplemente traducir el nivel en un gráfico (de la forma que quieras) o tomar una ventana de X muestras promediarlas y traducir esa cantidad. Y si querés el "Punchy" o el golpe podés aplicarle un pasa bajos a la canción original (no se si por código o quizás usando el componente LPF (?¿) ), tomar frecuencias menores a 150 hz (donde está la frecuencia fundamental del bombo, gralmente) y hacer lo mismo que antes para este resultado.

Para la animación podés relacionar velocidad de reproducción con nivel de onda, por decir algo.

  • Like 1

Share this post


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

UnitySpain © Todos los derechos reservados 2020
×
×
  • Create New...