#include "stdafx.h" #include "KPrimitiveSprite.h" #include "KUIControlDamage.h" #include "KResourceManager.h" //#define _DAMAGE_TEST ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // KDamageTextProcess Implement ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class KDamageTextProcess { public: KDamageTextProcess() { m_bIsValid = true; m_pParent = NULL; m_curTime = m_startTime = 0; } virtual ~KDamageTextProcess() { m_pParent = NULL; } void SetParent(KUIControlDamageText* pParent) { m_pParent = pParent; } bool GetIsValid() { return m_bIsValid; } virtual bool DoProcess(DWORD dwTime) = 0; protected: KUIControlDamageText* m_pParent; bool m_bIsValid; DWORD m_curTime; DWORD m_startTime; }; class KDamageTextProcessScale : public KDamageTextProcess { public: KDamageTextProcessScale(float fScaleFactor = 4.f, DWORD scaleTime = 600) { m_fScaleFactor = fScaleFactor; m_scaleTime = scaleTime; } virtual bool DoProcess(DWORD dwTime) { m_curTime = dwTime; if(m_startTime == 0) { m_startTime = m_curTime; return true; } DWORD timeDiff = m_curTime - m_startTime; float fRatio = getClampRatio(timeDiff, m_scaleTime); float fScaleFactor = 1.f + (m_fScaleFactor - 1.f) * fRatio; m_pParent->ChangeScale(fScaleFactor); return fRatio < 1.f; } private: float m_fScaleFactor; DWORD m_scaleTime; }; class KDamageTextProcessVisi : public KDamageTextProcess { public: KDamageTextProcessVisi(DWORD visiTime = 600) { m_visiTime = visiTime; } virtual bool DoProcess(DWORD dwTime) { m_curTime = dwTime; if(m_startTime == 0) { m_startTime = m_curTime; return true; } DWORD timeDiff = m_curTime - m_startTime; float fRatio = getClampRatio(timeDiff, m_visiTime); m_pParent->ChangePrimitiveAlpha(1.f - fRatio); return fRatio < 1.f; } private: DWORD m_visiTime; }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // KUIControlDamageText Implement ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "KUIWndManager.h" namespace CONTROL_DAMAGE_TEXT { KUIWnd* DamageTextCreator() { return new KUIControlDamageText; } bool bRegister = KUIFactory::GetInstance()->RegisterCreator( DamageTextCreator, "damage_text"); KUIControlDamageText* CreateDamageText(KUIWnd* pParent, KUIWndManager* pManager, LPCSTR aniName, int x, int y) { KUIWND_CREATE_ARG arg; arg.lpszAniName = aniName; arg.lpszClassName = "damage_text"; arg.pParent = pParent; arg.rcRect = KRect(x,y,-1,-1); arg.lpszID = "_damage_text_id"; arg.lpszSprName = pParent->GetSprName(); return static_cast( pManager->CreateControl(arg) ); } } KUIControlDamageText::KUIControlDamageText() { } KUIControlDamageText::~KUIControlDamageText() { SAFE_DELETE_VECTOR(m_vtProcess); } void KUIControlDamageText::Process(DWORD dwTime) { if(IsActivate() ) { bool isValid = m_vtProcess.empty(); for(size_t i = 0; i < m_vtProcess.size(); ++i) { isValid |= m_vtProcess.at(i)->DoProcess(dwTime); } if(false == isValid) { SetActivate(false); SetDestroy(true); } } } void KUIControlDamageText::Render(KViewportObject * pViewport, bool isFront) { if(IsActivate()) { KUIControl::Render(pViewport, isFront); } } void KUIControlDamageText::OnAlphaChangeNotify(float fAlpha) { KUIWnd::OnAlphaChangeNotify(fAlpha); } void KUIControlDamageText::ChangePrimitiveAlpha(float fAlpha) { for(int i = 0; i < m_nPieceCount; ++i) m_pSpriteList[i].SetVisibility( m_fAlpha * fAlpha); } void KUIControlDamageText::ChangeScale(float fScaleFactor) { for(int i = 0; i < m_nPieceCount; ++i) { m_pSpriteList[i].GetTransform()._11 = fScaleFactor; m_pSpriteList[i].GetTransform()._22 = fScaleFactor; } } void KUIControlDamageText::AddProcess(KDamageTextProcess* pProcess) { pProcess->SetParent(this); m_vtProcess.push_back(pProcess); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // KUIControlNumberEffectBase Implement ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// KUIControlNumberEffectBase::KUIControlNumberEffectBase(const DWORD* pStateTime, int beginState, int maxState) { m_pStateTime = pStateTime; m_dwEffectStartTime = m_dwTime = 0; m_nState = beginState; m_nMaxState = maxState; } void KUIControlNumberEffectBase::OnAlphaChangeNotify(float fAlpha) { // 외부에서 Sprite Primitive의 Visibility 조절을 막기 위해서 KUIWnd::OnAlphaChangeNotify(fAlpha); } void KUIControlNumberEffectBase::SetActivateChildAll(bool bActive) { std::list< KUIWnd* >::iterator it = m_listChild.begin(); for ( ; it != m_listChild.end() ; ++it ) { (*it)->SetActivate(bActive); } } void KUIControlNumberEffectBase::_CheckNextState(DWORD dwTimeDiff) { if(m_nState < m_nMaxState && dwTimeDiff >= m_pStateTime[m_nState]) { m_dwEffectStartTime = m_dwTime; m_nState++; m_ptOldPos = KPoint( m_rcRegion.left, m_rcRegion.top ); } } void KUIControlNumberEffectBase::_ChangeAlpha(float fAlpha) { for(size_t i = 0; i < m_vtPrNumberAdoptor.size(); ++i) { m_vtPrNumberAdoptor.at(i)->SetVisibility(m_fAlpha * fAlpha); } } // Child 한테 notify 안가고 Mover에만 Notify를 주기 위해서 void KUIControlNumberEffectBase::_MovePos(int x, int y) { int offsetx = x - m_rcRegion.left; int offsety = y - m_rcRegion.top; m_rcRegion.left += offsetx; m_rcRegion.top += offsety; m_rcRegion.right += offsetx; m_rcRegion.bottom += offsety; for(size_t i = 0; i < m_vtSprite.size(); ++i) m_vtPrNumberAdoptor.at(i)->SetAddPosition(offsetx,offsety); for(size_t i = 0; i < m_vtAdditionalControlMover.size(); ++i) m_vtAdditionalControlMover.at(i)->OnParentPosChangeNotify(offsetx,offsety); } void KUIControlNumberEffectBase::_CheckDestroy() { if(false == m_bDestroy && m_nMaxState == m_nState) { bool bDestroy = true; std::list< KUIWnd* >::iterator it = m_listChild.begin(); for ( ; it != m_listChild.end() ; ++it ) { bDestroy &= (*it)->IsDestroy(); } SetDestroy(bDestroy); if(bDestroy) { int x = 5; } } } void KUIControlNumberEffectBase::_initControl() { KUIControlNumber::_initControl(); m_vtStartTiemPerObject.resize(m_vtPrNumberAdoptor.size(), 0); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // KUIControlDamageExtra Implement ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class KUIControlDamageExtra : public KUIControlDamage { public: virtual void Process(DWORD dwTime) { if(IsActivate()) KUIControlDamage::Process(dwTime); } virtual void Render(KViewportObject * pViewport, bool isFront /* = false */) { if(IsActivate()) KUIControlDamage::Render(pViewport,isFront); } void AddPlusMark(LPCSTR plusMarkAniName) { KResSprite* pRes = KSpriteManager::GetManager()->GetResSprite(m_sSprName.c_str(), plusMarkAniName, 0); KSpritePrimitive* pPlusMark = new KSpritePrimitive; pPlusMark->SetRenderEnable(true); pPlusMark->SetRes(pRes); pPlusMark->SetPosition(m_rcRegion.left, m_rcRegion.top, m_fZPos); for(size_t i = 0; i < m_vtPrNumberAdoptor.size(); ++i) { m_vtPrNumberAdoptor.at(i)->SetAddPosition(pRes->GetSizeX(), 0, 0); } m_vtPrNumberAdoptor.push_back(pPlusMark); m_vtStartTiemPerObject.push_back(0); _registerSprite(pPlusMark); } }; /* namespace CONTROL_DAMAGE_EXTRA { KUIWnd* DamageExtraCreator() { return new KUIControlDamageExtra; } bool bRegister = KUIFactory::GetInstance()->RegisterCreator( DamageExtraCreator, "damage_extra"); KUIControlDamageExtra* CreateExtraDamage(LPCSTR plusAniName, LPCSTR aniName, LPCSTR damage, KUIWnd* pParent, KUIWndManager* pManager) { KUIWND_CREATE_ARG arg; arg.lpszAniName = aniName; arg.lpszClassName = "damage_extra"; arg.pParent = pParent; // AziaMafia FixSkill //arg.rcRect = KRect(pParent->GetRect().right, pParent->GetRect().top, -1, -1); arg.rcRect = KRect(pParent->GetRect().right, pParent->GetRect().top + 10, -1, -1); arg.lpszID = "_damage_extra_id"; arg.lpszSprName = pParent->GetSprName(); arg.lpszCaption = damage; KUIControlDamageExtra* pExtraDamage = static_cast( pManager->CreateControl(arg) ); pExtraDamage->AddPlusMark(plusAniName); return pExtraDamage; } } */ namespace CONTROL_DAMAGE_EXTRA { KUIWnd* DamageExtraCreator() { return new KUIControlDamageExtra; } bool bRegister = KUIFactory::GetInstance()->RegisterCreator(DamageExtraCreator, "damage_extra"); KUIControlDamageExtra* CreateExtraDamage(LPCSTR plusAniName, LPCSTR aniName, LPCSTR damage, KUIWnd* pParent, KUIWndManager* pManager) { KUIWND_CREATE_ARG arg; arg.lpszAniName = aniName; arg.lpszClassName = "damage_extra"; arg.pParent = pParent; arg.rcRect = KRect(pParent->GetRect().right, pParent->GetRect().top, -1, -1); arg.lpszID = "_damage_extra_id"; arg.lpszSprName = pParent->GetSprName(); arg.lpszCaption = damage; KUIControlDamageExtra* pExtraDamage = static_cast(pManager->CreateControl(arg)); pExtraDamage->AddPlusMark(plusAniName); return pExtraDamage; } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // KUIControlDamage Implement ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// namespace CONTROL_DAMAGE { KUIWnd* DamageCreator() { return new KUIControlDamage; } bool bRegister = KUIFactory::GetInstance()->RegisterCreator( DamageCreator, "damage"); enum DAMAGE_STATE { STATE_BEGIN = 0 , // 맨처음 시작할때 STATE_POPUP, // 숫자 하나 하나가 Scale 되는 상태 STATE_NORMAL, // 그냥 떠있는 상태 STATE_POPDOWN, // 점점 사라짐. TOTAL_STATE, }; DWORD STATE_TIME[TOTAL_STATE] = { 0, 0, 150, 750, }; struct SCALE_INFO { SCALE_INFO() { POPUP_SCALE_UP_TIME = 150; POPUP_SCALE_DOWN_TIME = 140; NEXT_POPUP_TIME = 80; SCALE_UP_FACTOR = 1.4f; SCALE_DOWN_FACTOR = 0.7f; } DWORD POPUP_SCALE_UP_TIME; DWORD POPUP_SCALE_DOWN_TIME; DWORD NEXT_POPUP_TIME; float SCALE_UP_FACTOR; float SCALE_DOWN_FACTOR; }; const SCALE_INFO DAMAGE_SCALE_INFO; const float MOVE_PER_SEC_IN_Y_AXIS = -0.15f; void scalePerObject(DWORD time, size_t size, KSpritePrimitive** ppAdoptorArray, DWORD* pTimeArray, const SCALE_INFO& info, float baseAlpha) { if(size == 0 || pTimeArray == NULL ) return; // 끝에 있는 녀석이 앞에 나오는 놈이다. bool bPopupFlag = true; // 다음번 숫자를 Popup시켜야 하는지를 Check for(int i = static_cast( size - 1 ); i >= 0; --i) { if(pTimeArray[i] == 0) { if(false == bPopupFlag) break; pTimeArray[i] = time; KSpritePrimitive* pPrimitive = ppAdoptorArray[i]; pPrimitive->GetTransform()._11 = info.SCALE_DOWN_FACTOR; pPrimitive->GetTransform()._22 = info.SCALE_DOWN_FACTOR; pPrimitive->SetRenderEnable( true ); break; } DWORD timeDiff = time - pTimeArray[i]; float fScaleFactor = 1.f; bPopupFlag = timeDiff > info.NEXT_POPUP_TIME; if(timeDiff > info.POPUP_SCALE_UP_TIME) { timeDiff -= info.POPUP_SCALE_UP_TIME; float fRatio = getClampRatio(timeDiff, info.POPUP_SCALE_DOWN_TIME); fScaleFactor = info.SCALE_UP_FACTOR- (info.SCALE_UP_FACTOR - 1.f) * fRatio; // 줄어들기 } else { float fRatio = getClampRatio(timeDiff, info.POPUP_SCALE_UP_TIME); fScaleFactor = info.SCALE_DOWN_FACTOR + (info.SCALE_UP_FACTOR - info.SCALE_DOWN_FACTOR) * fRatio; // 작은데서 늘어나기 } KSpritePrimitive* pPrimitive = ppAdoptorArray[i]; pPrimitive->GetTransform()._11 = fScaleFactor; pPrimitive->GetTransform()._22 = fScaleFactor; pPrimitive->SetVisibility(baseAlpha); } } } KUIControlDamage::KUIControlDamage() : KUIControlNumberEffectBase(CONTROL_DAMAGE::STATE_TIME, CONTROL_DAMAGE::STATE_BEGIN, CONTROL_DAMAGE::TOTAL_STATE) { SetGap(-3); } KUIControlDamage::~KUIControlDamage() { } void KUIControlDamage::Process(DWORD dwTime) { if( m_vtPrNumberAdoptor.empty() ) { // assert(false == m_vtPrNumberAdoptor.empty() ); SetDestroy( true ); return; } using namespace CONTROL_DAMAGE; KUIControlNumberEffectBase::Process( dwTime ); m_dwTime = dwTime; DWORD dwTimeDiff = m_dwTime - m_dwEffectStartTime; DWORD dwTimeDiffClamp = std::min(dwTimeDiff, STATE_TIME[m_nState] ); switch(m_nState) { case STATE_BEGIN: break; case STATE_POPUP: { // popup은 갯수별로 계산되어야 하므로 _MovePos( m_ptOldPos.x , m_ptOldPos.y + MOVE_PER_SEC_IN_Y_AXIS * dwTimeDiff); scalePerObject(m_dwTime, m_vtPrNumberAdoptor.size(), &m_vtPrNumberAdoptor.front(), &m_vtStartTiemPerObject.front(), DAMAGE_SCALE_INFO, m_fAlpha); } break; case STATE_NORMAL: { _MovePos( m_ptOldPos.x, m_ptOldPos.y + MOVE_PER_SEC_IN_Y_AXIS * dwTimeDiffClamp); } break; case STATE_POPDOWN: { float fStateInc = getClampRatio(dwTimeDiff, STATE_TIME[m_nState]); _ChangeAlpha( 1 - fStateInc); _MovePos( m_ptOldPos.x, m_ptOldPos.y + MOVE_PER_SEC_IN_Y_AXIS * dwTimeDiffClamp); } break; } _CheckDestroy(); _CheckNextState(dwTimeDiff); } void KUIControlDamage::AddDamageEtcText(LPCSTR aniName, LPCSTR perfectAni) { KUIWND_CREATE_ARG arg; arg.lpszAniName = aniName; arg.lpszClassName = "damage_etc"; arg.pParent = this; arg.rcRect = KRect(m_rcRegion.left, m_rcRegion.top, -1, -1); arg.lpszID = "_damage_etc_id"; arg.lpszSprName = GetSprName(); KUIControlDamageEtc* pPerfect = static_cast( m_pManager->CreateControl(arg) ); if(NULL != perfectAni) { pPerfect->AddPerfectText(perfectAni); } } void KUIControlDamage::AddExtraDamage(LPCSTR plusAniName, LPCSTR aniName, LPCSTR damageText) { _RegisterMover( CONTROL_DAMAGE_EXTRA::CreateExtraDamage(plusAniName,aniName,damageText, this, m_pManager) ); } void KUIControlDamage::_initControl() { KUIControlNumberEffectBase::_initControl(); size_t numberCount = m_vtPrNumberAdoptor.size(); for(size_t i = 0; i < numberCount; ++i) m_vtPrNumberAdoptor.at(i)->SetRenderEnable(false); #ifdef _DAMAGE_TEST if(m_sID != "_damage_extra_id") AddDamageEtcText("font_white_resist00"); if(m_sID != "_damage_extra_id") AddExtraDamage("font_add_red_plus", "font_addnumber_red", m_sCaption.c_str()); #endif } void KUIControlDamage::_CheckNextState(DWORD dwTimeDiff) { using namespace CONTROL_DAMAGE; if(m_nState != STATE_POPUP) { KUIControlNumberEffectBase::_CheckNextState(dwTimeDiff); } else { if(m_vtStartTiemPerObject.empty() ) return ; DWORD lastTime = m_vtStartTiemPerObject.front(); if( lastTime != 0 && (m_dwTime - lastTime) > DAMAGE_SCALE_INFO.POPUP_SCALE_DOWN_TIME + DAMAGE_SCALE_INFO.POPUP_SCALE_UP_TIME) { m_dwEffectStartTime = m_dwTime; m_nState++; m_ptOldPos = KPoint( m_rcRegion.left, m_rcRegion.top ); // Extra Damage Active SetActivateChildAll(true); } } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // KUIControlDamageCritical Implement ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// namespace CONTROL_DAMAGE_CRITICAL { KUIWnd* DamageCriticalCreator() { return new KUIControlDamageCritical; } bool bRegister = KUIFactory::GetInstance()->RegisterCreator( DamageCriticalCreator, "damage_critical"); enum DAMAGE_STATE { STATE_BEGIN = 0 , // 맨처음 시작할때 STATE_POPUP, // 숫자 하나 하나가 Scale 되는 상태 STATE_POPDOWN, // Alpha 사라짐 TOTAL_STATE, }; DWORD STATE_TIME[TOTAL_STATE] = { 0, 0, 600, }; struct POPUP_INFO { POPUP_INFO() { POPUP_TIME = 360; NEXT_POPUP_TIME = 120; POPUP_SCALE_FACTOR = 3.3f; POPUP_MOVE_FACTOR = 30; } DWORD POPUP_TIME; DWORD NEXT_POPUP_TIME; float POPUP_SCALE_FACTOR; int POPUP_MOVE_FACTOR; }; CONTROL_DAMAGE::SCALE_INFO CRITICAL_SCALE_INFO; POPUP_INFO CRITICAL_POPUP_INFO; struct NULL_OPERATOR { bool operator()(size_t idx) const { return true; } }; NULL_OPERATOR* NULL_OP = NULL; template void popupPerObject(DWORD time, size_t size, KSpritePrimitive** ppAdoptorArray, DWORD* pTimeArray, int* pXPosArray, const POPUP_INFO& info, float baseAlpha, T* pPopupStartOperator) { if( size <= 0 ) return; float fHalfSize = static_cast(size) / 2.f; // 끝에 있는 녀석이 앞에 나오는 놈이다. bool bPopupFlag = true; // 다음번 숫자를 Popup시켜야 하는지를 Check size_t rightOffsetSize = 0; for(int i = static_cast(size - 1); i >= 0; --i) { if(pPopupStartOperator) bPopupFlag &= pPopupStartOperator->operator()(i); if(pTimeArray[i] == 0 ) { if(bPopupFlag == false) break; pTimeArray[i] = time; ppAdoptorArray[i]->SetRenderEnable(true); break; } DWORD timeDiff = time - pTimeArray[i]; bPopupFlag = timeDiff > info.NEXT_POPUP_TIME; float fRatio = getClampRatio(timeDiff, info.POPUP_TIME); float fScaleFactor = 1.f + (info.POPUP_SCALE_FACTOR - 1.f) * fRatio; KSpritePrimitive* pPrimitive = ppAdoptorArray[i]; pPrimitive->GetTransform()._11 = fScaleFactor; pPrimitive->GetTransform()._22 = fScaleFactor; pPrimitive->SetVisibility( (1.f - fRatio) * baseAlpha); if(fRatio == 1.f) pPrimitive->SetRenderEnable( false ); float fOrder = fHalfSize - i - 1; int moveFactor = fOrder * info.POPUP_MOVE_FACTOR * fRatio; // 늘어난 녀석들의 길이 관리. if(i < fHalfSize) { moveFactor = rightOffsetSize + info.POPUP_MOVE_FACTOR * .5f * fRatio; rightOffsetSize += info.POPUP_MOVE_FACTOR * fRatio; } pPrimitive->GetTransform()._41 = pXPosArray[i] + moveFactor; } } } KUIControlDamageCritical::KUIControlDamageCritical() : KUIControlNumberEffectBase(CONTROL_DAMAGE_CRITICAL::STATE_TIME, CONTROL_DAMAGE_CRITICAL::STATE_BEGIN, CONTROL_DAMAGE_CRITICAL::TOTAL_STATE) { SetGap(-5); } void KUIControlDamageCritical::Process(DWORD dwTime) { if( m_vtPrNumberAdoptor.empty() ) { // assert(false == m_vtPrNumberAdoptor.empty() ); SetDestroy( true ); return; } using namespace CONTROL_DAMAGE_CRITICAL; KUIControlNumberEffectBase::Process( dwTime ); m_dwTime = dwTime; DWORD dwTimeDiff = m_dwTime - m_dwEffectStartTime; DWORD dwTimeDiffClamp = std::min(dwTimeDiff, STATE_TIME[m_nState] ); float fRatio = getClampRatio(dwTimeDiff, STATE_TIME[m_nState] ); size_t halfSize = m_vtPrNumberAdoptor.size() / 2; switch(m_nState) { case STATE_BEGIN: break; case STATE_POPUP: CRITICAL_SCALE_INFO.NEXT_POPUP_TIME = 120; CRITICAL_SCALE_INFO.POPUP_SCALE_UP_TIME = 185; CRITICAL_SCALE_INFO.POPUP_SCALE_DOWN_TIME = 175; _MovePos( m_ptOldPos.x, m_ptOldPos.y + CONTROL_DAMAGE::MOVE_PER_SEC_IN_Y_AXIS * dwTimeDiff); CONTROL_DAMAGE::scalePerObject(m_dwTime, halfSize, &m_vtPrNumberAdoptor.front(),&m_vtStartTiemPerObject.front(), CRITICAL_SCALE_INFO, m_fAlpha); popupPerObject(m_dwTime, halfSize, &m_vtPrNumberAdoptor.at(halfSize),&m_vtStartTiemPerObject.at(halfSize), &m_vtXPosPerObject.front(), CRITICAL_POPUP_INFO, m_fAlpha, NULL_OP); break; case STATE_POPDOWN: _MovePos( m_ptOldPos.x, m_ptOldPos.y + CONTROL_DAMAGE::MOVE_PER_SEC_IN_Y_AXIS * dwTimeDiffClamp); _ChangeAlpha(1.f - fRatio); break; } _CheckDestroy(); _CheckNextState(dwTimeDiff); } void KUIControlDamageCritical::OnPosChangeNofity(int XOffset, int YOffset) { KUIControlNumberEffectBase::OnPosChangeNofity(XOffset,YOffset); size_t count = m_vtXPosPerObject.size(); for(size_t i = 0; i < count; ++i) { KSpritePrimitive* pSource = m_vtPrNumberAdoptor.at(i ); m_vtXPosPerObject.at(i) = pSource->GetTransform()._41; } } void KUIControlDamageCritical::AddCriticalText(LPCSTR aniName) { KUIControlDamageText *pText = CONTROL_DAMAGE_TEXT::CreateDamageText(this, m_pManager, aniName, m_rcRegion.left, m_rcRegion.top); pText->AddProcess(new KDamageTextProcessScale); pText->AddProcess(new KDamageTextProcessVisi); pText->SetActivate(true); int offset = - ( pText->GetRect().GetWidth() - m_rcRegion.GetWidth() ) / 2; pText->MovePosOffset(offset,0); } void KUIControlDamageCritical::AddExtraDamage(LPCSTR plusAniName, LPCSTR aniName, LPCSTR damageText) { _RegisterMover( CONTROL_DAMAGE_EXTRA::CreateExtraDamage(plusAniName,aniName,damageText, this, m_pManager) ); } void KUIControlDamageCritical::_initControl() { KUIControlNumberEffectBase::_initControl(); size_t numberCount = m_vtPrNumberAdoptor.size(); for(size_t i = 0; i < numberCount; ++i) { KSpritePrimitive* pSource = m_vtPrNumberAdoptor.at(i ); pSource->SetRenderEnable(false); m_vtXPosPerObject.push_back(pSource->GetTransform()._41 ); // 여분의 양을 복사 KSpritePrimitive* pClone = new KSpritePrimitive; pClone->SetRenderEnable(false); pClone->SetRes(pSource->GetRes()); pClone->SetPosition(pSource->GetPosition() ); m_vtPrNumberAdoptor.push_back(pClone); _registerSprite(pClone); } // 이것도 다시 설정 m_vtStartTiemPerObject.resize(m_vtPrNumberAdoptor.size(), 0); #ifdef _DAMAGE_TEST AddCriticalText("font_red_critical00"); if(m_sID != "_damage_extra_id") AddExtraDamage("font_add_red_plus", "font_addnumber_red", m_sCaption.c_str()); #endif } void KUIControlDamageCritical::_CheckNextState(DWORD dwTimeDiff) { using namespace CONTROL_DAMAGE_CRITICAL; if(m_nState != STATE_POPUP) { KUIControlNumberEffectBase::_CheckNextState(dwTimeDiff); } else { if(m_vtStartTiemPerObject.empty() ) return ; DWORD lastTime = m_vtStartTiemPerObject.front(); if( lastTime != 0 && (m_dwTime - lastTime) > CRITICAL_POPUP_INFO.POPUP_TIME) { m_dwEffectStartTime = m_dwTime; m_nState++; m_ptOldPos = KPoint( m_rcRegion.left, m_rcRegion.top ); // Extra Damage Activate SetActivateChildAll(true); } } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // KUIControlHealing Implement ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// namespace CONTROL_HEALING { KUIWnd* HealingCreator() { return new KUIControlHealing; } bool bRegister = KUIFactory::GetInstance()->RegisterCreator( HealingCreator, "healing"); enum HEALING_STATE { STATE_BEGIN , // 맨처음 시작할때 STATE_POPUP, // 숫자 하나 하나가 올라갔다가 내려오는 상태 STATE_POPDOWN, // 점점 사라짐. TOTAL_STATE, }; DWORD STATE_TIME[TOTAL_STATE] = { 0, 0, 750, }; enum MOVE_TIME { MOVE_UP =0, MOVE_DOWN, SHAKE_UP, SHAKE_DOWN, TOTAL_TIME, }; int getCurMoveTypeByTimeDiff(DWORD* pTimeDiff, DWORD* pMoveTimeTable) { int tableIndex = 3; DWORD timeSum = 0; for(int i = 0; i < TOTAL_TIME; ++i) { if(*pTimeDiff < timeSum) { tableIndex = i - 1; *pTimeDiff -= (timeSum - pMoveTimeTable[i - 1]); return tableIndex; } timeSum += pMoveTimeTable[i]; } *pTimeDiff = pMoveTimeTable[TOTAL_TIME - 1]; return tableIndex; } int getHeightOffsetByType(int type, int* pMoveHeightTable) { int sum = 0; for(int i = 0; i < type; ++i) sum += pMoveHeightTable[i]; return sum; } struct JUMP_INFO { JUMP_INFO(DWORD* pTimeTable, int* pHeightTable, DWORD nextPopupTime) { MOVE_TIME_TABLE = pTimeTable; MOVE_HEIGHT_TABLE = pHeightTable; NEXT_POPUP_TIME = nextPopupTime; } DWORD* MOVE_TIME_TABLE; int* MOVE_HEIGHT_TABLE; DWORD NEXT_POPUP_TIME; }; DWORD MOVE_TIME_TABLE[TOTAL_TIME] = { 150, 250, 100, 100, }; int MOVE_HEIGHT_TABLE[TOTAL_TIME] = { -40, 67, -12, 12, }; const DWORD POPUP_MOVE_TOTAL_TIME = MOVE_TIME_TABLE[MOVE_UP] + MOVE_TIME_TABLE[MOVE_DOWN]; const DWORD POPUP_SHAKE_TOTAL_TIME = MOVE_TIME_TABLE[SHAKE_UP] + MOVE_TIME_TABLE[SHAKE_DOWN]; const DWORD POPUP_TOTAL_TIME = POPUP_MOVE_TOTAL_TIME + POPUP_SHAKE_TOTAL_TIME; JUMP_INFO HEALING_JUMP_INFO(MOVE_TIME_TABLE, MOVE_HEIGHT_TABLE, 50); void jumpPerObject(DWORD time, size_t size, KSpritePrimitive** ppAdoptorArray, DWORD* pTimeArray, int topPosition, const JUMP_INFO& info) { if(size == 0) return ; // 끝에 있는 녀석이 앞에 나오는 놈이다. bool bPopupFlag = true; // 다음번 숫자를 Popup시켜야 하는지를 Check for(int i = static_cast( size - 1); i >= 0; --i) { if(pTimeArray[i] == 0) { if(false == bPopupFlag) break; pTimeArray[i] = time; break; } DWORD timeDiff = time - pTimeArray[i]; bPopupFlag = timeDiff > info.NEXT_POPUP_TIME; int moveOffset = 0; int moveType = getCurMoveTypeByTimeDiff(&timeDiff, info.MOVE_TIME_TABLE); int startOffset = getHeightOffsetByType(moveType, info.MOVE_HEIGHT_TABLE); int height = info.MOVE_HEIGHT_TABLE[moveType]; switch(moveType) { case MOVE_UP: moveOffset = height * getClampRatioSqrt(timeDiff, info.MOVE_TIME_TABLE[moveType] ); break; case SHAKE_UP: moveOffset = height * getClampRatio(timeDiff, info.MOVE_TIME_TABLE[moveType] ); break; case MOVE_DOWN: moveOffset = height * getClampRatioPow(timeDiff, info.MOVE_TIME_TABLE[moveType] ); break; case SHAKE_DOWN: moveOffset = height * getClampRatio(timeDiff, info.MOVE_TIME_TABLE[moveType] ); break; } const K3DMatrix& mat = ppAdoptorArray[i]->GetTransform(); ppAdoptorArray[i]->SetPosition(mat._41, topPosition + startOffset + moveOffset, mat._43 ); } } } KUIControlHealing::KUIControlHealing() : KUIControlNumberEffectBase(CONTROL_HEALING::STATE_TIME, CONTROL_HEALING::STATE_BEGIN, CONTROL_DAMAGE_CRITICAL::TOTAL_STATE) { SetGap(-3); } KUIControlHealing::~KUIControlHealing() { } void KUIControlHealing::Process(DWORD dwTime) { if( m_vtPrNumberAdoptor.empty() ) { // assert(false == m_vtPrNumberAdoptor.empty() ); SetDestroy( true ); return; } //using namespace CONTROL_HEALING; KUIControlNumberEffectBase::Process( dwTime ); m_dwTime = dwTime; DWORD dwTimeDiff = m_dwTime - m_dwEffectStartTime; switch(m_nState) { case CONTROL_HEALING::STATE_BEGIN: break; case CONTROL_HEALING::STATE_POPUP: { CONTROL_HEALING::jumpPerObject(m_dwTime, m_vtPrNumberAdoptor.size(), &m_vtPrNumberAdoptor.front(), &m_vtStartTiemPerObject.front(), m_rcRegion.top, CONTROL_HEALING::HEALING_JUMP_INFO); } break; case CONTROL_HEALING::STATE_POPDOWN: { float fStateInc = getClampRatio(dwTimeDiff, CONTROL_HEALING::STATE_TIME[m_nState]); _ChangeAlpha( 1 - fStateInc); } break; } _CheckDestroy(); _CheckNextState(dwTimeDiff); } int KUIControlHealing::GetEachNumberState(size_t idx) { using namespace CONTROL_HEALING; DWORD timeDiff = m_dwTime - m_vtStartTiemPerObject.at(idx); return getCurMoveTypeByTimeDiff(&timeDiff, HEALING_JUMP_INFO.MOVE_TIME_TABLE); } void KUIControlHealing::_CheckNextState(DWORD dwTimeDiff) { using namespace CONTROL_HEALING; if(m_nState != STATE_POPUP) { KUIControlNumberEffectBase::_CheckNextState(dwTimeDiff); } else { if(m_vtStartTiemPerObject.empty() ) return ; DWORD lastTime = m_vtStartTiemPerObject.front(); if( lastTime != 0 && (m_dwTime - lastTime) > POPUP_TOTAL_TIME) { m_dwEffectStartTime = m_dwTime; m_nState++; m_ptOldPos = KPoint( m_rcRegion.left, m_rcRegion.top ); } } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // KUIControlHealingMaximize Implement ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// namespace CONTROL_HEALING_MAXIMIZE { KUIWnd* HealingCreator() { return new KUIControlHealingMaximize; } bool bRegister = KUIFactory::GetInstance()->RegisterCreator( HealingCreator, "healing_maximize"); struct POPUP_OP { POPUP_OP(KUIControlHealingMaximize* pParent) { _pParent = pParent; } bool operator()(size_t idx) const { int state = _pParent->GetEachNumberState(idx); return state == CONTROL_HEALING::SHAKE_DOWN || state == CONTROL_HEALING::SHAKE_UP ; } KUIControlHealingMaximize* _pParent; }; } KUIControlHealingMaximize::KUIControlHealingMaximize() { } KUIControlHealingMaximize::~KUIControlHealingMaximize() { } void KUIControlHealingMaximize::Process(DWORD dwTime) { if( m_vtPrNumberAdoptor.empty() ) { // assert(false == m_vtPrNumberAdoptor.empty() ); SetDestroy( true ); return; } if(m_nState == CONTROL_HEALING::STATE_POPUP) { KUIControlNumberEffectBase::Process( dwTime ); m_dwTime = dwTime; size_t halfSize = m_vtPrNumberAdoptor.size() / 2; CONTROL_HEALING::jumpPerObject(m_dwTime, halfSize, &m_vtPrNumberAdoptor.front(), &m_vtStartTiemPerObject.front(), m_rcRegion.top, CONTROL_HEALING::HEALING_JUMP_INFO); CONTROL_HEALING_MAXIMIZE::POPUP_OP op(this); static CONTROL_DAMAGE_CRITICAL::POPUP_INFO info; info.NEXT_POPUP_TIME = 80; CONTROL_DAMAGE_CRITICAL::popupPerObject(m_dwTime, halfSize, &m_vtPrNumberAdoptor.at(halfSize), &m_vtStartTiemPerObject.at(halfSize), &m_vtXPosPerObject.front(), info, m_fAlpha, &op); _CheckNextState(m_dwTime); } else { KUIControlHealing::Process( dwTime ); } } void KUIControlHealingMaximize::OnPosChangeNofity(int XOffset, int YOffset) { KUIControlNumberEffectBase::OnPosChangeNofity(XOffset,YOffset); size_t count = m_vtXPosPerObject.size(); for(size_t i = 0; i < count; ++i) { KSpritePrimitive* pSource = m_vtPrNumberAdoptor.at(i ); m_vtXPosPerObject.at(pSource->GetTransform()._41 ); } } void KUIControlHealingMaximize::AddMaxHealText(LPCSTR aniName) { KUIControlDamageText *pText = CONTROL_DAMAGE_TEXT::CreateDamageText(this, m_pManager, aniName, m_rcRegion.left, m_rcRegion.top - 20); pText->AddProcess(new KDamageTextProcessScale(2.5f, 375)); pText->AddProcess(new KDamageTextProcessVisi(450)); int offset = - ( pText->GetRect().GetWidth() - m_rcRegion.GetWidth() ) / 2; pText->MovePosOffset(offset,0); } void KUIControlHealingMaximize::_initControl() { KUIControlHealing::_initControl(); size_t numberCount = m_vtPrNumberAdoptor.size(); for(size_t i = 0; i < numberCount; ++i) { KSpritePrimitive* pSource = m_vtPrNumberAdoptor.at (i ); m_vtXPosPerObject.push_back(pSource->GetTransform()._41 ); // 여분의 양을 복사 KSpritePrimitive* pClone = new KSpritePrimitive; pClone->SetRenderEnable( false ); pClone->SetRes(pSource->GetRes()); pClone->SetPosition(pSource->GetPosition() ); m_vtPrNumberAdoptor.push_back(pClone); _registerSprite(pClone); } size_t halfSize = m_vtPrNumberAdoptor.size() / 2; for(size_t i = halfSize; i < m_vtPrNumberAdoptor.size(); ++i) { KSpritePrimitive* pSource = m_vtPrNumberAdoptor.at (i ); K3DVector pos = pSource->GetPosition(); pos.y += CONTROL_HEALING::MOVE_HEIGHT_TABLE[CONTROL_HEALING::MOVE_UP] + CONTROL_HEALING::MOVE_HEIGHT_TABLE[CONTROL_HEALING::MOVE_DOWN]; pSource->SetPosition(pos); } // 이것도 다시 설정 m_vtStartTiemPerObject.resize(m_vtPrNumberAdoptor.size(), 0); AddMaxHealText("font_green_maxheal00"); } void KUIControlHealingMaximize::_CheckNextState(DWORD dwTimeDiff) { if(m_nState != CONTROL_HEALING::STATE_POPUP) { KUIControlHealing::_CheckNextState(dwTimeDiff); } else { if(m_vtStartTiemPerObject.empty() ) return ; // Time 및 Object는 반대로 배열되어 있다. 즉 // "369" 라는 숫자가 있으면 각 실제로 배열에는 [9,6,3] 의 data가 들어 있다. DWORD lastTime = m_vtStartTiemPerObject.front(); DWORD halfTime = m_vtStartTiemPerObject.at( m_vtStartTiemPerObject.size() / 2 ); DWORD firstJumpTime = m_vtStartTiemPerObject.at( m_vtStartTiemPerObject.size() / 2 - 1 ); // Popup과 Jump가 전부 끝났음.. if( lastTime != 0 && (m_dwTime - lastTime) > CONTROL_HEALING::POPUP_TOTAL_TIME && halfTime != 0 && (m_dwTime - halfTime) > CONTROL_DAMAGE_CRITICAL::CRITICAL_POPUP_INFO.POPUP_TIME ) { m_dwEffectStartTime = m_dwTime; m_nState++; m_ptOldPos = KPoint( m_rcRegion.left, m_rcRegion.top ); } // 첫번째 놈이 Jump하고 나서 적정 시간이 지나면 MaxHeal 출력 if( firstJumpTime != 0 && (m_dwTime - firstJumpTime) >= CONTROL_HEALING::POPUP_MOVE_TOTAL_TIME - 100) { SetActivateChildAll(true); } } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // KUIControlDamageEtc Implement ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// namespace CONTROL_DAMAGE_ETC { KUIWnd* DamageEtcCreator() { return new KUIControlDamageEtc; } bool bRegister = KUIFactory::GetInstance()->RegisterCreator( DamageEtcCreator, "damage_etc"); enum DAMAGE_ETC_STATE { STATE_BEGIN , // 맨처음 시작할때 STATE_MOVEUP, // 시작해서 올라갈때 STATE_MOVEDOWN, // 시작해서 떨어질때 STATE_SHAKEUP, // 튕겨서 올라감 STATE_SHAKEDOWN, // 튕겼다가 내려감 STATE_POPDOWN, // 알파로 사라짐 TOTAL_STATE, }; DWORD TIME_TABLE[TOTAL_STATE] = { 0, 100, 200, 50, 50, 750, }; int MOVE_HEIGHT_TABLE[TOTAL_STATE] = { 0, -40, 80, -12, 12, 0, }; } KUIControlDamageEtc::KUIControlDamageEtc() { m_nState = CONTROL_DAMAGE_ETC::STATE_BEGIN; m_dwEffectStartTime = 0; m_dwTime = 0; m_delayTime = 0; } KUIControlDamageEtc::~KUIControlDamageEtc() { } void KUIControlDamageEtc::Process(DWORD dwTime) { using namespace CONTROL_DAMAGE_ETC; KUIControl::Process( dwTime ); m_dwTime = dwTime; DWORD dwTimeDiff = m_dwTime - m_dwEffectStartTime; if(m_dwEffectStartTime == 0) { m_dwEffectStartTime = m_dwTime; return; } if(m_delayTime != 0) { if( dwTimeDiff > m_delayTime ) m_delayTime = 0; return; } int height = MOVE_HEIGHT_TABLE[m_nState]; switch(m_nState) { case STATE_BEGIN: #ifdef _DAMAGE_TEST if( m_sID != "_damage_perfect_id") AddPerfectText("font_white_perfect00"); #endif break; case STATE_MOVEUP: case STATE_SHAKEUP: _MovePos(m_ptOldPos.x, m_ptOldPos.y + height * getClampRatioSqrt(dwTimeDiff, TIME_TABLE[m_nState] ) ); break; case STATE_MOVEDOWN: case STATE_SHAKEDOWN: _MovePos(m_ptOldPos.x, m_ptOldPos.y + height * getClampRatioPow(dwTimeDiff, TIME_TABLE[m_nState] ) ); break; case STATE_POPDOWN: _ChangeAlpha(1.f - getClampRatio(dwTimeDiff, TIME_TABLE[m_nState]) ); break; } _CheckNextState(dwTimeDiff); } void KUIControlDamageEtc::Render(KViewportObject * pViewport, bool isFront) { if(m_delayTime == 0) KUIControl::Render(pViewport,isFront); } void KUIControlDamageEtc::OnAlphaChangeNotify(float fAlpha) { // 외부에서 Sprite Primitive의 Visibility 조절을 막기 위해서 KUIWnd::OnAlphaChangeNotify(fAlpha); } void KUIControlDamageEtc::AddPerfectText(LPCSTR aniName) { KUIWND_CREATE_ARG arg; arg.lpszAniName = aniName; arg.lpszClassName = "damage_etc"; arg.pParent = this; arg.rcRect = KRect(m_rcRegion.left + 40, m_rcRegion.top + 15, -1, -1); arg.lpszID = "_damage_perfect_id"; arg.lpszSprName = GetSprName(); KUIControlDamageEtc* pPerfect = static_cast( m_pManager->CreateControl(arg) ); pPerfect->SetDelayTime(200); } void KUIControlDamageEtc::_ChangeAlpha(float fAlpha) { for(int i = 0; i < m_nPieceCount; ++i) m_pSpriteList[i].SetVisibility( m_fAlpha * fAlpha); } void KUIControlDamageEtc::_MovePos(int x, int y) { int offsetx = x - m_rcRegion.left; int offsety = y - m_rcRegion.top; m_rcRegion.left += offsetx; m_rcRegion.top += offsety; m_rcRegion.right += offsetx; m_rcRegion.bottom += offsety; for(int i = 0; i < m_nPieceCount; ++i) m_pSpriteList[i].SetAddPosition( offsetx, offsety); } void KUIControlDamageEtc::_CheckNextState(DWORD dwTimeDiff) { if(false == m_bDestroy && CONTROL_DAMAGE_ETC::TOTAL_STATE == m_nState) { bool bDestroy = true; std::list< KUIWnd* >::iterator it = m_listChild.begin(); for ( ; it != m_listChild.end() ; ++it ) { bDestroy &= (*it)->IsDestroy(); } SetDestroy(bDestroy); } if(m_nState < CONTROL_DAMAGE_ETC::TOTAL_STATE && dwTimeDiff >= CONTROL_DAMAGE_ETC::TIME_TABLE[m_nState] ) { m_dwEffectStartTime = m_dwTime; m_nState++; m_ptOldPos = KPoint( m_rcRegion.left, m_rcRegion.top ); } }