Jump to content
Sign in to follow this  
J4v1v1g2

Estructura de subtitulo y audio.

Recommended Posts

Hi gente

Estoy ajustando un poco la programación que tenia de los subtitulos y se me ocurrió una estructura mas sencilla a la hora de la programación, el problema es que no se si se podría realizar tal y como lo tengo pensado, os comento.

Inicialmente tengo la estructura con los ( IEnumerator ) controlando los segundos para pasar de un subtitulo a otro, el tema es que quiero evitar meter cosas en el update como puede ser el  (IsPlaying), para no sobrecargar el procesamiento ya que es un juego principalmente para móvil, y según tengo entendido contra menos cosas en el update mejor.

resumidamente la estructura seria algo así:

IEnumerator subtitulo_1()//---------------------------------------------SUBTITULO 1
    {
        yield return new WaitForSeconds (3f);

        if (ui_juego_vr == true)                                          //--chekeo del modo vr
        {
           texto_cuadro.text = texto1;                                 //--Dialogo del subtitulo
           voz_sub.Play ();                                                  //--Audio

            StartCoroutine (subtitulo_2 ());                         //-comienzo subtitulo 2

         }

     }

IEnumerator subtitulo_2()//---------------------------------------------SUBTITULO 2
    {
        yield return new WaitForSeconds (2f);

        if (ui_juego_vr == true)                            //--chekeo del modo vr
        {
           texto_cuadro.text = texo_2;                  //--Dialogo del subtitulo
           voz2_sub.Play ();                                 //--Audio

         }

     }

Básicamente una vez que empieza el subtitulo se controla el cambio por los segundos de IEnumerator. 

La pregunta seria, si hay alguna manera de detectar cuando acaba el voz_sub.Play ();  para mandarlo  al subtitulo 2 al acabar el audio sin tener que ir calculando los subtitulo a segundos.

La idea seria controlarlo por void, sin tener que pasar por el update, mas o menos algo asi.

