/** ******************************************************************************* @file /gui/model/UnitFormation.cpp @brief Formace jednotky, razeni vojacku v utvarech @author Vajicek @version 0.1 ******************************************************************************/ #include #include #include "gui/model/UnitFormation.h" #include "gui/model/guiUnit.h" #include "gui/model/guiBuilding.h" #include "gui/model/guimap.h" #include "gui/common/mymath_ext.h" #include "common/Log.h" //----------------------------------------------------------------------------- namespace gui{ //vrati velikost prekryvu ku dylce dobou intervalu float intersectionRatio1D(float a1, float a2, float b1, float b2) { float c; if(a1>a2){c=a1;a1=a2;a2=c;} if(b1>b2){c=b1;b1=b2;b2=c;} //inkluze a v b if((a1 <= b1) && (b2 <= a2)) return b2-b1; //inkluze b v a if((b1 <= a1) && (a2 <= b2)) return a2-a1; //prunik a a b if(a1 < b1 && b1 < a2) return (a2-b1); else if(b1 < a1 && a1 < b2) return (b2-a1); //neinkluze return 0; } float intersectionRatio(TUnitMemberPosition* a, TUnitMemberPosition* b){ TUnitMemberPosition* c; //srovnat podle y if((a->p2fPos.y-a->p2fDim.y/2) > (b->p2fPos.y-b->p2fDim.y/2)) {c = a;a = b;b = c;} float yr = intersectionRatio1D( a->p2fPos.y-a->p2fDim.y/2, a->p2fPos.y+a->p2fDim.y/2, b->p2fPos.y-b->p2fDim.y/2, b->p2fPos.y+b->p2fDim.y/2); float xr = intersectionRatio1D( a->p2fPos.x-a->p2fDim.x/2, a->p2fPos.x+a->p2fDim.x/2, b->p2fPos.x-b->p2fDim.x/2, b->p2fPos.x+b->p2fDim.x/2); float r = yr * xr / MIN(b->p2fDim.x*b->p2fDim.y, a->p2fDim.x*a->p2fDim.y); return r; } //----------------------------------------------------------------------------- /* nastaveni stredu a smeru formace */ void TFormation::setStandardFormation(P2F* p, P2F* d){ //globalni poloha pro jednotku CopyV2(p2fPosition.p, p->p); CopyV2(p2fDirection.p, d->p); NormalizeV2(p2fDirection.p); #ifdef STEERING //vesak na virtualni prekazky TObstacle* oo[20]; int ooc = 0; TSteeringKernelController* skc = unit->map->skc; P2F pos, dir; P2F memberDim; getUnitMemberDim(0, &memberDim); float r = SizeV2(memberDim.p)/2; //pro "size" pozic vumpPositions_c = 0; int size = (int)unit->vMembers.size(); for(int i = 0; i < size; i++) { //najdi spravnou pozici getStandardFormationMemberPos(i, &pos, &dir); //vytvor virtualni prekazku oo[ooc] = new TObstacle(&pos, r*1.1f); //najdi nejblizsi volnou if(skc->Root)skc->findNearestFreePosition(oo[ooc]); //vloz virtualni prekazku if(skc->Root)skc->insertObstacle(oo[ooc]); //vloz do formace vumpPositions[vumpPositions_c].p2fDir=dir; vumpPositions[vumpPositions_c].p2fDim=memberDim; vumpPositions[vumpPositions_c].p2fPos=oo[ooc]->p2fPosition; vumPositionUsed[vumpPositions_c] = NULL; vumpPositions_c++; ooc++; } //zrus virtualni prekazky for(int k = 0; k < ooc; k++) { if(skc->Root)skc->removeObstacle(oo[k]); delete oo[k]; } #else //vypocti polohy pro cleny TUnitMemberPosition ump; vumpPositions_c = 0; getUnitMemberDim(0, &ump.p2fDim); int size = (int)unit->vMembers.size(); for(int i = 0; i < size; i++) { findFreeMemberPosition(vumpPositions_c, &(ump.p2fPos), &(ump.p2fDir)); vumpPositions[vumpPositions_c] = ump; vumPositionUsed[vumpPositions_c] = NULL; vumpPositions_c++; } #endif } void TFormation::setStandardFormation(int hexindex, int dir){ //TODO: doimplementovat //setStandardFormation(P2F* p, P2F* d); } /* poloha a smer formace jednotky */ void TFormation::getUnitPos(P2F* p, P2F* d){ CopyV2(p->p, p2fPosition.p); CopyV2(d->p, p2fDirection.p); } void TFormation::setToFormation(){ TUnitMember* unitmember; P3F p = {0, 0, 0}; P3F d = {0, 0, 0}; P3F u = {0, 0, 1}; //najdi clena pro kazdou pozici vunitmember::iterator m_it = unit->vMembers.begin(); for(int i = 0; i < vumpPositions_c; i++) { unitmember = *m_it; // findFreeMemberPosition(i, &(p.p2f), &(d.p2f)); //nastav pozici unitmember->calculateAABB(); unitmember->place(&p, &d, &u); // m_it++; } } TUnitMember* TFormation::getUnitMember(int no){ vunitmember::iterator m_it = unit->vMembers.begin(); while( m_it != unit->vMembers.end() && no ) { m_it++; no--; } if(m_it == unit->vMembers.end())return NULL; return *m_it; } /* rozmery prumerne jednotky ve formaci jednotky */ void TFormation::getUnitMemberDim(int no, P2F* dim){ getUnitMember(no)->getModelDim(dim); } /* nastavi tereni prekazky */ void TFormation::avoidTerrainObstacles(TTerrainEntity* ter) { terrain_obstacle = ter; } /* najde 2d reseni nejblizsiho volneho bodu k prekazce terrain_obstacle */ void TFormation::findFreeMemberPosition(int no, P2F* pos, P2F* dir){ //spravna pozice ve formaci getStandardFormationMemberPos(no, pos, dir); //pokud jednotce prekazi prekazka if(terrain_obstacle){ P3F p3f1 = {pos->x, pos->y, 0}; P3F p3f2 = {0, 0, 0}; terrain_obstacle->findClosestFreePosition(getUnitMember(no), &p3f1, &p3f2); CopyV2(pos->p, p3f2.p); } } TFormation::TFormation(TUnit* un){ unit = un; SETV2(p2fPosition.p, 0,0); SETV2(p2fDirection.p, 0,1); // terrain_obstacle = NULL; // vumpPositions_c = 0; } //----------------------------------------------------------------------------- /* vypocte muze v rade - charakteristika formace */ int TRowFormation::getMenInRow(){ return unit->guiuiInfo.iMenInRow; } int TRowFormation::getRowCount(){ int mir = getMenInRow(); int menCount = unit->getUnitMemberCount(); return (int)ceil(menCount/((float)mir)); } /* melo by spocitat nejvhodnejsiho clena pro nahrazeni */ int TRowFormation::getNearestMemberWithHighestNo(int no){ return 0; } TRowFormation::TRowFormation(TUnit* un) :TFormation(un) { } //----------------------------------------------------------------------------- void THorseFormation::getStandardFormationMemberPos(int no, P2F* p, P2F* d){ int mir = getMenInRow(); float row = (float)(no/mir); float col = (float)(no%mir); int menCount = unit->getUnitMemberCount(); P2F memberDim; getUnitMemberDim(0, &memberDim); // int rowCount = (int)ceil(menCount/(float)mir); int menInLastRow = menCount - (rowCount-1)*mir; //sirka & vyska jednotky int colCount = mir>menCount?menCount:mir; float uroww = memberDim.x * ( mir + 1.5f * (mir-1) ); float ucolw = memberDim.y * ( rowCount + 0.5f * (rowCount-1) ); //pozice v obdelniku float roww = (col+1-0.5f) * ( uroww/((row==rowCount-1)?menInLastRow:mir) ); float colw = -(row+1-0.5f) * ( ucolw/rowCount ); P2F c; NormalV2(p2fDirection.p, c.p); TVector scatter(RAND(-memberDim.x/2, memberDim.x/2), RAND(-memberDim.x/2, memberDim.x/2), 0); *p = (scatter + TVector(p2fPosition) + TVector(c)*(roww-uroww/2) + TVector(p2fDirection)*(colw+ucolw/2)).toP2F(); *d = p2fDirection; } THorseFormation::THorseFormation(TUnit* un) :TRowFormation(un) { } //----------------------------------------------------------------------------- /* specialni verze pro spocitani poloh v radove formaci pesaku*/ void TFootMenFormation::getStandardFormationMemberPos(int no, P2F* p, P2F* d){ int mir = getMenInRow(); float row = (float)(no/mir); float col = (float)(no%mir); int menCount = unit->getUnitMemberCount(); P2F memberDim; getUnitMemberDim(0, &memberDim); // int rowCount = (int)ceil(menCount/(float)mir); int menInLastRow = menCount - (rowCount-1)*mir; //sirka & vyska jednotky int colCount = mir>menCount?menCount:mir; float uroww = memberDim.x * ( mir + 1.0f * (mir-1) ); float ucolw = memberDim.y * ( rowCount + 1.0f * (rowCount-1) ); //pozice v obdelniku float roww = (col+1-0.5f) * ( uroww/((row==rowCount-1)?menInLastRow:mir) ); float colw = -(row+1-0.5f) * ( ucolw/rowCount ); P2F c; NormalV2(p2fDirection.p, c.p); TVector scatter(RAND(-memberDim.x/2, memberDim.x/2), RAND(-memberDim.x/2, memberDim.x/2), 0); *p = (scatter + TVector(p2fPosition) + TVector(c)*(roww-uroww/2) + TVector(p2fDirection)*(colw+ucolw/2)).toP2F(); *d = p2fDirection; } TFootMenFormation::TFootMenFormation(TUnit* un) :TRowFormation(un) { } //----------------------------------------------------------------------------- void TIndividualFormation::getStandardFormationMemberPos(int no, P2F* p, P2F* d){ CopyV2(p->p, p2fPosition.p); CopyV2(d->p, p2fDirection.p); } TIndividualFormation::TIndividualFormation(TUnit* u) :TFormation(u) { } }//namespace /*****************************************************************************/