public void AdaptToControlParam_Opt(float weight, apAnimPlayUnit.BLEND_METHOD blendMethod) { if (!_isCalculated) { return; } switch (_targetControlParam._valueType) { //case apControlParam.TYPE.Bool: // _targetControlParam.SetCalculated_Bool(_value_Bool, weight, blendMethod); // break; case apControlParam.TYPE.Int: _targetControlParam.SetCalculated_Int(_value_Int, weight, blendMethod); break; case apControlParam.TYPE.Float: _targetControlParam.SetCalculated_Float(_value_Float, weight, blendMethod); break; case apControlParam.TYPE.Vector2: _targetControlParam.SetCalculated_Vector2(_value_Vec2, weight, blendMethod); break; //case apControlParam.TYPE.Vector3: // _targetControlParam.SetCalculated_Vector3(_value_Vec3, weight, blendMethod); // break; //case apControlParam.TYPE.Color: // _targetControlParam.SetCalculated_Color(_value_Color, weight, blendMethod); // break; } }
// Functions //------------------------------------------------- public bool AddTrack( #if UNITY_2017_1_OR_NEWER PlayableDirector playableDirector, #endif string trackName, int layer, apAnimPlayUnit.BLEND_METHOD blendMethod) { #if UNITY_2017_1_OR_NEWER if (playableDirector == null) { Debug.LogError("AnyPortrait : AddTimelineTrack() is Failed. PlayableDirector is Null."); return(false); } if (playableDirector.playableAsset == null) { Debug.LogError("AnyPortrait : AddTimelineTrack() is Failed. PlayableAsset(Timeline) is Null."); return(false); } #endif if (string.IsNullOrEmpty(trackName)) { Debug.LogError("AnyPortrait : AddTimelineTrack() is Failed. Track Name is empty."); return(false); } #if UNITY_2017_1_OR_NEWER bool isValidTrack = DirectorTrackSet.CheckTrackValidation(playableDirector, playableDirector.playableAsset, trackName); if (!isValidTrack) { Debug.LogError("AnyPortrait : AddTimelineTrack() is Failed. The requested track could not be found."); return(false); } //이미 등록된 Director에 대하여 새로운 Track을 추가하는 경우일 수 있다. //없다면 새로 Director를 만들고, 있으면 재활용 DirectorTrackSet targetDirectorSet = _trackSets.Find(delegate(DirectorTrackSet a) { return(a._playableDirector == playableDirector && a._playableAsset == playableDirector.playableAsset); }); if (targetDirectorSet == null) { //새로운 Director로 등록해야 한다. targetDirectorSet = new DirectorTrackSet(); targetDirectorSet.SetPlayableDirector(playableDirector, playableDirector.playableAsset); _trackSets.Add(targetDirectorSet); _nTrackSets = _trackSets.Count; } bool result = targetDirectorSet.AddTrack(trackName, layer, blendMethod, _portrait, _animPlayManager); return(result); #else return(false); #endif }
//추가 : AnimPlayData로 PlayQueued를 바로 실행하는 함수가 나오면서, 이름으로 검색하는 건 오버로드로 뺌 public apAnimPlayData CrossFadeQueued(string animClipName, int layer, apAnimPlayUnit.BLEND_METHOD blendMethod, float fadeTime, bool isAutoEndIfNotloop = false) { apAnimPlayData playData = GetAnimPlayData_Opt(animClipName); if (playData == null) { Debug.LogError("CrossFade Failed : No AnimClip [" + animClipName + "]"); return(null); } return(CrossFadeQueued(playData, layer, blendMethod, fadeTime, isAutoEndIfNotloop)); }
public apAnimPlayData CrossFadeAt(string animClipName, int frame, int layer, apAnimPlayUnit.BLEND_METHOD blendMethod, float fadeTime, PLAY_OPTION playOption = PLAY_OPTION.StopSameLayer, bool isAutoEndIfNotloop = false) { apAnimPlayData playData = GetAnimPlayData_Opt(animClipName); if (playData == null) { Debug.LogError("CrossFade Failed : No AnimClip [" + animClipName + "]"); return(null); } return(CrossFadeAt(playData, frame, layer, blendMethod, fadeTime, playOption, isAutoEndIfNotloop)); }
public void ReadyToUpdate() { _isCalculated = false; _isPlaying = false; _playedLayer = 0; _playOrder = 0; _blendMethod = apAnimPlayUnit.BLEND_METHOD.Interpolation; _speed = 0.0f; _weight = 0.0f; _timeRatio = -1.0f; }
/// <summary> /// Wait for the previous animation to finish, then play it smoothly. /// (If the previously playing animation is a loop animation, it will not be executed.) /// </summary> /// <param name="animClipName">Name of the Animation Clip</param> /// <param name="fadeTime">Fade Time</param> /// <param name="layer">The layer to which the animation is applied. From 0 to 20</param> /// <param name="blendMethod">How it is blended with the animation of the lower layers</param> /// <param name="isAutoEndIfNotloop">If True, animation that does not play repeatedly is automatically terminated.</param> /// <returns>Animation data to be played. If it fails, null is returned.</returns> public apAnimPlayData CrossFadeQueued(string animClipName, int layer, apAnimPlayUnit.BLEND_METHOD blendMethod, float fadeTime, bool isAutoEndIfNotloop = false) { //Debug.LogError("Start CrossFadeQueued [" + animClipName + "]"); apAnimPlayData playData = GetAnimPlayData_Opt(animClipName); if (playData == null) { Debug.LogError("CrossFade Failed : No AnimClip [" + animClipName + "]"); return(null); } if (layer < MIN_LAYER_INDEX || layer > MAX_LAYER_INDEX) { Debug.LogError("CrossFade Failed : Layer " + layer + " is invalid. Layer must be between " + MIN_LAYER_INDEX + " ~ " + MAX_LAYER_INDEX); return(null); } if (fadeTime < 0.0f) { fadeTime = 0.0f; } //Debug.Log("CrossFadeQueued [" + animClipName + "]"); apAnimPlayQueue playQueue = _animPlayQueues[layer]; apAnimPlayUnit resultPlayUnit = playQueue.PlayQueued(playData, blendMethod, fadeTime, isAutoEndIfNotloop); if (resultPlayUnit == null) { return(null); } //float delayTime = resultPlayUnit.DelayToPlayTime; //float delayTime = Mathf.Clamp01(resultPlayUnit.RemainPlayTime - fadeTime); //if (playOption == PLAY_OPTION.StopAllLayers) //{ // //다른 레이어를 모두 정지시킨다. - 단, 딜레이를 준다. // for (int i = 0; i < _animPlayQueues.Count; i++) // { // if (i == layer) // { continue; } // _animPlayQueues[i].StopAll(delayTime); // } //} RefreshPlayOrders(); return(playData); }
//---------------------------------------------------------------------------------------- public apAnimPlayData PlayAt(string animClipName, int frame, int layer, apAnimPlayUnit.BLEND_METHOD blendMethod, PLAY_OPTION playOption = PLAY_OPTION.StopSameLayer, bool isAutoEndIfNotloop = false, bool isDebugMsg = true) { apAnimPlayData playData = GetAnimPlayData_Opt(animClipName); if (playData == null) { if (isDebugMsg) { Debug.LogError("PlayAt Failed : No AnimClip [" + animClipName + "]"); } return(null); } return(PlayAt(playData, frame, layer, blendMethod, playOption, isAutoEndIfNotloop, isDebugMsg)); }
/// <summary> /// AnimClip 이름을 인자로 받아서 애니메이션을 재생한다. /// Fade 타임을 받아서 다른 모든 클립에서 자연스럽게 변환된다. /// </summary> /// <param name="animClipName">Clip 이름. 맞지 않을 경우 처리 실패</param> /// <param name="layer">실행되는 레이어. 0부터 실행되며 최대값은 20</param> /// <param name="blendMethod">다른 레이어와 블렌드시 옵션</param> /// <param name="playOption">StopAllLayer인 경우 요청된 레이어 외의 Clip들이 다음 Clip이 실행되는 순간 같이 종료된다.</param> /// <param name="isAutoEndIfNotloop">[Loop 타입이 아닌 경우] True이면 재생 종료시 자동으로 처리 데이터가 삭제된다.</param> /// <param name="fadeTime">페이드 시간. 기본값은 0.3</param> /// <returns></returns> public apAnimPlayData CrossFade(string animClipName, int layer, apAnimPlayUnit.BLEND_METHOD blendMethod, float fadeTime, PLAY_OPTION playOption = PLAY_OPTION.StopSameLayer, bool isAutoEndIfNotloop = false) { apAnimPlayData playData = GetAnimPlayData_Opt(animClipName); if (playData == null) { Debug.LogError("CrossFade Failed : No AnimClip [" + animClipName + "]"); return(null); } if (layer < MIN_LAYER_INDEX || layer > MAX_LAYER_INDEX) { Debug.LogError("CrossFade Failed : Layer " + layer + " is invalid. Layer must be between " + MIN_LAYER_INDEX + " ~ " + MAX_LAYER_INDEX); return(null); } if (fadeTime < 0.0f) { fadeTime = 0.0f; } apAnimPlayQueue playQueue = _animPlayQueues[layer]; apAnimPlayUnit resultPlayUnit = playQueue.Play(playData, blendMethod, fadeTime, isAutoEndIfNotloop); if (resultPlayUnit == null) { return(null); } //float fadeInTime = resultPlayUnit.FadeInTime; if (playOption == PLAY_OPTION.StopAllLayers) { //다른 레이어를 모두 정지시킨다. - 단, 딜레이를 준다. for (int i = 0; i < _animPlayQueues.Count; i++) { if (i == layer) { continue; } _animPlayQueues[i].StopAll(fadeTime); } } RefreshPlayOrders(); return(playData); }
//public void SetCalculated_Bool(bool bValue, float weight, apAnimPlayUnit.BLEND_METHOD blendMethod) //{ // weight = Mathf.Clamp01(weight); // _totalWeight += weight; // if(!_isUpdated) // { // _bool_CalculatedLayer = bValue; // _isUpdated = true; // return; // } // if(blendMethod == apAnimPlayUnit.BLEND_METHOD.Interpolation) // { // if(weight > 0.5f) // { // _bool_CalculatedLayer = bValue; // } // } // else // { // //Bool에 Additive가 있나? // if(bValue) // { // _bool_CalculatedLayer = true; // } // } //} public void SetCalculated_Int(int iValue, float weight, apAnimPlayUnit.BLEND_METHOD blendMethod) { weight = Mathf.Clamp01(weight); _totalWeight += weight; if (blendMethod == apAnimPlayUnit.BLEND_METHOD.Interpolation || !_isUpdated) { _int_CalculatedLayer = (int)(_int_CalculatedLayer * (1.0f - weight) + iValue * (weight) + 0.5f); } else { _int_CalculatedLayer += (int)(iValue * weight + 0.5f); } _isUpdated = true; }
public void SetCalculated_Float(float fValue, float weight, apAnimPlayUnit.BLEND_METHOD blendMethod) { weight = Mathf.Clamp01(weight); _totalWeight += weight; if (blendMethod == apAnimPlayUnit.BLEND_METHOD.Interpolation || !_isUpdated) { _float_CalculatedLayer = _float_CalculatedLayer * (1.0f - weight) + fValue * (weight); } else { _float_CalculatedLayer += fValue * weight; } _isUpdated = true; }
private apAnimPlayUnit MakePlayUnit(apAnimPlayData playData, apAnimPlayUnit.BLEND_METHOD blendMethod, bool isAutoEndIfNotloop) { //새로 만들고 //그 전에.. //재생중인 PlayUnit이 있으면 그걸 사용하자 //레이어는 같아야 한다. apAnimPlayUnit existPlayUnit = null; for (int i = 0; i < _animPlayUnits.Count; i++) { if (_animPlayUnits[i]._linkedAnimClip == playData._linkedAnimClip && _animPlayUnits[i].IsUpdatable ) { existPlayUnit = _animPlayUnits[i]; break; } } if (existPlayUnit != null) { //Debug.Log("아직 재생중인 PlayUnit을 다시 재생하는 요청이 왔다. [" + existPlayUnit._linkedAnimClip._name + "]"); existPlayUnit.SetSubOption(blendMethod, isAutoEndIfNotloop, GetNextPlayUnitRequestOrder(), GetNextRequestLinkKey()); _nPlayedUnit = _animPlayUnits.Count; return(existPlayUnit); } apAnimPlayUnit newPlayUnit = new apAnimPlayUnit(this, GetNextPlayUnitRequestOrder(), GetNextRequestLinkKey()); newPlayUnit.SetAnimClip(playData, _layer, blendMethod, isAutoEndIfNotloop, false); //if(!newPlayUnit._linkedAnimClip.IsPlaying) //{ // if(newPlayUnit.Frame != newPlayUnit.StartFrame) // { // Debug.Log("새로운 재생 요청 - 프레임이 초기화되지 않음 [" + newPlayUnit._linkedAnimClip._name + "]"); // } // newPlayUnit.ResetPlay(); //} //리스트에 넣자 _animPlayUnits.Add(newPlayUnit); _nPlayedUnit = _animPlayUnits.Count; _isInitPlayUnit = false; return(newPlayUnit); }
public void SetData(int playedLayer, int playOrder, apAnimPlayUnit.BLEND_METHOD blendMethod, float speed, float weight, float timeRatio) { _isCalculated = true; _isPlaying = true; _playedLayer = playedLayer; _playOrder = playOrder; _blendMethod = blendMethod; _speed = speed; _weight = weight; _timeRatio = timeRatio; }
/// <summary> /// Play the animation /// </summary> /// <param name="animClipName">Name of the Animation Clip</param> /// <param name="layer">The layer to which the animation is applied. From 0 to 20</param> /// <param name="blendMethod">How it is blended with the animation of the lower layers</param> /// <param name="playOption">How to stop which animations</param> /// <param name="isAutoEndIfNotloop">If True, animation that does not play repeatedly is automatically terminated.</param> /// <returns>Animation data to be played. If it fails, null is returned.</returns> public apAnimPlayData Play(apAnimPlayData playData, int layer, apAnimPlayUnit.BLEND_METHOD blendMethod, PLAY_OPTION playOption = PLAY_OPTION.StopSameLayer, bool isAutoEndIfNotloop = false, bool isDebugMsg = true) { if (playData == null) { if (isDebugMsg) { Debug.LogError("Play Failed : Unknown AnimPlayData"); } return(null); } if (layer < MIN_LAYER_INDEX || layer > MAX_LAYER_INDEX) { if (isDebugMsg) { Debug.LogError("Play Failed : Layer " + layer + " is invalid. Layer must be between " + MIN_LAYER_INDEX + " ~ " + MAX_LAYER_INDEX); } return(null); } apAnimPlayQueue playQueue = _animPlayQueues[layer]; apAnimPlayUnit resultPlayUnit = playQueue.Play(playData, blendMethod, 0.0f, isAutoEndIfNotloop); if (resultPlayUnit == null) { return(null); } if (playOption == PLAY_OPTION.StopAllLayers) { //다른 레이어를 모두 정지시킨다. for (int i = 0; i < _animPlayQueues.Count; i++) { if (i == layer) { continue; } _animPlayQueues[i].StopAll(0.0f); } } RefreshPlayOrders(); return(playData); }
public void SetData(bool isClipA, float weight, float localPlayedTime, apAnimPlayUnit.BLEND_METHOD blendMethod, int layerIndex) { _isCalculated = true; _isPlaying = true; if (isClipA) { _playOrder = 0; } else { _playOrder = 1; } //TimelineClip의 Speed는 LocalTime 계산시 포함되어있다. //_speed = speed; _weight = weight; _timeRatio = localPlayedTime / _animClip.TimeLength; _blendMethod = blendMethod; _layerIndex = layerIndex; }
/// <summary> /// Wait for the previous animation to finish, then play it. /// (If the previously playing animation is a loop animation, it will not be executed.) /// </summary> /// <param name="animClipName">Name of the Animation Clip</param> /// <param name="layer">The layer to which the animation is applied. From 0 to 20</param> /// <param name="blendMethod">How it is blended with the animation of the lower layers</param> /// <param name="isAutoEndIfNotloop">If True, animation that does not play repeatedly is automatically terminated.</param> /// <returns>Animation data to be played. If it fails, null is returned.</returns> public apAnimPlayData PlayQueued(apAnimPlayData playData, int layer, apAnimPlayUnit.BLEND_METHOD blendMethod, bool isAutoEndIfNotloop = false) { if (playData == null) { Debug.LogError("PlayQueued Failed : Unknown AnimPlayData"); return(null); } if (layer < MIN_LAYER_INDEX || layer > MAX_LAYER_INDEX) { Debug.LogError("PlayQueued Failed : Layer " + layer + " is invalid. Layer must be between " + MIN_LAYER_INDEX + " ~ " + MAX_LAYER_INDEX); return(null); } apAnimPlayQueue playQueue = _animPlayQueues[layer]; apAnimPlayUnit resultPlayUnit = playQueue.PlayQueued(playData, blendMethod, 0.0f, isAutoEndIfNotloop); if (resultPlayUnit == null) { return(null); } //if (playOption == PLAY_OPTION.StopAllLayers) //{ // //다른 레이어를 모두 정지시킨다. - 단, 딜레이를 준다. // for (int i = 0; i < _animPlayQueues.Count; i++) // { // if (i == layer) // { continue; } // _animPlayQueues[i].StopAll(delayTime); // } //} RefreshPlayOrders(); return(playData); }
//트랙을 추가한다. public bool AddTrack(string trackName, int layer, apAnimPlayUnit.BLEND_METHOD blendMethod, apPortrait portrait, apAnimPlayManager animPlayManager) { //이미 적용된 트랙이 있다면, 에러 메시지를 보낸다. bool isExist = _trackData.Exists(delegate(TimelineTrackData a) { return(a._trackName.Equals(trackName)); }); if (isExist) { Debug.LogError("AnyPortrait : A track with the same name has already been registered. [ " + trackName + " ]"); return(false); } TimelineTrackData newTrackData = new TimelineTrackData(this); bool isResult = newTrackData.SetTrack(trackName, layer, blendMethod, portrait, animPlayManager); if (!isResult) { return(false); } //리스트에 트랙 추가 _trackData.Add(newTrackData); _nTrackData = _trackData.Count; //트랙을 추가했으면, Layer에 맞게 정렬한다. (오름차순) _trackData.Sort(delegate(TimelineTrackData a, TimelineTrackData b) { return(a._layerIndex - b._layerIndex); }); for (int i = 0; i < _trackData.Count; i++) { _trackData[i].SetLayerOrder(i); //<<레이어의 순서를 다시 지정한다. } return(true); }
private apAnimPlayUnit MakePlayUnit(apAnimPlayData playData, apAnimPlayUnit.BLEND_METHOD blendMethod, bool isAutoEndIfNotloop) { //새로 만들고 //그 전에.. //재생중인 PlayUnit이 있으면 그걸 사용하자 //레이어는 같아야 한다. apAnimPlayUnit existPlayUnit = null; for (int i = 0; i < _animPlayUnits.Count; i++) { if (_animPlayUnits[i]._linkedAnimClip == playData._linkedAnimClip && _animPlayUnits[i].IsUpdatable ) { existPlayUnit = _animPlayUnits[i]; break; } } if (existPlayUnit != null) { //Debug.Log("아직 재생중인 PlayUnit을 다시 재생하는 요청이 왔다. [" + existPlayUnit._linkedAnimClip._name + "]"); existPlayUnit.SetSubOption(blendMethod, isAutoEndIfNotloop); _nPlayedUnit = _animPlayUnits.Count; return(existPlayUnit); } apAnimPlayUnit newPlayUnit = new apAnimPlayUnit(this); newPlayUnit.SetAnimClip(playData, _layer, blendMethod, isAutoEndIfNotloop, false); //리스트에 넣자 _animPlayUnits.Add(newPlayUnit); _nPlayedUnit = _animPlayUnits.Count; return(newPlayUnit); }
//---------------------------------------------------- // 재생/정지 요청 함수들 //---------------------------------------------------- /// <summary> /// AnimClip을 PlayUnit에 담아서 재생한다. /// Queue에 저장된 모든 클립은 무시되며 블렌드되지 않는다. /// </summary> /// <param name="blendMethod"></param> /// <param name="isAutoEndIfNotloop">True이면 Clip의 재생 후 자동으로 종료한다. (Loop일 경우 무시됨)</param> public apAnimPlayUnit Play(apAnimPlayData playData, apAnimPlayUnit.BLEND_METHOD blendMethod, float blendTime = 0.0f, bool isAutoEndIfNotloop = true) { //Request를 생성한다. apAnimPlayRequest request = PopRequest(); request.SetCurrentPlayedUnits(this, _animPlayUnits); apAnimPlayUnit newPlayUnit = MakePlayUnit(playData, blendMethod, isAutoEndIfNotloop); //newPlayUnit.Play(); //Play 명령을 준다. request.PlayNew(newPlayUnit, blendTime); #region [미사용 코드] //TODO : 이 AnimClip을 CalculatedParam에 연결해야한다. //Debug.LogError("TODO : 이 AnimClip을 CalculatedParam에 연결해야한다"); ////플레이 유닛은 플레이 시작 ////나머지는 End로 만든다. //for (int i = 0; i < _animPlayUnits.Count; i++) //{ // if (newPlayUnit != _animPlayUnits[i]) // { // _animPlayUnits[i].SetEnd(); // } //} #endregion _nPlayedUnit = _animPlayUnits.Count; //Debug.Log("Next Play Units [" + _nPlayedUnit + "]"); return(newPlayUnit); }
//---------------------------------------------------- // 재생/정지 요청 함수들 //---------------------------------------------------- //AnimClip을 PlayUnit에 담아서 재생한다. //Queue에 저장된 모든 클립은 무시되며 블렌드되지 않는다. public apAnimPlayUnit Play(apAnimPlayData playData, apAnimPlayUnit.BLEND_METHOD blendMethod, float blendTime = 0.0f, bool isAutoEndIfNotloop = true) { //현재 상태에서 실행되지 않은 Queued 애니메이션 재생 요청은 삭제한다. PushAllNoActiveRequests(); //Request를 생성한다. apAnimPlayRequest request = PopRequest(); //request.SetCurrentPlayedUnits(this, _animPlayUnits); request.SetCurrentPlayedUnits(this); //현재 플레이 중인 AnimPlayUnit들의 LinkKey를 넣어준다. //Debug.Log("Add Play Unit Link Key"); for (int i = 0; i < _animPlayUnits.Count; i++) { //Debug.Log(_animPlayUnits[i]._linkedAnimClip._name + " : " + _animPlayUnits[i].LinkKey + " / " + _animPlayUnits[i].PlayStatus); request.AddPrevPlayUnitKeyLink(_animPlayUnits[i].LinkKey, _animPlayUnits[i].UnitWeight); } apAnimPlayUnit newPlayUnit = MakePlayUnit(playData, blendMethod, isAutoEndIfNotloop); //newPlayUnit.Play(); newPlayUnit.Resume(); //Pause가 걸려있으면 풀어주자 //Play 명령을 준다. request.PlayNew(newPlayUnit, blendTime); //이때, 만약 PlayQueued 타입이며 newPlayUnit을 타겟으로 하는게 있으면 처리할 때 무력화시켜야 한다. apAnimPlayRequest overlapQueuedRequest = _requests_Live.Find(delegate(apAnimPlayRequest a) { return(a != request && a.RequestType == apAnimPlayRequest.REQUEST_TYPE.Queued && a._nextPlayUnit == newPlayUnit); }); if (overlapQueuedRequest != null) { //Debug.Log("겹치는 Queue Request를 그냥 바로 삭제"); PushRequest(overlapQueuedRequest); } #region [미사용 코드] //TODO : 이 AnimClip을 CalculatedParam에 연결해야한다. //Debug.LogError("TODO : 이 AnimClip을 CalculatedParam에 연결해야한다"); ////플레이 유닛은 플레이 시작 ////나머지는 End로 만든다. //for (int i = 0; i < _animPlayUnits.Count; i++) //{ // if (newPlayUnit != _animPlayUnits[i]) // { // _animPlayUnits[i].SetEnd(); // } //} #endregion _nPlayedUnit = _animPlayUnits.Count; //Order를 갱신한다. RefreshOrder(); //Debug.Log("Next Play Units [" + _nPlayedUnit + "]"); return(newPlayUnit); }
/// <summary> /// Wait for the previous animation to finish, then play it smoothly. /// (If the previously playing animation is a loop animation, it will not be executed.) /// </summary> /// <param name="animClipName">Name of the Animation Clip</param> /// <param name="fadeTime">Fade Time</param> /// <param name="layer">The layer to which the animation is applied. From 0 to 20</param> /// <param name="blendMethod">How it is blended with the animation of the lower layers</param> /// <param name="isAutoEndIfNotloop">If True, animation that does not play repeatedly is automatically terminated.</param> /// <returns>Animation data to be played. If it fails, null is returned.</returns> public apAnimPlayData CrossFadeQueuedAt(apAnimPlayData playData, int frame, int layer, apAnimPlayUnit.BLEND_METHOD blendMethod, float fadeTime, bool isAutoEndIfNotloop = false) { if (playData == null) { Debug.LogError("CrossFadeQueuedAt Failed : Unknown AnimPlayData"); return(null); } if (layer < MIN_LAYER_INDEX || layer > MAX_LAYER_INDEX) { Debug.LogError("CrossFadeQueuedAt Failed : Layer " + layer + " is invalid. Layer must be between " + MIN_LAYER_INDEX + " ~ " + MAX_LAYER_INDEX); return(null); } if (fadeTime < 0.0f) { fadeTime = 0.0f; } //Debug.Log("CrossFadeQueued [" + animClipName + "]"); apAnimPlayQueue playQueue = _animPlayQueues[layer]; apAnimPlayUnit resultPlayUnit = playQueue.PlayQueuedAt(playData, frame, blendMethod, fadeTime, isAutoEndIfNotloop); if (resultPlayUnit == null) { return(null); } RefreshPlayOrders(); return(playData); }
public override void OnInspectorGUI() { //return; LoadImages(); //base.OnInspectorGUI(); apPortrait targetPortrait = target as apPortrait; if (targetPortrait != _targetPortrait) { _targetPortrait = targetPortrait; Init(); } if (_targetPortrait == null) { //Profiler.EndSample(); return; } //Profiler.BeginSample("anyPortrait Inspector GUI"); //return; if (apEditor.IsOpen()) { //에디터가 작동중에는 안보이도록 하자 //EditorGUILayout.LabelField("Editor is opened"); GUILayout.Space(10); EditorGUILayout.LabelField(_guiContent_EditorIsOpen, GUILayout.Height(36)); //Profiler.EndSample(); return; } try { bool request_OpenEditor = false; bool request_QuickBake = false; bool request_RefreshMeshes = false; bool prevImportant = _targetPortrait._isImportant; MonoBehaviour prevAnimEventListener = _targetPortrait._optAnimEventListener; int prevSortingLayerID = _targetPortrait._sortingLayerID; apPortrait.SORTING_ORDER_OPTION prevSortingOrderOption = _targetPortrait._sortingOrderOption; int prevSortingOrder = _targetPortrait._sortingOrder; if (!EditorApplication.isPlaying) { int iconWidth = 32; int iconHeight = 34; int buttonHeight = 34; //추가 19.5.26 : 용량 최적화 기능이 추가되었는가 if (!_targetPortrait._isSizeOptimizedV117) { GUILayout.Space(10); Color prevBackColor = GUI.backgroundColor; GUI.backgroundColor = new Color(1.0f, 0.7f, 0.7f, 1.0f); GUILayout.Box("[File size reduction] has not been applied.\nExecute the [Bake] again.", _guiStyle_subTitle, GUILayout.Width((int)EditorGUIUtility.currentViewWidth - 36), GUILayout.Height(40)); GUI.backgroundColor = prevBackColor; } if (!_targetPortrait._isOptimizedPortrait) { GUILayout.Space(10); EditorGUILayout.BeginHorizontal(GUILayout.Height(iconHeight)); GUILayout.Space(5); EditorGUILayout.LabelField(_guiContent_OpenEditor, _guiStyle_buttonIcon, GUILayout.Width(iconWidth), GUILayout.Height(iconHeight)); GUILayout.Space(5); if (GUILayout.Button("Open Editor and Select", GUILayout.Height(buttonHeight))) { request_OpenEditor = true; } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(GUILayout.Height(iconHeight)); GUILayout.Space(5); EditorGUILayout.LabelField(_guiContent_QuickBake, _guiStyle_buttonIcon, GUILayout.Width(iconWidth), GUILayout.Height(iconHeight)); GUILayout.Space(5); if (GUILayout.Button("Quick Bake", GUILayout.Height(buttonHeight))) { request_QuickBake = true; } EditorGUILayout.EndHorizontal(); } else { GUILayout.Space(10); EditorGUILayout.BeginHorizontal(GUILayout.Height(iconHeight)); GUILayout.Space(5); EditorGUILayout.LabelField(_guiContent_OpenEditor, _guiStyle_buttonIcon, GUILayout.Width(iconWidth), GUILayout.Height(iconHeight)); GUILayout.Space(5); if (GUILayout.Button("Open Editor (Not Selectable)", GUILayout.Height(buttonHeight))) { //열기만 하고 선택은 못함 request_OpenEditor = true; } EditorGUILayout.EndHorizontal(); } //추가 12.18 : Mesh를 리프레시 하자 EditorGUILayout.BeginHorizontal(GUILayout.Height(iconHeight)); GUILayout.Space(5); EditorGUILayout.LabelField(_guiContent_RefreshMeshes, _guiStyle_buttonIcon, GUILayout.Width(iconWidth), GUILayout.Height(iconHeight)); GUILayout.Space(5); if (GUILayout.Button("Refresh Meshes", GUILayout.Height(buttonHeight))) { request_RefreshMeshes = true; } EditorGUILayout.EndHorizontal(); } GUILayout.Space(10); //BasicSettings //----------------------------------------------------------------------------- //"Basic Settings" int width = (int)EditorGUIUtility.currentViewWidth; int subTitleWidth = width - 44; int subTitleHeight = 26; GUILayout.Box(_guiContent_BasicSettings, _guiStyle_subTitle, GUILayout.Width(subTitleWidth), GUILayout.Height(subTitleHeight)); _targetPortrait._isImportant = EditorGUILayout.Toggle("Is Important", _targetPortrait._isImportant); _targetPortrait._optAnimEventListener = (MonoBehaviour)EditorGUILayout.ObjectField("Event Listener", _targetPortrait._optAnimEventListener, typeof(MonoBehaviour), true); GUILayout.Space(5); //추가3.22 //Sorting Layer string[] sortingLayerName = new string[SortingLayer.layers.Length]; int layerIndex = -1; for (int i = 0; i < SortingLayer.layers.Length; i++) { sortingLayerName[i] = SortingLayer.layers[i].name; if (SortingLayer.layers[i].id == _targetPortrait._sortingLayerID) { layerIndex = i; } } int nextLayerIndex = EditorGUILayout.Popup("Sorting Layer", layerIndex, sortingLayerName); apPortrait.SORTING_ORDER_OPTION nextSortingOption = (apPortrait.SORTING_ORDER_OPTION)EditorGUILayout.EnumPopup("Sorting Order Option", _targetPortrait._sortingOrderOption); int nextLayerOrder = _targetPortrait._sortingOrder; if (_targetPortrait._sortingOrderOption == apPortrait.SORTING_ORDER_OPTION.SetOrder) { nextLayerOrder = EditorGUILayout.IntField("Sorting Order", _targetPortrait._sortingOrder); if (nextLayerOrder != _targetPortrait._sortingOrder) { _targetPortrait.SetSortingOrder(nextLayerOrder); } } if (nextLayerIndex != layerIndex) { //Sorting Layer를 바꾸자 if (nextLayerIndex >= 0 && nextLayerIndex < SortingLayer.layers.Length) { string nextLayerName = SortingLayer.layers[nextLayerIndex].name; _targetPortrait.SetSortingLayer(nextLayerName); } } if (nextSortingOption != _targetPortrait._sortingOrderOption) { _targetPortrait._sortingOrderOption = nextSortingOption; //변경된 Sorting Order Option에 따라서 바로 Sorting을 해야한다. _targetPortrait.ApplySortingOptionToOptRootUnits(); switch (_targetPortrait._sortingOrderOption) { case apPortrait.SORTING_ORDER_OPTION.SetOrder: _targetPortrait.SetSortingOrder(_targetPortrait._sortingOrder); break; case apPortrait.SORTING_ORDER_OPTION.DepthToOrder: case apPortrait.SORTING_ORDER_OPTION.ReverseDepthToOrder: _targetPortrait.SetSortingOrderChangedAutomatically(true); _targetPortrait.RefreshSortingOrderByDepth(); break; } } if (prevImportant != _targetPortrait._isImportant || prevAnimEventListener != _targetPortrait._optAnimEventListener || prevSortingLayerID != _targetPortrait._sortingLayerID || prevSortingOrderOption != _targetPortrait._sortingOrderOption || prevSortingOrder != _targetPortrait._sortingOrder) { apEditorUtil.SetEditorDirty(); } GUILayout.Space(5); //빌보드 apPortrait.BILLBOARD_TYPE nextBillboard = (apPortrait.BILLBOARD_TYPE)EditorGUILayout.EnumPopup("Billboard Type", _targetPortrait._billboardType); if (nextBillboard != _targetPortrait._billboardType) { _targetPortrait._billboardType = nextBillboard; apEditorUtil.SetEditorDirty(); } GUILayout.Space(20); // Root Portraits //----------------------------------------------------------------------------- GUILayout.Box(_guiContent_RootPortraits, _guiStyle_subTitle, GUILayout.Width(subTitleWidth), GUILayout.Height(subTitleHeight)); _isFold_RootPortraits = EditorGUILayout.Foldout(_isFold_RootPortraits, "Portraits"); if (_isFold_RootPortraits) { for (int i = 0; i < _targetPortrait._optRootUnitList.Count; i++) { apOptRootUnit rootUnit = _targetPortrait._optRootUnitList[i]; EditorGUILayout.ObjectField("[" + i + "]", rootUnit, typeof(apOptRootUnit), true); } } GUILayout.Space(20); // Animation Settings //----------------------------------------------------------------------------- GUILayout.Box(_guiContent_AnimationSettings, _guiStyle_subTitle, GUILayout.Width(subTitleWidth), GUILayout.Height(subTitleHeight)); _isFold_AnimationClips = EditorGUILayout.Foldout(_isFold_AnimationClips, "Animation Clips"); if (_isFold_AnimationClips) { for (int i = 0; i < _targetPortrait._animClips.Count; i++) { EditorGUILayout.BeginHorizontal(); GUILayout.Space(5); apAnimClip animClip = _targetPortrait._animClips[i]; if (animClip._uniqueID == _targetPortrait._autoPlayAnimClipID) { EditorGUILayout.LabelField("[" + i + "] (Auto)", GUILayout.Width(80)); } else { EditorGUILayout.LabelField("[" + i + "]", GUILayout.Width(80)); } EditorGUILayout.TextField(animClip._name); try { AnimationClip nextAnimationClip = EditorGUILayout.ObjectField(animClip._animationClipForMecanim, typeof(AnimationClip), false) as AnimationClip; if (nextAnimationClip != animClip._animationClipForMecanim) { UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty(); Undo.IncrementCurrentGroup(); Undo.RegisterCompleteObjectUndo(_targetPortrait, "Animation Changed"); animClip._animationClipForMecanim = nextAnimationClip; } } catch (Exception) { } EditorGUILayout.EndHorizontal(); } } GUILayout.Space(10); AnimationClip nextEmptyAnimClip = EditorGUILayout.ObjectField("Empty Anim Clip", _targetPortrait._emptyAnimClipForMecanim, typeof(AnimationClip), false) as AnimationClip; if (nextEmptyAnimClip != _targetPortrait._emptyAnimClipForMecanim) { UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty(); Undo.IncrementCurrentGroup(); Undo.RegisterCompleteObjectUndo(_targetPortrait, "Animation Changed"); _targetPortrait._emptyAnimClipForMecanim = nextEmptyAnimClip; } GUILayout.Space(10); //EditorGUILayout.LabelField("Mecanim Settings"); EditorGUILayout.LabelField(_guiContent_Mecanim, GUILayout.Height(24)); bool isNextUsingMecanim = EditorGUILayout.Toggle("Use Mecanim", _targetPortrait._isUsingMecanim); if (_targetPortrait._isUsingMecanim != isNextUsingMecanim) { UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty(); Undo.IncrementCurrentGroup(); Undo.RegisterCompleteObjectUndo(_targetPortrait, "Mecanim Setting Changed"); _targetPortrait._isUsingMecanim = isNextUsingMecanim; } if (_targetPortrait._isUsingMecanim) { //GUILayout.Space(10); try { Animator nextAnimator = EditorGUILayout.ObjectField("Animator", _targetPortrait._animator, typeof(Animator), true) as Animator; if (nextAnimator != _targetPortrait._animator) { //하위에 있는 Component일 때에만 변동 가능 if (nextAnimator == null) { _targetPortrait._animator = null; } else { if (nextAnimator == _targetPortrait.GetComponent <Animator>()) { _targetPortrait._animator = nextAnimator; } else { EditorUtility.DisplayDialog("Invalid Animator", "Invalid Animator. Only the Animator, which is its own component, is valid.", "Okay"); } } } } catch (Exception) { } if (_targetPortrait._animator == null) { //1. Animator가 없다면 // > 생성하기 // > 생성되어 있다면 다시 링크 GUIStyle guiStyle_WarningText = new GUIStyle(GUI.skin.label); guiStyle_WarningText.normal.textColor = Color.red; EditorGUILayout.LabelField("Warning : No Animator!", guiStyle_WarningText); GUILayout.Space(5); if (GUILayout.Button("Add / Check Animator", GUILayout.Height(25))) { UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty(); Undo.IncrementCurrentGroup(); Undo.RegisterCompleteObjectUndo(_targetPortrait, "Mecanim Setting Changed"); Animator animator = _targetPortrait.gameObject.GetComponent <Animator>(); if (animator == null) { animator = _targetPortrait.gameObject.AddComponent <Animator>(); } _targetPortrait._animator = animator; } } else { //2. Animator가 있다면 if (GUILayout.Button("Refresh Layers", GUILayout.Height(25))) { UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty(); Undo.IncrementCurrentGroup(); Undo.RegisterCompleteObjectUndo(_targetPortrait, "Mecanim Setting Changed"); //Animator의 Controller가 있는지 체크해야한다. if (_targetPortrait._animator.runtimeAnimatorController == null) { //AnimatorController가 없다면 Layer는 초기화 _targetPortrait._animatorLayerBakedData.Clear(); } else { //AnimatorController가 있다면 레이어에 맞게 설정 _targetPortrait._animatorLayerBakedData.Clear(); UnityEditor.Animations.AnimatorController animatorController = _targetPortrait._animator.runtimeAnimatorController as UnityEditor.Animations.AnimatorController; if (animatorController != null && animatorController.layers.Length > 0) { for (int iLayer = 0; iLayer < animatorController.layers.Length; iLayer++) { apAnimMecanimData_Layer newLayerData = new apAnimMecanimData_Layer(); newLayerData._layerIndex = iLayer; newLayerData._layerName = animatorController.layers[iLayer].name; newLayerData._blendType = apAnimMecanimData_Layer.MecanimLayerBlendType.Unknown; switch (animatorController.layers[iLayer].blendingMode) { case UnityEditor.Animations.AnimatorLayerBlendingMode.Override: newLayerData._blendType = apAnimMecanimData_Layer.MecanimLayerBlendType.Override; break; case UnityEditor.Animations.AnimatorLayerBlendingMode.Additive: newLayerData._blendType = apAnimMecanimData_Layer.MecanimLayerBlendType.Additive; break; } _targetPortrait._animatorLayerBakedData.Add(newLayerData); } } } } GUILayout.Space(5); EditorGUILayout.LabelField("Animator Controller Layers"); for (int i = 0; i < _targetPortrait._animatorLayerBakedData.Count; i++) { apAnimMecanimData_Layer layer = _targetPortrait._animatorLayerBakedData[i]; EditorGUILayout.BeginHorizontal(); GUILayout.Space(5); EditorGUILayout.LabelField("[" + layer._layerIndex + "]", GUILayout.Width(50)); EditorGUILayout.TextField(layer._layerName); apAnimMecanimData_Layer.MecanimLayerBlendType nextBlendType = (apAnimMecanimData_Layer.MecanimLayerBlendType)EditorGUILayout.EnumPopup(layer._blendType); EditorGUILayout.EndHorizontal(); if (nextBlendType != layer._blendType) { UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty(); Undo.IncrementCurrentGroup(); Undo.RegisterCompleteObjectUndo(_targetPortrait, "Mecanim Setting Changed"); _targetPortrait._animatorLayerBakedData[i]._blendType = nextBlendType; } } } } GUILayout.Space(20); //추가 3.4 : 타임라인 설정 #if UNITY_2017_1_OR_NEWER EditorGUILayout.LabelField(_guiContent_Timeline, GUILayout.Height(24)); _isFold_Timeline = EditorGUILayout.Foldout(_isFold_Timeline, "Track Data"); if (_isFold_Timeline) { int nextTimelineTracks = EditorGUILayout.DelayedIntField("Size", _nTimelineTrackSet); if (nextTimelineTracks != _nTimelineTrackSet) { //TimelineTrackSet의 개수가 바뀌었다. UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty(); Undo.IncrementCurrentGroup(); Undo.RegisterCompleteObjectUndo(_targetPortrait, "Track Setting Changed"); _nTimelineTrackSet = nextTimelineTracks; if (_nTimelineTrackSet < 0) { _nTimelineTrackSet = 0; } //일단 이전 개수만큼 복사를 한다. int nPrev = 0; List <apPortrait.TimelineTrackPreset> prevSets = new List <apPortrait.TimelineTrackPreset>(); if (targetPortrait._timelineTrackSets != null && targetPortrait._timelineTrackSets.Length > 0) { for (int i = 0; i < targetPortrait._timelineTrackSets.Length; i++) { prevSets.Add(targetPortrait._timelineTrackSets[i]); } nPrev = targetPortrait._timelineTrackSets.Length; } //배열을 새로 만들자 targetPortrait._timelineTrackSets = new apPortrait.TimelineTrackPreset[_nTimelineTrackSet]; //가능한 이전 소스를 복사한다. for (int i = 0; i < _nTimelineTrackSet; i++) { if (i < nPrev) { targetPortrait._timelineTrackSets[i] = new apPortrait.TimelineTrackPreset(); targetPortrait._timelineTrackSets[i]._playableDirector = prevSets[i]._playableDirector; targetPortrait._timelineTrackSets[i]._trackName = prevSets[i]._trackName; targetPortrait._timelineTrackSets[i]._layer = prevSets[i]._layer; targetPortrait._timelineTrackSets[i]._blendMethod = prevSets[i]._blendMethod; } else { targetPortrait._timelineTrackSets[i] = new apPortrait.TimelineTrackPreset(); } } apEditorUtil.ReleaseGUIFocus(); } GUILayout.Space(5); if (targetPortrait._timelineTrackSets != null) { apPortrait.TimelineTrackPreset curTrackSet = null; for (int i = 0; i < targetPortrait._timelineTrackSets.Length; i++) { //트랙을 하나씩 적용 curTrackSet = targetPortrait._timelineTrackSets[i]; EditorGUILayout.LabelField("[" + i + "] : " + (curTrackSet._playableDirector == null ? "<None>" : curTrackSet._playableDirector.name)); PlayableDirector nextDirector = EditorGUILayout.ObjectField("Director", curTrackSet._playableDirector, typeof(PlayableDirector), true) as PlayableDirector; string nextTrackName = EditorGUILayout.DelayedTextField("Track Name", curTrackSet._trackName); int nextLayer = EditorGUILayout.DelayedIntField("Layer", curTrackSet._layer); apAnimPlayUnit.BLEND_METHOD nextBlendMethod = (apAnimPlayUnit.BLEND_METHOD)EditorGUILayout.EnumPopup("Blend", curTrackSet._blendMethod); if (nextDirector != curTrackSet._playableDirector || nextTrackName != curTrackSet._trackName || nextLayer != curTrackSet._layer || nextBlendMethod != curTrackSet._blendMethod ) { UnityEditor.SceneManagement.EditorSceneManager.MarkAllScenesDirty(); Undo.IncrementCurrentGroup(); Undo.RegisterCompleteObjectUndo(_targetPortrait, "Track Setting Changed"); curTrackSet._playableDirector = nextDirector; curTrackSet._trackName = nextTrackName; curTrackSet._layer = nextLayer; curTrackSet._blendMethod = nextBlendMethod; apEditorUtil.ReleaseGUIFocus(); } GUILayout.Space(5); } } } GUILayout.Space(20); #endif bool isChanged = false; // Control Parameters //----------------------------------------------------------------------------- if (_guiContent_Category == null) { _guiContent_Category = apGUIContentWrapper.Make("Category", false); } GUILayout.Box(_guiContent_ControlParams, _guiStyle_subTitle, GUILayout.Width(subTitleWidth), GUILayout.Height(subTitleHeight)); #if UNITY_2017_3_OR_NEWER _curControlCategory = (apControlParam.CATEGORY)EditorGUILayout.EnumFlagsField(_guiContent_Category.Content, _curControlCategory); #else _curControlCategory = (apControlParam.CATEGORY)EditorGUILayout.EnumMaskPopup(_guiContent_Category.Content, _curControlCategory); #endif EditorGUILayout.Space(); //1. 컨르롤러를 제어할 수 있도록 하자 if (_controlParams != null) { for (int i = 0; i < _controlParams.Count; i++) { if ((int)(_controlParams[i]._category & _curControlCategory) != 0) { if (GUI_ControlParam(_controlParams[i])) { isChanged = true; } } } } GUILayout.Space(30); //2. 토글 버튼을 두어서 기본 Inspector 출력 여부를 결정하자. string strBaseButton = "Show All Properties"; if (_showBaseInspector) { strBaseButton = "Hide Properties"; } if (GUILayout.Button(strBaseButton, GUILayout.Height(20))) { _showBaseInspector = !_showBaseInspector; } if (_showBaseInspector) { base.OnInspectorGUI(); } if (!Application.isPlaying && isChanged) { //플레이 중이라면 자동으로 업데이트 될 것이다. _targetPortrait.UpdateForce(); } if (_targetPortrait != null) { if (request_OpenEditor) { if (_targetPortrait._isOptimizedPortrait) { RequestDelayedOpenEditor(_targetPortrait, REQUEST_TYPE.Open); } else { RequestDelayedOpenEditor(_targetPortrait, REQUEST_TYPE.OpenAndSet); } //apEditor anyPortraitEditor = apEditor.ShowWindow(); //if (anyPortraitEditor != null && !_targetPortrait._isOptimizedPortrait) //{ // anyPortraitEditor.SetPortraitByInspector(_targetPortrait, false); //} } else if (request_QuickBake) { RequestDelayedOpenEditor(_targetPortrait, REQUEST_TYPE.QuickBake); //apEditor anyPortraitEditor = apEditor.ShowWindow(); //if (anyPortraitEditor != null) //{ // anyPortraitEditor.SetPortraitByInspector(_targetPortrait, true); // Selection.activeObject = _targetPortrait.gameObject; //} } else if (request_RefreshMeshes) { _targetPortrait.OnMeshResetInEditor(); } } } catch (Exception ex) { Debug.LogError("apInspector_Portrait Exception : " + ex); } //Profiler.EndSample(); }
public apAnimPlayData PlayQueuedAt(string animClipName, int frame, int layer, apAnimPlayUnit.BLEND_METHOD blendMethod, bool isAutoEndIfNotloop = false) { apAnimPlayData playData = GetAnimPlayData_Opt(animClipName); if (playData == null) { Debug.LogError("PlayQueuedAt Failed : No AnimClip [" + animClipName + "]"); return(null); } return(PlayQueuedAt(playData, frame, layer, blendMethod, isAutoEndIfNotloop)); }
// Functions //--------------------------------------------- // 외부 제어 함수들 - 주로 Timeline #if UNITY_2017_1_OR_NEWER public bool AddTimelineTrack(UnityEngine.Playables.PlayableDirector playableDirector, string trackName, int layer, apAnimPlayUnit.BLEND_METHOD blendMethod) { if (_timlinePlay == null) { Debug.LogError("AnyPortrait : AddTimelineTrack() is Failed. It is not ready to be associated with the Timeline. Please try again in the next frame."); return(false); } return(_timlinePlay.AddTrack(playableDirector, trackName, layer, blendMethod)); }
//추가 3.8 : 타임라인 관련 함수들 //Timeline이 유니티 2017의 기능이므로 그 전에는 막혀있다. #if UNITY_2017_1_OR_NEWER public bool AddTimelineTrack(UnityEngine.Playables.PlayableDirector playableDirector, string trackName, int layer, apAnimPlayUnit.BLEND_METHOD blendMethod) { if (!_isMecanim) { Debug.LogError("AnyPortrait : AddTimelineTrack() is Failed. Mecanim is not activated."); return(false); } return(_mecanim.AddTimelineTrack(playableDirector, trackName, layer, blendMethod)); }
//AnimClip을 PlayUnit에 담아서 재생한다. //Queue에 저장된 클립들이 모두 끝나면 블렌드 없이 바로 실행된다. public apAnimPlayUnit PlayQueued(apAnimPlayData playData, apAnimPlayUnit.BLEND_METHOD blendMethod, float blendTime = 0.0f, bool isAutoEndIfNotloop = true) { //현재 재생되는 플레이 유닛 중에서 "가장 많이 남은 플레이 시간"을 기준으로 타이머를 잡자 //Fade 타임은 없고, 자동 삭제 타이머 + 자동 재생 대기 타이머를 지정 //현재 Queue에 있는 객체가 없다면 Play와 동일하다 //수정 : //이전에는 Queue 조건을 PlayUnit이 재생되는가..로 판별했다. -> 그러면 Stop 도중의 Unit도 Queue로 인식해버림 //이젠 이전에 존재하는 Request가 있는지 확인하고 Chain으로 연결한다. //Chain 연결시에는 연결된 양쪽이 서로를 알고 있어야 한다. //Request가 없는 경우에 한해서 PlayUnit에 연결한다. //마지막 연결이 apAnimPlayRequest lastRequest = null; if (_requests_Live.Count > 0) { //1. Request가 있는 경우/ //Chain을 시도한다. //마지막 Request를 찾는다. (End가 아닌거면 다 됨) for (int i = _requests_Live.Count - 1; i >= 0; i--) { if (_requests_Live[i].Status != apAnimPlayRequest.STATUS.End) { lastRequest = _requests_Live[i]; break; } } //아직 처리중인 마지막 Request가 있을 때 //Request 타입과 해당 AnimPlayUnit에 따라 //1) Chain+Queued을 할지, 2) 그냥 Play를 할 지, 3) 처리를 포기할 지 //결정을 한다. if (lastRequest != null) { int chainType = -1; switch (lastRequest.RequestType) { case apAnimPlayRequest.REQUEST_TYPE.New: case apAnimPlayRequest.REQUEST_TYPE.Queued: { //대기 중이거나 재생 중이다. //1. 같은 PlayUnit이라면 -> Loop 타입이라면 취소, Once 타입이라면 Chain 처리 //2. Loop 타입이라면 -> 그냥 Play //3. 그외 -> Chain 처리 if (lastRequest._nextPlayUnit._linkedAnimClip == playData._linkedAnimClip) { //1. 같은 PlayUnit이다. if (lastRequest._nextPlayUnit.IsLoop) { //Loop 타입이라면 취소 chainType = QUEUE_CHAIN__3_SKIP; } else { //Once 타입이라면 Chain 처리 //chainType = QUEUE_CHAIN__1_LINK_CHAIN; //변경 : 이미 같은 애니메이션에 대하여 New, Queued가 등록된 요청이다. //처리하지 않는걸로 하자 chainType = QUEUE_CHAIN__3_SKIP; } } else if (lastRequest._nextPlayUnit.IsLoop) { //2. 마지막 PlayUnit이 Loop 타입이다. // -> 그냥 Play chainType = QUEUE_CHAIN__2_PLAY; } else { //3. 그외 -> Chain 처리 chainType = QUEUE_CHAIN__1_LINK_CHAIN; } } break; case apAnimPlayRequest.REQUEST_TYPE.Stop: { //정지 요청이 있다. //Chain 없이 Play를 시도한다. (Stop 이후이므로) chainType = QUEUE_CHAIN__2_PLAY; } break; } switch (chainType) { case QUEUE_CHAIN__1_LINK_CHAIN: { //Last Unit과 Chain으로 연결한다. } break; case QUEUE_CHAIN__2_PLAY: //Debug.LogError("Play Queued -> 2) Play"); return(Play(playData, blendMethod, blendTime, isAutoEndIfNotloop)); case QUEUE_CHAIN__3_SKIP: //Debug.LogError("Play Queued -> 3) Skip"); return(null); } } } apAnimPlayUnit lastPlayUnit = null; if (lastRequest != null) { //Chain 처리가 되었다면 //-> LastPlayUnit은 Chain된 Request의 PlayUnit으로 삼는다. lastPlayUnit = lastRequest._nextPlayUnit; } else { //Chain 처리가 안되었을 때 //마지막 PlayUnit을 비교하여 처리한다. //1. 마지막 PlayUnit이 없는 경우 -> 바로 Play //2. 마지막 PlayUnit이 Loop 타입이어서 기다릴 수 없는 경우 -> 바로 Play if (_nPlayedUnit == 0) { //Debug.LogError("현재 남은 PlayUnit이 없으므로 바로 실행 [" + playData._animClipName + "]"); return(Play(playData, blendMethod, blendTime, isAutoEndIfNotloop)); } //마지막 PlayUnit을 가져오자 lastPlayUnit = _animPlayUnits[_animPlayUnits.Count - 1]; if (lastPlayUnit.IsLoop) { //만약 마지막 PlayUnit이 Loop라면 => Queued 되지 않는다. 자동으로 [Play]로 바뀜 //Debug.LogError("마지막 PlayUnit [" + lastPlayUnit._linkedAnimClip._name + "] 이 Loop 타입이어서 그냥 무시하고 CrossFade로 실행"); return(Play(playData, blendMethod, blendTime, isAutoEndIfNotloop)); } } if (lastPlayUnit != null && lastPlayUnit._linkedAnimClip == playData._linkedAnimClip) { //Debug.LogError("이미 재생중인 애니메이션이다."); return(null); } //Request를 생성한다. apAnimPlayRequest request = PopRequest(); //request.SetCurrentPlayedUnits(this, _animPlayUnits); request.SetCurrentPlayedUnits(this); //현재 플레이 중인 AnimPlayUnit들의 LinkKey를 넣어준다. for (int i = 0; i < _animPlayUnits.Count; i++) { request.AddPrevPlayUnitKeyLink(_animPlayUnits[i].LinkKey, _animPlayUnits[i].UnitWeight); } apAnimPlayUnit newPlayUnit = MakePlayUnit(playData, blendMethod, isAutoEndIfNotloop); newPlayUnit.Pause(); //Play Queued 명령을 준다. request.PlayQueued(newPlayUnit, lastPlayUnit, blendTime); //추가 : Chain 처리를 해주자 if (lastRequest != null) { //if(lastRequest._chainedRequest_Next != null) //{ // Debug.LogError("마지막 Unit을 Chain하려고 했으나 이미 연결되어 있다;;;"); //} //LastRequest.Next <-> Request.Prev lastRequest._chainedRequest_Next = request; request._chainedRequest_Prev = lastRequest; } #region [미사용 코드] 미리 시간을 예상해서 처리하는 것은 문제가 많다. //float maxRemainPlayTime = -1.0f; //float curRemainPlayTime = 0.0f; //bool isAnyOnceAnimClip = false; //for (int i = 0; i < _nPlayedUnit; i++) //{ // _tmpCurPlayUnit = _animPlayUnits[i]; // if(_tmpCurPlayUnit.IsLoop) // { // //하나라도 루프이면 실패다. // //Queue에 넣어도 작동하지 않는다. // //>수정 // //루프는 무시하고 Queue 시간을 잡자 // //만약 Loop를 만나고 Queue가 있다면 그냥 기본값인 0.5초를 Queue 시간으로 쓴다. // //Debug.LogError("PlayQueued Failed : Any Clip has Loop Option. Adding to Queue will be ignored"); // //return null; // continue; // } // isAnyOnceAnimClip = true; // curRemainPlayTime = _tmpCurPlayUnit.GetRemainPlayTime; // if(maxRemainPlayTime < curRemainPlayTime) // { // maxRemainPlayTime = curRemainPlayTime; // } //} //if(!isAnyOnceAnimClip) //{ // maxRemainPlayTime = 0.5f; //} //if(maxRemainPlayTime < 0.0f) //{ // maxRemainPlayTime = 0.0f; //} ////최대 RemainPlayTime 만큼 Delay한다. //// Delay후 신규 플레이 또는 플레이 종료를 한다. ////Fade 시간은 0 //apAnimPlayUnit newPlayUnit = MakePlayUnit(playData, blendMethod, isAutoEndIfNotloop); //newPlayUnit.Play(0.0f, maxRemainPlayTime); ////Debug.LogError("TODO : 이 AnimClip을 CalculatedParam에 연결해야한다"); //for (int i = 0; i < _nPlayedUnit; i++) //{ // _tmpCurPlayUnit = _animPlayUnits[i]; // if (newPlayUnit != _tmpCurPlayUnit) // { // _tmpCurPlayUnit.FadeOut(0.0f, maxRemainPlayTime); // } //} #endregion _nPlayedUnit = _animPlayUnits.Count; //Order를 갱신한다. RefreshOrder(); return(newPlayUnit); }
/// <summary> /// AnimClip을 PlayUnit에 담아서 재생한다. /// Queue에 저장된 클립들이 모두 끝나면 블렌드 없이 바로 실행된다. /// </summary> /// <param name="blendMethod"></param> /// <param name="isAutoEndIfNotloop">True이면 Clip의 재생 후 자동으로 종료한다. (Loop일 경우 무시됨)</param> /// <returns></returns> public apAnimPlayUnit PlayQueued(apAnimPlayData playData, apAnimPlayUnit.BLEND_METHOD blendMethod, float blendTime = 0.0f, bool isAutoEndIfNotloop = true) { //현재 재생되는 플레이 유닛 중에서 "가장 많이 남은 플레이 시간"을 기준으로 타이머를 잡자 //Fade 타임은 없고, 자동 삭제 타이머 + 자동 재생 대기 타이머를 지정 //현재 Queue에 있는 객체가 없다면 Play와 동일하다 if (_nPlayedUnit == 0) { return(Play(playData, blendMethod, blendTime, isAutoEndIfNotloop)); } //마지막 PlayUnit을 가져오자 apAnimPlayUnit lastPlayUnit = _animPlayUnits[_animPlayUnits.Count - 1]; if (lastPlayUnit.IsLoop) { //만약 마지막 PlayUnit이 Loop라면 => Queued 되지 않는다. 자동으로 [Play]로 바뀜 return(Play(playData, blendMethod, blendTime, isAutoEndIfNotloop)); } //Request를 생성한다. apAnimPlayRequest request = PopRequest(); request.SetCurrentPlayedUnits(this, _animPlayUnits); apAnimPlayUnit newPlayUnit = MakePlayUnit(playData, blendMethod, isAutoEndIfNotloop); newPlayUnit.Pause(); //Play Queued 명령을 준다. request.PlayQueued(newPlayUnit, lastPlayUnit, blendTime); #region [미사용 코드] 미리 시간을 예상해서 처리하는 것은 문제가 많다. //float maxRemainPlayTime = -1.0f; //float curRemainPlayTime = 0.0f; //bool isAnyOnceAnimClip = false; //for (int i = 0; i < _nPlayedUnit; i++) //{ // _tmpCurPlayUnit = _animPlayUnits[i]; // if(_tmpCurPlayUnit.IsLoop) // { // //하나라도 루프이면 실패다. // //Queue에 넣어도 작동하지 않는다. // //>수정 // //루프는 무시하고 Queue 시간을 잡자 // //만약 Loop를 만나고 Queue가 있다면 그냥 기본값인 0.5초를 Queue 시간으로 쓴다. // //Debug.LogError("PlayQueued Failed : Any Clip has Loop Option. Adding to Queue will be ignored"); // //return null; // continue; // } // isAnyOnceAnimClip = true; // curRemainPlayTime = _tmpCurPlayUnit.GetRemainPlayTime; // if(maxRemainPlayTime < curRemainPlayTime) // { // maxRemainPlayTime = curRemainPlayTime; // } //} //if(!isAnyOnceAnimClip) //{ // maxRemainPlayTime = 0.5f; //} //if(maxRemainPlayTime < 0.0f) //{ // maxRemainPlayTime = 0.0f; //} ////최대 RemainPlayTime 만큼 Delay한다. //// Delay후 신규 플레이 또는 플레이 종료를 한다. ////Fade 시간은 0 //apAnimPlayUnit newPlayUnit = MakePlayUnit(playData, blendMethod, isAutoEndIfNotloop); //newPlayUnit.Play(0.0f, maxRemainPlayTime); ////Debug.LogError("TODO : 이 AnimClip을 CalculatedParam에 연결해야한다"); //for (int i = 0; i < _nPlayedUnit; i++) //{ // _tmpCurPlayUnit = _animPlayUnits[i]; // if (newPlayUnit != _tmpCurPlayUnit) // { // _tmpCurPlayUnit.FadeOut(0.0f, maxRemainPlayTime); // } //} #endregion _nPlayedUnit = _animPlayUnits.Count; return(newPlayUnit); }
/// <summary> /// [Editor] 업데이트 중 Control Param 제어 Timeline에 대해 업데이트 후 적용을 한다. /// [Runtime] isAdaptToWeight = false로 두고 나머지 처리를 한다. /// </summary> /// <param name="isAdaptToWeight1">[Editor]에서 Weight=1로 두고 적용을 한다</param> public void UpdateControlParam(bool isAdaptToWeight1, int optLayer = 0, float optWeight = 1.0f, apAnimPlayUnit.BLEND_METHOD optBlendMethod = apAnimPlayUnit.BLEND_METHOD.Interpolation) { if (_controlParamResult.Count == 0) { return; } for (int i = 0; i < _controlParamResult.Count; i++) { _controlParamResult[i].Init(); } apAnimTimeline timeline = null; apAnimTimelineLayer layer = null; int curFrame = CurFrame; float curFrameF = CurFrameFloat; //apAnimKeyframe firstKeyframe = null; //apAnimKeyframe lastKeyframe = null; apAnimKeyframe curKeyframe = null; apAnimKeyframe prevKeyframe = null; apAnimKeyframe nextKeyframe = null; int lengthFrames = _endFrame - _startFrame; int tmpCurFrame = 0; apAnimControlParamResult cpResult = null; for (int iTL = 0; iTL < _timelines.Count; iTL++) { timeline = _timelines[iTL]; if (timeline._linkType != LINK_TYPE.ControlParam) { continue; } for (int iL = 0; iL < timeline._layers.Count; iL++) { layer = timeline._layers[iL]; if (layer._linkedControlParam == null || layer._linkedControlParamResult == null) { continue; } cpResult = layer._linkedControlParamResult; //firstKeyframe = layer._firstKeyFrame; //lastKeyframe = layer._lastKeyFrame; for (int iK = 0; iK < layer._keyframes.Count; iK++) { curKeyframe = layer._keyframes[iK]; prevKeyframe = curKeyframe._prevLinkedKeyframe; nextKeyframe = curKeyframe._nextLinkedKeyframe; if (curFrame == curKeyframe._frameIndex || ((curKeyframe._isLoopAsStart || curKeyframe._isLoopAsEnd) && curKeyframe._loopFrameIndex == curFrame) ) { cpResult.SetKeyframeResult(curKeyframe, 1.0f); } else if (curKeyframe.IsFrameIn(curFrame, apAnimKeyframe.LINKED_KEY.Prev)) { //Prev - Cur 범위 안에 들었다. if (prevKeyframe != null) { //Prev 키가 있다면 tmpCurFrame = curFrame; if (tmpCurFrame > curKeyframe._frameIndex) { //한바퀴 돌았다면 tmpCurFrame -= lengthFrames; } //TODO : 여길 나중에 "정식 Curve로 변경"할 것 //float itp = apAnimCurve.GetCurvedRelativeInterpolation(curKeyframe._curveKey, prevKeyframe._curveKey, tmpCurFrame, true); //>> 변경 float itp = curKeyframe._curveKey.GetItp_Int(tmpCurFrame, true); cpResult.SetKeyframeResult(curKeyframe, itp); } else { //Prev 키가 없다면 이게 100%다 cpResult.SetKeyframeResult(curKeyframe, 1.0f); } } else if (curKeyframe.IsFrameIn(curFrame, apAnimKeyframe.LINKED_KEY.Next)) { //Cur - Next 범위 안에 들었다. if (nextKeyframe != null) { //Next 키가 있다면 tmpCurFrame = curFrame; if (tmpCurFrame < curKeyframe._frameIndex) { //한바퀴 돌았다면 tmpCurFrame += lengthFrames; } //TODO : 여길 나중에 "정식 Curve로 변경"할 것 //float itp = apAnimCurve.GetCurvedRelativeInterpolation(curKeyframe._curveKey, nextKeyframe._curveKey, tmpCurFrame, false); //>> 변경 float itp = curKeyframe._curveKey.GetItp_Int(tmpCurFrame, false); cpResult.SetKeyframeResult(curKeyframe, itp); } else { //Prev 키가 없다면 이게 100%다 cpResult.SetKeyframeResult(curKeyframe, 1.0f); } } } } } //Control Param에 적용을 해야한다. if (isAdaptToWeight1) { //Editor인 경우 Weight 1로 강제한다. for (int i = 0; i < _controlParamResult.Count; i++) { _controlParamResult[i].AdaptToControlParam(); } } else { //Runtime인 경우 지정된 Weight, Layer로 처리한다. for (int i = 0; i < _controlParamResult.Count; i++) { //Debug.Log("AnimClip [" + _name + " > Control Param : " + _controlParamResult[i]._targetControlParam._keyName + " ]"); _controlParamResult[i].AdaptToControlParam_Opt(optWeight, optBlendMethod); } } }
public bool SetTrack(string trackName, int layerIndex, apAnimPlayUnit.BLEND_METHOD blendMethod, apPortrait portrait, apAnimPlayManager animPlayManager) { #if UNITY_2017_1_OR_NEWER //PlayableDirector playDirector = _parentTrackSet._playableDirector; PlayableAsset playAsset = _parentTrackSet._playableAsset; #endif _trackName = trackName; _layerIndex = layerIndex; #if UNITY_2017_1_OR_NEWER _layerOrder = _layerIndex; #endif _blendMethod = blendMethod; if (string.IsNullOrEmpty(_trackName)) { //이름이 빈칸이거나 null이다. return(false); } _clipData = new List <TimelineClipData>(); #if UNITY_2017_1_OR_NEWER _timelineClips = new List <TimelineClip>(); _clipDataByTrack = new Dictionary <TimelineClip, TimelineClipData>(); #endif _nClipData = 0; //연결을 하자 bool isFind = false; #if UNITY_2017_1_OR_NEWER _animationTrack = null; #endif //그 전에 AnimClip <-> AnimationClipAsset을 서로 연결해야한다. apAnimClip curAnimClip = null; AnimationClip curAnimationClipAsset = null; Dictionary <AnimationClip, apAnimClip> animClipAsset2AnimClip = new Dictionary <AnimationClip, apAnimClip>(); for (int i = 0; i < portrait._animClips.Count; i++) { curAnimClip = portrait._animClips[i]; if (curAnimClip == null) { continue; } curAnimationClipAsset = curAnimClip._animationClipForMecanim; if (curAnimationClipAsset == null) { continue; } if (animClipAsset2AnimClip.ContainsKey(curAnimationClipAsset)) { continue; } animClipAsset2AnimClip.Add(curAnimationClipAsset, curAnimClip); } //apAnimClip에 해당하는 apOptRootUnit을 알아야 한다. //apAnimPlayData에 그 정보가 저장되어 있으니 참조하자 apAnimPlayData curPlayData = null; Dictionary <apAnimClip, apOptRootUnit> animClip2RootUnit = new Dictionary <apAnimClip, apOptRootUnit>(); for (int i = 0; i < animPlayManager._animPlayDataList.Count; i++) { curPlayData = animPlayManager._animPlayDataList[i]; if (curPlayData == null) { continue; } if (curPlayData._linkedAnimClip == null || curPlayData._linkedOptRootUnit == null) { continue; } if (animClip2RootUnit.ContainsKey(curPlayData._linkedAnimClip)) { continue; } //apAnimClip -> apOptRootUnit으로 연결 데이터 추가 animClip2RootUnit.Add(curPlayData._linkedAnimClip, curPlayData._linkedOptRootUnit); } #if UNITY_2017_1_OR_NEWER foreach (PlayableBinding playableBinding in playAsset.outputs) { #endif #if UNITY_2018_1_OR_NEWER bool isAnimTrack = playableBinding.sourceObject != null && playableBinding.sourceObject is AnimationTrack; #elif UNITY_2017_1_OR_NEWER bool isAnimTrack = playableBinding.streamType == DataStreamType.Animation; #endif //if (playableBinding.streamType != DataStreamType.Animation) #if UNITY_2017_1_OR_NEWER if (!isAnimTrack) { //애니메이션 타입이 아니라면 패스 continue; } AnimationTrack animTrack = playableBinding.sourceObject as AnimationTrack; if (animTrack == null) { continue; } //if(animTrack.isEmpty) //{ // //클립이 아예 없는데용 // continue; //} if (!animTrack.name.Equals(_trackName)) { //이름이 다르다. continue; } if (animTrack.isEmpty) { //클립이 아예 없는데용 //continue; Debug.LogWarning("AnyPortrait : ( Warning ) No Clip in the requested track. [ " + trackName + " ]"); //일단 처리는 하자 } //이름도 같고 유효한 트랙을 찾았다! isFind = true; _animationTrack = animTrack; AnimationClip animClipInTrack = null; apAnimClip targetAnimClip = null; apOptRootUnit targetRootUnit = null; foreach (TimelineClip timelineClip in _animationTrack.GetClips()) { //Track의 TimelineClip 중에서 유효한 AnimationClip만 선택한다. animClipInTrack = timelineClip.animationClip; if (!animClipAsset2AnimClip.ContainsKey(animClipInTrack)) { //유효한 AnimationClip이 아니다. continue; } targetAnimClip = animClipAsset2AnimClip[animClipInTrack]; if (targetAnimClip == null) { //animClip이 비어있다. continue; } if (!animClip2RootUnit.ContainsKey(targetAnimClip)) { //apAnimClip -> apOptRootUnit을 조회할 수 없다. continue; } targetRootUnit = animClip2RootUnit[targetAnimClip]; if (targetRootUnit == null) { //RootUnit이 null이다. continue; } TimelineClipData newClipData = new TimelineClipData(timelineClip, targetAnimClip, targetRootUnit); _clipData.Add(newClipData); _timelineClips.Add(timelineClip); _clipDataByTrack.Add(timelineClip, newClipData); //_clipDataByAnimClip.Add(targetAnimClip, newClipData); _nClipData++; } //Debug.Log("Track [" + trackName + "] Added"); //<<추가>> 시간대에 따라서 Sort _clipData.Sort(delegate(TimelineClipData a, TimelineClipData b) { return((int)((a._timelineClip.start - b._timelineClip.start) * 100.0)); }); if (isFind) { break; } } #endif if (!isFind) { Debug.LogError("AnyPortrait : No track with the requested name. [" + trackName + "]"); } return(isFind); }