void subtitulo_1()    //---------------------------------------------SUBTITULO 1
    {
        if (ui_juego_vr == true)                                           //--chekeo del modo vr
        {
           texto_cuadro.text = texto1;                                 //--Dialogo del subtitulo
           voz_sub.Play ();                                                  //--Audio

           (chequea el final del audio " voz_sub.Play (); " y ejecuta el " void subtitulo_2(); "               

         }

     }

void subtitulo_2()    //---------------------------------------------SUBTITULO 2
    {
        if (ui_juego_vr == true)                            //--chekeo del modo vr

        {
           texto_cuadro.text = texo_2;                  //--Dialogo del subtitulo
           voz2_sub.Play ();                                 //--Audio

         }

     }

Espero que mas o menos se entienda la idea, ya que solo leyendo este post ya me lio hasta yo y eso que es lo que estoy progamando :7_sweat_smile:.

Atentamente

Javier García

Edited by pioj
Javivi, por favor, usa el <> para pegar código.

Share this post


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

para no sobrecargar el procesamiento ya que es un juego principalmente para móvil, y según tengo entendido contra menos cosas en el update mejor.

No es tan así, el hecho de simplemente poner "void Update(){ //dejarlo vacio }" hace que para cada gameObject que lo tenga (ponele en un componente) el motor tenga que llamar a todos estos updates, es mucho más pesado que hacer lo que está dentro (en este caso nada). Probá de meter Updates vacíos a 3000 objs y fijate que pasa en el profiler. Por esto tiene la mala fama. Osea la frase evitá el Update es una frase muy vaga muchas veces injustificada, es más yo te diría evitá tener varias corrutinas, si tenes 3000 corrutinas corriendo vs 3000 updates corriendo adivina quien va más rápido.

Si vas a tener un manager de dialogos estas atendiendo a un problema que no va a existir nunca, hasta que tengas, no se, 3000 managers de dialogo ?

Tiene sentido si vas a usar las corrutinas por comodidad, y por supuesto, no vas a tener miles de ellas.

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

Subtítulo 1 y 2 son subtitulos reales o solo tenés esos dos IEnumerators? si son reales y tenés que hacer X IEnumerators para los X subtítulos te diría que abandones ya mismo ese método.

 

7 hours ago, J4v1v1g2 said:

La pregunta seria, si hay alguna manera de detectar cuando acaba el voz_sub.Play ();  para mandarlo  al subtitulo 2 al acabar el audio sin tener que ir calculando los subtitulo a segundos.

Pero bueno, segun lo que pedís podés hacer un while algo así:

 IEnumerator subtitulo_1()//---------------------------------------------SUBTITULO 1
    {
        yield return new WaitForSeconds (3f);

        if (ui_juego_vr == true)                                          //--chekeo del modo vr
        {
           texto_cuadro.text = texto1;                                 //--Dialogo del subtitulo
           
			voz_sub.Play ();                                                  //--Audio
			
			while(voz_sub.siPlaying) <----
				yield return null;

			

            StartCoroutine (subtitulo_2 ());                         //-comienzo subtitulo 2

         }

     } 

 

Pero tené en cuenta lo de arriba, hacer un IEnumerator para cada subtitulo no es para nada eficiente.

Edited by lightbug

Share this post


Link to post
Share on other sites

Hi lightbug

Gracias por la rápida respuesta, como podrás ver la programación no es que sea mi campo:7_sweat_smile:,ese esquema fue un tutorial que encontré Internet y después de hacer la prueba, me di cuenta de que tenia que haber una manera mas sencilla de realizarlo y eliminar los  IEnumerator de la programación a ser posible.

La Idea era preparar los subtitulos de la escena en un gameobject e ir llamándolos conforme los necesitara, y si hay alguno en 2 partes que se vinculen ellos mismos desde el script, que en este caso seria intentar pasar del 2 al 3. 

 

void Subtitulo_1();
{
	texto_cuadro.text = texto1;           
	voz_sub.Play ();
}

void Subtitulo_2();
{
	texto_cuadro.text = texto2;           
	voz_sub2.Play ();
	(CHEKEO DEL AUDIO);
	Subtitulo_3();
}

void Subtitulo_3();
{
	texto_cuadro.text = texto3;           
	voz_sub3.Play ();
}

sorry de antemano por el mareo por todo el mareo que pueda ocasionar la pregunta :7_sweat_smile:

Share this post


Link to post
Share on other sites

Ah ok, igual como dato, si necesitas tener muchos elementos (vamos a llamarlos diálogos), como por ej subtitulos + audio correspondiente podés tener como base un scirptableObject, por ej, algo así:

using UnityEngine;

[CreateAssetMenu(menuName = "DialogueSystem/Dialogue")]
public class DialogueDataProfile : ScriptableObject
{
	[System.Serializable]
	public class DialogueData
	{
		[TextArea(3,10)] //<--- esto es una maravilla
		public string m_dialogueString;
		public AudioClip m_audioClip;
	}

	public DialogueData[] m_dataArray;
}

Entonces te vas en tu proyecto a "Create/DialogueSystem/Dialogue" (le mande este nombre pero llamalo como quieras) y ya tenés un dialogo.

di2.jpg

Di.JPG

Incluso podés crearte más, por ej una secuencia de dialogos, osea otro ScriptableObject que contenga este SCo de recién, para no se, setear esta vez los personajes que lo dirán, acá tenés que ser creativo y productivo, pero la principal idea es diferenciar lógica (el pasar de un dialogo a otro, reproducir audio, etc)  y datos (los diálogos), entonces no terminas teniendo texto1 , subtitulo14, etc.

Desde un componente cualquiera tuyo (idealemnte el Manager de diálogos) podés ir pasando de arriba a abajo, reproduciendo y mostrando el elemento del arreglo DialogueData como quieras, siempre tenés que tener una referencia al Sco para poder tomar sus datos.

También podrías usas una cola "queue" (en vez del array que puse) ya que te interesa ir sacando el que venga, creo que es más eficiente, no se la verdad, no las uso demasiado.

Edited by lightbug

Share this post


Link to post
Share on other sites

Gracias por el nuevo enfoque aunque esto me a liado un poco mas de lo que creía, solo me faltaría aprender a poder controlar los elemento para poder meter el texto del elemento en el canvas correspondiente , en principio me a creado un archivo en unity, pero no tengo ni idea de como manejarlo, tienes algún link de un vídeo o alguna web para poder echarle un ojo y pillarle algo de manejo, con todo te pongo la imagen del archivo que me ha creado a ver si te animas y puedes echarme una mano aclarándome un poco mas el manejo del archivo por aquí, aunque el link también me serviría ya que no quiero agobiar con esto mucho mas por el foro:7_sweat_smile:

 

 

imagen.jpg

 

Edited by J4v1v1g2

Share this post


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

Gracias por el nuevo enfoque aunque esto me a liado un poco mas de lo que creía, solo me faltaría aprender a poder controlar los elemento para poder meter el texto del elemento en el canvas correspondiente

Lo que menos quiero es liarte más jaja pero pensalo a estos objetos como datos, que vos vas llenando tranquilamente en el editor (me refiero directamente sobre el archivo y no desde el inspector), la diferencia es que si tenés muchos elementos podés leer todo desde un mismo lugar y no vive en la escena, sino en tu proyecto, es una base de datos.

A la hora de llamar a la string o al audioclip lo unico que tenés que hacer es algo así:

// Antes ----------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------
public string text1;


//Y lo llamabas
Dialogo = text1; //ponele


// Ahora ----------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------


//aca va el obj que creaste, el dialogo...
//lo arrastras al inspector!!
public DialogueProfile data;


//Y lo llamas cuando quieras así, por ej la pos 0 (primer dialogo)
Dialogo = data.m_dataArray[0].m_dialogueString;

Aca llamé al "0" pero vos podrías llamar al que quieras, es a modo de ejemplo nada más.

Obviamente podés expandirlo, para que lo veas todavía mejor, imaginate esta escena (puede ser el caso de tu juego como que no, solo a modo de ejemplo), hay una coversación entre tres personajes, uno dice una serie de oraciones, luego interrumpe otro, diciendo algo, luego el tercero empieza hablar, etc... cada vez que habla alguien aparece una imagen de quien está hablando con un fondo característico de cada uno, en una posición de la pantalla, con una cierta musica, bla bla... La cosa es que con este enfoque es relativamente sencillo hacerlo. Suponiendo que tenés un manager que hace lo que tiene que hacer, vos podés definir:

  • Un Sco llamado "Character" para cada personaje, donde personalizas todo, imagen, fondo, fuente que vas a usar, musica que suena, etc
  • Un Sco llamado "DialogueItem" (este que te pasé, cualquiera el nombre jaja) qeu tiene basicamente lo que dice, quizas + audio, y traducciones, que se yo...
  • Un Sco llamado "DialogueSequence" que contiene un clase formada por "Character(singular) y Dialogues", y lo que quieras, tiempos, delays, etc, (utiles para el manager luego)

Entonces, a que voy, el manager no tiene porque saber de "Character" ni de "DialogueItem", pero lo que si maneja es de "DialogueSequence"... cuando se dé cierto evento, el disparador del evento llama al manager y le pasa una secuencia que tiene (podés metersela como una referencia, arrastrando hasta el inspector)  para que la reproduzca.

//El manager

//Aca te enfocás en los delays, las corrutinas, los updates, etc

public void StartSequence(DialogueSequence seq){
	
	...
}

Se que es mucho de golpe, pero pensalo así, eliminaste todo texto1, texto2, separaste logica, de datos, y quizás muy importante, con solo cambiar una secuencia desarrollaste otro argumento en tu historia, es decir, que el desarrollo del juego (por lo menos la parte de los dialogos) ahora se basa en crear estas secuencias. Ni hablar que podés cargarlas usando cualquier formato, como JSOn o el que se te ocurra.

No digo que debas cambiar todo, solo digo que lo investigues. Si querés averiguar más de Sco busca en Unity Learn o en Youtube, hay muchos ejemplos de porque son tan útiles, y no son para nada complicados.

 

Share this post


Link to post
Share on other sites

A costado ,pero creo que al final ya le he pillado el truquillo, no podre decir que hoy no me he acostado sabiendo algo nuevo, a ver si mañana acabo el script y no sale ninguna problemilla mas :6_smile:

 

Share this post


Link to post
Share on other sites

Hola este problema que tuviste me animo a hacer un script en base al que tu hiciste, no se si sea mas cómodo pero aquí esta xP

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

public class SubTitulos : MonoBehaviour{

	public string[] subtitulos;
	public AudioClip[] audio;
	public float[] tiempo; // Tiempo para iniciar cada dialogo.
	public int contador;

	public Text cuadroTexto;
	public AudioSource voz;

	public void Iniciar (){
		contador = 0;
		StartCoroutine (Subtitulo());
	}
	public void Parar (){
		StopAllCoroutines ();
	}

	public void Retornar (){
		StartCoroutine (Subtitulo());
	}

	IEnumerator Subtitulo (){
		yield return new WaitForSeconds (tiempo[contador]);
		cuadroTexto.text = subtitulos [contador];
		voz.clip = audio [contador];
		voz.Play ();
		yield return new WaitForSeconds (voz.clip.length);
		contador += 1;
		if(contador >= subtitulos.Length){
			// aqui puedes poner alguna funcion para que se ejecute al terminar todos los subtitulos.
		}else{
			Retornar ();
		}
	}
}

si no te es útil quizás a otro por eso igual lo subo :'v le sea de utilidad igual lo hice por que necesito uno para mi proyecto xD.

Edit: olvide decir que le añadí eso que pediste al inicio de verificar si ya acabo el audio, no creo que sea necesario eso en su lugar puedes usar "yield return new WaitForSeconds (voz.clip.length);" esto hara que espere a que la voz se termine indirectamente :'v.

Saludos!

hace 9 horas, lightbug said:

Ah ok, igual como dato, si necesitas tener muchos elementos (vamos a llamarlos diálogos), como por ej subtitulos + audio correspondiente podés tener como base un scirptableObject, por ej, algo así:


using UnityEngine;

[CreateAssetMenu(menuName = "DialogueSystem/Dialogue")]
public class DialogueDataProfile : ScriptableObject
{
	[System.Serializable]
	public class DialogueData
	{
		[TextArea(3,10)] //<--- esto es una maravilla
		public string m_dialogueString;
		public AudioClip m_audioClip;
	}

	public DialogueData[] m_dataArray;
}

Entonces te vas en tu proyecto a "Create/DialogueSystem/Dialogue" (le mande este nombre pero llamalo como quieras) y ya tenés un dialogo.

di2.jpg

Di.JPG

Incluso podés crearte más, por ej una secuencia de dialogos, osea otro ScriptableObject que contenga este SCo de recién, para no se, setear esta vez los personajes que lo dirán, acá tenés que ser creativo y productivo, pero la principal idea es diferenciar lógica (el pasar de un dialogo a otro, reproducir audio, etc)  y datos (los diálogos), entonces no terminas teniendo texto1 , subtitulo14, etc.

Desde un componente cualquiera tuyo (idealemnte el Manager de diálogos) podés ir pasando de arriba a abajo, reproduciendo y mostrando el elemento del arreglo DialogueData como quieras, siempre tenés que tener una referencia al Sco para poder tomar sus datos.

También podrías usas una cola "queue" (en vez del array que puse) ya que te interesa ir sacando el que venga, creo que es más eficiente, no se la verdad, no las uso demasiado.

Wow siempre busque como hacer eso y nunca lo encontré, eso me va a ser muy útil muchas gracias aunque no sea conmigo :'v

jajajajaja Te amo lightbug (En el buen sentido de la palabra) aquí la versión final lo usare en todos mis proyectos :'v

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

[CreateAssetMenu(menuName = "DialogueSystem/Dialogue")]
public class DialogueDataProfile : ScriptableObject
{
	[System.Serializable]
	public class DialogueData
	{
		[TextArea(3,10)] //<--- esto es una maravilla
		public string dialogo;
		public AudioClip audio;
		public float tieIni; // Tiempo para iniciar;
	}

	public DialogueData[] m_dataArray;
}

public class SubTitulos : MonoBehaviour{

	//public string[] subtitulos;
	//public AudioClip[] audio;
	//public float[] tiempo; // Tiempo para iniciar cada dialogo.
	public DialogueDataProfile.DialogueData[] dialogos;
	public int contador;

	public Text cuadroTexto;
	public AudioSource voz;

	public void Iniciar (){
		contador = 0;
		StartCoroutine (Subtitulo());
	}
	public void Parar (){
		StopAllCoroutines ();
	}

	public void Retornar (){
		StartCoroutine (Subtitulo());
	}

	IEnumerator Subtitulo (){
		yield return new WaitForSeconds (dialogos[contador].tieIni);
		cuadroTexto.text = dialogos[contador].dialogo;
		voz.clip = dialogos[contador].audio;
		voz.Play ();
		yield return new WaitForSeconds (voz.clip.length);
		contador += 1;
		if(contador >= dialogos.Length){
			// aqui puedes poner alguna funcion para que se ejecute al terminar todos los subtitulos.
		}else{
			Retornar ();
		}
	}
}

ahora con la mejora :3

Edited by Misterio El GatoConSuerte

Share this post


Link to post
Share on other sites
7 hours ago, Misterio El GatoConSuerte said:

Wow siempre busque como hacer eso y nunca lo encontré, eso me va a ser muy útil muchas gracias aunque no sea conmigo :'v

jajajajaja Te amo lightbug (En el buen sentido de la palabra) aquí la versión final lo usare en todos mis proyectos :'v

Jajaja Que bueno que te haya servido :5_smiley::91_thumbsup:

Share this post


Link to post
Share on other sites

la verdad es que la explicación de lightbug me va a venir al pelo para unas cosas que tengo que reorganizar, eres un crack:6_smile:

solo me queda el ultimo ajuste.

void VR()
{
	if (VR == true)
		{
			texto_cuadro.text = data.m_dataArray [0].m_dialogueString;
			voz_sub.clip = data.m_dataArray [0].m_audioClip;
			voz_sub.Play ();
			
			if(voz_sub.isPlaying)
			{
				(ESPERAR 1 SEGUNDO Y REPETIR EL isPlaying)<<-solo necesito repetir en blucle del isplaying. 
			}else{
				Finish();
			}						
		}
{

void Finish();

 

Share this post


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

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