由于项目需要,做了个简单的本地音乐播放器demo,记录一下,万一以后就用到了。
UI不方便贴图,只贴关键功能的代码。
功能1:从本地选择音频文件。
这部分代码是在网上搜索到的,由于不知道原创是哪位前辈(因为所有人都标着原创),所以就不贴出处了,代码看起来感觉很懵,但是其实可以直接复制粘贴使用,只限pc端。
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
public class LocalDialog {
//链接指定系统函数 打开文件对话框
[DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
public static extern bool GetOpenFileName([In, Out] OpenFileName ofn);
public static bool GetOFN([In, Out] OpenFileName ofn)
{
return GetOpenFileName(ofn);
}
//链接指定系统函数 另存为对话框
[DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
public static extern bool GetSaveFileName([In, Out] OpenFileName ofn);
public static bool GetSFN([In, Out] OpenFileName ofn)
{
return GetSaveFileName(ofn);
}
}
using UnityEngine;
using System.Collections;
using System;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class OpenFileName
{
public int structSize = 0;
public IntPtr dlgOwner = IntPtr.Zero;
public IntPtr instance = IntPtr.Zero;
public String filter = null;
public String customFilter = null;
public int maxCustFilter = 0;
public int filterIndex = 0;
public String file = null;
public int maxFile = 0;
public String fileTitle = null;
public int maxFileTitle = 0;
public String initialDir = null;
public String title = null;
public int flags = 0;
public short fileOffset = 0;
public short fileExtension = 0;
public String defExt = null;
public IntPtr custData = IntPtr.Zero;
public IntPtr hook = IntPtr.Zero;
public String templateName = null;
public IntPtr reservedPtr = IntPtr.Zero;
public int reservedInt = 0;
public int flagsEx = 0;
}
使用方式如下,LocalDialog.GetOFN(openFileName) ==true 表示选择了文件,在这里面进行操作,其中allsonglist存储了所有已经添加的文件路径,所以先判断下是否已添加。updatePlayPrefab为更新本地存储的,show为ui显示方法。
public void checkSong()
{
OpenFileName openFileName = new OpenFileName();
openFileName.structSize = Marshal.SizeOf(openFileName);
openFileName.filter = "mp3文件(*.mp3)\0*.mp3";
openFileName.file = new string(new char[256]);
openFileName.maxFile = openFileName.file.Length;
openFileName.fileTitle = new string(new char[64]);
openFileName.maxFileTitle = openFileName.fileTitle.Length;
openFileName.initialDir = Application.streamingAssetsPath.Replace('/', '\\');//默认路径
openFileName.title = "窗口标题";
openFileName.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000008;
if (LocalDialog.GetOFN(openFileName))
{
if(allSongList.Contains(openFileName.file))
{
Tip.show("歌曲已存在,无需重复添加");
}
else
{
allSongList.Add(openFileName.file);
updatePlayPrefab();
show();
}
//Debug.Log(openFileName.fileTitle);
}
}
功能2:本地歌曲路径储存以及更新
即歌曲列表显示用户已经选择过的音乐,原理是用特殊字符串连接各个文件路径,然后使用PlayerPrefs存储,打开应用的时候解析数据,显示列表。下面为解析,字符串的简单处理
const string songData = "SongListData";
string[] sign =new string[] {"_|bzy|_" } ;//地址之间分隔符
public void OnEnable()
{
allSongList = new List<string>();
//
if (PlayerPrefs.HasKey(songData))
{
string value = PlayerPrefs.GetString(songData);
Debug.Log(value);
string[] strArr = value.Split(sign,StringSplitOptions.None);
for (int i = 0; i < strArr.Length; i++)
{
if(!string.IsNullOrEmpty( strArr[i]))
{
allSongList.Add(strArr[i]);
Debug.Log(allSongList[i]);
}
}
}
else
{
PlayerPrefs.SetString(songData,"");
}
show();
}
下面是存储更新,每次选择音乐以及删除的时候都要更新
string playPrefabValue;
void updatePlayPrefab()
{
playPrefabValue = string.Empty;
string mid = string.Empty;
for (int i = 0; i < allSongList.Count; i++)
{
playPrefabValue = string.Format("{0}{1}{2}", i == 0 ? "" : playPrefabValue,i == 0 ? "" : sign[0], allSongList[i]);
}
PlayerPrefs.SetString(songData,playPrefabValue);
}
功能3:播放,上一首,下一首,删除
播放需要用到audiosource组件,给组件的audioclip赋值,然后调用play播放,audioclip的获取需要用到www。为了避免多次下载audioclip,应该将下载过的audioclip存储起来,这里使用了字典,key为文件路径。clip.length为时长。
int currentIndex;//当前播放的索引
string currentSongPath;//当前播放的路径
Dictionary<string,AudioClip> allClipList;//key path , value audioclip
public void playMusic(string path)
{
CancelInvoke("playNext");
if (allClipList == null) allClipList = new Dictionary<string, AudioClip>();
if(string.IsNullOrEmpty(path))
{
currentIndex = 0;
currentSongPath = allSongList[currentIndex];
currentSongNameTxt.text = Path.GetFileName(currentSongPath);
}
else
{
currentIndex = allSongList.IndexOf(path);
currentSongPath = path;
currentSongNameTxt.text = Path.GetFileName(path);
}
if (allClipList.ContainsKey(currentSongPath))//clip已下载
{
audio.clip = allClipList[currentSongPath];
audio.Play();
Invoke("playNext", clip.length);
}
else
{
StartCoroutine("DownLoad");
}
//Invoke("playNext",5);
}
IEnumerator DownLoad()
{
Debug.Log("下载。。。。");
WWW www = new WWW("file://" + currentSongPath);
yield return www;
if (string.IsNullOrEmpty(www.error))
{
clip = www.GetAudioClip();
allClipList.Add(currentSongPath,clip);
audio.clip = clip;
audio.Play();
Invoke("playNext",clip.length);
}
else
{
Debug.LogError(www.error);
}
}
//下一曲
public void playNext()
{
currentIndex = (currentIndex + 1) % allSongList.Count;
playMusic(allSongList[currentIndex]);
}
//上一曲
public void playLast()
{
currentIndex = currentIndex == 0 ? allSongList.Count - 1 : (currentIndex - 1) % allSongList.Count;
playMusic(allSongList[currentIndex]);
}
删除
public void deleteSong(string path)
{
if (!allSongList.Contains(path))
{
Debug.Log("删除失败,不包含此歌曲");
}
else
{
if (allClipList.ContainsKey(path)) allClipList.Remove(path);
allSongList.Remove(path);
updatePlayPrefab();
show();
}
}
播放模式什么的也好说,不需要也就没实现。记录结束