//Log Dir http://docs.unity3d.com/Manual/LogFiles.html using UnityEngine; using System.Collections; using System.Collections.Generic; using System; using System.IO; using System.Text; using System.Runtime.InteropServices; using UnityEngine.UI; public abstract class GenericPlayerManager : MonoBehaviour { private struct AnimationReference { public string name; public string subtitle; public AnimationState state; public short type; public AnimationReference(string name, string subtitle, AnimationState state, short type) { this.name = name; this.subtitle = subtitle; this.state = state; this.type = type; } } private const string DEFAULT_ANIMATION = "_default"; private const string NONE_ANIMATION = "_defaultWORD"; private const float FADE_LENGTH = 0.6F; private const float WORD_DEFAULT_SPEED = 1.1F; private const float WORD_MAX_SPEED = 2F; // Velocidade da primeira letra de uma palavra private const float LETTER_FIRST_SPEED = 1.8F; // Velocidade máxima de uma letra que o slider pode configurar private const float LETTER_FIRST_MAX_SPEED = 2.8F; // Taxa de velocidade da primeira letra de uma palavra equivalente a velocidade de uma palavra private const float LETTER_FIRST_UNIT_SPEED = (LETTER_FIRST_MAX_SPEED - LETTER_FIRST_SPEED) / (WORD_MAX_SPEED - WORD_DEFAULT_SPEED); // Velocidade das outras letras private const float LETTER_DEFAULT_SPEED = 2.8F; // Velocidade máxima de uma letra que o slider pode configurar private const float LETTER_MAX_SPEED = 4.3F; // Taxa de velocidade das outras letras equivalente a velocidade de uma palavra private const float LETTER_UNIT_SPEED = (LETTER_MAX_SPEED - LETTER_DEFAULT_SPEED) / (WORD_MAX_SPEED - WORD_DEFAULT_SPEED); // Velocidade de reprodução de números private const float NUMBER_DEFAULT_SPEED = 1.5F; // Velocidade máxima de um número que o slider pode configurar private const float NUMBER_MAX_SPEED = 2.9F; // Taxa de velocidade equivalente a uma unidade de velocidade de uma palavra private const float NUMBER_UNIT_SPEED = (NUMBER_MAX_SPEED - NUMBER_DEFAULT_SPEED) / (WORD_MAX_SPEED - WORD_DEFAULT_SPEED); private const short TYPE_NONE = -1; private const short TYPE_WORD = 0; private const short TYPE_LETTER = 1; private const short TYPE_NUMBER = 2; private static float hSlidersecond = WORD_DEFAULT_SPEED; private float letterSpeed = LETTER_DEFAULT_SPEED; private float numberSpeed = NUMBER_DEFAULT_SPEED; protected string glosa = ""; private static String[] stringPos = { DEFAULT_ANIMATION };//vetor que sera usado para quebrar a glosa private GameObject AVATAR; private Animation COMPONENT_ANIMATION; public Text SUBTITLES; // Guarda os nomes das palavras ja carregadas. private HashSet loadedAssetBundles = new HashSet(); // Guarda os nomes das palavras que nao tem assetbundle. private HashSet nonexistentAssetBundles = new HashSet(); // Lista de animações sendo reproduzidas. // Utilizada para alterar velocidade e apresentar a legenda. private volatile Queue animQueue = new Queue(); // "play" flag. Indica se está carregando a glosa. private volatile bool loading = false; protected bool playing = false; protected bool paused = false; public virtual void Start() { AVATAR = GameObject.FindGameObjectWithTag("avatar");//referencia para o avatar COMPONENT_ANIMATION = AVATAR.GetComponent();//referencia para o componente animador do avatar Application.ExternalCall("onLoadPlayer");//var onLoadPlayer = function(){} } protected virtual void setSubtitle(string text) { SUBTITLES.text = text; } // Define a velocidade das animacões com base no slider da GUI public void setSlider(float x) { hSlidersecond = x; letterSpeed = getProporcionalSpeed(LETTER_DEFAULT_SPEED, LETTER_UNIT_SPEED); numberSpeed = getProporcionalSpeed(NUMBER_DEFAULT_SPEED, NUMBER_UNIT_SPEED); if ( ! paused) foreach (AnimationReference reference in animQueue) if (reference.type != TYPE_NONE && reference.state != null) reference.state.speed = getSpeedByType(reference.type); } private float getProporcionalSpeed(float speed, float unit) { return speed + (hSlidersecond - WORD_DEFAULT_SPEED) * unit; } private float getSpeedByType(short type) { switch (type) { case TYPE_WORD: return hSlidersecond; case TYPE_LETTER: return letterSpeed; case TYPE_NUMBER: return numberSpeed; } return 2F; } public void stop_animations() { StopCoroutine("loadAndPlay"); loading = false; playing = false; paused = false; onPlayingStateChange(); stopAnimations(); } public void stopAnimations() { try { StopCoroutine("handleStates"); } catch (NullReferenceException nre) { Debug.Log("StopCoroutine handlestates nullreff::"+nre.ToString()); } setSubtitle(""); try { animQueue.Clear(); } catch (NullReferenceException nre) { Debug.Log("SetQueueList null reff::"+nre.ToString()); } COMPONENT_ANIMATION.Stop(); COMPONENT_ANIMATION.CrossFade(DEFAULT_ANIMATION, FADE_LENGTH, PlayMode.StopAll); } /* * Manda reproduzir animação e adiciona a file de animações a serem reproduzidas. * * Caso não haja SUBTITLE, name será utilizado como SUBTITLE. * Caso não haja fadeLength, será atribuido FADE_LENGTH. * Caso não haja velocidade, hSlidersecond será atribuída. */ private AnimationState playAnimation(short type, string name, string subtitle, float speed) { try { AnimationState state = COMPONENT_ANIMATION.CrossFadeQueued(name, FADE_LENGTH, QueueMode.CompleteOthers); state.speed = speed; animQueue.Enqueue(new AnimationReference(name, subtitle, state, type)); return state; } catch (NullReferenceException nre) { Debug.Log("'" + name + "' não foi encontrado!\n" + nre.ToString()); } return null; } private AnimationState playAnimation(short type, string name, string subtitle) { return playAnimation(type, name, subtitle, getSpeedByType(type)); } private AnimationState playAnimation(short type, string name) { return playAnimation(type, name, name); } /** * Returns the asset bundle named aniName. * * @return AssetBundle - se for encontrado. * null - se ocorrer num erro. */ protected abstract WWW loadAssetBundle(string aniName); /** * Listen to changes in the playing status. */ protected abstract void onPlayingStateChange(); public void play() { if (playing) { paused = ! paused; foreach (AnimationReference reference in animQueue) if (reference.state != null) reference.state.speed = paused ? 0F : getSpeedByType(reference.type); } else { playing = true; try{ if (loading) stop_animations(); else stopAnimations(); } catch (NullReferenceException nre) { nre.ToString(); } StartCoroutine("loadAndPlay"); } onPlayingStateChange(); } /* * Destaca caractere de uma string. */ private string highlight(string word, int index) { string subtitle = ""; int last = 0; if (index == 0) subtitle += "" + word[0] + ""; else subtitle += word[0]; for (int i = 1; i < word.Length; i++) { if ((word[i] >= 65 && word[i] <= 90) || (word[i] >= 48 && word[i] <= 57)) subtitle += "-"; if (i == index || (last == index && word[i] == word[last])) { subtitle += "" + word[i] + ""; if (i == index) last = i; } else { subtitle += word[i]; last = i; } } return subtitle; } /** * Spells word. * * @return last animation's subtitle. */ private string spellWord(string word) { string lastAnimationSubtitle = ""; bool defaultPlayed = false; // A reprodução da primeira letra deve ser longa para não ser cortada no fade letterSpeed = getProporcionalSpeed(LETTER_FIRST_SPEED, LETTER_FIRST_UNIT_SPEED); for (int i = 0; i < word.Length; i++) { char second = word[i]; lastAnimationSubtitle = highlight(word, i); // Se for uma letra if (second >= 65 && second <= 90) playAnimation(TYPE_LETTER, second.ToString(), lastAnimationSubtitle, letterSpeed); // Se for um número else if (second >= 48 && second <= 57) playAnimation(TYPE_NUMBER, second.ToString(), lastAnimationSubtitle, numberSpeed); // Se for uma vírgula else if (second == 44) playAnimation(TYPE_WORD, second.ToString(), lastAnimationSubtitle); // Não há animação else { // Reproduz animação default apenas uma vez if ( ! defaultPlayed) { defaultPlayed = true; playAnimation(TYPE_NONE, DEFAULT_ANIMATION, lastAnimationSubtitle); // A reprodução da próxima letra deve ser longa para não ser cortada no fade letterSpeed = getProporcionalSpeed(LETTER_FIRST_SPEED, LETTER_FIRST_UNIT_SPEED); } Debug.Log("Animação \"" + second + "\" inexistente."); continue; } defaultPlayed = false; letterSpeed = getProporcionalSpeed(LETTER_DEFAULT_SPEED, LETTER_UNIT_SPEED); } return lastAnimationSubtitle; } private IEnumerator loadAndPlay() { loading = true; string lastAnimationSubtitle = ""; bool spelled = false; // Default playAnimation(TYPE_NONE, DEFAULT_ANIMATION, "", 2F); StartCoroutine("handleStates"); stringPos = glosa.Split(' '); foreach (string aniName in stringPos) { try { if (String.IsNullOrEmpty(aniName)) continue; } catch (Exception e) { Debug.Log(e + " :: NotNullNotEmpty"); } bool nonexistent = nonexistentAssetBundles.Contains(aniName); bool loaded = loadedAssetBundles.Contains(aniName); if ( ! nonexistent && ! loaded) { // Função loadAssetBundle é definida pela classe filha WWW www = loadAssetBundle(aniName); if (www != null) { yield return www; AssetBundle bundle = null; if (www.error == null) bundle = www.assetBundle; if (bundle != null && ! String.IsNullOrEmpty(bundle.mainAsset.name)) { AnimationClip aniClip = bundle.mainAsset as AnimationClip; bundle.Unload(false); if (aniClip) { COMPONENT_ANIMATION.AddClip(aniClip, aniName); loadedAssetBundles.Add(aniName); loaded = true; } else Debug.Log ("Sinal \"" + aniName + "\" não carregado corretamente."); } } } // Reproduz palavra if (loaded) { if (spelled) { // Default playAnimation(TYPE_NONE, DEFAULT_ANIMATION, lastAnimationSubtitle); spelled = false; } playAnimation(TYPE_WORD, aniName); lastAnimationSubtitle = aniName; } // Soletra palavra else { // Se a animação não foi carregada e nem está marcada como não existente, // adiciona ao set de animações não existentes if ( ! nonexistent) nonexistentAssetBundles.Add(aniName); // Se já houve o soletramento de alguma palavra, reproduz animação default if (spelled) playAnimation(TYPE_NONE, DEFAULT_ANIMATION, lastAnimationSubtitle, 1.6F); else spelled = true; lastAnimationSubtitle = spellWord(aniName); } } // Default playAnimation(TYPE_NONE, DEFAULT_ANIMATION, lastAnimationSubtitle); loading = false; } /* * Sincroniza as legendas com as animações. */ IEnumerator handleStates() { // Enquanto estiver executando a rotina "loadAndPlay" // ou existir animações na fila de reprodução while (loading || animQueue.Count > 0) { if (animQueue.Count > 0) { AnimationReference reference = animQueue.Peek(); setSubtitle(reference.subtitle); while (COMPONENT_ANIMATION.IsPlaying(reference.name)) yield return null; animQueue.Dequeue(); } else yield return null; setSubtitle(""); } playing = false; paused = false; onPlayingStateChange(); } }