///// <summary> ///// AnimClip을 PlayUnit에 담아서 바로 재생한다. ///// Queue에 저장된 모든 클립에 바로 FadeOut을 지정하여 자연스럽게 종료하도록 한다. ///// </summary> ///// <param name="blendMethod"></param> ///// <param name="isAutoEndIfNotloop">True이면 Clip의 재생 후 자동으로 종료한다. (Loop일 경우 무시됨)</param> //public apAnimPlayUnit CrossFade(apAnimPlayData playData, apAnimPlayUnit.BLEND_METHOD blendMethod, bool isAutoEndIfNotloop, float fadeTime) //{ // apAnimPlayUnit newPlayUnit = MakePlayUnit(playData, blendMethod, isAutoEndIfNotloop); // newPlayUnit.Play(fadeTime, 0.0f); // //TODO : 이 AnimClip을 CalculatedParam에 연결해야한다. // //Debug.LogError("TODO : 이 AnimClip을 CalculatedParam에 연결해야한다"); // //플레이 유닛은 플레이 시작 // //나머지는 End로 만든다. // for (int i = 0; i < _animPlayUnits.Count; i++) // { // if (newPlayUnit != _animPlayUnits[i]) // { // _animPlayUnits[i].FadeOut(fadeTime); // } // } // _nPlayedUnit = _animPlayUnits.Count; // return newPlayUnit; //} ///// <summary> ///// AnimClip을 PlayUnit에 담아서 기다린 뒤 재생한다. ///// Queue에 저장된 클립들이 모두 끝나면 Fade Time만큼 섞어서 재생한다. ///// </summary> ///// <param name="animClip"></param> ///// <param name="blendMethod"></param> ///// <param name="isAutoEndIfNotloop">True이면 Clip의 재생 후 자동으로 종료한다. (Loop일 경우 무시됨)</param> ///// <returns></returns> //public apAnimPlayUnit CrossFadeQueued(apAnimPlayData playData, apAnimPlayUnit.BLEND_METHOD blendMethod, bool isAutoEndIfNotloop, float fadeTime) //{ // //현재 재생되는 플레이 유닛 중에서 "가장 많이 남은 플레이 시간"을 기준으로 타이머를 잡자 // //Fade 타임은 없고, 자동 삭제 타이머 + 자동 재생 대기 타이머를 지정 // //현재 Queue에 있는 객체가 없다면 CrossFade와 동일하다 // if(_nPlayedUnit == 0) // { // return CrossFade(playData, blendMethod, isAutoEndIfNotloop, fadeTime); // } // 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 시간을 잡자 // //만약 Loop를 만나고 Queue가 있다면 그냥 기본값인 0.5초를 Queue 시간으로 쓴다. // //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; // } // //딜레이 시간 = 최대 "남은 시간" - "페이드아웃 시간" // //-----------------..............---> // //[ 딜레이 ] + [ 페이드아웃 ] // //Debug.Log("------------------------------------------------------------"); // //Debug.Log("CrossFadeQueued Request [" + playData._animClipName + "]"); // float delayTime = maxRemainPlayTime - fadeTime; // //Debug.Log("Max Remain Time : " + maxRemainPlayTime); // //Debug.Log("Fade Time : " + fadeTime); // //Debug.Log("Delay Time : " + delayTime); // if(delayTime < 0.0f) // { // // 만약 남은 시간이 적어서 Delay 시간이 음수가 된다면 // //Delay Time = 0으로 두고 // //남은 시간이 모두 FadeTime이다. // fadeTime = maxRemainPlayTime; // delayTime = 0.0f; // //Debug.LogError("Adjusted > Fade Time : " + fadeTime + " / Delay Time : 0"); // } // //Debug.Log("------------------------------------------------------------"); // //최대 RemainPlayTime 만큼 Delay한다. // // Delay후 신규 플레이 또는 플레이 종료를 한다. // //Fade 시간은 0 // apAnimPlayUnit newPlayUnit = MakePlayUnit(playData, blendMethod, isAutoEndIfNotloop); // newPlayUnit.Play(fadeTime, delayTime); // //Debug.LogError("TODO : 이 AnimClip을 CalculatedParam에 연결해야한다"); // for (int i = 0; i < _nPlayedUnit; i++) // { // _tmpCurPlayUnit = _animPlayUnits[i]; // if (newPlayUnit != _tmpCurPlayUnit) // { // _tmpCurPlayUnit.FadeOut(fadeTime, delayTime); // } // } // _nPlayedUnit = _animPlayUnits.Count; // return newPlayUnit; //} #endregion //모든 PlayUnit을 종료한다. Clear와 달리 blendTime을 지원한다. //이 프레임에서 바로 종료하는게 아니므로, 만약 바로 정리를 하고자 한다면 ReleaseForce를 호출하자 public void StopAll(float blendTime) { //현재 상태에서 실행되지 않은 Queued 애니메이션 재생 요청은 삭제한다. PushAllNoActiveRequests(); //Stop을 하면서 서서히 줄어드는 걸 요청한다. 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); if (blendTime < 0.0001f) { if (_animPlayUnits[i]._linkedAnimClip != null) { if (!_animPlayUnits[i]._linkedAnimClip.IsPlaying_Opt) { _animPlayUnits[i]._linkedAnimClip.ResetFrame(); } } } } request.Stop(blendTime); //Order를 갱신한다. RefreshOrder(); }
//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); }
//---------------------------------------------------- // 재생/정지 요청 함수들 //---------------------------------------------------- //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); }