public void Link(apPortrait portrait, apAnimPlayManager animPlayManager, apAnimPlayMecanim animPlayMecanim) { ClearTracks(); #if UNITY_2017_1_OR_NEWER _portrait = portrait; #endif _animPlayManager = animPlayManager; #if UNITY_2017_1_OR_NEWER //_animPlayMecanim = animPlayMecanim; #endif //Inspector에서 지정된 트랙 정보가 있다면 먼저 등록한다. #if UNITY_2017_1_OR_NEWER if (portrait._timelineTrackSets != null && portrait._timelineTrackSets.Length > 0) { apPortrait.TimelineTrackPreset trackSetData = null; for (int i = 0; i < portrait._timelineTrackSets.Length; i++) { trackSetData = portrait._timelineTrackSets[i]; AddTrack(trackSetData._playableDirector, trackSetData._trackName, trackSetData._layer, trackSetData._blendMethod); } } #endif }
// Init //---------------------------------------------- public apAnimPlayQueue(int layer, apPortrait portrait, apAnimPlayManager playManager) { _layer = layer; _portrait = portrait; _playManager = playManager; Clear(); _isAnyUnitChanged = false; _requests_Live.Clear(); _requests_Total.Clear(); _requests_Remained.Clear(); AddRequestPool(); //<<Pool을 만든다. }
//업데이트 public void Update(apAnimPlayManager animPlayManager) { #if UNITY_2017_1_OR_NEWER _lastPlayedTimelineClip = null; #endif if (_nTrackData == 0) { return; } for (int i = 0; i < _nTrackData; i++) { _curTrackData = _trackData[i]; _curTrackData.Update(animPlayManager); } //0번 레이어의 마지막으로 재생된 클립 정보를 받자 #if UNITY_2017_1_OR_NEWER _lastPlayedTimelineClip = _trackData[0]._lastPlayedTimelineClip; #endif _lastPlayedLocalTime = _trackData[0]._lastPlayedLocalTime; }
public void LinkPortrait(apPortrait portrait, apAnimPlayManager animPlayManager) { _portrait = portrait; _animPlayManager = animPlayManager; _animator = _portrait._animator; _animController = null; _isValidAnimator = false; if (_animator == null) { //Debug.LogError("No Animator"); return; } _animController = _animator.runtimeAnimatorController; if (_animController == null) { Debug.LogError("AnyPortrait : No RuntimeAnimatorController on Animator"); return; } _isValidAnimator = true; _layers.Clear(); _clipData.Clear(); _clipDataByAsset.Clear(); _clipDataByAnimClip.Clear(); //레이어 정보를 담자 _nLayers = _animator.layerCount; //저장된 AnimClip 체크를 위해서 리스트를 만들자 //유효하지 않은 AnimClip은 제외해야한다. List <AnimationClip> allClips = new List <AnimationClip>(); List <AnimationClip> validClips = new List <AnimationClip>(); for (int iLayer = 0; iLayer < _animator.layerCount; iLayer++) { MecanimLayer newLayer = new MecanimLayer(); newLayer._index = iLayer; newLayer._blendType = apAnimPlayUnit.BLEND_METHOD.Interpolation; if (iLayer < portrait._animatorLayerBakedData.Count) { if (portrait._animatorLayerBakedData[iLayer]._blendType == apAnimMecanimData_Layer.MecanimLayerBlendType.Additive) { //미리 설정된 데이터가 있고, Additive라면 Additive로 설정 newLayer._blendType = apAnimPlayUnit.BLEND_METHOD.Additive; } } _layers.Add(newLayer); } //어떤 AnimClip이 있는지 체크하자 for (int i = 0; i < _animController.animationClips.Length; i++) { if (!allClips.Contains(_animController.animationClips[i])) { allClips.Add(_animController.animationClips[i]); } } //apAnimClip <-> AnimationClip Asset을 서로 연결하자 _animClip2Asset.Clear(); _asset2AnimClip.Clear(); //Debug.Log("animPlayManager._animPlayDataList Count : " + animPlayManager._animPlayDataList.Count); for (int i = 0; i < animPlayManager._animPlayDataList.Count; i++) { apAnimPlayData playData = animPlayManager._animPlayDataList[i]; //Debug.Log("[" + i + "] : " + playData._animClipName); apAnimClip animClip = playData._linkedAnimClip; if (animClip == null) { //Debug.LogError("[" + i + "] : " + playData._animClipName + " >> Linked Anim Clip is Null"); continue; } AnimationClip assetClip = animClip._animationClipForMecanim; if (assetClip != null) { _animClip2Asset.Add(animClip, assetClip); _asset2AnimClip.Add(assetClip, animClip); MecanimClipData newClipData = new MecanimClipData(assetClip, animClip, playData._linkedOptRootUnit); _clipData.Add(newClipData); _clipDataByAsset.Add(assetClip, newClipData); _clipDataByAnimClip.Add(animClip, newClipData); if (!validClips.Contains(assetClip)) { validClips.Add(assetClip); } //Debug.Log("[" + i + "] : " + playData._animClipName + " >> " + assetClip.name); } else { if (Application.isPlaying) { Debug.LogError("[" + i + "] : " + playData._animClipName + " >> AnimAsset is Null"); } } } _nClipData = _clipData.Count; //여기서 유효성 체크 //(유효성 체크는 Application 실행 시에) //if (Application.isPlaying) { for (int i = 0; i < allClips.Count; i++) { if (!validClips.Contains(allClips[i])) { if (allClips[i] != _portrait._emptyAnimClipForMecanim) { //유효하지 않은 Clip이 발견되었다. Debug.LogError("AnyPortrait : ( Caution! ) Contains an invalid AnimationClip. An error may occur when playing. [" + allClips[i].name + " < " + _portrait.gameObject.name + "]"); Debug.LogError("Valid Clips : " + validClips.Count); } } } } }
//트랙을 추가한다. 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); }
public void Update(apAnimPlayManager animPlayManager) { #if UNITY_2017_1_OR_NEWER _c_curTime = _parentTrackSet._playableDirector.time; _lastPlayedTimelineClip = null; #endif _lastPlayedLocalTime = 0.0f; //1. 전체 Reday To Update for (int i = 0; i < _nClipData; i++) { _clipData[i].ReadyToUpdate(); } #if UNITY_2017_1_OR_NEWER //2. 범위 체크해서 업데이트 여부 결정과 Set Data _c_curClipData = null; _c_clipA = null; _c_clipB = null; _c_localTimeA = 0.0; _c_localTimeB = 0.0; _c_weightA = 0.0f; _c_weightB = 0.0f; _c_nPlayClips = 0; for (int i = 0; i < _nClipData; i++) { _c_curClipData = _clipData[i]; if (_c_curTime < _c_curClipData._timelineClip.start || _c_curTime > _c_curClipData._timelineClip.end) { continue; } if (_c_clipA == null) { _c_clipA = _c_curClipData; _c_nPlayClips = 1; _c_localTimeA = _c_clipA._timelineClip.ToLocalTimeUnbound(_c_curTime); } else if (_c_clipB == null) { //단, A와 AnimClip이 겹치면 안된다. if (_c_clipA._animClip != _c_curClipData._animClip) { _c_clipB = _c_curClipData; _c_nPlayClips = 2; _c_localTimeB = _c_clipB._timelineClip.ToLocalTimeUnbound(_c_curTime); break; //B까지 연결했으면 끝 } } } if (_c_nPlayClips == 1) { //PlayClip이 1개일 때 if (_c_localTimeA < _c_clipA._timelineClip.easeInDuration) { _c_weightA = GetWeightIn(_c_localTimeA, _c_clipA._timelineClip.easeInDuration); } else if (_c_localTimeA < _c_clipA._timelineClip.duration - _c_clipA._timelineClip.easeOutDuration) { _c_weightA = 1.0f; } else { _c_weightA = GetWeightOut(_c_localTimeA, _c_clipA._timelineClip.easeOutDuration, _c_clipA._timelineClip.duration); } _c_clipA.SetData(true, _c_weightA, (float)_c_localTimeA, _blendMethod, _layerOrder); //Clip A가 마지막에 계산되었다. _lastPlayedTimelineClip = _c_clipA._timelineClip; _lastPlayedLocalTime = (float)_c_localTimeA; } else if (_c_nPlayClips == 2) { //PlayClip이 2개일 때 (무조건 Blend) _c_weightA = GetWeightOut(_c_localTimeA, _c_clipA._timelineClip.blendOutDuration, _c_clipA._timelineClip.duration); _c_weightB = 1.0f - _c_weightA; _c_clipA.SetData(true, _c_weightA, (float)_c_localTimeA, _blendMethod, _layerOrder); _c_clipB.SetData(false, _c_weightB, (float)_c_localTimeB, _blendMethod, _layerOrder); //Clip B가 마지막에 계산되었다. _lastPlayedTimelineClip = _c_clipB._timelineClip; _lastPlayedLocalTime = (float)_c_localTimeB; } //3. 클립데이터 확인하여 Link/Unlink 및 Update for (int i = 0; i < _nClipData; i++) { _c_curClipData = _clipData[i]; if (!_c_curClipData._isCalculated) { //업데이트가 안되었다면 Release if (_c_curClipData._isCalculatedPrev) { //이전 프레임에서는 계산이 되었던 ClipData다. _c_curClipData.Unlink(); } } else { //업데이트가 되었으면 연결을 하고, 프레임과 Weight를 업데이트 한다. if (!_c_curClipData._isCalculatedPrev) { //이전 프레임에서는 계산이 안되었다. _c_curClipData.Link(); //Root Unit을 갱신할 수도 있다. animPlayManager.SetOptRootUnit(_c_curClipData._linkedRootUnit); } //업데이트 <중요!> _c_curClipData.UpdateTimelineClipAndPlayUnit(); } //Prev 갱신 _c_curClipData._isCalculatedPrev = _c_curClipData._isCalculated; } #endif }
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); }