/** ******************************************************************************* @file /gui/engine/UnitControllers.cpp @brief Kontrolery na ovladani jednotek a vojacku @author Vajicek @version 0.1 ******************************************************************************/ #include "gui/engine/UnitControllers.h" // #include "gui/common/mymath_ext.h" #include "gui/engine/SceneScripts.h" #include "gui/model/guiUnit.h" #include "gui/model/guimap.h" #include "common/Log.h" #include "common/exc.h" // #include //----------------------------------------------------------------------------- namespace gui{ //utils //----------------------------------------------------------------------------- void rotate(P2F* v, float a, P2F* r){ r->x = (float)(v->x*cos(a)+v->y*sin(a)); r->y = (float)(-v->x*sin(a)+v->y*cos(a)); } float trunc(float min, float val, float max) { return MIN(MAX(min, val), max); } //TObstacle //----------------------------------------------------------------------------- TObstacle::TObstacle(P2F* position, float radius) { if(position)p2fPosition = *position; fRadius = radius; } void TObstacle::getCenterOfGravity(P2F *position){ *position = p2fPosition; } int TObstacle::collision(TObstacle* o) { float d = DISTV2(p2fPosition.p, o->p2fPosition.p); return (d < (fRadius+o->fRadius)); } int TObstacle::collision(P2F* a) { float d = DISTV2(p2fPosition.p, a->p); return (d < fRadius); } int TObstacle::collision(float cx, float cy, float size) { return p2fPosition.x>(cx-size-fRadius) && p2fPosition.x<(cx+size+fRadius) && p2fPosition.y>(cy-size-fRadius) && p2fPosition.y<(cy+size+fRadius); } int TObstacle::collision(TQuadrant* q) { return p2fPosition.x>(q->p2fCenter.x-q->fSize/2+fRadius) && p2fPosition.x<(q->p2fCenter.x+q->fSize/2-fRadius) && p2fPosition.y>(q->p2fCenter.y-q->fSize/2+fRadius) && p2fPosition.y<(q->p2fCenter.y+q->fSize/2-fRadius); } //TAgent //----------------------------------------------------------------------------- TAgent::TAgent( TSteeringKernelController* skc, float radius, float mass, float max_speed, float max_force, float max_rotation_speed) :TObstacle(NULL, radius) { // pNextGoal = NULL; // steeringmap = skc; // fGoalSensor = radius; fOutlook = max_speed+radius; fMass = mass; fMaxForce = max_force; fMaxSpeed = max_speed; fMaxRotationSpeed = max_rotation_speed; // SETV2(p2fVelocity.p, 0, 0); } void TAgent::collisionAvoid(P2F *avoid_force) { SETV2(avoid_force->p, 0, 0); MX3 m; SetMX3(m, p2fDirection.x, p2fDirection.y, 0, p2fDirection.y, -p2fDirection.x, 0, 0, 0, 1); //projdi se zasobnikem hierarchii prekazek TQuadrant* stack[30]; int sstack = 0; float dist = FLT_MAX; //zacni u korene stack[sstack++] = steeringmap->Root; while(sstack){ //vyber vrchol zasobniku TQuadrant* q = stack[--sstack]; //je v blizkem okoli if( q->collision(p2fPosition.x, p2fPosition.y, fOutlook) ) { //pridej potomky for(int i = 0; i < 4; i++){ if(q->Subquadrant[i]) stack[sstack++] = q->Subquadrant[i]; assert(sstack<30); } //hledej prekazky ve vyhledu for(std::vector::iterator it = q->Obstacles.begin(); it != q->Obstacles.end(); it++) { TObstacle *o = (TObstacle*)(*it); if(o == this)continue; //transformace do agentova prostoru P3F w, v; SETV3(w.p, o->p2fPosition.x-p2fPosition.x, o->p2fPosition.y-p2fPosition.y, 0); ApplyVectorMX3(w.p, m, v.p); //kolize s vyhledem if(v.y<-(o->fRadius+fRadius) || v.y>(o->fRadius+fRadius))continue; if(v.x<0 || v.x>(fOutlook+o->fRadius+fRadius))continue; //smer uhybneho manevru P2F avoid_steer; SETV2(avoid_steer.p, p2fDirection.y, -p2fDirection.x); // P2F ww, gp; o->getCenterOfGravity(&gp); SETV2(ww.p, gp.x-p2fPosition.x, gp.y-p2fPosition.y); // float cosa = ScalMulV2(avoid_steer.p, ww.p); if(cosa>0)MulV2(avoid_steer.p, -1); float d = SizeV2(ww.p); if( d < dist){ dist = d; float avoid_factor = fMaxSpeed;//(fMaxSpeed/fOutlook)*(fOutlook-(d-o->fRadius-fRadius)); MulV2(avoid_steer.p, avoid_factor/SizeV2(avoid_steer.p) ); CopyV2(avoid_force->p, avoid_steer.p); } }//for }//if }//while } void TAgent::seek(P2F *seek_force) { P2F desired_velocity = *pNextGoal; SubV2(desired_velocity.p, p2fPosition.p); MulV2(desired_velocity.p, fMaxSpeed/SizeV2(desired_velocity.p)); *seek_force=desired_velocity; SubV2(seek_force->p, p2fVelocity.p); } void TAgent::truncateVelocity(P2F* new_velocity){ //orezani na max rychlost float new_velocity_size = SizeV2(new_velocity->p); NormalizeV2(new_velocity->p); MulV2(new_velocity->p, trunc(0, new_velocity_size, fMaxSpeed)); //orezani na zmenu uhlu float angle = Angle2Db(new_velocity, &p2fDirection); P2F pp; SETV2(pp.p, p2fDirection.y, -p2fDirection.x); if (angle>fMaxRotationSpeed) { //smer otaceni float rotdir = Angle2Db(&pp, new_velocity)>(1.57f)?-1.0f:1.0f; //mezni rychlost P2F rotated_dir; rotate(&p2fDirection, fMaxRotationSpeed*rotdir, &rotated_dir); //prusecik s new_velocity-Velocity P2F v = *new_velocity; SubV2(v.p, p2fVelocity.p); float u = (rotated_dir.y*p2fVelocity.x - p2fVelocity.y*rotated_dir.x)/(v.y*rotated_dir.x - rotated_dir.y*v.x); //korigovana nova rychlost *new_velocity = v; MulV2(new_velocity->p, u); AddV2(new_velocity->p, p2fVelocity.p); //rychlost if(angle>1.57){ SETV2(p2fVelocity.p, 0, 0); } else{ p2fVelocity = *new_velocity; } //smer if(SizeV2(p2fVelocity.p)>0) p2fDirection = p2fVelocity; else p2fDirection = rotated_dir; NormalizeV2(p2fDirection.p); } else { p2fVelocity = *new_velocity; p2fDirection = *new_velocity; NormalizeV2(p2fDirection.p); } } #define BURNER_HACK 8 void TAgent::steer(float frac) { P2F steer_force; SETV2(steer_force.p, 0, 0); //SEEK P2F seek_steer; seek(&seek_steer); //OBSTACLE AVOIDANCE P2F avoidance_steer; collisionAvoid(&avoidance_steer); //APPLY FORCES if(SizeV2(avoidance_steer.p)>0){ AddV2( steer_force.p, avoidance_steer.p); if(SizeV2(p2fVelocity.p) fMaxForce)MulV2(steer_force.p, fMaxForce/steer_force_size); //TRUNCATE VELOCITY P2F new_velocity = p2fVelocity; P2F velocity_dif = steer_force; MulV2(velocity_dif.p, frac); AddV2(new_velocity.p, velocity_dif.p); if(SizeV2(new_velocity.p)>0.0001) truncateVelocity(&new_velocity); //CHANGE POSITION P2F pos_dif = p2fVelocity; MulV2(pos_dif.p, frac); AddV2(p2fPosition.p, pos_dif.p); //GOAL REACHED if( DISTV2(p2fPosition.p, pNextGoal->p) < fGoalSensor ) nextGoal(); } void TAgent::clearRoute() { vRoute.clear(); vRoute.push_back(p2fPosition); pNextGoal = NULL; } void TAgent::addGoal(P2F* goal) { //pridej nakonec vRoute.push_back(*goal); } void TAgent::nextGoal() { if(pNextGoal) { //predchozi pPreviousGoal = pNextGoal; //najdi pristi for(std::vector::iterator it = vRoute.begin(); it != vRoute.end(); it++) { if(&(*it) == pNextGoal){ //posun se na dalsiho it++; if( it != vRoute.end()) pNextGoal = &(*it); else pNextGoal = NULL; break; } }//for }//if else { if(vRoute.size()>1){ pPreviousGoal = &(vRoute[0]); pNextGoal = &(vRoute[1]); } }//else } //TQuadrant //----------------------------------------------------------------------------- TQuadrant::TQuadrant(TQuadrant* parent, int q) { SETV2(p2fCenter.p, parent->p2fCenter.x + ((q%2==0)?-1:1)*parent->fSize/2, parent->p2fCenter.y + ((q<2)?-1:1)*parent->fSize/2); fSize = parent->fSize/2; for(int i = 0; i < 4 ; i++)Subquadrant[i]=NULL; Parent = parent; } TQuadrant::~TQuadrant(){ //smaz prekazky while( !Obstacles.empty() ){ TObstacle* o = *( Obstacles.begin() ); delObstacle( o ); delete o; } //smaz subkvadranty for(int i = 0; i < 4 ; i++) if(Subquadrant[i])delete Subquadrant[i]; } TQuadrant::TQuadrant(float cx, float cy, float size) { SETV2(p2fCenter.p, cx, cy); fSize = size; for(int i = 0; i < 4 ; i++)Subquadrant[i] = NULL; Parent = NULL; } TQuadrant* TQuadrant::addObstacle(TObstacle* o) { //je v tomto? if( o->collision( p2fCenter.x, p2fCenter.y, fSize ) ) { //ano //zkus potomky int b1 = o->collision( p2fCenter.x - fSize/4, p2fCenter.y - fSize/4, fSize/2 ); int b2 = o->collision( p2fCenter.x + fSize/4, p2fCenter.y - fSize/4, fSize/2 ); int b3 = o->collision( p2fCenter.x - fSize/4, p2fCenter.y + fSize/4, fSize/2 ); int b4 = o->collision( p2fCenter.x + fSize/4, p2fCenter.y + fSize/4, fSize/2 ); //jde to do nejakeho? //ano -> vloz do nej int subq = -1; if ( b1 && !b2 && !b3 && !b4) subq = 0; else if(!b1 && b2 && !b3 && !b4) subq = 1; else if(!b1 && !b2 && b3 && !b4) subq = 2; else if(!b1 && !b2 && !b3 && b4) subq = 3; if(subq > -1) { if( Subquadrant[subq] == NULL ) Subquadrant[subq] = new TQuadrant(this, subq); Subquadrant[subq]->addObstacle(o); } //ano+ne -> vloz do tohoto Obstacles.push_back(o); return this; } else { //ne //vytvor int subq = -1; if (o->p2fPosition.x > p2fCenter.x && o->p2fPosition.y > p2fCenter.y) subq = 0; else if(o->p2fPosition.x < p2fCenter.x && o->p2fPosition.y > p2fCenter.y) subq = 1; else if(o->p2fPosition.x > p2fCenter.x && o->p2fPosition.y < p2fCenter.y) subq = 2; else if(o->p2fPosition.x < p2fCenter.x && o->p2fPosition.y < p2fCenter.y) subq = 3; TQuadrant* q = new TQuadrant(p2fCenter.x+(o->p2fPosition.x > p2fCenter.x?1:-1)*fSize/2, p2fCenter.y+(o->p2fPosition.y > p2fCenter.y?1:-1)*fSize/2, fSize*2); q->Subquadrant[subq]=this; Parent = q; //zkus vlozit do nej return q->addObstacle(o); } //vrat sam sebe, nebo novy koren return this; } TObstacle* TQuadrant::delObstacle(TObstacle* o) { //je v blizkem okoli if( collision(o->p2fPosition.x, o->p2fPosition.y, o->fRadius) ) { //je tady? for(std::vector::iterator it = Obstacles.begin(); it != Obstacles.end(); it++) { //hura! if( (*it) == o ){ Obstacles.erase(it); return o; }//if }//for //treba bude v synech for(int i = 0; i < 4; i++){ if(Subquadrant[i] && Subquadrant[i]->delObstacle(o)){ //spocti podkvadranty int qc = 0;; for( int k = 0; k < 4; k++ ) if(Subquadrant[i]->Subquadrant[k])qc++; //nema podkvadranty ani prekazky -> zrus quadrant if( (qc==0) && (Subquadrant[i]->Obstacles.size()==0) ){ delete Subquadrant[i]; Subquadrant[i] = NULL; } return o; } }//for }//if return NULL; } int TQuadrant::collision(float cx, float cy, float size) { int res = //jeden rozmer ( ((p2fCenter.x+fSize/2)>(cx+size/2)&&(p2fCenter.x-fSize/2)>(cx+size/2))|| ((p2fCenter.x+fSize/2)<(cx-size/2)&&(p2fCenter.x-fSize/2)<(cx-size/2)) ) || //druhy rozmer ( ((p2fCenter.y+fSize/2)>(cy+size/2)&&(p2fCenter.y-fSize/2)>(cy+size/2))|| ((p2fCenter.y+fSize/2)<(cy-size/2)&&(p2fCenter.y-fSize/2)<(cy-size/2)) ); return !res; } int TQuadrant::collision(TObstacle* o){ //je v blizkem okoli if( collision(o->p2fPosition.x, o->p2fPosition.y, o->fRadius) ) { int col = 0; //koliduj s quadrantama for(int i = 0; i < 4; i++){ if(Subquadrant[i]) if( Subquadrant[i]->collision(o) )return 1; } //koliduj sp prekazkama for(std::vector::iterator it = Obstacles.begin(); it != Obstacles.end(); it++) { TObstacle *obst = (TObstacle*)(*it); if( o->collision(obst) )return 1; } }//if return 0; } TQuadrant* TQuadrant::buildQuadrantTree(std::vector* obstacles) { //vyrob koren TQuadrant* root = NULL; //projdi vsechny a zmer velikost korene float maxx=-FLT_MAX; float minx=FLT_MAX; float maxy=-FLT_MAX; float miny=FLT_MAX; for(std::vector::iterator it = obstacles->begin(); it != obstacles->end(); it++) { TObstacle* o = (TObstacle*)(*it); if(o->p2fPosition.x+o->fRadius > maxx)maxx = o->p2fPosition.x+o->fRadius; if(o->p2fPosition.x-o->fRadius < minx)minx = o->p2fPosition.x-o->fRadius; if(o->p2fPosition.y+o->fRadius > maxy)maxy = o->p2fPosition.y+o->fRadius; if(o->p2fPosition.y-o->fRadius < miny)miny = o->p2fPosition.y-o->fRadius; } float size = MAX((maxx-minx), (maxy-miny))/2; float cx = (maxx+minx)/2; float cy = (maxy+miny)/2; root = new TQuadrant(cx, cy, size); for(std::vector::iterator it2 = obstacles->begin(); it2 != obstacles->end(); it2++) { root->addObstacle((TObstacle*)(*it2)); } return root; } //TSteeringKernelController //----------------------------------------------------------------------------- void TSteeringKernelController::findNearestFreePosition(TObstacle* o) { float r = 0; //vzdalenost od spravne polohy float full_per = 0; //obvod float per = 0; //pozice po obvodu float rad = o->fRadius; //polomer float ang; //uhel int col; //priznak kolize P2F displacement = {0,0}; //posunuti P2F orig_center; //pocatek // CopyV2(orig_center.p, o->p2fPosition.p); //kolecko while(1) { //pozice na kruznicich if(per>full_per){ per = 0; r += rad; full_per = (float)M_PI*2*r; } // ang = (full_per)?(float)(2*M_PI*(per/full_per)):0; col = 0; per += rad; // displacement.x = r*sin(ang); displacement.y = r*cos(ang); // CopyV2(o->p2fPosition.p, orig_center.p); AddV2(o->p2fPosition.p, displacement.p); //KOLIDUJ if(!Root)return; col = Root->collision(o); //ukoncujici podminka if(!col) return; } CopyV2(o->p2fPosition.p, orig_center.p); } void TSteeringKernelController::insertObstacle(TObstacle* o) { //pridej prekazku Root->addObstacle(o); //zakoren while(Root->Parent) Root = Root->Parent; } void TSteeringKernelController::removeObstacle(TObstacle* o) { //odstran Root->delObstacle(o); } void TSteeringKernelController::moveObstacle(TObstacle* o) { //removeObstacle(o); //insertObstacle(o); } void TSteeringKernelController::draw(){ //projdi se zasobnikem hierarchii prekazek TQuadrant* stack[30]; int sstack = 0; TguiMap* map = (TguiMap*)data; //zacni u korene stack[sstack++] = Root; while(sstack){ //vyber vrchol zasobniku TQuadrant* q = stack[--sstack]; //pridej potomky for(int i = 0; i < 4; i++){ if(q->Subquadrant[i]) stack[sstack++] = q->Subquadrant[i]; assert(sstack<30); } //hledej prekazky ve vyhledu for(std::vector::iterator it = q->Obstacles.begin(); it != q->Obstacles.end(); it++) { TObstacle* o = *it; map->drawCircle(o->p2fPosition.x, o->p2fPosition.y, o->fRadius); } } } void TSteeringKernelController::buildStructures(TguiMap* gmap){ //projed mapu a ziskej prekazky std::vector obstacles; TObstacle* o = NULL; data = (void*)gmap; //projed hexy for(int i = 0; i < gmap->hexycount; i++) { //ziskej teren TTerrainEntity* t = (TTerrainEntity*)gmap->hexy[i]->getProxy(ptTerrain); if(t) for(Tsceneobjs::iterator it = t->objs.begin(); it != t->objs.end(); it++) { float radius = 0.65f*SizeV2( (*it)->aabbDim.p )/2; o = new TObstacle( &((*it)->aabbCenter.p2f), radius); obstacles.push_back(o); } TUnit* u = (TUnit*)gmap->hexy[i]->getProxy(ptDynamic); if(u) for(vunitmember::iterator it = u->vMembers.begin(); it != u->vMembers.end(); it++) { TUnitMember *um = *it; // obstacles.push_back(um->sc); } } //vytvor koren Root = TQuadrant::buildQuadrantTree(&obstacles); } TSteeringKernelController::TSteeringKernelController() { RTTID("stkctrl"); Root = NULL; } TSteeringKernelController::~TSteeringKernelController(){ if(Root) delete Root; } void TSteeringKernelController::update(int absoluteTime) { } //TSteeringController //----------------------------------------------------------------------------- float st_radius(TUnitMember* um){ return SizeV2(um->aabbDim.p)/2; } float st_mass(TUnitMember* um){ return 1; } float st_maxspeed(TUnitMember* um){ return um->unit->guiuiInfo.speed*1000; } float st_maxforce(TUnitMember* um){ return 100; } float st_maxrotationspeed(TUnitMember* um){ return 0.4f; } TSteeringController::TSteeringController(TSteeringKernelController* cntrl, TUnitMember* um) : TAgent(cntrl, st_radius(um), st_mass(um), st_maxspeed(um), st_maxforce(um), st_maxrotationspeed(um)) { RTTID("stctrl"); stkctrl = cntrl; data = (void*)um; } void TSteeringController::update(int absoluteTime) { TUnitMember* unitmember = (TUnitMember*)data; // int step = absoluteTime - iLastTime; if( step < 30 )return; iLastTime = absoluteTime; // float dist = step*fTimeRatio; // steer(dist/1000); // P3F pos, dir, up; SETV3(pos.p, p2fPosition.x, p2fPosition.y, 0); SETV3(dir.p, p2fDirection.x, p2fDirection.y, 0); SETV3(up.p, 0, 0, 1); unitmember->place(&pos, &dir, &up); //ukonceni if( pNextGoal == NULL ){ clearRoute(); unitmember->stopAnimation(0); deactivate(0); } } void TSteeringController::refreshPosition(){ TUnitMember* unitmember = (TUnitMember*)data; P3F dir; P3F scpos; // unitmember->getDirection(&dir); unitmember->getPosition(&scpos); // CopyV2(p2fPosition.p, scpos.p); CopyV2(p2fDirection.p, dir.p); } void TSteeringController::walk(int points_c, P2F* points, int startAt) { //synchronizuj agenta s polohou modelu refreshPosition(); //napln trasu clearRoute(); for(int i=0; i < points_c; i++){ //na vzdalenost polomeru v opacnem smeru nez je tecna P2F cil = points[2*i]; P2F tecna = points[2*i+1]; P2F predcil = cil; NormalizeV2(tecna.p); MulV2(tecna.p, fRadius); SubV2(predcil.p, tecna.p); AddV2(cil.p, tecna.p); // addGoal(&predcil); addGoal(&cil); } //inicializuj nextGoal(); // if(startAt>0) activate(startAt, 0); else activate(KTime(), 0); } void TSteeringController::draw(TguiMap* gmap) { P2F prev; //najdi pristi for(std::vector::iterator it = vRoute.begin(); it != vRoute.end(); it++) { if(it == vRoute.begin()){ prev = *it; } else{ gmap->drawLine(prev.x, prev.y, (*it).x, (*it).y); prev = *it; } }//for } //TUnitController //----------------------------------------------------------------------------- TUnitController::TUnitController(TUnit *unit){ RTTID("unitctrl"); data = (void*)unit; } void TUnitController::update(int absoluteTime){ //bude aktivni kdyz potomci budou aktivni if(iActiveChilds == 0){ deactivate(0); } } void TUnitController::test() { } //TUnitMemberController //----------------------------------------------------------------------------- /***************POHYB PO KRIVKACH*****************/ /* nastavi krivku pohybu - napoji na predchozi */ void TUnitMemberController::joinPath(TSheduledAction* sa, int points_c, P2F* points) { TUnitMember* unitmember = (TUnitMember*)data; TGenericCurve* path = (TGenericCurve*)(sa->pData); // P3F* spoint = path->controlPoint(path->controlPointCount()-2); P3F* sdir = path->controlPoint(path->controlPointCount()-1); P2F* prev_point = &(spoint->p2f); P2F* prev_dir = &(sdir->p2f); P3F pdir; float dist; float ang; for(int i = 0; i < points_c; i++) { //vzdalenost k predchozimu dist = ( TVector(*prev_point) - TVector(points[2*i]) ).len(); ang = Angle2Db(prev_dir, &(points[2*i+1])); //preskakuj stejne if(dist < 0.01 && ang < 0.001) continue; prev_point = &( points[2*i] ); prev_dir = &( points[2*i+1] ); //vloz body path->addPoint(points[2*i].x, points[2*i].y, 0); //tecna pdir = ( TVector(points[2*i+1]).norm() * MAX(dist,1) * pathSmoothness ).toP3F(); path->addPoint(pdir.x, pdir.y, 0); } // path->build(); //nastav rychlost float spd = unitmember->unit->guiuiInfo.speed; sa->iDuration = ROUND( path->length() / spd); } /* krivka mezi vice pozicema - nepouziva se*/ void TUnitMemberController::planPath(TSheduledAction* sa, int points_c, P2F* points) { TUnitMember* unitmember = (TUnitMember*)data; TGenericCurve* path = NULL; //nova cesta path = new TJoinHermiteanCubic(20); sa->pData = (void*)path; P2F* pre = 0; for(int i = 0; i < points_c; i++){ //preskakuje uzlove body na stejnem miste pre = &points[2*i]; //vloz body path->addPoint(points[2*i].x, points[2*i].y, 0); path->addPoint(points[2*i+1].x, points[2*i+1].y, 0); } // path->build(); //nastav rychlost float spd = unitmember->unit->guiuiInfo.speed; sa->iDuration = ROUND( path->length() / spd); } void TUnitMemberController::planPathFromHere(TSheduledAction* sa, int points_c, P2F* points){ TUnitMember* unitmember = (TUnitMember*)data; TGenericCurve* path = NULL; P3F spos, sdir; //aktualni pozice a smer unitmember->getPosition(&spos); unitmember->getDirection(&sdir); //nova cesta path = new TJoinHermiteanCubic(20); sa->pData = (void*)path; //vloz prvni bod a poc smer path->addPoint(spos.x, spos.y, 0); //tecna float dist = ( TVector(points[0]) - TVector(spos) ).len(); sdir = ( TVector(sdir).norm() * dist * pathSmoothness ). toP3F(); path->addPoint(sdir.x, sdir.y, 0); joinPath(sa, points_c, points); } /**********************AKCE***********************/ /* naplanuje akci, ktera naplanuje cestu z aktualni pozice */ void TUnitMemberController::planWalk(int points_c, P2F* points, P2F* tangents, int startAt){ TSheduledAction* sa; TPathPointsBuff* ppb; //data pro cestu ppb = (TPathPointsBuff*)KMemAlloc(sizeof(TPathPointsBuff) + (2*points_c-1)*sizeof(P2F)); for(int i = 0; i < points_c; i++){ ppb->points[2*i] = points[i]; ppb->points[2*i+1] = tangents[i]; } ppb->points_c = points_c; //nova akce sa = createAction(umcaPlanWalk, ppb, startAt, 0); // if(startAt>0) insertAction(sa); else linkActionAfterLast(sa); // if(!iActived)activate(KTime(), 0); } /* naplanuje cestu - nepouziva se */ void TUnitMemberController::walk(int points_c, P2F* points, int startAt){ TSheduledAction* sa; //nova akce sa = createAction(umcaWalk, NULL, startAt, 0); // try{ planPathFromHere(sa, points_c, points); // if(startAt>0) insertAction(sa); else linkActionAfterLast(sa); // if(!iActived)activate(KTime(), 0); } catch(E_8K_GUI e){ KMemFree(sa); } } void TUnitMemberController::fadeout(int delay, int startAt){ TSheduledAction* sa; // sa = createAction(umcaFadeOut, NULL, startAt, delay); // if(startAt>0) insertAction(sa); else linkActionAfterLast(sa); // if(!iActived)activate(KTime(), 0); } void TUnitMemberController::fadein(int delay, int startAt){ TSheduledAction* sa; // sa = createAction(umcaFadeIn, NULL, startAt, delay); // if(startAt>0) insertAction(sa); else linkActionAfterLast(sa); // if(!iActived)activate(KTime(), 0); } void TUnitMemberController::script(TSceneScript* c, int startAt){ TSheduledAction* sa; // removeActions(umcaScript); // sa = createAction(umcaScript, c, startAt, 0); // if(startAt>0) insertAction(sa); else linkActionAfterLast(sa); // if(!iActived)activate(KTime(), 0); } void TUnitMemberController::disappear(int startAt){ TSheduledAction* sa; // sa = createAction(umcaDisapper, NULL, startAt, 0); // if(startAt>0) insertAction(sa); else linkActionAfterLast(sa); // if(!iActived)activate(KTime(), 0); } TSheduledAction* TUnitMemberController::createAction(int act, void* data, int start, int dur){ TSheduledAction* ac = TScheduler::createAction(act, data, start, dur); if(ac->iAction == umcaScript) ((TSceneScript*)ac->pData)->getRef(); return ac; } void TUnitMemberController::disposeAction(TSheduledAction* ac){ if(ac->iAction == umcaScript) ((TSceneScript*)ac->pData)->ungetRef(); TScheduler::disposeAction(ac); } /****************AKTUALIZACE AKCI****************/ int TUnitMemberController::updateAction(int rtime, TSheduledAction* sa) { TUnitMember* unitmember = (TUnitMember*)data; float t; // if(sa->iDuration) t = float(rtime)/sa->iDuration; else t = 1; //out-of range if(t > 1) t = 1; if(t < 0) t = 0; //---------------------------------------- //--- PRUBEH a ZACATEK akce podle typu --- //---------------------------------------- switch(sa->iAction){ /************** steering ****************/ #ifdef STEERING case umcaWalk:{ //steerovani dosahlo konce -> okamzite skonci! if( unitmember->sc->pNextGoal == NULL ){ t=1; sa->iDuration = 0; } }break; case umcaPlanWalk:{ //naplanuj novou akci if(!sa->iStarted){ //data pro naplanovanou cestu TPathPointsBuff *ppb = (TPathPointsBuff*)sa->pData; //steeruj a animuj unitmember->sc->walk(ppb->points_c, ppb->points); unitmember->walk(); //premen akci sa->iStart = (int)(rtime/fTimeRatio+sa->iStart); sa->iAction=umcaWalk; sa->iStarted = 1; sa->iDuration = 1000000; KMemFree(ppb); } }break; /********** pohyb po krivkach ***********/ #else case umcaWalk:{ if(!sa->iStarted){ unitmember->walk(); sa->iStarted = 1; //debug curpath = (TGenericCurve*)(sa->pData); } }//umyslne navazuje kvuli spolecne akci case umcaPlanWalk:{ if(!sa->iStarted){ //data pro naplanovanou cestu TPathPointsBuff *ppb = (TPathPointsBuff*)sa->pData; // try{ planPathFromHere(sa, ppb->points_c, ppb->points); t = 0; sa->iStart = (int)(rtime/fTimeRatio+sa->iStart); sa->iAction=umcaWalk; sa->iStarted = 1; unitmember->walk(); //debug curpath = (TGenericCurve*)(sa->pData); } catch(E_8K_GUI e){ break; } KMemFree(ppb); } // TGenericCurve* path = (TGenericCurve*)(sa->pData); // P3F pos, dir, up; SETV3(up.p, 0,0,1); path->eval(t,&pos); path->evalDerivation(t,&dir); // unitmember->place(&pos, &dir, &up); }break; #endif /****************************************/ case umcaScript:{ assert(sa->pData); ((TSceneScript*)sa->pData)->decision((TScriptedObject*)unitmember); }break; case umcaFadeOut:{ if(!sa->iStarted) sa->iStarted = 1; unitmember->setTransparency( 1 - MIN(1, MAX(t, 0) ) ); unitmember->selectable = false; }break; case umcaFadeIn:{ if(!sa->iStarted) sa->iStarted = 1; unitmember->setTransparency( MIN(1, MAX(t, 0) ) ); unitmember->selectable = true; }break; case umcaDisapper:{ unitmember->ungetRef(); return 0; }break; } //------------------ //--- KONEC akce --- //------------------ if(t == 1){ switch(sa->iAction){ /************** steering ****************/ #ifdef STEERING case umcaPlanWalk: case umcaWalk: break; /********** pohyb po krivkach ***********/ #else case umcaPlanWalk: case umcaWalk:{ unitmember->stopAnimation(0); delete (TGenericCurve*)(sa->pData); sa->pData = NULL; //debug curpath = NULL; }break; #endif /****************************************/ case umcaDistantAttack: case umcaAttack:{ unitmember->stopAnimation(1); }break; } return 1; }//konec akce return 1; } TUnitMemberController::TUnitMemberController(TUnitMember* um){ RTTID("umcntrl"); data = (TUnitMember*)um; pathSmoothness = RAND(0.1f,1.5f); curpath = NULL; } }//namespace /*****************************************************************************/