// Only called if action_idx has changed since last time void UpdateLoopList(LetterAnimation animation) { // add any new loops from the next action index to the loop list foreach (ActionLoopCycle loop in animation.m_loop_cycles) { if (loop.m_start_action_idx == m_anim_state_vars.m_action_index) { // add this new loop into the ordered active loop list int new_loop_cycle_span = loop.SpanWidth; int loop_idx = 0; foreach (ActionLoopCycle active_loop in m_anim_state_vars.m_active_loop_cycles) { if (loop.m_start_action_idx == active_loop.m_start_action_idx && loop.m_end_action_idx == active_loop.m_end_action_idx) { // This loop is already in the active loop list, don't re-add loop_idx = -1; break; } if (new_loop_cycle_span < active_loop.SpanWidth) { break; } loop_idx++; } if (loop_idx >= 0) { m_anim_state_vars.m_active_loop_cycles.Insert(loop_idx, loop.Clone()); } } } }
public void ContinueAction(float animation_timer, LetterAnimation animation, AnimatePerOptions animate_per) { if (m_anim_state_vars.m_waiting_to_sync) { m_anim_state_vars.m_break_delay = 0; m_anim_state_vars.m_waiting_to_sync = false; // reset timer offset to compensate for the sync-up wait time m_anim_state_vars.m_timer_offset = animation_timer; // Progress letter animation index to next, and break out of the loop int prev_action_idx = m_anim_state_vars.m_action_index; // Set next action index SetNextActionIndex(animation); if (m_anim_state_vars.m_active) { if (!m_anim_state_vars.m_reverse && m_anim_state_vars.m_action_index_progress > m_anim_state_vars.m_action_index) { // Repeating the action again; check for unqiue random variable requests. animation.GetAction(m_anim_state_vars.m_action_index).SoftReset(animation.GetAction(prev_action_idx), m_progression_variables, animate_per); } if (prev_action_idx != m_anim_state_vars.m_action_index) { UpdateLoopList(animation); } } } }
public void Reset(LetterAnimation animation) { m_anim_state_vars.Reset(); if (animation.m_loop_cycles.Count > 0) { UpdateLoopList(animation); } }
public void Reset(LetterAnimation animation) { m_anim_state_vars.Reset(); if (animation.NumLoops > 0) { UpdateLoopList(animation); } }
public void SetMeshState(int action_idx, float action_progress, LetterAnimation animation, AnimatePerOptions animate_per) { if (action_idx >= 0 && action_idx < animation.m_letter_actions.Count) { SetupMesh(animation.m_letter_actions[action_idx], Mathf.Clamp(action_progress, 0, 1), true, m_progression_variables, animate_per, Mathf.Clamp(action_progress, 0, 1)); } else { // action not found for this letter. Position letter in its default position Vector3[] mesh_verts = new Vector3[4]; for (int idx = 0; idx < 4; idx++) { mesh_verts[idx] = m_base_vertices[idx] + m_base_offset; } m_mesh.vertices = mesh_verts; m_mesh.colors = new Color[] { Color.white, Color.white, Color.white, Color.white }; } }
public void SetMeshState(int action_idx, float action_progress, LetterAnimation animation, AnimatePerOptions animate_per, EffectManager effect_manager) { if (action_idx >= 0 && action_idx < animation.NumActions) { SetupMesh(animation.GetAction(action_idx), action_idx > 0 ? animation.GetAction(action_idx - 1) : null, Mathf.Clamp(action_progress, 0, 1), m_progression_variables, animate_per, Mathf.Clamp(action_progress, 0, 1), effect_manager); } else { // action not found for this letter. Position letter in its default position if (mesh_verts == null || mesh_verts.Length == 0) { mesh_verts = new Vector3[4]; } for (int idx = 0; idx < 4; idx++) { mesh_verts[idx] = m_base_vertices[idx] + m_base_offset; } m_mesh.vertices = mesh_verts; m_mesh.colors = new Color[] { Color.white, Color.white, Color.white, Color.white }; } }
public Tween PlayLetterAnimation(List <TextMeshProUGUI> l, LetterAnimation at, int index) { var oldColor = (l[index].color.a > 0) ? Color.white : Color.clear; var newColor = (oldColor.a > 0) ? Color.clear : Color.white; Tween t = null; switch (at) { case LetterAnimation.FadeIn: l[index].fontStyle = FontStyles.Bold; t = l[index].DOColor(Color.white, 0.1f); break; case LetterAnimation.FadeOut: t = l[index].DOColor(Color.clear, 0.1f).OnComplete(() => { l[index].transform.DORotate(Vector3.zero, 0.0f); l[index].transform.DOScale(Vector3.one, 1.0f).OnComplete(() => { l[index].gameObject.SetActive(false); }); }); break; case LetterAnimation.FadeOutIn: l[index].DOColor(Color.clear, 0.1f).OnComplete(() => { t = l[index].DOColor(Color.white, 0.1f); }); break; case LetterAnimation.PunchScale: t = l[index].transform.DOScale(Vector3.one * 1.2f, 0.1f).SetLoops(2, LoopType.Yoyo).SetEase(Ease.OutElastic, 1.0f, 1.0f); break; case LetterAnimation.DoublePunch: t = l[index].transform.DOScale(Vector3.one * 1.2f, 0.1f).SetLoops(4, LoopType.Yoyo).SetEase(Ease.InBounce, 1.0f, 1.0f); break; case LetterAnimation.FlipLetters: var currentRot = l[index].transform.rotation.y; var newRot = (currentRot < 180.0f) ? 180.0f : 0.0f; t = l[index].transform.DORotate(new Vector3(0.0f, newRot, 0.0f), 1.0f, RotateMode.Fast); break; case LetterAnimation.Rotate: t = l[index].transform.DORotate(new Vector3(0.0f, 0.0f, 360.0f), 1.0f, RotateMode.FastBeyond360); break; case LetterAnimation.UnderLine: var newLine = (l[index].fontStyle == FontStyles.Underline) ? FontStyles.Bold : FontStyles.Underline; l[index].fontStyle = newLine; break; case LetterAnimation.ChangeColour: var dur = Random.value; while (dur < 0.5f) { dur = Random.value; } t = l[index].DOColor(GetRandomColour(), dur); break; case LetterAnimation.Wave: t = l[index].rectTransform.DOAnchorPosY(l[index].rectTransform.anchoredPosition.y - 20.0f, 0.5f).SetLoops(2, LoopType.Yoyo).SetEase(Ease.InBack, 2.0f, 0.5f); break; case LetterAnimation.Stretch: t = l[index].transform.DOScaleY(1.3f, 0.5f).SetLoops(2, LoopType.Yoyo).SetEase(Ease.OutElastic, 2.0f, 1.0f); break; } return(t); }
private void Start() { _letterGraphic = transform.GetChild(0); _letterAnimation = _letterGraphic.GetComponent<LetterAnimation>(); _stack = transform.parent; _rigidbody = gameObject.GetComponent<Rigidbody>(); _collider = gameObject.GetComponent<Collider>(); DeactivatePhysics(); }
public void ImportData(string data, bool force_clear_old_audio_particles = false) { if (force_clear_old_audio_particles) ClearCachedAudioParticleInstances(true); var json_data = JSONObject.Parse(data, true); if (json_data != null) { m_animate_per = (AnimatePerOptions)(int)json_data["m_animate_per"].Number; m_display_axis = (TextDisplayAxis)(int)json_data["m_display_axis"].Number; if (json_data.ContainsKey("m_begin_delay")) m_begin_delay = (float)json_data["m_begin_delay"].Number; if (json_data.ContainsKey("m_begin_on_start")) m_begin_on_start = json_data["m_begin_on_start"].Boolean; if (json_data.ContainsKey("m_character_size")) m_character_size = (float)json_data["m_character_size"].Number; if (json_data.ContainsKey("m_line_height")) m_line_height_factor = (float)json_data["m_line_height"].Number; if (json_data.ContainsKey("m_max_width")) m_max_width = (float)json_data["m_max_width"].Number; if (json_data.ContainsKey("m_on_finish_action")) m_on_finish_action = (ON_FINISH_ACTION)(int)json_data["m_on_finish_action"].Number; if (json_data.ContainsKey("m_px_offset")) m_px_offset = json_data["m_px_offset"].Obj.JSONtoVector2(); // if(json_data.ContainsKey("m_text")) m_text = json_data["m_text"].Str; if (json_data.ContainsKey("m_text_alignment")) m_text_alignment = (TextAlignment)(int)json_data["m_text_alignment"].Number; if (json_data.ContainsKey("m_text_anchor")) m_text_anchor = (TextAnchor)(int)json_data["m_text_anchor"].Number; if (json_data.ContainsKey("m_time_type")) m_time_type = (AnimationTime)(int)json_data["m_time_type"].Number; m_master_animations = new List<LetterAnimation>(); LetterAnimation letter_anim; foreach (var animation_data in json_data["LETTER_ANIMATIONS_DATA"].Array) { letter_anim = new LetterAnimation(); letter_anim.ImportData(animation_data.Obj); m_master_animations.Add(letter_anim); } } else // Import string is not valid JSON, therefore assuming it is in the legacy data import format. this.ImportLegacyData(data); if (!Application.isPlaying && m_text.Equals("")) m_text = "TextFx"; if (!m_text.Equals("")) SetText(m_text); ResetAnimation(); }
public IEnumerator SequentialLetterAnimation(List <TextMeshProUGUI> l, float delay, LetterAnimation at, SequenceType st) { switch (st) { case SequenceType.None: yield return(new WaitForSeconds(1.0f)); break; case SequenceType.Forward: if (at == LetterAnimation.FadeIn) { yield return(new WaitForSeconds(1.5f)); } for (int i = 0; i < l.Count; i++) { PlayLetterAnimation(l, at, i); yield return(new WaitForSeconds(delay)); } break; case SequenceType.Backward: for (int i = l.Count - 1; i >= 0; i--) { PlayLetterAnimation(l, at, i); yield return(new WaitForSeconds(delay)); } break; case SequenceType.Single: var index = Random.Range(0, l.Count); PlayLetterAnimation(l, at, index); break; case SequenceType.GroupedOrdered: break; case SequenceType.GroupedUnordered: break; case SequenceType.sGroupedUnordered: break; case SequenceType.sEven: for (int i = 0; i < l.Count; i += 2) { PlayLetterAnimation(l, at, i); yield return(new WaitForSeconds(delay)); } break; case SequenceType.Even: for (int i = 0; i < l.Count; i += 2) { PlayLetterAnimation(l, at, i); } break; case SequenceType.sOdd: for (int i = 1; i < l.Count; i += 2) { PlayLetterAnimation(l, at, i); yield return(new WaitForSeconds(delay)); } break; case SequenceType.Odd: for (int i = 1; i < l.Count; i += 2) { PlayLetterAnimation(l, at, i); } break; } yield return(new WaitForSeconds(2.0f)); if (inHighScoreMenu) { MakeTextAnimate(false, l, true); } else { MakeTextAnimate(false, l, false); } }
public void Reset(LetterAnimation animation) { m_anim_state_vars.Reset(); if (animation.NumLoops > 0) UpdateLoopList(animation); }
// Animates the letter mesh and return the current action index in use public LETTER_ANIMATION_STATE AnimateMesh(bool force_render, float timer, TextAnchor text_anchor, int lowest_action_progress, LetterAnimation animation, AnimatePerOptions animate_per, float delta_time, EffectManager effect_manager) { m_last_animate_per = animate_per; if (animation.m_letter_actions.Count > 0 && m_anim_state_vars.m_action_index < animation.m_letter_actions.Count) { if (!m_anim_state_vars.m_active && !force_render) { return(LETTER_ANIMATION_STATE.STOPPED); } bool first_action_call = false; if (m_anim_state_vars.m_action_index != m_anim_state_vars.m_prev_action_index) { SetCurrentLetterAction(animation.m_letter_actions[m_anim_state_vars.m_action_index]); first_action_call = true; m_anim_state_vars.m_started_action = false; } else if (m_current_letter_action == null) { SetCurrentLetterAction(animation.m_letter_actions[m_anim_state_vars.m_action_index]); } m_anim_state_vars.m_prev_action_index = m_anim_state_vars.m_action_index; if (force_render) { SetupMesh(m_current_letter_action, m_anim_state_vars.m_action_progress, true, m_progression_variables, animate_per, m_anim_state_vars.m_linear_progress); } if (m_anim_state_vars.m_waiting_to_sync) { if (m_current_letter_action.m_action_type == ACTION_TYPE.BREAK) { if (!force_render && m_anim_state_vars.m_break_delay > 0) { m_anim_state_vars.m_break_delay -= delta_time; if (m_anim_state_vars.m_break_delay <= 0) { ContinueAction(timer, animation, animate_per); return(LETTER_ANIMATION_STATE.PLAYING); } } return(LETTER_ANIMATION_STATE.WAITING); } else if (lowest_action_progress < m_anim_state_vars.m_action_index_progress) { return(LETTER_ANIMATION_STATE.PLAYING); } else if (!force_render) { m_anim_state_vars.m_waiting_to_sync = false; // reset timer offset to compensate for the sync-up wait time m_anim_state_vars.m_timer_offset = timer; } } else if (!force_render && (m_current_letter_action.m_action_type == ACTION_TYPE.BREAK || (!m_anim_state_vars.m_reverse && m_current_letter_action.m_force_same_start_time && lowest_action_progress < m_anim_state_vars.m_action_index_progress))) { // Force letter to wait for rest of letters to be in sync m_anim_state_vars.m_waiting_to_sync = true; m_anim_state_vars.m_break_delay = Mathf.Max(m_current_letter_action.m_duration_progression.GetValue(m_progression_variables, animate_per), 0); return(LETTER_ANIMATION_STATE.PLAYING); } if (force_render) { return(m_anim_state_vars.m_active ? LETTER_ANIMATION_STATE.PLAYING : LETTER_ANIMATION_STATE.STOPPED); } finished_action = -1; m_anim_state_vars.m_action_progress = 0; m_anim_state_vars.m_linear_progress = 0; m_action_timer = timer - m_anim_state_vars.m_timer_offset; if ((m_anim_state_vars.m_reverse || m_action_timer > m_action_delay)) { m_anim_state_vars.m_linear_progress = (m_action_timer - (m_anim_state_vars.m_reverse ? 0 : m_action_delay)) / m_action_duration; if (m_anim_state_vars.m_reverse) { if (m_action_timer >= m_action_duration) { m_anim_state_vars.m_linear_progress = 0; } else { m_anim_state_vars.m_linear_progress = 1 - m_anim_state_vars.m_linear_progress; } } if (!m_anim_state_vars.m_started_action) { // TODO: implement more robust check for "in-sync" actions having already played the asigned audio/effect // Just started animating action after delay. Handle any OnStart events if (m_current_letter_action.m_audio_on_start != null && (m_progression_variables.m_letter_value == 0 || !m_current_letter_action.m_starting_in_sync || m_current_letter_action.m_audio_on_start_delay.m_progression != ValueProgression.Constant)) { effect_manager.PlayAudioClip(m_current_letter_action.m_audio_on_start, m_current_letter_action.m_audio_on_start_delay.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_audio_on_start_offset.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_audio_on_start_volume.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_audio_on_start_pitch.GetValue(m_progression_variables, animate_per)); } if (m_current_letter_action.m_emitter_on_start != null && (m_current_letter_action.m_emitter_on_start_per_letter || m_progression_variables.m_letter_value == 0)) { effect_manager.PlayParticleEffect(m_current_letter_action.m_emitter_on_start, m_current_letter_action.m_emitter_on_start_delay.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_emitter_on_start_duration.GetValue(m_progression_variables, animate_per), m_mesh, m_current_letter_action.m_emitter_on_start_offset.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_emitter_on_start_follow_mesh); } m_anim_state_vars.m_started_action = true; } m_anim_state_vars.m_action_progress = EasingManager.GetEaseProgress(m_current_letter_action.m_ease_type, m_anim_state_vars.m_linear_progress); if ((!m_anim_state_vars.m_reverse && m_anim_state_vars.m_linear_progress >= 1) || (m_anim_state_vars.m_reverse && m_action_timer >= m_action_duration + m_action_delay)) { m_anim_state_vars.m_action_progress = m_anim_state_vars.m_reverse ? 0 : 1; m_anim_state_vars.m_linear_progress = m_anim_state_vars.m_reverse ? 0 : 1; if (!m_anim_state_vars.m_reverse) { finished_action = m_anim_state_vars.m_action_index; } int prev_action_idx = m_anim_state_vars.m_action_index; float prev_delay = m_action_delay; // Set next action index SetNextActionIndex(animation); if (m_anim_state_vars.m_active) { if (!m_anim_state_vars.m_reverse) { m_anim_state_vars.m_started_action = false; } if (!m_anim_state_vars.m_reverse && m_anim_state_vars.m_action_index_progress > m_anim_state_vars.m_action_index) { // Repeating the action again; check for unqiue random variable requests. animation.m_letter_actions[m_anim_state_vars.m_action_index].SoftReset(animation.m_letter_actions[prev_action_idx], m_progression_variables, animate_per, m_anim_state_vars.m_action_index == 0); } else if (m_anim_state_vars.m_reverse) { animation.m_letter_actions[m_anim_state_vars.m_action_index].SoftResetStarts(animation.m_letter_actions[prev_action_idx], m_progression_variables, animate_per); } // Add to the timer offset m_anim_state_vars.m_timer_offset += prev_delay + m_action_duration; if (prev_action_idx != m_anim_state_vars.m_action_index) { UpdateLoopList(animation); } else { SetCurrentLetterAction(animation.m_letter_actions[m_anim_state_vars.m_action_index]); } } } } SetupMesh(m_current_letter_action, m_anim_state_vars.m_action_progress, force_render || first_action_call, m_progression_variables, animate_per, m_anim_state_vars.m_linear_progress); if (finished_action > -1) { // TODO: implement more robust check for "in-sync" actions having already played the asigned audio/effect if (m_current_letter_action.m_audio_on_finish != null && (m_progression_variables.m_letter_value == 0 || !m_current_letter_action.m_starting_in_sync)) { effect_manager.PlayAudioClip(m_current_letter_action.m_audio_on_finish, m_current_letter_action.m_audio_on_finish_delay.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_audio_on_finish_offset.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_audio_on_finish_volume.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_audio_on_finish_pitch.GetValue(m_progression_variables, animate_per)); } if (m_current_letter_action.m_emitter_on_finish != null && (m_current_letter_action.m_emitter_on_finish_per_letter || m_progression_variables.m_letter_value == 0)) { effect_manager.PlayParticleEffect(m_current_letter_action.m_emitter_on_finish, m_current_letter_action.m_emitter_on_finish_delay.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_emitter_on_finish_duration.GetValue(m_progression_variables, animate_per), m_mesh, m_current_letter_action.m_emitter_on_finish_offset.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_emitter_on_finish_follow_mesh); } } } else { // no actions found for this letter. Position letter in its default position Vector3[] mesh_verts = new Vector3[4]; for (int idx = 0; idx < 4; idx++) { mesh_verts[idx] = m_base_vertices[idx] + m_base_offset; } m_mesh.vertices = mesh_verts; m_anim_state_vars.m_active = false; } return(m_anim_state_vars.m_active ? LETTER_ANIMATION_STATE.PLAYING : LETTER_ANIMATION_STATE.STOPPED); }
void SetNextActionIndex(LetterAnimation animation) { // based on current active loop list, return the next action index // increment action progress count m_anim_state_vars.m_action_index_progress++; ActionLoopCycle current_loop; for (int loop_idx = 0; loop_idx < m_anim_state_vars.m_active_loop_cycles.Count; loop_idx++) { current_loop = m_anim_state_vars.m_active_loop_cycles[loop_idx]; if ((current_loop.m_loop_type == LOOP_TYPE.LOOP && m_anim_state_vars.m_action_index == current_loop.m_end_action_idx) || (current_loop.m_loop_type == LOOP_TYPE.LOOP_REVERSE && ((m_anim_state_vars.m_reverse && m_anim_state_vars.m_action_index == current_loop.m_start_action_idx) || (!m_anim_state_vars.m_reverse && m_anim_state_vars.m_action_index == current_loop.m_end_action_idx))) ) { // Reached end of loop cycle. Deduct one cycle from loop count. bool end_of_loop_cycle = current_loop.m_loop_type == LOOP_TYPE.LOOP || m_anim_state_vars.m_reverse; if (end_of_loop_cycle) { current_loop.m_number_of_loops--; } // Switch reverse status if (current_loop.m_loop_type == LOOP_TYPE.LOOP_REVERSE) { m_anim_state_vars.m_reverse = !m_anim_state_vars.m_reverse; } current_loop.FirstPass = false; if (end_of_loop_cycle && current_loop.m_number_of_loops == 0) { // loop cycle finished // Remove this loop from active loop list m_anim_state_vars.m_active_loop_cycles.RemoveAt(loop_idx); loop_idx--; if (current_loop.m_loop_type == LOOP_TYPE.LOOP_REVERSE) { // Don't allow anim to progress back through actions, skip to action beyond end of reverse loop m_anim_state_vars.m_action_index = current_loop.m_end_action_idx; } } else { if (current_loop.m_number_of_loops < 0) { current_loop.m_number_of_loops = -1; } // return to the start of this loop again if (current_loop.m_loop_type == LOOP_TYPE.LOOP) { m_anim_state_vars.m_action_index = current_loop.m_start_action_idx; } return; } } else { break; } } m_anim_state_vars.m_action_index += (m_anim_state_vars.m_reverse ? -1 : 1); // check for animation reaching end if (m_anim_state_vars.m_action_index >= animation.NumActions) { m_anim_state_vars.m_active = false; m_anim_state_vars.m_action_index = animation.NumActions - 1; } return; }
public void ContinueAction(float animation_timer, LetterAnimation animation, AnimatePerOptions animate_per) { if(m_anim_state_vars.m_waiting_to_sync) { m_anim_state_vars.m_break_delay = 0; m_anim_state_vars.m_waiting_to_sync= false; // reset timer offset to compensate for the sync-up wait time m_anim_state_vars.m_timer_offset = animation_timer; // Progress letter animation index to next, and break out of the loop int prev_action_idx = m_anim_state_vars.m_action_index; // Set next action index SetNextActionIndex(animation); if(m_anim_state_vars.m_active) { if(!m_anim_state_vars.m_reverse && m_anim_state_vars.m_action_index_progress > m_anim_state_vars.m_action_index) { // Repeating the action again; check for unqiue random variable requests. animation.m_letter_actions[m_anim_state_vars.m_action_index].SoftReset(animation.m_letter_actions[prev_action_idx], m_progression_variables, animate_per); } if(prev_action_idx != m_anim_state_vars.m_action_index) { UpdateLoopList(animation); } } } }
// Only called if action_idx has changed since last time void UpdateLoopList(LetterAnimation animation) { // add any new loops from the next action index to the loop list foreach(ActionLoopCycle loop in animation.m_loop_cycles) { if(loop.m_start_action_idx == m_anim_state_vars.m_action_index) { // add this new loop into the ordered active loop list int new_loop_cycle_span = loop.SpanWidth; int loop_idx = 0; foreach(ActionLoopCycle active_loop in m_anim_state_vars.m_active_loop_cycles) { if(loop.m_start_action_idx == active_loop.m_start_action_idx && loop.m_end_action_idx == active_loop.m_end_action_idx) { // This loop is already in the active loop list, don't re-add loop_idx = -1; break; } if(new_loop_cycle_span < active_loop.SpanWidth) { break; } loop_idx++; } if(loop_idx >= 0) { m_anim_state_vars.m_active_loop_cycles.Insert(loop_idx, loop.Clone()); } } } }
// Animates the letter mesh and return the current action index in use public LETTER_ANIMATION_STATE AnimateMesh(bool force_render, float timer, TextAnchor text_anchor, int lowest_action_progress, LetterAnimation animation, AnimatePerOptions animate_per, float delta_time, EffectManager effect_manager) { m_last_animate_per = animate_per; m_effect_manager_handle = effect_manager; if (animation.NumActions > 0 && m_anim_state_vars.m_action_index < animation.NumActions) { if (!m_anim_state_vars.m_active && !force_render) { return(LETTER_ANIMATION_STATE.STOPPED); } if (m_anim_state_vars.m_action_index != m_anim_state_vars.m_prev_action_index) { SetCurrentLetterAction(animation.GetAction(m_anim_state_vars.m_action_index), animate_per); m_anim_state_vars.m_started_action = false; } else if (m_current_letter_action == null) { SetCurrentLetterAction(animation.GetAction(m_anim_state_vars.m_action_index), animate_per); } m_anim_state_vars.m_prev_action_index = m_anim_state_vars.m_action_index; if (force_render) { SetupMesh(m_current_letter_action, m_anim_state_vars.m_action_index > 0 ? animation.GetAction(m_anim_state_vars.m_action_index - 1) : null, m_anim_state_vars.m_action_progress, m_progression_variables, animate_per, m_anim_state_vars.m_linear_progress, m_effect_manager_handle); } if (m_anim_state_vars.m_waiting_to_sync) { if (m_current_letter_action.m_action_type == ACTION_TYPE.BREAK) { if (!force_render && m_anim_state_vars.m_break_delay > 0) { m_anim_state_vars.m_break_delay -= delta_time; if (m_anim_state_vars.m_break_delay <= 0) { ContinueAction(timer, animation, animate_per); return(LETTER_ANIMATION_STATE.PLAYING); } } return(LETTER_ANIMATION_STATE.WAITING); } else if (lowest_action_progress < m_anim_state_vars.m_action_index_progress) { return(LETTER_ANIMATION_STATE.PLAYING); } else if (!force_render) { m_anim_state_vars.m_waiting_to_sync = false; // reset timer offset to compensate for the sync-up wait time m_anim_state_vars.m_timer_offset = timer; } } else if (!force_render && (m_current_letter_action.m_action_type == ACTION_TYPE.BREAK || (!m_anim_state_vars.m_reverse && m_current_letter_action.m_force_same_start_time && lowest_action_progress < m_anim_state_vars.m_action_index_progress))) { // Force letter to wait for rest of letters to be in sync m_anim_state_vars.m_waiting_to_sync = true; m_anim_state_vars.m_break_delay = Mathf.Max(m_current_letter_action.m_duration_progression.GetValue(m_progression_variables, animate_per), 0); return(LETTER_ANIMATION_STATE.PLAYING); } if (force_render) { return(m_anim_state_vars.m_active ? LETTER_ANIMATION_STATE.PLAYING : LETTER_ANIMATION_STATE.STOPPED); } m_anim_state_vars.m_action_progress = 0; m_anim_state_vars.m_linear_progress = 0; m_action_timer = timer - m_anim_state_vars.m_timer_offset; if ((m_anim_state_vars.m_reverse || m_action_timer > m_action_delay)) { m_anim_state_vars.m_linear_progress = (m_action_timer - (m_anim_state_vars.m_reverse ? 0 : m_action_delay)) / m_action_duration; if (m_anim_state_vars.m_reverse) { if (m_action_timer >= m_action_duration) { m_anim_state_vars.m_linear_progress = 0; } else { m_anim_state_vars.m_linear_progress = 1 - m_anim_state_vars.m_linear_progress; } } if (!m_anim_state_vars.m_started_action) { // Trigger any action onStart audio or particle effects TriggerAudioEffect(animate_per, PLAY_ITEM_EVENTS.ON_START); TriggerParticleEffects(animate_per, PLAY_ITEM_EVENTS.ON_START); m_anim_state_vars.m_started_action = true; } m_anim_state_vars.m_action_progress = EasingManager.GetEaseProgress(m_current_letter_action.m_ease_type, m_anim_state_vars.m_linear_progress); if ((!m_anim_state_vars.m_reverse && m_anim_state_vars.m_linear_progress >= 1) || (m_anim_state_vars.m_reverse && m_action_timer >= m_action_duration + m_action_delay)) { m_anim_state_vars.m_action_progress = m_anim_state_vars.m_reverse ? 0 : 1; m_anim_state_vars.m_linear_progress = m_anim_state_vars.m_reverse ? 0 : 1; if (!m_anim_state_vars.m_reverse && m_anim_state_vars.m_action_index != -1) { TriggerParticleEffects(animate_per, PLAY_ITEM_EVENTS.ON_FINISH); TriggerAudioEffect(animate_per, PLAY_ITEM_EVENTS.ON_FINISH); } int prev_action_idx = m_anim_state_vars.m_action_index; float prev_delay = m_action_delay; // Set next action index SetNextActionIndex(animation); if (m_anim_state_vars.m_active) { if (!m_anim_state_vars.m_reverse) { m_anim_state_vars.m_started_action = false; } if (!m_anim_state_vars.m_reverse && m_anim_state_vars.m_action_index_progress > m_anim_state_vars.m_action_index) { // Repeating the action again; check for unqiue random variable requests. animation.GetAction(m_anim_state_vars.m_action_index).SoftReset(animation.GetAction(prev_action_idx), m_progression_variables, animate_per, m_anim_state_vars.m_action_index == 0); } else if (m_anim_state_vars.m_reverse) { animation.GetAction(m_anim_state_vars.m_action_index).SoftResetStarts(animation.GetAction(prev_action_idx), m_progression_variables, animate_per); } // Add to the timer offset m_anim_state_vars.m_timer_offset += prev_delay + m_action_duration; if (prev_action_idx != m_anim_state_vars.m_action_index) { UpdateLoopList(animation); } else { SetCurrentLetterAction(animation.GetAction(m_anim_state_vars.m_action_index), animate_per); } } } } SetupMesh(m_current_letter_action, m_anim_state_vars.m_action_index > 0 ? animation.GetAction(m_anim_state_vars.m_action_index - 1) : null, m_anim_state_vars.m_action_progress, m_progression_variables, animate_per, m_anim_state_vars.m_linear_progress, m_effect_manager_handle); } else { // no actions found for this letter. Position letter in its default position if (mesh_verts == null || mesh_verts.Length == 0) { mesh_verts = new Vector3[4]; } for (int idx = 0; idx < 4; idx++) { mesh_verts[idx] = m_base_vertices[idx] + m_base_offset; } m_mesh.vertices = mesh_verts; m_anim_state_vars.m_active = false; } return(m_anim_state_vars.m_active ? LETTER_ANIMATION_STATE.PLAYING : LETTER_ANIMATION_STATE.STOPPED); }
void SetNextActionIndex(LetterAnimation animation) { // based on current active loop list, return the next action index // increment action progress count m_anim_state_vars.m_action_index_progress++; ActionLoopCycle current_loop; for(int loop_idx=0; loop_idx < m_anim_state_vars.m_active_loop_cycles.Count; loop_idx++) { current_loop = m_anim_state_vars.m_active_loop_cycles[loop_idx]; if((current_loop.m_loop_type == LOOP_TYPE.LOOP && m_anim_state_vars.m_action_index == current_loop.m_end_action_idx) || (current_loop.m_loop_type == LOOP_TYPE.LOOP_REVERSE && ((m_anim_state_vars.m_reverse && m_anim_state_vars.m_action_index == current_loop.m_start_action_idx) || (!m_anim_state_vars.m_reverse && m_anim_state_vars.m_action_index == current_loop.m_end_action_idx))) ) { // Reached end of loop cycle. Deduct one cycle from loop count. bool end_of_loop_cycle = current_loop.m_loop_type == LOOP_TYPE.LOOP || m_anim_state_vars.m_reverse; if(end_of_loop_cycle) { current_loop.m_number_of_loops--; } // Switch reverse status if(current_loop.m_loop_type == LOOP_TYPE.LOOP_REVERSE) { m_anim_state_vars.m_reverse = !m_anim_state_vars.m_reverse; } current_loop.FirstPass = false; if(end_of_loop_cycle && current_loop.m_number_of_loops == 0) { // loop cycle finished // Remove this loop from active loop list m_anim_state_vars.m_active_loop_cycles.RemoveAt(loop_idx); loop_idx--; if(current_loop.m_loop_type == LOOP_TYPE.LOOP_REVERSE) { // Don't allow anim to progress back through actions, skip to action beyond end of reverse loop m_anim_state_vars.m_action_index = current_loop.m_end_action_idx; } } else { if(current_loop.m_number_of_loops < 0) { current_loop.m_number_of_loops = -1; } // return to the start of this loop again if(current_loop.m_loop_type == LOOP_TYPE.LOOP) { m_anim_state_vars.m_action_index = current_loop.m_start_action_idx; } return; } } else { break; } } m_anim_state_vars.m_action_index += (m_anim_state_vars.m_reverse ? -1 : 1); // check for animation reaching end if(m_anim_state_vars.m_action_index >= animation.m_letter_actions.Count) { m_anim_state_vars.m_active = false; m_anim_state_vars.m_action_index = animation.m_letter_actions.Count -1; } return; }
public void SetMeshState(int action_idx, float action_progress, LetterAnimation animation, AnimatePerOptions animate_per) { if(action_idx >= 0 && action_idx < animation.m_letter_actions.Count) { SetupMesh(animation.m_letter_actions[action_idx], Mathf.Clamp(action_progress, 0,1), true, m_progression_variables, animate_per, Mathf.Clamp(action_progress, 0,1)); } else { // action not found for this letter. Position letter in its default position Vector3[] mesh_verts = new Vector3[4]; for(int idx=0; idx < 4; idx++) { mesh_verts[idx] = m_base_vertices[idx] + m_base_offset; } m_mesh.vertices = mesh_verts; m_mesh.colors = new Color[]{Color.white, Color.white, Color.white, Color.white}; } }
public void Reset(LetterAnimation animation) { m_anim_state_vars.Reset(); if(animation.m_loop_cycles.Count > 0) { UpdateLoopList(animation); } }
void HandleLegacyAnimationInstance() { if(m_master_animation != null && m_master_animation.m_letter_actions.Count > 0) { Debug.LogWarning("Converting Legacy TextFx animation."); //Legacy master animation is active. Add to new animations list and clear it. m_master_animations = new List<LetterAnimation>(); m_master_animations.Add(m_master_animation); // Reset legacy animation data to avoid catching this step again m_master_animation = null; SetText(m_text); } }
// Only called if action_idx has changed since last time private void UpdateLoopList(LetterAnimation animation) { // add any new loops from the next action index to the loop list ActionLoopCycle loop; for (var idx = 0; idx < animation.NumLoops; idx++) { loop = animation.GetLoop(idx); if (loop.m_start_action_idx == m_anim_state_vars.m_action_index) { // add this new loop into the ordered active loop list var new_loop_cycle_span = loop.SpanWidth; var loop_idx = 0; foreach (var active_loop in m_anim_state_vars.m_active_loop_cycles) { if (loop.m_start_action_idx == active_loop.m_start_action_idx && loop.m_end_action_idx == active_loop.m_end_action_idx) { // This loop is already in the active loop list, don't re-add loop_idx = -1; break; } if (new_loop_cycle_span < active_loop.SpanWidth) break; loop_idx++; } if (loop_idx >= 0) m_anim_state_vars.m_active_loop_cycles.Insert(loop_idx, loop.Clone()); } } }
// Animates the letter mesh and return the current action index in use public LETTER_ANIMATION_STATE AnimateMesh(bool force_render, float timer, TextAnchor text_anchor, int lowest_action_progress, LetterAnimation animation, AnimatePerOptions animate_per, float delta_time, EffectManager effect_manager) { m_last_animate_per = animate_per; m_effect_manager_handle = effect_manager; if (animation.NumActions > 0 && m_anim_state_vars.m_action_index < animation.NumActions) { if (!m_anim_state_vars.m_active && !force_render) return LETTER_ANIMATION_STATE.STOPPED; if (m_anim_state_vars.m_action_index != m_anim_state_vars.m_prev_action_index) { SetCurrentLetterAction(animation.GetAction(m_anim_state_vars.m_action_index), animate_per); m_anim_state_vars.m_started_action = false; } else if (m_current_letter_action == null) SetCurrentLetterAction(animation.GetAction(m_anim_state_vars.m_action_index), animate_per); m_anim_state_vars.m_prev_action_index = m_anim_state_vars.m_action_index; if (force_render) SetupMesh(m_current_letter_action, m_anim_state_vars.m_action_index > 0 ? animation.GetAction(m_anim_state_vars.m_action_index - 1) : null, m_anim_state_vars.m_action_progress, m_progression_variables, animate_per, m_anim_state_vars.m_linear_progress, m_effect_manager_handle); if (m_anim_state_vars.m_waiting_to_sync) { if (m_current_letter_action.m_action_type == ACTION_TYPE.BREAK) { if (!force_render && m_anim_state_vars.m_break_delay > 0) { m_anim_state_vars.m_break_delay -= delta_time; if (m_anim_state_vars.m_break_delay <= 0) { ContinueAction(timer, animation, animate_per); return LETTER_ANIMATION_STATE.PLAYING; } } return LETTER_ANIMATION_STATE.WAITING; } if (lowest_action_progress < m_anim_state_vars.m_action_index_progress) return LETTER_ANIMATION_STATE.PLAYING; if (!force_render) { m_anim_state_vars.m_waiting_to_sync = false; // reset timer offset to compensate for the sync-up wait time m_anim_state_vars.m_timer_offset = timer; } } else if (!force_render && (m_current_letter_action.m_action_type == ACTION_TYPE.BREAK || (!m_anim_state_vars.m_reverse && m_current_letter_action.m_force_same_start_time && lowest_action_progress < m_anim_state_vars.m_action_index_progress))) { // Force letter to wait for rest of letters to be in sync m_anim_state_vars.m_waiting_to_sync = true; m_anim_state_vars.m_break_delay = Mathf.Max(m_current_letter_action.m_duration_progression.GetValue(m_progression_variables, animate_per), 0); return LETTER_ANIMATION_STATE.PLAYING; } if (force_render) return m_anim_state_vars.m_active ? LETTER_ANIMATION_STATE.PLAYING : LETTER_ANIMATION_STATE.STOPPED; m_anim_state_vars.m_action_progress = 0; m_anim_state_vars.m_linear_progress = 0; m_action_timer = timer - m_anim_state_vars.m_timer_offset; if ((m_anim_state_vars.m_reverse || m_action_timer > m_action_delay)) { m_anim_state_vars.m_linear_progress = (m_action_timer - (m_anim_state_vars.m_reverse ? 0 : m_action_delay)) / m_action_duration; if (m_anim_state_vars.m_reverse) if (m_action_timer >= m_action_duration) m_anim_state_vars.m_linear_progress = 0; else m_anim_state_vars.m_linear_progress = 1 - m_anim_state_vars.m_linear_progress; if (!m_anim_state_vars.m_started_action) { // Trigger any action onStart audio or particle effects TriggerAudioEffect(animate_per, PLAY_ITEM_EVENTS.ON_START); TriggerParticleEffects(animate_per, PLAY_ITEM_EVENTS.ON_START); m_anim_state_vars.m_started_action = true; } m_anim_state_vars.m_action_progress = EasingManager.GetEaseProgress(m_current_letter_action.m_ease_type, m_anim_state_vars.m_linear_progress); if ((!m_anim_state_vars.m_reverse && m_anim_state_vars.m_linear_progress >= 1) || (m_anim_state_vars.m_reverse && m_action_timer >= m_action_duration + m_action_delay)) { m_anim_state_vars.m_action_progress = m_anim_state_vars.m_reverse ? 0 : 1; m_anim_state_vars.m_linear_progress = m_anim_state_vars.m_reverse ? 0 : 1; if (!m_anim_state_vars.m_reverse && m_anim_state_vars.m_action_index != -1) { TriggerParticleEffects(animate_per, PLAY_ITEM_EVENTS.ON_FINISH); TriggerAudioEffect(animate_per, PLAY_ITEM_EVENTS.ON_FINISH); } var prev_action_idx = m_anim_state_vars.m_action_index; var prev_delay = m_action_delay; // Set next action index SetNextActionIndex(animation); if (m_anim_state_vars.m_active) { if (!m_anim_state_vars.m_reverse) m_anim_state_vars.m_started_action = false; if (!m_anim_state_vars.m_reverse && m_anim_state_vars.m_action_index_progress > m_anim_state_vars.m_action_index) // Repeating the action again; check for unqiue random variable requests. animation.GetAction(m_anim_state_vars.m_action_index).SoftReset(animation.GetAction(prev_action_idx), m_progression_variables, animate_per, m_anim_state_vars.m_action_index == 0); else if (m_anim_state_vars.m_reverse) animation.GetAction(m_anim_state_vars.m_action_index).SoftResetStarts(animation.GetAction(prev_action_idx), m_progression_variables, animate_per); // Add to the timer offset m_anim_state_vars.m_timer_offset += prev_delay + m_action_duration; if (prev_action_idx != m_anim_state_vars.m_action_index) UpdateLoopList(animation); else SetCurrentLetterAction(animation.GetAction(m_anim_state_vars.m_action_index), animate_per); } } } SetupMesh(m_current_letter_action, m_anim_state_vars.m_action_index > 0 ? animation.GetAction(m_anim_state_vars.m_action_index - 1) : null, m_anim_state_vars.m_action_progress, m_progression_variables, animate_per, m_anim_state_vars.m_linear_progress, m_effect_manager_handle); } else { // no actions found for this letter. Position letter in its default position if (mesh_verts == null || mesh_verts.Length == 0) mesh_verts = new Vector3[4]; for (var idx = 0; idx < 4; idx++) mesh_verts[idx] = m_base_vertices[idx] + m_base_offset; m_mesh.vertices = mesh_verts; m_anim_state_vars.m_active = false; } return m_anim_state_vars.m_active ? LETTER_ANIMATION_STATE.PLAYING : LETTER_ANIMATION_STATE.STOPPED; }
// Animates the letter mesh and return the current action index in use public LETTER_ANIMATION_STATE AnimateMesh( bool force_render, float timer, TextAnchor text_anchor, int lowest_action_progress, LetterAnimation animation, AnimatePerOptions animate_per, float delta_time, EffectManager effect_manager) { m_last_animate_per = animate_per; if(animation.m_letter_actions.Count > 0 && m_anim_state_vars.m_action_index < animation.m_letter_actions.Count) { if(!m_anim_state_vars.m_active && !force_render) { return LETTER_ANIMATION_STATE.STOPPED; } bool first_action_call = false; if(m_anim_state_vars.m_action_index != m_anim_state_vars.m_prev_action_index) { SetCurrentLetterAction(animation.m_letter_actions[m_anim_state_vars.m_action_index]); first_action_call = true; m_anim_state_vars.m_started_action = false; } else if(m_current_letter_action == null) { SetCurrentLetterAction(animation.m_letter_actions[m_anim_state_vars.m_action_index]); } m_anim_state_vars.m_prev_action_index = m_anim_state_vars.m_action_index; if(force_render) { SetupMesh(m_current_letter_action, m_anim_state_vars.m_action_progress, true, m_progression_variables, animate_per, m_anim_state_vars.m_linear_progress); } if(m_anim_state_vars.m_waiting_to_sync) { if(m_current_letter_action.m_action_type == ACTION_TYPE.BREAK) { if(!force_render && m_anim_state_vars.m_break_delay > 0) { m_anim_state_vars.m_break_delay -= delta_time; if(m_anim_state_vars.m_break_delay <= 0) { ContinueAction(timer, animation, animate_per); return LETTER_ANIMATION_STATE.PLAYING; } } return LETTER_ANIMATION_STATE.WAITING; } else if(lowest_action_progress < m_anim_state_vars.m_action_index_progress) { return LETTER_ANIMATION_STATE.PLAYING; } else if(!force_render) { m_anim_state_vars.m_waiting_to_sync = false; // reset timer offset to compensate for the sync-up wait time m_anim_state_vars.m_timer_offset = timer; } } else if(!force_render && (m_current_letter_action.m_action_type == ACTION_TYPE.BREAK || (!m_anim_state_vars.m_reverse && m_current_letter_action.m_force_same_start_time && lowest_action_progress < m_anim_state_vars.m_action_index_progress))) { // Force letter to wait for rest of letters to be in sync m_anim_state_vars.m_waiting_to_sync = true; m_anim_state_vars.m_break_delay = Mathf.Max(m_current_letter_action.m_duration_progression.GetValue(m_progression_variables, animate_per), 0); return LETTER_ANIMATION_STATE.PLAYING; } if(force_render) { return m_anim_state_vars.m_active ? LETTER_ANIMATION_STATE.PLAYING : LETTER_ANIMATION_STATE.STOPPED; } finished_action = -1; m_anim_state_vars.m_action_progress = 0; m_anim_state_vars.m_linear_progress = 0; m_action_timer = timer - m_anim_state_vars.m_timer_offset; if((m_anim_state_vars.m_reverse || m_action_timer > m_action_delay)) { m_anim_state_vars.m_linear_progress = (m_action_timer - (m_anim_state_vars.m_reverse ? 0 : m_action_delay)) / m_action_duration; if(m_anim_state_vars.m_reverse) { if(m_action_timer >= m_action_duration) { m_anim_state_vars.m_linear_progress = 0; } else { m_anim_state_vars.m_linear_progress = 1 - m_anim_state_vars.m_linear_progress; } } if(!m_anim_state_vars.m_started_action) { // TODO: implement more robust check for "in-sync" actions having already played the asigned audio/effect // Just started animating action after delay. Handle any OnStart events if(m_current_letter_action.m_audio_on_start != null && (m_progression_variables.m_letter_value == 0 || !m_current_letter_action.m_starting_in_sync || m_current_letter_action.m_audio_on_start_delay.m_progression != ValueProgression.Constant)) { effect_manager.PlayAudioClip( m_current_letter_action.m_audio_on_start, m_current_letter_action.m_audio_on_start_delay.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_audio_on_start_offset.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_audio_on_start_volume.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_audio_on_start_pitch.GetValue(m_progression_variables, animate_per)); } if(m_current_letter_action.m_emitter_on_start != null && (m_current_letter_action.m_emitter_on_start_per_letter || m_progression_variables.m_letter_value == 0)) { effect_manager.PlayParticleEffect( m_current_letter_action.m_emitter_on_start, m_current_letter_action.m_emitter_on_start_delay.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_emitter_on_start_duration.GetValue(m_progression_variables, animate_per), m_mesh, m_current_letter_action.m_emitter_on_start_offset.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_emitter_on_start_follow_mesh); } m_anim_state_vars.m_started_action = true; } m_anim_state_vars.m_action_progress = EasingManager.GetEaseProgress(m_current_letter_action.m_ease_type, m_anim_state_vars.m_linear_progress); if((!m_anim_state_vars.m_reverse && m_anim_state_vars.m_linear_progress >= 1) || (m_anim_state_vars.m_reverse && m_action_timer >= m_action_duration + m_action_delay)) { m_anim_state_vars.m_action_progress = m_anim_state_vars.m_reverse ? 0 : 1; m_anim_state_vars.m_linear_progress = m_anim_state_vars.m_reverse ? 0 : 1; if(!m_anim_state_vars.m_reverse) { finished_action = m_anim_state_vars.m_action_index; } int prev_action_idx = m_anim_state_vars.m_action_index; float prev_delay = m_action_delay; // Set next action index SetNextActionIndex(animation); if(m_anim_state_vars.m_active) { if(!m_anim_state_vars.m_reverse) { m_anim_state_vars.m_started_action = false; } if(!m_anim_state_vars.m_reverse && m_anim_state_vars.m_action_index_progress > m_anim_state_vars.m_action_index) { // Repeating the action again; check for unqiue random variable requests. animation.m_letter_actions[m_anim_state_vars.m_action_index].SoftReset(animation.m_letter_actions[prev_action_idx], m_progression_variables, animate_per, m_anim_state_vars.m_action_index == 0); } else if(m_anim_state_vars.m_reverse) { animation.m_letter_actions[m_anim_state_vars.m_action_index].SoftResetStarts(animation.m_letter_actions[prev_action_idx], m_progression_variables, animate_per); } // Add to the timer offset m_anim_state_vars.m_timer_offset += prev_delay + m_action_duration; if(prev_action_idx != m_anim_state_vars.m_action_index) { UpdateLoopList(animation); } else { SetCurrentLetterAction(animation.m_letter_actions[m_anim_state_vars.m_action_index]); } } } } SetupMesh(m_current_letter_action, m_anim_state_vars.m_action_progress, force_render || first_action_call, m_progression_variables, animate_per, m_anim_state_vars.m_linear_progress); if(finished_action > -1) { // TODO: implement more robust check for "in-sync" actions having already played the asigned audio/effect if(m_current_letter_action.m_audio_on_finish != null && (m_progression_variables.m_letter_value == 0 || !m_current_letter_action.m_starting_in_sync)) { effect_manager.PlayAudioClip( m_current_letter_action.m_audio_on_finish, m_current_letter_action.m_audio_on_finish_delay.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_audio_on_finish_offset.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_audio_on_finish_volume.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_audio_on_finish_pitch.GetValue(m_progression_variables, animate_per)); } if(m_current_letter_action.m_emitter_on_finish != null && (m_current_letter_action.m_emitter_on_finish_per_letter || m_progression_variables.m_letter_value == 0)) { effect_manager.PlayParticleEffect( m_current_letter_action.m_emitter_on_finish, m_current_letter_action.m_emitter_on_finish_delay.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_emitter_on_finish_duration.GetValue(m_progression_variables, animate_per), m_mesh, m_current_letter_action.m_emitter_on_finish_offset.GetValue(m_progression_variables, animate_per), m_current_letter_action.m_emitter_on_finish_follow_mesh); } } } else { // no actions found for this letter. Position letter in its default position Vector3[] mesh_verts = new Vector3[4]; for(int idx=0; idx < 4; idx++) { mesh_verts[idx] = m_base_vertices[idx] + m_base_offset; } m_mesh.vertices = mesh_verts; m_anim_state_vars.m_active = false; } return m_anim_state_vars.m_active ? LETTER_ANIMATION_STATE.PLAYING : LETTER_ANIMATION_STATE.STOPPED; }
void Start() { List <string[]> configAnimNames = new List <string[]> { TextFxQuickSetupAnimConfigs.IntroAnimNames, TextFxQuickSetupAnimConfigs.MainAnimNames, TextFxQuickSetupAnimConfigs.OutroAnimNames }; // Calculate starting animations int introAnimIndex = Mathf.Clamp(m_introStartEffect, 1, configAnimNames[0].Length); int mainAnimIndex = Mathf.Clamp(m_mainStartEffect, 1, configAnimNames[1].Length); int outroAnimIndex = Mathf.Clamp(m_outroStartEffect, 1, configAnimNames[2].Length); if (m_introStartEffect < 1) { // Pick a random intro anim, which has no audio do { introAnimIndex = Random.Range(1, configAnimNames [0].Length); }while(configAnimNames[0][introAnimIndex] == "Epic" || configAnimNames[0][introAnimIndex] == "Mental House" || configAnimNames[0][introAnimIndex] == "Type Writer"); } if (m_mainStartEffect < 1) { // Pick a random main anim, which has no audio do { mainAnimIndex = Random.Range(1, configAnimNames [1].Length); }while(configAnimNames[1][mainAnimIndex] == "Windy"); } if (m_outroStartEffect < 1) { // Pick a random starting intro anim, which isn't a noisey one do { outroAnimIndex = Random.Range(1, configAnimNames [2].Length); }while(configAnimNames[2][outroAnimIndex] == "Shot Drop"); } List <Dropdown.OptionData> dropdownOptions; int[] animIndex = new int[] { introAnimIndex, mainAnimIndex, outroAnimIndex }; for (int idx = 0; idx < 3; idx++) { // Populate dropdown values dropdownOptions = new List <Dropdown.OptionData>(); foreach (string animName in configAnimNames[idx]) { dropdownOptions.Add(new Dropdown.OptionData(animName)); } m_animSectionDropdowns[idx].options = dropdownOptions; TextFxAnimationManager.PRESET_ANIMATION_SECTION animSection = (TextFxAnimationManager.PRESET_ANIMATION_SECTION)idx; m_animSectionDropdowns [idx].value = animIndex[idx]; // Assign dropdown listeners m_animSectionDropdowns[idx].onValueChanged.AddListener((int index) => { AnimationSectionSet(animSection, index, true); }); // Set header images to inactive colours m_sectionHeaderImages[idx].color = SECTION_INACTIVE_COLOUR; } m_animationSections = new TextFxAnimationManager.PresetAnimationSection[] { m_effect.AnimationManager.m_preset_intro, m_effect.AnimationManager.m_preset_main, m_effect.AnimationManager.m_preset_outro }; m_floatVariableSettingsPool = new ObjectPool <FloatVariableSetting>(m_floatVariableSettingPrefab.gameObject, 5); m_vector3VariableSettingsPool = new ObjectPool <Vector3VariableSetting>(m_vector3VariableSettingPrefab.gameObject, 5); m_toggleVariableSettingsPool = new ObjectPool <ToggleVariableSetting>(m_toggleVariableSettingPrefab.gameObject, 5); m_colourVariableSettingsPool = new ObjectPool <ColourVariableSetting>(m_colourVariableSettingPrefab.gameObject, 5); m_floatVariableSettingsInUse = new List <FloatVariableSetting> [3]; m_vector3VariableSettingsInUse = new List <Vector3VariableSetting> [3]; m_toggleVariableSettingsInUse = new List <ToggleVariableSetting> [3]; m_colourVariableSettingsInUse = new List <ColourVariableSetting> [3]; // Add playback button callbacks m_playButton.onClick.AddListener(() => { if (!m_effect.AnimationManager.Playing) { PlayAnimation(); } else { if (m_effect.AnimationManager.Paused) { m_effect.AnimationManager.Paused = false; m_playButtonText.text = "Pause"; } else { m_effect.AnimationManager.Paused = true; m_playButtonText.text = "Play"; } } }); m_resetButton.onClick.AddListener(() => { m_effect.AnimationManager.ResetAnimation(); m_playButtonText.text = "Play"; HideContinueButton(); }); m_continueButton.onClick.AddListener(() => { if (!m_effect.AnimationManager.Paused) { LetterAnimation letterAnim = m_effect.AnimationManager.GetAnimation(0); if (letterAnim != null && (letterAnim.CurrentAnimationState == LETTER_ANIMATION_STATE.WAITING || letterAnim.CurrentAnimationState == LETTER_ANIMATION_STATE.WAITING_INFINITE)) { m_effect.AnimationManager.ContinuePastBreak(); } else { m_effect.AnimationManager.ContinuePastLoop(); } } }); m_continueButton.gameObject.SetActive(false); m_sectionsActive = new bool[3]; m_textInput.text = "Hello World!"; #if UNITY_4 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2 m_textInput.onValueChange.AddListener((string new_string) => { #else m_textInput.onValueChanged.AddListener((string new_string) => { #endif m_effect.SetText(new_string); }); // Preset the animation sections, so it's not empty on start AnimationSectionSet(TextFxAnimationManager.PRESET_ANIMATION_SECTION.INTRO, introAnimIndex); AnimationSectionSet(TextFxAnimationManager.PRESET_ANIMATION_SECTION.MAIN, mainAnimIndex); AnimationSectionSet(TextFxAnimationManager.PRESET_ANIMATION_SECTION.OUTRO, outroAnimIndex); // Select Intro section AnimationSectionSelected(0); // Play intro sequence StartCoroutine(DoIntro(6, m_skipTitleEffectIntro)); } IEnumerator DoIntro(float waitTime, bool skipTitleEffect = false) { yield return(false); m_animEditorContent.gameObject.SetActive(false); // play intro title effect m_titleEffect.GameObject.SetActive(true); m_titleEffect.AnimationManager.PlayAnimation(1f); if (!skipTitleEffect) { yield return(new WaitForSeconds(waitTime)); } m_titleEffect.GameObject.SetActive(false); float timer = 0; Quaternion rotation = Quaternion.Euler(0, 90, 0); Vector3 rotationVec = new Vector3(0, 90, 0); m_animEditorContent.rotation = Quaternion.Euler(0, 90, 0); m_animEditorContent.gameObject.SetActive(true); while (timer <= 0.5f) { rotationVec.y = Mathf.Lerp(90, 0, timer / 0.5f); rotation.eulerAngles = rotationVec; m_animEditorContent.rotation = rotation; timer += Time.deltaTime; yield return(false); } rotationVec.y = 0; rotation.eulerAngles = rotationVec; m_animEditorContent.rotation = rotation; PlayAnimation(0.5f); } void PlayAnimation(float delay = 0) { m_effect.AnimationManager.PlayAnimation(delay, AnimationFinished); m_playButtonText.text = "Pause"; ShowContinueButton(); StartCoroutine("HighlightContinueButton"); } void ShowContinueButton() { m_continueButton.image.color = Color.white; m_continueButton.gameObject.SetActive(true); m_playButton.image.color = Color.white; } void HideContinueButton() { m_continueButton.gameObject.SetActive(false); StopCoroutine("HighlightContinueButton"); m_playButton.image.color = m_playbackButtonHighlightColour; } IEnumerator HighlightContinueButton() { yield return(new WaitForSeconds(4f)); m_continueButton.image.color = m_playbackButtonHighlightColour; } void AnimationFinished() { m_playButtonText.text = "Play"; HideContinueButton(); } void RecycleSectionSettingComponents(int sectionIndex) { if (m_floatVariableSettingsInUse[sectionIndex] != null) { foreach (FloatVariableSetting fVar in m_floatVariableSettingsInUse[sectionIndex]) { m_floatVariableSettingsPool.Recycle(fVar); } } if (m_vector3VariableSettingsInUse[sectionIndex] != null) { foreach (Vector3VariableSetting vVar in m_vector3VariableSettingsInUse[sectionIndex]) { m_vector3VariableSettingsPool.Recycle(vVar); } } if (m_toggleVariableSettingsInUse[sectionIndex] != null) { foreach (ToggleVariableSetting tVar in m_toggleVariableSettingsInUse[sectionIndex]) { m_toggleVariableSettingsPool.Recycle(tVar); } } if (m_colourVariableSettingsInUse[sectionIndex] != null) { foreach (ColourVariableSetting cVar in m_colourVariableSettingsInUse[sectionIndex]) { m_colourVariableSettingsPool.Recycle(cVar); } } }
public void SetMeshState(int action_idx, float action_progress, LetterAnimation animation, AnimatePerOptions animate_per, EffectManager effect_manager) { if (action_idx >= 0 && action_idx < animation.NumActions) SetupMesh(animation.GetAction(action_idx), action_idx > 0 ? animation.GetAction(action_idx - 1) : null, Mathf.Clamp(action_progress, 0, 1), m_progression_variables, animate_per, Mathf.Clamp(action_progress, 0, 1), effect_manager); else { // action not found for this letter. Position letter in its default position if (mesh_verts == null || mesh_verts.Length == 0) mesh_verts = new Vector3[4]; for (var idx = 0; idx < 4; idx++) mesh_verts[idx] = m_base_vertices[idx] + m_base_offset; m_mesh.vertices = mesh_verts; m_mesh.colors = new[] { Color.white, Color.white, Color.white, Color.white }; } }
private void DrawLoopTree(LetterAnimation selected_animation) { if (font_manager.NumAnimations == 0) return; var main_editor_height = Instance.position.height - WINDOW_BORDER_TOP - WINDOW_BORDER_BOTTOM; var num_actions = selected_animation.NumActions; var gui_y_offset = WINDOW_BORDER_TOP; var action_idx = 0; gui_y_offset = WINDOW_BORDER_TOP; // Draw A's m_state_node_rects = new Rect[num_actions]; EditorGUI.LabelField(new Rect(state_overview_x, gui_y_offset, 100, LINE_HEIGHT * 2), "Loops [" + selected_animation.NumLoops + "]", EditorStyles.boldLabel); gui_y_offset += LINE_HEIGHT * 2; if (GUI.Button(new Rect(state_overview_x, gui_y_offset, 60, LINE_HEIGHT), new GUIContent(m_display_loops_tree ? "Hide" : "Show", (m_display_loops_tree ? "Hide" : "Show") + " the loops setup menu."))) m_display_loops_tree = !m_display_loops_tree; gui_y_offset += LINE_HEIGHT * 2; LOOP_SCROLL_POS = GUI.BeginScrollView(new Rect(state_overview_x, gui_y_offset, MainEditorX - state_overview_x - 14, main_editor_height - (gui_y_offset - WINDOW_BORDER_TOP)), LOOP_SCROLL_POS, new Rect(0, 0, MainEditorX - 35, selected_animation.NumActions * ACTION_NODE_SPACING)); gui_y_offset = 0; for (action_idx = 0; action_idx < selected_animation.NumActions; action_idx++) { GUI.Label(new Rect(20, gui_y_offset, 40, 20), "A" + action_idx, EditorStyles.boldLabel); if (m_display_loops_tree) m_state_node_rects[action_idx] = new Rect(20 - ACTION_NODE_MARGIN, gui_y_offset - ACTION_NODE_MARGIN, 20 + (2 * ACTION_NODE_MARGIN), 20 + (2 * ACTION_NODE_MARGIN)); gui_y_offset += ACTION_NODE_SPACING; } if (m_display_loops_tree) { // Draw existing loops Vector2 point1, point2; // Draw Loop assignment-in-progress line, triggered by users click and drag on action nodes if (m_mouse_down_node_idx >= 0) DrawLine(m_mouse_down_pos, new Vector2(m_mouse_down_pos.x, m_mouse_drag_pos.y), Color.gray, 3); state_overview_width = 0; var num_loops = selected_animation.NumLoops; var my_style = EditorStyles.miniButton; my_style.alignment = TextAnchor.MiddleLeft; my_style.normal.textColor = Color.black; // Loop through loop list, drawing loop line representations on loop timeline and adding loop list entries float loops_list_x; ActionLoopCycle loop_cycle; var last_span_width = -1; var indent_num = 0; float line_offset_x = 0; float loop_list_line_y = 0; GUI.SetNextControlName("LoopsTitle"); // Display loop list header EditorGUI.LabelField(new Rect(loop_tree_width + 60, loop_list_line_y, 100, LINE_HEIGHT), "Active Loops", EditorStyles.boldLabel); loop_list_line_y += LINE_HEIGHT; EditorGUI.LabelField(new Rect(loop_tree_width + 52, loop_list_line_y, 30, LINE_HEIGHT), new GUIContent("From", "The index of the action to start this loop."), EditorStyles.miniBoldLabel); EditorGUI.LabelField(new Rect(loop_tree_width + 87, loop_list_line_y, 20, LINE_HEIGHT), new GUIContent("To", "The index of the action to end this loop."), EditorStyles.miniBoldLabel); EditorGUI.LabelField(new Rect(loop_tree_width + 110, loop_list_line_y, 42, LINE_HEIGHT), new GUIContent("#Loops", "The number of times to run through this loop. Enter zero to run loop infinitely."), EditorStyles.miniBoldLabel); EditorGUI.LabelField(new Rect(loop_tree_width + 190, loop_list_line_y, 40, LINE_HEIGHT), new GUIContent("Type", "The type/behaviour of this loop."), EditorStyles.miniBoldLabel); EditorGUI.LabelField(new Rect(loop_tree_width + 262, loop_list_line_y, 70, LINE_HEIGHT), new GUIContent("DFO [?]", "'Delay First Only' - Letter action delays (non-constant) will only be applied for the first forward pass through the loop. This stops the letters getting more and more out of sequence with every loop interation."), EditorStyles.miniBoldLabel); loop_list_line_y += LINE_HEIGHT; for (var loop_idx = 0; loop_idx < num_loops; loop_idx++) { loop_cycle = selected_animation.GetLoop(loop_idx); if (last_span_width == -1) last_span_width = loop_cycle.SpanWidth; // Check for invalid loops if (loop_cycle.m_start_action_idx >= num_actions || loop_cycle.m_end_action_idx >= num_actions) { // invalid loop. Delete it. selected_animation.RemoveLoop(loop_idx); loop_idx--; num_loops--; continue; } // Represent loop as a line on the Action timeline if (last_span_width != loop_cycle.SpanWidth) { last_span_width = loop_cycle.SpanWidth; indent_num++; } line_offset_x = 20 + (indent_num * LOOP_LINE_OFFSET); if (loop_cycle.m_start_action_idx != loop_cycle.m_end_action_idx) { point1 = m_state_node_rects[loop_cycle.m_start_action_idx].center + new Vector2(line_offset_x, 0); point2 = m_state_node_rects[loop_cycle.m_end_action_idx].center + new Vector2(line_offset_x, 0); DrawLine(point1, point2, loop_cycle.m_loop_type == LOOP_TYPE.LOOP ? LOOP_COLOUR : LOOP_REVERSE_COLOUR, 2); DrawLine(point1 + new Vector2(0, -2), point1 + new Vector2(0, 2), loop_cycle.m_loop_type == LOOP_TYPE.LOOP ? LOOP_COLOUR : LOOP_REVERSE_COLOUR, 6); DrawLine(point2 + new Vector2(0, -2), point2 + new Vector2(0, 2), loop_cycle.m_loop_type == LOOP_TYPE.LOOP ? LOOP_COLOUR : LOOP_REVERSE_COLOUR, 6); } else { point1 = m_state_node_rects[loop_cycle.m_start_action_idx].center + new Vector2(line_offset_x, -2); point2 = m_state_node_rects[loop_cycle.m_end_action_idx].center + new Vector2(line_offset_x, 2); DrawLine(point1, point2, loop_cycle.m_loop_type == LOOP_TYPE.LOOP ? LOOP_COLOUR : LOOP_REVERSE_COLOUR, 6); } // Display loop number my_style.normal.textColor = loop_cycle.m_loop_type == LOOP_TYPE.LOOP ? LOOP_COLOUR : LOOP_REVERSE_COLOUR; EditorGUI.LabelField(new Rect(point1.x, (point1.y + point2.y) / 2 - 10, loop_cycle.m_number_of_loops > 9 ? 30 : 20, 20), loop_cycle.m_number_of_loops <= 0 ? "~" : "" + loop_cycle.m_number_of_loops, my_style); //EditorStyles.miniButton); // Display list view of loop cycle loops_list_x = loop_tree_width; EditorGUI.LabelField(new Rect(loops_list_x, loop_list_line_y, 100, LINE_HEIGHT), "Loop " + (loop_idx + 1)); loops_list_x += 58; EditorGUI.LabelField(new Rect(loops_list_x, loop_list_line_y, 20, LINE_HEIGHT), "" + loop_cycle.m_start_action_idx); loops_list_x += 30; EditorGUI.LabelField(new Rect(loops_list_x, loop_list_line_y, 20, LINE_HEIGHT), "" + loop_cycle.m_end_action_idx); loops_list_x += 32; loop_cycle.m_number_of_loops = EditorGUI.IntField(new Rect(loops_list_x, loop_list_line_y, 20, LINE_HEIGHT), loop_cycle.m_number_of_loops); loops_list_x += 30; loop_cycle.m_loop_type = (LOOP_TYPE)EditorGUI.EnumPopup(new Rect(loops_list_x, loop_list_line_y, 110, LINE_HEIGHT), loop_cycle.m_loop_type); loops_list_x += 130; loop_cycle.m_delay_first_only = EditorGUI.Toggle(new Rect(loops_list_x, loop_list_line_y, 20, LINE_HEIGHT), loop_cycle.m_delay_first_only); loops_list_x += 30; if (GUI.Button(new Rect(loops_list_x, loop_list_line_y, 24, LINE_HEIGHT), "x")) { selected_animation.RemoveLoop(loop_idx); num_loops--; continue; } loop_list_line_y += LINE_HEIGHT; } loop_list_line_y += 5; // "Add new loop" line loops_list_x = loop_tree_width; EditorGUI.LabelField(new Rect(loops_list_x, loop_list_line_y, 100, LINE_HEIGHT), "New", EditorStyles.boldLabel); loops_list_x += 58; new_loop_from = EditorGUI.IntField(new Rect(loops_list_x, loop_list_line_y, 20, LINE_HEIGHT), new_loop_from); loops_list_x += 30; new_loop_to = EditorGUI.IntField(new Rect(loops_list_x, loop_list_line_y, 20, LINE_HEIGHT), new_loop_to); loops_list_x += 32; if (GUI.Button(new Rect(loops_list_x, loop_list_line_y, 40, LINE_HEIGHT), "Add")) { selected_animation.AddLoop(new_loop_from, new_loop_to, false); font_manager.PrepareAnimationData(); new_loop_from = 0; new_loop_to = 0; // Force keyboard focus loss from any of the loop adding fields. GUI.FocusControl("LoopsTitle"); } // Set the width of the loop tree segment loop_tree_width = (int)line_offset_x + BASE_LOOP_LIST_POSITION_OFFSET; // Add additional width of loop list menu state_overview_width = loop_tree_width + LOOP_LIST_WIDTH; var eventType = Event.current.type; var mousePos = Event.current.mousePosition; if (eventType == EventType.MouseDown && mousePos.x < MainEditorX) { var rect_idx = 0; foreach (var node_rect in m_state_node_rects) { if (node_rect.Contains(mousePos)) { m_mouse_down_node_idx = rect_idx; m_mouse_down_pos = node_rect.center; m_mouse_drag_pos = m_mouse_down_pos; } rect_idx ++; } } else if (eventType == EventType.MouseDrag) { if (m_mouse_down_node_idx >= 0) { m_mouse_drag_pos = mousePos; Instance.Repaint(); } } else if (eventType == EventType.MouseUp) { if (m_mouse_down_node_idx >= 0 && mousePos.x < MainEditorX) { var rect_idx = 0; foreach (var node_rect in m_state_node_rects) { if (node_rect.Contains(mousePos)) { // Debug.LogError("you joined : " + m_mouse_down_node_idx + " and " + rect_idx + " with button " + Event.current.button); int start, end; if (m_mouse_down_node_idx < rect_idx) { start = m_mouse_down_node_idx; end = rect_idx; } else { start = rect_idx; end = m_mouse_down_node_idx; } selected_animation.AddLoop(start, end, Event.current.button == 1); font_manager.PrepareAnimationData(); break; } rect_idx ++; } } m_mouse_down_node_idx = -1; Instance.Repaint(); } } else state_overview_width = 0; GUI.EndScrollView(); }
public static int ImportLegacyData(this LetterAnimation letter_anim, List <object> data_list, int index_offset = 0) { KeyValuePair <string, string> value_pair; string key, value; int idx; int loop_idx = 0, action_idx = 0; for (idx = index_offset; idx < data_list.Count; idx++) { value_pair = (KeyValuePair <string, string>)data_list[idx]; key = value_pair.Key; value = value_pair.Value; if (key.Equals("ANIM_DATA_END")) { // reached end of this animations import data break; } switch (key) { case "m_letters_to_animate": List <object> letter_list = value.StringToList(';'); letter_anim.m_letters_to_animate = new List <int>(); if (letter_list != null) { foreach (object obj in letter_list) { letter_anim.m_letters_to_animate.Add(int.Parse(obj.ToString())); } } break; case "m_letters_to_animate_custom_idx": letter_anim.m_letters_to_animate_custom_idx = int.Parse(value); break; case "m_letters_to_animate_option": letter_anim.m_letters_to_animate_option = (LETTERS_TO_ANIMATE)int.Parse(value); break; // LOOP DATA IMPORT case "LOOP_DATA_START": if (loop_idx == letter_anim.NumLoops) { letter_anim.AddLoop(); } break; case "LOOP_DATA_END": loop_idx++; break; case "m_delay_first_only": letter_anim.GetLoop(loop_idx).m_delay_first_only = bool.Parse(value); break; case "m_end_action_idx": letter_anim.GetLoop(loop_idx).m_end_action_idx = int.Parse(value); break; case "m_loop_type": letter_anim.GetLoop(loop_idx).m_loop_type = (LOOP_TYPE)int.Parse(value); break; case "m_number_of_loops": letter_anim.GetLoop(loop_idx).m_number_of_loops = int.Parse(value); break; case "m_start_action_idx": letter_anim.GetLoop(loop_idx).m_start_action_idx = int.Parse(value); break; // ACTION DATA IMPORT case "ACTION_DATA_START": if (action_idx == letter_anim.NumActions) { letter_anim.AddAction(); } idx = letter_anim.GetAction(action_idx).ImportLegacyData(data_list, idx + 1); action_idx++; break; } } // Remove any extra LoopData or LetterAction instances that existed prior to importing if (letter_anim.NumLoops > loop_idx) { letter_anim.RemoveLoops(loop_idx, letter_anim.NumLoops - loop_idx); } if (letter_anim.NumActions > action_idx) { letter_anim.RemoveActions(action_idx, letter_anim.NumActions - action_idx); } return(idx); }