//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 class AnimationReference { public string name; public string subtitle; public AnimationState state; public short type; public bool playing; public AnimationReference(string name, string subtitle, AnimationState state, short type) { this.name = name; this.subtitle = subtitle; this.state = state; this.type = type; this.playing = false; } } protected class DefaultSignSpeed { public static float DEFAULT = 1.1F; public static float DEFAULT_MAX = 2F; private float speed; private float max; // Relação entre a velocidade do tipo representado e a velocidade DEFAULT. private float unit; public DefaultSignSpeed() { this.speed = DEFAULT; this.max = DEFAULT_MAX; this.unit = 1F; } public DefaultSignSpeed(float defaultSpeed, float defaultMaxSpeed) { this.speed = defaultSpeed; this.max = defaultMaxSpeed; this.unit = (this.max - this.speed) / (DEFAULT_MAX - DEFAULT); } public float Speed { get { return this.speed; } set { this.speed = value; this.unit = calculateUnit(); } } public float Max { get { return this.max; } set { this.speed = value; this.unit = calculateUnit(); } } public float Unit { get { return this.unit; } } private float calculateUnit() { return (this.max - this.speed) / (DEFAULT_MAX - DEFAULT); } /* * Retorna velocidade em relação ao estado do slider. * @param slider - estado do slider (valor entre DefaultSignSpeed.DEFAULT e DefaultSignSpeed.DEFAULT_MAX) */ public float getProporcionalSpeed(float slider) { return this.speed + (slider - DEFAULT) * this.unit; } } private const string DEFAULT_ANIMATION = "_default"; private const string NONE_ANIMATION = "_defaultWORD"; protected float fadeLength = 0.6F; protected DefaultSignSpeed defaultWordSpeed = new DefaultSignSpeed(); protected DefaultSignSpeed defaultFirstLetterSpeed = new DefaultSignSpeed(2.1F, 2.8F); protected DefaultSignSpeed defaultLetterSpeed = new DefaultSignSpeed(3F, 4.3F); protected DefaultSignSpeed defaultNumberSpeed = new DefaultSignSpeed(1.5F, 2.9F); 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 float hSlidersecond = DefaultSignSpeed.DEFAULT; private float wordSpeed = DefaultSignSpeed.DEFAULT; private float letterSpeed = DefaultSignSpeed.DEFAULT; private float numberSpeed = DefaultSignSpeed.DEFAULT; protected string glosa = ""; private static String[] stringPos = { DEFAULT_ANIMATION };//vetor que sera usado para quebrar a glosa private GameObject AVATAR; private Animation COMPONENT_ANIMATION; private BoxCollider AVATAR_COLLIDER; 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(); private volatile bool loadingSingleAnimation = false; private volatile bool loading = false; private volatile bool playing = false; private volatile bool paused = false; public virtual void Start() { wordSpeed = defaultWordSpeed.Speed; letterSpeed = defaultLetterSpeed.Speed; numberSpeed = defaultNumberSpeed.Speed; AVATAR = GameObject.FindGameObjectWithTag("avatar");//referencia para o avatar COMPONENT_ANIMATION = AVATAR.GetComponent();//referencia para o componente animador do avatar AVATAR_COLLIDER = GameObject.FindGameObjectWithTag("avatar").GetComponent(); } public bool isLoadingSingleAnimation() { return loadingSingleAnimation; } public bool isLoading() { return loading; } public bool isPlaying() { return playing; } public bool isPaused() { return paused; } public void SetAvatarCollider(bool isActive) { AVATAR_COLLIDER.enabled = isActive; } 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; wordSpeed = defaultWordSpeed.getProporcionalSpeed(x); letterSpeed = defaultLetterSpeed.getProporcionalSpeed(x); numberSpeed = defaultNumberSpeed.getProporcionalSpeed(x); if ( ! paused) foreach (AnimationReference reference in animQueue) if (reference.type != TYPE_NONE && reference.state != null) reference.state.speed = getSpeedByType(reference.type); } private float getSpeedByType(short type) { switch (type) { case TYPE_WORD: return wordSpeed; 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, fadeLength, 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 fadeLength. * 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, fadeLength, 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 switchPauseState(bool paused) { if (this.paused != paused) { this.paused = paused; foreach (AnimationReference reference in animQueue) if (reference.state != null) reference.state.speed = paused ? 0F : getSpeedByType(reference.type); onPlayingStateChange(); } } public void switchPauseState() { switchPauseState( ! paused); } public bool play() { if (playing) switchPauseState(); else play(true, true, true); return true; } public bool play(bool stopLoading, bool stopPlaying, bool forceLoading) { try { if (loading) { if (stopLoading) stop_animations(); else return false; } else if (playing) { if (stopPlaying) stopAnimations(); else if ( ! forceLoading) return false; } } catch (NullReferenceException nre) { nre.ToString(); } StartCoroutine("loadAndPlay"); return true; } /* * 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 = defaultLetterSpeed.getProporcionalSpeed(hSlidersecond); 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 = defaultLetterSpeed.getProporcionalSpeed(hSlidersecond); } Debug.Log("Animação \"" + second + "\" inexistente."); continue; } defaultPlayed = false; letterSpeed = defaultLetterSpeed.getProporcionalSpeed(hSlidersecond); } return lastAnimationSubtitle; } protected IEnumerator loadAnimation(string name) { loadingSingleAnimation = true; // Função loadAssetBundle é definida pela classe filha WWW www = loadAssetBundle(name); 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, name); // Reproduz palavra loadedAssetBundles.Add(name); yield break; } else Debug.Log ("Sinal \"" + name + "\" não carregado corretamente."); } } // Soletra palavra nonexistentAssetBundles.Add(name); loadingSingleAnimation = false; } private IEnumerator loadAndPlay() { loading = true; onPlayingStateChange(); string lastAnimationSubtitle = ""; bool spelled = false; // Default playAnimation(TYPE_NONE, DEFAULT_ANIMATION, "", 2F); if ( ! playing) { playing = true; 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; } bool isPunctuation = false; if (aniName[0] == '[') { if (aniName.Equals("[PONTO]")) { isPunctuation = true; lastAnimationSubtitle = "."; } else if (aniName.Equals("[INTERROGACAO]")) { isPunctuation = true; lastAnimationSubtitle = "?"; } else if (aniName.Equals("[EXCLAMACAO]")) { isPunctuation = true; lastAnimationSubtitle = "!"; } else { lastAnimationSubtitle = aniName; } } if (isPunctuation) playAnimation(TYPE_WORD, aniName, lastAnimationSubtitle); else playAnimation(TYPE_WORD, 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); Debug.Log("~~ To spell: " + aniName); if (aniName.Equals("[PONTO]") || aniName.Equals("[INTERROGACAO]") || aniName.Equals("[EXCLAMACAO]")) { playAnimation(TYPE_NONE, DEFAULT_ANIMATION, "", 1.6F); continue; } // 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, ""); loading = false; onPlayingStateChange(); } //int _id = 0; /* * 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)) { reference.playing = true; yield return null; } if (reference.state == null) animQueue.Dequeue(); else yield return null; } else yield return null; setSubtitle(""); } playing = false; paused = false; onPlayingStateChange(); } }