今天就跟大家聊聊有关Unity中怎么实现卡拉OK歌词过渡效果,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。
站在用户的角度思考问题,与客户深入沟通,找到余江网站设计与余江网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:成都做网站、成都网站制作、企业官网、英文网站、手机端网站、网站推广、域名注册、虚拟主机、企业邮箱。业务覆盖余江地区。
歌词效果类 ↓
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.UI;using System;using DG.Tweening;using DG.Tweening.Core;/// /// 用于显示歌词过渡的效果/// 1. 获得路径加载并解析歌词文件信息/// 2. 判断当前歌曲是否播放( 歌曲暂停的时候歌词效果也暂停 , 歌曲停止的时候歌词效果消失 )/// 3. 判断歌曲快进或快退事件/// public class LayricPanelEffect : MonoSingleton{ #region *********************************************************************字段 //由外部传入的声音资源 [HideInInspector,SerializeField] public AudioSource audioSource; //歌词前景颜色;歌词后景颜色 [SerializeField] public Color32 frontTextColor = Color.white, backTextColor = Color.black, outlineColor = Color.white; //歌词面板的前景部分和后景部分 public RectTransform rectFrontLyricText, rectBackLyricMask; public Slider slider; //歌词文件路径 [HideInInspector,SerializeField] public string lyricFilePath; //是否开始播放当前行歌词内容 public bool isStartLyricEffectTransition = true; //歌词调整进度 ( 纠错 ) // [HideInInspector] public float lyricAdjust = -5f; //歌词文本信息 // [HideInInspector] [SerializeField,HideInInspector] public Text _lyricText; public Text _textContentLyric, _textLogMessage; private Vector2 tempFrontSizeDelta, tempBackSizeDelta; //用于访问歌词正文部分的内容在KscWord类中 private KSC.KscWord kscword = new KSC.KscWord (); private KSC.KscWord curKscword = new KSC.KscWord (); //内部定时器( 由外部传入参数来控制 , 用来记录歌曲播放的当前时间轴 ) private float _timer = 0.00f; #endregion /// /// 初始化一些变量 /// void InitSomething () { //坚持对歌词文件进行赋值操作 if (_lyricText == null || rectFrontLyricText.GetComponent () == null) { if (rectFrontLyricText.GetComponent () == null) { _lyricText = rectFrontLyricText.gameObject.AddComponent (); } _lyricText = rectFrontLyricText.GetComponent (); //保持歌词实现自适应 rectFrontLyricText.GetComponent ().horizontalFit = ContentSizeFitter.FitMode.PreferredSize; rectFrontLyricText.GetComponent ().verticalFit = ContentSizeFitter.FitMode.PreferredSize; } rectBackLyricMask.GetComponentInChildren ().text = _lyricText.text; //歌词颜色的更改初始化 rectBackLyricMask.GetComponentInChildren ().color = backTextColor; rectBackLyricMask.GetComponentInChildren ().effectColor = outlineColor; rectFrontLyricText.GetComponent ().color = frontTextColor; //歌词过渡的前景部分 ( 用于判断过度遮罩的长度范围 ) tempFrontSizeDelta = rectFrontLyricText.sizeDelta; tempBackSizeDelta = rectBackLyricMask.sizeDelta; //是否开始当前歌词行播放标志位 isStartLyricEffectTransition = true; } void Awake () { //初始化 InitSomething (); } /// /// 控制歌词面板的显示 /// 1. 仅仅显示歌词面板信息 , 没有过渡效果! /// /// 歌词正文部分行号. /// If set to true 显示面板歌词 public void LyricPanelControllerView (KSC.KscWord curRowInfo, bool isPanelView) {// Debug.Log ("当前行是否开始=====>" + isPanelView.ToString ()); _textLogMessage.text = isStartLyricEffectTransition.ToString (); rectBackLyricMask.sizeDelta = new Vector2 (0f, rectFrontLyricText.sizeDelta.y); rectBackLyricMask.GetComponentInChildren ().text = _lyricText.text = ""; if (isPanelView) { //根据时间得到当前播放的是第i行的歌词 //处理歌词面板信息 , 显示歌词 foreach (var item in curRowInfo.PerLineLyrics) { _lyricText.text += item; rectBackLyricMask.GetComponentInChildren ().text = _lyricText.text; } StartCoroutine (LyricPanelControllerEffect (curRowInfo, isPanelView)); } else { StopAllCoroutines (); rectBackLyricMask.sizeDelta = new Vector2 (0f, rectFrontLyricText.sizeDelta.y);// StartCoroutine (LyricPanelControllerEffect (curRowInfo, isPanelView)); //当前歌词结束以后将歌词框初始化成0 rectBackLyricMask.GetComponentInChildren ().text = _lyricText.text = string.Empty; } } /// /// 开始实现歌此过渡效果, 仅仅效果实现 /// 1. 使用Dotween的doSizedata实现 /// 2. 动态调整蒙板的sizedata宽度 /// 3. 根据歌曲当前播放的时间进度进行调整 /// /// The panel controller effect. /// If set to true is panel effect. public IEnumerator LyricPanelControllerEffect (KSC.KscWord curRowInfo, bool isPanelEffect) { //当前时间歌词播放进度的百分比比例 int curWordIndex = 0; if (isPanelEffect) { rectBackLyricMask.DORewind (); yield return null; rectBackLyricMask.sizeDelta = new Vector2 (0f, rectFrontLyricText.sizeDelta.y); //开始效果过渡 if (audioSource.isPlaying) { for (int i = 0; i < curKscword.PerLinePerLyricTime.Length; i++) { rectBackLyricMask.DOSizeDelta ( new Vector2 (((float)(i + 1) / curKscword.PerLinePerLyricTime.Length) * rectFrontLyricText.sizeDelta.x, rectFrontLyricText.sizeDelta.y) , curKscword.PerLinePerLyricTime [i] / 1000f , false).SetEase (Ease.Linear);// Debug.Log ("第" + i + "个歌词时间"); yield return new WaitForSeconds (curKscword.PerLinePerLyricTime [i] / 1000f); } } else { Debug.LogError ("歌曲没有播放 !!!!"); } } else { yield return null; rectBackLyricMask.DOSizeDelta (new Vector2 (0f, rectFrontLyricText.sizeDelta.y), 0f, true); } } /// /// 开始播放音乐的时候调用 /// /// 歌词文件路径. /// Audiosource用于判断播放状态. /// 前景色. /// 后景. /// 如果设置为 true 则使用系统配置的默认颜色. public void StartPlayMusic (string lyricFilePath, AudioSource audioSource, Color frontColor, Color backColor, Color outlineColor, bool isIgronLyricColor) { _timer = 0f; //初始化ksc文件 KSC.InitKsc (lyricFilePath); this.lyricFilePath = lyricFilePath; this.audioSource = audioSource; _textContentLyric.text = string.Empty; if (!isIgronLyricColor) { //歌曲颜色信息 this.frontTextColor = frontColor; this.backTextColor = backColor; this.outlineColor = outlineColor; } #region ****************************************************输出歌词文件信息 //对初始化完成后的信息进行输出 if (KSC.Instance.SongName != null) { print ("歌名==========>" + KSC.Instance.SongName); } if (KSC.Instance.Singer != null) { print ("歌手==========>" + KSC.Instance.Singer); } if (KSC.Instance.Pinyin != null) { print ("拼音==========>" + KSC.Instance.Pinyin); } if (KSC.Instance.SongClass != null) { print ("歌类==========>" + KSC.Instance.SongClass); } if (KSC.Instance.InternalNumber > 0) { print ("歌曲编号=======>" + KSC.Instance.InternalNumber); } if (KSC.Instance.Mcolor != Color.clear) { print ("男唱颜色=======>" + KSC.Instance.Mcolor); } if (KSC.Instance.Mcolor != Color.clear) { print ("女唱颜色=======>" + KSC.Instance.Wcolor); } if (KSC.Instance.SongStyle != null) { print ("风格==========>" + KSC.Instance.SongStyle); } if (KSC.Instance.WordCount > 0) { print ("歌名字数=======>" + KSC.Instance.WordCount); } if (KSC.Instance.LangClass != null) { print ("语言种类=======>" + KSC.Instance.LangClass); } //一般是独唱歌曲的时候使用全Tag标签展现参数信息 foreach (var item in KSC.Instance.listTags) { print (item); } #endregion //显示整个歌词内容 for (int i = 0; i < KSC.Instance.Add.Values.Count; i++) { KSC.Instance.Add.TryGetValue (i, out kscword); for (int j = 0; j < kscword.PerLineLyrics.Length; j++) { _textContentLyric.text += kscword.PerLineLyrics [j]; } _textContentLyric.text += "\n"; } } /// /// 停止播放按钮 /// public void StopPlayMusic () { Debug.Log ("停止播放按钮"); } /// /// 主要用于歌词部分的卡拉OK过渡效果 /// 1. 动态赋值歌词框的长度 /// 2. 支持快进快退同步显示 /// int row = 0, tempRow = 0; void FixedUpdate () { #region *********************************************************播放过渡效果核心代码 //如果是播放状态并且没有快进或快退 , 获得当前播放时间 , 如果都下一句歌词了 , 则切换到下一句歌词进行过渡效果 //1. 是否是暂停; //2. 是否开始播放 //3. 是否播放停止 if (audioSource != null && audioSource.isPlaying) { //进度条 slider.value = _timer / audioSource.clip.length; //快进快退快捷键 if (Input.GetKey (KeyCode.RightArrow)) { audioSource.time = Mathf.Clamp ((audioSource.time + 1f), 0f, 4.35f * 60f); } else if (Input.GetKey (KeyCode.LeftArrow)) { audioSource.time = Mathf.Clamp ((audioSource.time - 1f), 0f, 4.35f * 60f);// } else if (Input.GetKeyUp (KeyCode.LeftArrow)) { isStartLyricEffectTransition = true; rectBackLyricMask.GetComponentInChildren ().text = rectFrontLyricText.GetComponent ().text = string.Empty; } //实时计时 _timer = audioSource.time; //歌曲开始播放的时间 _textLogMessage.text = _timer.ToString ("F2"); for (int i = 0; i < KSC.Instance.Add.Count; i++) { KSC.Instance.Add.TryGetValue (i, out kscword); //根据时间判断当前播放的是哪一行的歌词文件 ( 减去0.01可保证两句歌词衔接太快的时候的bug ) if ((_timer >= (kscword.PerLineLyricStartTimer + lyricAdjust + 0.1f) && _timer <= (kscword.PerLintLyricEndTimer + lyricAdjust - 0.1f)) && isStartLyricEffectTransition) { tempRow = i; KSC.Instance.Add.TryGetValue (tempRow, out curKscword); isStartLyricEffectTransition = false; Debug.Log ("当前播放====>" + i + "行"); //歌词面板显示当前播放内容 LyricPanelControllerView (curKscword, !isStartLyricEffectTransition); } else if ((_timer >= (curKscword.PerLintLyricEndTimer + lyricAdjust)) && !isStartLyricEffectTransition) { isStartLyricEffectTransition = true; //设置不显示歌词内容 LyricPanelControllerView (curKscword, !isStartLyricEffectTransition); } }// KSC.Instance.Add.TryGetValue (row, out kscword);//// //根据时间判断当前播放的是哪一行的歌词文件 ( 减去0.01可保证两句歌词衔接太快的时候的bug )// if ((_timer >= (kscword.PerLineLyricStartTimer + lyricAdjust + 0.1f) && _timer <= (kscword.PerLintLyricEndTimer + lyricAdjust)) && isStartLyricEffectTransition) {// tempRow = row;// KSC.Instance.Add.TryGetValue (tempRow, out curKscword);// isStartLyricEffectTransition = false;// Debug.Log ("当前播放====>" + row + "行");// //歌词面板显示当前播放内容// LyricPanelControllerView (curKscword, !isStartLyricEffectTransition);// } else if ((_timer >= (curKscword.PerLintLyricEndTimer + lyricAdjust)) && !isStartLyricEffectTransition) {// isStartLyricEffectTransition = true;// //设置不显示歌词内容// LyricPanelControllerView (curKscword, !isStartLyricEffectTransition);// row = (row + 1) % KSC.Instance.Add.Count;// } #endregion } }}
###KSC文件解析类 ↓
using System.Collections;using System.Collections.Generic;using UnityEngine;using System.IO;using System.Text;using UnityEngine.UI;using System;using System.Text.RegularExpressions;using System.Runtime.InteropServices;/// /// KSC歌词文件解析属性, 单例工具类 ( 解析解析解析解析解析解析解析解析解析!!!!!!重要的事情多说几遍 )/// 1. 歌词部分标题信息用单例instance访问/// 2. 正文信息部分使用KSCWord对象访问( 每句开始时间\结束时间\每句歌词文字的数组\每句歌词文件时间的数组 )/// public class KSC : Singleton{ /// /// 歌曲 歌名 /// public string SongName { get; set; } /// /// 歌名字数 歌名字数 /// public int WordCount{ get; set; } /// /// 歌名字数 歌名的拼音声母 /// public string Pinyin{ get; set; } /// /// 歌名字数 歌曲语言种类 /// public string LangClass{ get; set; } /// /// 歌类,如男女乐队等 /// public string SongClass{ get; set; } /// /// 艺术家 演唱者,对唱则用斜杠"/"分隔 /// public string Singer { get; set; } /// /// 歌曲编号 歌曲编号 /// public int InternalNumber{ get; set; } /// /// 歌曲风格 /// public string SongStyle{ get; set; } /// /// 视频编号 /// public string VideoFileName{ get; set; } /// /// 前景颜色 /// public Color Mcolor{ get; set; } /// /// 后景颜色 /// public Color Wcolor{ get; set; } /// /// 偏移量 /// public string Offset { get; set; } /// /// 各类标签 /// public List listTags = new List (); /// /// 歌词正文部分信息 ( key = 行号 value = 解析出来的歌词正文部分的每句歌词信息 ) /// public Dictionary Add = new Dictionary (); /// /// 获得歌词信息 /// /// 歌词路径 /// 返回歌词信息(Lrc实例) public static KSC InitKsc (string LrcPath) { int row = 0; //KscWord对象 //清除之前的歌曲歌词, 保持当前 KSC.Instance.Add.Clear (); using (FileStream fs = new FileStream (LrcPath, FileMode.Open, FileAccess.Read, FileShare.Read)) { string line = string.Empty; using (StreamReader sr = new StreamReader (fs, Encoding.Default)) { while ((line = sr.ReadLine ()) != null) { //每次循环新建一个对象用于存储不同行数内容 KSC.KscWord kscWord = new KSC.KscWord (); #region ######################################合唱歌曲格式 if (line.StartsWith ("karaoke.songname := '")) { Instance.SongName = SplitStrInfo (line); } else if (line.StartsWith ("karaoke.internalnumber := ")) { if (SplitIntInfo (line) != 0) { Instance.InternalNumber = SplitIntInfo (line); } } else if (line.StartsWith ("karaoke.singer := '")) { Instance.Singer = SplitStrInfo (line); } else if (line.StartsWith ("karaoke.wordcount := ")) { if (SplitIntInfo (line) != 0) { Instance.WordCount = SplitIntInfo (line); } } else if (line.StartsWith ("karaoke.pinyin := '")) { Instance.Pinyin = SplitStrInfo (line); } else if (line.StartsWith ("karaoke.langclass := '")) { Instance.LangClass = SplitStrInfo (line); } else if (line.StartsWith ("karaoke.songclass := '")) { Instance.SongClass = SplitStrInfo (line); } else if (line.StartsWith ("karaoke.songstyle := '")) { Instance.SongStyle = SplitStrInfo (line); } else if (line.StartsWith ("karaoke.videofilename :='")) { Instance.VideoFileName = SplitStrInfo (line); } else if (line.StartsWith ("mcolor :=rgb(")) { if (SplitColorInfo (line) != Color.clear) { Instance.Mcolor = SplitColorInfo (line); } } else if (line.StartsWith ("wcolor :=rgb(")) { if (SplitColorInfo (line) != Color.clear) { Instance.Wcolor = SplitColorInfo (line); } #endregion #region ##################################################独唱歌曲风格 } else if (line.StartsWith ("karaoke.tag('")) { //获取tag标签的参数信息 KSC.Instance.listTags.Add (SplitTagInfo (line)); #endregion #region ################################################歌词正文部分解析 } else if (line.StartsWith (("karaoke.add"))) { //表示歌词正文部分 if (SplitLyricStartTime (line) != null) { //行号 ( 从0行开始 ) //获取每句歌词部分的开始时间 kscWord.PerLineLyricStartTimer = SplitLyricStartTime (line); //获取每句歌词部分的结束时间 kscWord.PerLintLyricEndTimer = SplitLyricEndTime (line); //获取每行歌词的内容,并存储到KSCWord中 ( 歌词文字的数组信息 左 → 右 ) kscWord.PerLineLyrics = SplitPerLineLyrics (line); //获取每行中单个文字的过渡时间数组 ( 歌词文字过渡时间数组 左 → 右 ) kscWord.PerLinePerLyricTime = SplitPerLinePerLyricTime (line); KSC.Instance.Add.Add (row, kscWord); row++; } } else { //忽略ksc文件中的其他部分 if (line != "" && !line.Contains ("CreateKaraokeObject") && !line.Contains ("karaoke.rows") && !line.Contains ("karaoke.clear;") && !Regex.IsMatch (line, @"^\//")) { Debug.LogWarning ("歌词含有不能解析的部分 ===> " + line); } } #endregion } } } Debug.Log ("LyricFileInitialized" + " Path : \n" + LrcPath); return Instance; } #region ****************************************************************解析歌词用的正则表达式部分 需更新 /// /// 处理信息(私有方法) /// /// /// 返回基础信息 public static string SplitStrInfo (string line) {// char[] ch = new char[]{ '', '' };// return line.Substring (line.IndexOf ("'") + 1).TrimEnd (ch); string pattern = @"'\S{1,20}'"; //获取歌曲标签信息 Match match = Regex.Match (line, pattern); //去除两端的小分号 string resout = string.Empty; resout = match.Value.Replace ("\'", string.Empty); return resout; } /// /// 处理参数是数字的情况 /// /// The int info. /// Line. public static int SplitIntInfo (string line) { string pattern = @"\d+"; //获取歌曲标签参数为数字的信息 Match match = Regex.Match (line, pattern); //去除两端的小分号 int result = 0; result = Int32.Parse (match.Value); return result; } /// /// 处理参数颜色色值的情况 如: mcolor :=rgb(0, 0, 255); /// /// The color info. /// Line. public static Color32 SplitColorInfo (string line) { string pattern = @"[r,R][g,G][b,G]?[\(](2[0-4][0-9])|25[0-5]|[01]?[0-9][0-9]?"; //获取歌曲标签参数为颜色值的信息 MatchCollection matches = Regex.Matches (line, pattern); return new Color (float.Parse (matches [0].ToString ()), float.Parse (matches [1].ToString ()), float.Parse (matches [2].ToString ())); } /// /// 获取歌曲的标签部分信息 如 : karaoke.tag('语种', '国语'); // 国语/粤语/台语/外语 /// /// The tag info. public static string SplitTagInfo (string line) { string temp; string pattern = @"\([\W|\w]+\)"; //获取歌曲标签参数为颜色值的信息 Match match = Regex.Match (line, pattern); temp = match.Value.Replace ("(", string.Empty).Replace (")", string.Empty).Replace ("'", string.Empty).Replace (",", ":"); return temp; } /// /// 获取每句歌词正文部分的开始时间 (单位 : 秒) /// /// The lyric start time. /// Line. public static float SplitLyricStartTime (string line) { float time = 0f; Regex regex = new Regex (@"\d{2}:\d{2}\.\d{2,3}", RegexOptions.IgnoreCase); //匹配单句歌词时间 如: karaoke.add('00:29.412', '00:32.655' MatchCollection mc = regex.Matches (line); time = (float)TimeSpan.Parse ("00:" + mc [0].Value).TotalSeconds; return time; } /// /// 获取每句歌词正文部分的结束时间 (单位 : 秒) /// /// The lyric start time. /// Line. public static float SplitLyricEndTime (string line) { Regex regex = new Regex (@"\d{2}:\d{2}\.\d{2,3}", RegexOptions.IgnoreCase); //匹配单句歌词时间 如: karaoke.add('00:29.412', '00:32.655' MatchCollection mc = regex.Matches (line); float time = (float)TimeSpan.Parse ("00:" + mc [1].Value).TotalSeconds; return time; } /// /// 获取每句歌词部分的每个文字 和 PerLinePerLyricTime相匹配 (单位 : 秒) /// /// The line lyrics. /// Line. public static string[] SplitPerLineLyrics (string line) { List listStrResults = new List (); string pattern1 = @"\[[\w|\W]{1,}]{1,}"; //获取歌曲正文每个单词 如 : karaoke.add('00:25.183', '00:26.730', '[五][十][六][个][星][座]', '312,198,235,262,249,286'); string pattern2 = @"\'(\w){1,}\'"; //获取歌曲正文每个单词 如 : karaoke.add('00:28.420', '00:35.431', '夕阳底晚风里', '322,1256,2820,217,1313,1083'); Match match = (line.Contains ("[") && line.Contains ("]")) ? Regex.Match (line, pattern1) : Regex.Match (line, pattern2); //删除掉 [ ] ' if (match.Value.Contains ("[") && match.Value.Contains ("]")) { //用于合唱类型的歌词文件 string[] resultStr = match.Value.Replace ("][", "/").Replace ("[", string.Empty).Replace ("]", string.Empty).Split ('/'); foreach (var item in resultStr) { listStrResults.Add (item); } } else if (match.Value.Contains ("'")) { //用于独唱类型的歌词文件 ( 尚未测试英文歌词文件!!!!!!!!!!!!!!!!!!!!!!! ) char[] tempChar = match.Value.Replace ("'", string.Empty).ToCharArray (); foreach (var item in tempChar) { listStrResults.Add (item.ToString ()); } } return listStrResults.ToArray (); } /// /// 获取每句歌词部分的每个文字需要的过渡时间 和 PerLineLyrics相匹配 (单位 : 秒) /// /// The line per lyric time. /// Line. public static float[] SplitPerLinePerLyricTime (string line) { string pattern = @"\'((\d){0,}\,{0,1}){0,}\'"; //获取歌曲正文每个单词过渡时间 如 : karaoke.add('00:25.183', '00:26.730', '[五][十][六][个][星][座]', '312,198,235,262,249,286'); string str = null; List listfloat = new List (); //删除掉 多余项 str = Regex.Match (line, pattern).Value.Replace ("'", string.Empty);// Debug.Log (str); foreach (var item in str.Split (',')) { listfloat.Add (float.Parse (item)); } return listfloat.ToArray (); } #endregion #region ********************************************************************歌词正文部分的时间与文字信息 /// /// 用单独的类来管理歌词的正文部分 ( 在KSC类下 )主要用来存储每句歌词和每个歌词的时间信息 /// 1. 每句歌词的时间的 ( 开始 - 结束 ) /// 2. 每句歌词中单个文字的时间信息 (集合的形式实现) /// public class KscWord { /// /// 每行歌词部分开始的时间 (单位 : 秒) (key=行号,value=时间) /// public float PerLineLyricStartTimer { get; set; } /// /// 每行歌词部分结束时间 (单位 : 秒) (key=行号,value=时间) /// public float PerLintLyricEndTimer { get; set; } /// /// 每行歌词的单个文字集合 /// public string[] PerLineLyrics{ get; set; } /// /// 每行歌词中单个文字的速度过渡信息 (单位 : 毫秒) /// public float[] PerLinePerLyricTime{ get; set; } } #endregion}
看完上述内容,你们对Unity中怎么实现卡拉OK歌词过渡效果有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注创新互联行业资讯频道,感谢大家的支持。
分享文章:Unity中怎么实现卡拉OK歌词过渡效果
网页路径:
http://cxhlcq.com/article/jjipes.html