Live2d

3.5k words

Desc

live2d

Image text
Image text

Code

Live2D Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public Animator animator;
public List<string> clipNameArr;

public void V_PlayClipByIndex(int idx)
{
if (idx >= clipNameArr.Count)
{
return;
}
animator.Play(clipNameArr[idx]);
}
public GameObject V_LoadLive2D(PathData pathData)
{
// 加载模型数据
CubismModel3Json jsonData = m_LoadLive2DJson(pathData.jsonPath);
// 创建预制体
GameObject prefab = ResourceManager.Instance.V_LoadPrefabFromResource(pathData.prefabPath);
GameObject live2dGo;
try
{
live2dGo = GameObject.Instantiate(prefab);
}
catch(Exception e)
{
Debug.Log(pathData);
return null;
}
animator = live2dGo.GetComponent<Animator>();

// 创建AnimatorController
string controllerPath = pathData.animPath;
AnimatorController animatorController = AnimatorController.CreateAnimatorControllerAtPath(controllerPath);
AnimatorControllerLayer layer = animatorController.layers[0];
// 添加AnimationClip
SerializableMotion[] arr = jsonData.FileReferences.Motions.Motions[0];
// AnimatorState lastAnimationState = null ;
clipNameArr = new List<string>();
for (int i = 0; i < arr.Length; i++)
{
string clipName = arr[i].File.Split(".")[0];
string clipPath = string.Format("{0}/{1}.anim", pathData.clipPath, clipName);
AnimationClip clip = AssetDatabase.LoadAssetAtPath<AnimationClip>(clipPath);
if (clip != null)
{
string name = clip.name.Split(".")[0];
if (clipNameArr.IndexOf(name) >= 0)
{
continue;
}
clip.events = new AnimationEvent[0];//取消动画事件
AnimatorStateMachine stateMachine = layer.stateMachine;
AnimatorState state = stateMachine.AddState(clip.name.Split(".")[0]);
state.motion = clip;
stateMachine.AddAnyStateTransition(state);
{
clipNameArr.Add(name);
}
}
}
clipNameArr.Sort();
AssetDatabase.SaveAssets();

animator.runtimeAnimatorController = animatorController;

return live2dGo;
}

private CubismModel3Json m_LoadLive2DJson(string path)
{
CubismModel3Json data=CubismModel3Json.LoadAtPath(path);
return data;
}

PathData

少女前线的路径相对于碧蓝航线不太一样,用PathData来获取资源对应路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class PathData 
{
public string jsonPath;
public string prefabPath;
public string animPath;
public string clipPath;
public PathData(string path)
{
jsonPath = string.Format("Assets/Resources/BLHX/{0}/{1}.model3.json", path, path);
prefabPath = string.Format("BLHX/{0}/{1}", path, path);
animPath = string.Format("Assets/Resources/BLHX/{0}/{1}.controller", path, path); ;
clipPath = string.Format("Assets/Resources/BLHX/{0}", path);
}
}

交互相关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

private void m_AddEventCallBack()
{
if (dropdown)
{
dropdown.onValueChanged.AddListener(V_ChangeClip);
}
}

public void V_ChangeClip(int value)
{
Live2DController.Instance.V_PlayClipByIndex(value);
}


private void m_UpdateShow()
{
if (indexText)
{
indexText.text = string.Format("{0}/{1}",index,directoryInfos.Length);
}
if (dropdown)
{
dropdown.ClearOptions();
List<OptionData> options = new List<OptionData>();
List<string> clipNames = Live2DController.Instance.clipNameArr;
if (clipNames == null)
{
return;
}
for(int i = 0; i < clipNames.Count; i++)
{
OptionData data = new OptionData();
data.text = clipNames[i];
options.Add(data);
}
dropdown.options = options;
}
}

模型素材 Github