Live2D下载地址
Live2D导入Unity后文件结构如下,并且官方也提供了多个演示场景以供大家学习使用。
基本功能和使用。
导入前的Live2D文件结构如下:
分别为表情的Json配置文件,动作的Json配置文件,贴图以及物理Json配置文件等。
将此导入Unity后Live2D会自动处理配置文件,并在Runtime文件夹下生成Liv2D的预制体,expressionList表情列表和fadeMotionList动作列表,列表的引用关系Live2D已自动处理。
Live2D预制体所挂脚本:
可选功能脚本:
LookController与LookTarget配合使用,控制Live2D的鼠标追踪效果。
Mouth,EyeBlink控制Live2D自动眨眼功能和嘴巴张闭。
Expression表情管理。
Fade 动作淡入淡出管理。
同时自动眨眼还有鼠标追踪等功能,需要在相应可动部位添加相应功能脚本。
如自动眨眼:
嘴巴:
鼠标追踪:
这些都是Live2D提供的基本功能,只需要挂载相应脚本便可实现功能。
示例脚本:
using Live2D.Cubism.Core;
using Live2D.Cubism.Framework;
using Live2D.Cubism.Framework.Expression;
using Live2D.Cubism.Framework.Motion;
using Live2D.Cubism.Framework.Raycasting;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Live2D.Cubism.Samples.OriginalWorkflow.Demo
{
[RequireComponent(typeof(CubismMotionController))]
[RequireComponent(typeof(CubismRaycaster))]
public class CubismSampleController : MonoBehaviour
{
///
/// MotionController to be operated.
///
private CubismMotionController _motionController;
///
/// ExpressionController to be operated.
///
private CubismExpressionController _expressionController;
///
/// Operation animation clip from the inspector.
///
[SerializeField]
private AnimationClip _bodyAnimation;
///
/// Array of motion set in tapbody.
///
[SerializeField]
private AnimationClip[] _tapBodyMotions;
///
/// Motion set in roop motion.
///
private AnimationClip _roopMotion;
///
/// List of Drawables info.
///
private List<HitDrawableInfomation> _hasHitDrawables;
///
/// Component that performs ray judgment on Drawables of model.
///
private CubismRaycaster _raycaster;
///
/// Raycast Hit Results.
///
private CubismRaycastHit[] _raycastResults;
///
/// Enumeration type for hit area discrimination.
///
private enum HitArea
{
Head,
Body
}
///
/// Structure that stores Drawable information for which hit area is specified.
///
private struct HitDrawableInfomation
{
///
/// Drawable with component set.
///
public CubismDrawable drawable;
///
/// HitArea.
///
public HitArea hitArea;
}
///
/// Load model.
///
private void Start()
{
var model = this.FindCubismModel();
// Get components.
_motionController = model.GetComponent<CubismMotionController>();
_expressionController = model.GetComponent<CubismExpressionController>();
_raycaster = model.GetComponent<CubismRaycaster>();
// Set behavior at the end of animation.
_motionController.AnimationEndHandler = AnimationEnded;
// Get up to 4 results of collision detection.
_raycastResults = new CubismRaycastHit[4];
// Cache the drawable in which the component is set.
{
_hasHitDrawables = new List<HitDrawableInfomation>();
var hitAreas = Enum.GetValues(typeof(HitArea));
var drawables = model.Drawables;
for (var i = 0; i < hitAreas.Length; i++)
{
for (var j = 0; j < drawables.Length; j++)
{
var cubismHitDrawable = drawables[j].GetComponent<CubismHitDrawable>();
if (cubismHitDrawable)
{
if (cubismHitDrawable.Name == hitAreas.GetValue(i).ToString())
{
var hitDrawable = new HitDrawableInfomation();
hitDrawable.drawable = drawables[j];
hitDrawable.hitArea = (HitArea)i;
_hasHitDrawables.Add(hitDrawable);
break;
}
}
}
}
}
}
///
/// Update.
///
private void Update()
{
// Play if animation is specified.
SpecifiedAnimationCheck();
if(!Input.GetMouseButtonDown(0))
{
return;
}
// Cast ray from pointer position.
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
var hitCount = _raycaster.Raycast(ray, _raycastResults);
// Motion playback according to the hit location.
for (var i = 0; i < hitCount; i++)
{
var hitDrawable = _raycastResults[i].Drawable;
for (var j = 0; j < _hasHitDrawables.Count; j++)
{
if (hitDrawable == _hasHitDrawables[j].drawable)
{
var hitArea = _hasHitDrawables[j].hitArea;
// Tap body.
if (hitArea == HitArea.Body)
{
// Decide motion to play at random.
var motionIndex = UnityEngine.Random.Range(0, _tapBodyMotions.Length - 1);
Debug.Log("Tap body : Play : " + _tapBodyMotions[motionIndex].name);
_motionController.PlayAnimation(_tapBodyMotions[motionIndex], isLoop: false, priority:CubismMotionPriority.PriorityNormal);
}
// Tap head.
else if (hitArea == HitArea.Head)
{
// Decide expression motion to play at random.
var expressionNum = _expressionController.ExpressionsList.CubismExpressionObjects.Length;
var expressionIndex = UnityEngine.Random.Range(0, expressionNum - 1);
_expressionController.CurrentExpressionIndex = expressionIndex;
Debug.Log("Tap head : Play : " + _expressionController.ExpressionsList.CubismExpressionObjects[expressionIndex].name);
}
break;
}
}
}
}
///
/// Check the specified animation and play it.
///
private void SpecifiedAnimationCheck()
{
if(_bodyAnimation != _roopMotion)
{
_roopMotion = _bodyAnimation;
Debug.Log("Body animation : Play : " + _roopMotion.name);
_motionController.PlayAnimation(_roopMotion, priority:CubismMotionPriority.PriorityIdle);
}
}
///
/// Called at the end of the animation.
///
///
private void AnimationEnded(float instanceId)
{
// Play roop motion.
_motionController.PlayAnimation(_roopMotion, priority:CubismMotionPriority.PriorityIdle);
Debug.Log("Body animation : Play : " + _roopMotion.name);
}
}
}
注意,可交互部位要挂载相应功能脚本,点击才会生效。如要点击身体部位,可在预制体的Drawables下将相关区域挂载CubismHitDrawable与CubismRaycastable脚本。如:
如此,射线检测到点击的相应区域,便可播放相应的动作或者表情了。