Exemple #1
0
/**
 @brief pCenter(or vCenter)를 중심으로 radius범위내의 유닛들을 얻어 어레이에 담는다.
 @return 얻어낸 타겟수
 @param pCenter 중심타겟. null이면 vCenter를 사용한다.
 @param vCenter 중심좌표. pCenter가 있다면 사용되지 않는다.
 @param pixelRadius 픽셀단위 반지름.
 @param bitSideFilter 검색해야할 진영
 @param numCost 총 코스트값. 각 유닛은 크기 코스트가 있으며 타겟이 검색될때마다 numCost에서 차감한다. 0이되면 더이상 담지 않는다. 차감한 코스값이 마이너스가 될수는 없다.
                0은 코스트에 관계없이 무조건 타겟1개만 검색. -1은 무효값. 
 @param bIncludeCenter 중심타겟(pCenter가 있을경우)을 대상에 포함할지 말지. pCenter가 없다면 이 옵션은 무시된다.
*/
int XEObjMngWithType::GetListUnitRadius2( XVector<XSPUnit> *pOutAry,
																					XEBaseWorldObj *pCenter,
																					const XE::VEC2& vCenter,
																					float pixelRadius,
																					BIT bitSideFilter,
																					int numCost,
																					bool bIncludeCenter,
																					BIT bitFlag ) const		// 생존필터  
{
	if( numCost < 0 )
		return 0;
	//
	XVector<XSPUnit> aryInNew;				// pOutAry에 이미 타겟이 있는채로 들어왔을때 그것은 제한 리스트
	XVector<XSPUnit> aryIn = *pOutAry;	// 기존타겟에 반경검사타겟까지 포함.
	int costSum = 0;
	for( auto spUnit : m_listUnits ) {
		if( spUnit->IsDestroy() )
			continue;
		XBREAK( spUnit == nullptr );
		if( (spUnit->GetCamp() & bitSideFilter) == 0 )
			continue;
		if( (bitFlag & XSKILL::xTF_LIVE) == 0 && spUnit->IsLive() )
			continue;
		if( (bitFlag & XSKILL::xTF_DEAD) == 0 && spUnit->IsDead() )
			continue;
		// 시전대상을 포함하지 않는 조건일때 유닛이 시전대상이면 스킵
		if( pCenter
				&& pCenter->GetsnObj() == spUnit->GetsnObj()		// spUnit이 중심타겟일때
				&& bIncludeCenter == false )										// 중심타겟안포함 옵션이면 스킵한다.
			continue;
		if( bitFlag & XSKILL::xTF_DIFF_SQUAD ) {
			// spUnit이 이미 찾은 유닛과 같은 부대면 스킵
			bool bExisted = false;
			for( auto& spFinded : aryIn ) {
				if( spUnit->GetpSquadObj()->GetsnSquadObj() == spFinded->GetpSquadObj()->GetsnSquadObj() ) {
					bExisted = true;
					break;
				}
			}
			if( bExisted )
				continue;
		}
		const XE::VEC2 vDist = spUnit->GetvwPos().ToVec2() - vCenter;
		const float distsq = vDist.Lengthsq();
		// 코스트와 관계없이 일단 범위안에 들어가는 타겟은 모두 담은후 거기서 다시 코스트에 따라 랜덤으로 꺼낸다.
		if( distsq <= pixelRadius * pixelRadius ) {
			aryIn.Add( spUnit );
			aryInNew.Add( spUnit );
			costSum += spUnit->GetSizeCost();		// 배열에 들어간 유닛들의 토탈코스트
		} // in radius
	} // for
	// 목표코스트를 다 채우지 못했거나 딱맞게 채웠을때는 전체 리스트에서 랜덤으로 뽑을필요가 없으므로 그냥 검색된 리스트를 모두 리턴한다.
	if( costSum <= numCost ) {
		*pOutAry = aryIn;
		return pOutAry->Size();
	}
	int currCost = numCost;
// 	XVector<XSPUnit> ary = *pOutAry;
// 	pOutAry->Clear();
	// 영역안에 들어온 타겟들을 대상으로 다시 코스트에 따라 실제 타겟을 선정한다.
	while( aryInNew.Size() > 0 ) {
		auto spUnit = aryInNew.PopFromRandom();
		if( numCost == 0 ) {
			if( pOutAry->Size() == 0 )
				pOutAry->Add( spUnit );
			return 1;
		} else {
			const auto costUnit = spUnit->GetSizeCost();
			if( costUnit <= currCost ) {
				// 유닛 코스트가 남은 코스트를 깔수 있을때만.
				currCost -= costUnit;
				XBREAK( currCost < 0 );
				pOutAry->Add( spUnit );
				if( currCost == 0 )				// 코스트를 다 채웠으면 리턴.
					return pOutAry->Size();
			}
		}
	}
	return pOutAry->size();
}