📄 worldmodelpredict.cpp
字号:
Log.log( 560, "intercept: move to (%f,%f) in %d cycles", posTo.getX(),posTo.getY(), iCycle); //是我们的死球,并且不是门球 if( isDeadBallUs() && !isGoalKickUs()) // do not dash backwards //不向后跑,就是说优先转身,然后跑向目标点 soc = predictCommandToMoveToPos( obj, posTo, iCycle, 0 ); else //预测跑向目标点的指令 soc = predictCommandToMoveToPos( obj, posTo, iCycle ); } //返回指令 return soc;}/*! This command returns the command for object 'obj' to intercept the ball. It needs the command 'socClose' as the command to intercept a close ball (may be CMD_ILLEGAL). 'iCycles' will be filled with the number of cycles to get to this ball position and 'posIntercept' will be filled with the final interception point. When posIn, velIn, angBodyIn are equal to NULL, the agent information is used in the calculations. *//* 返回obj物体截球的指令。它需要利用interceptClose指令返回的指令去截住近距离的球。 iCycles记录了截球需要周期数,posIntercept记录了最终的截球点。 posIn,velIn,angBodyIn都是NULL时,将取得当前球员的状态用来计算。*/SoccerCommand WorldModel::predictCommandToInterceptBall( ObjectT obj, SoccerCommand socClose, int *iCycles, VecPosition *posIntercept, VecPosition *posIn, VecPosition *velIn, AngDeg *angBodyIn ){ FeatureT feature_type = FEATURE_INTERCEPTION_POINT_BALL; // check whether we already have calculated this value // 查看是否我们已经计算过这个值 if( isFeatureRelevant( feature_type ) ) { //直接设定已经计算过的值 int i = max(0,((int)getFeature(feature_type).getInfo()-getCurrentCycle())); if( iCycles != NULL ) *iCycles = i; if( posIntercept != NULL ) *posIntercept = predictPosAfterNrCycles( OBJECT_BALL, i ); //返回计算过的指令 Log.log( 463, "intercept, use old info, feature %d: %d", feature_type, max(0,((int)getFeature( feature_type ).getInfo()-getCurrentCycle()))); return getFeature( feature_type ).getCommand(); } // declare all needed variables // 定义使用到的所有的变量 SoccerCommand soc;//命令/指令 VecPosition pos, vel;//用来取得(/预测)球员的位置和速度 Stamina sta;//用来取得(/预测)球员的体力 VecPosition posPred, posBall(0,0), posBallTmp, velBall, posAgent;//... AngDeg angBody, angNeck;//... double dMaxDist = getMaximalKickDist( obj );//取得最大可踢距离 int iMinCyclesBall=100, iFirstBall=100;//记录最小周期截球点,首个截球点 double dBestX = UnknownDoubleValue;//最佳截球X坐标 double dMinOldIntercept = 100;//求新的截球点和原来截球点的距离 double dDistanceOfIntercept = 10.0;//求最佳截球距离 int iOldIntercept = UnknownIntValue;//求最佳截球周期 static Time timeLastIntercepted(-1,0);//静态变量,记录上一次预测截球指令的时间 static VecPosition posOldIntercept;//记录以前计算得出的截球点 // 这里主要是用于每两个周期重新对截球点进行一次计算,防止球的状态改变导致原来的截球路线错误 // didn't intercept ball in last two cycles -> reset old interception point // 在之前的两个周期内没有截球成功 -> 将旧的截球点重置,并且开始重新计时 if( (getCurrentTime() - timeLastIntercepted) > 2 ) { posOldIntercept.setVecPosition( UnknownDoubleValue, UnknownDoubleValue); timeLastIntercepted = getCurrentTime(); } Log.log( 468, "old interception point: (%f,%f)", posOldIntercept.getX(), posOldIntercept.getY() ); // 对于之后球会到达的所有的点,取得最佳截球点 int iCyclesBall = 0; // for each new pos of the ball, check whether agent can reach ball // and update the best interception point while( iCyclesBall <= PS->getPlayerWhenToIntercept() && //判断是否超过了截球最大周期 iCyclesBall <= iFirstBall + 10 && //这个条件主要用于选择最佳截球点 isInField( posBall ) == true ) //判断球有没有出界 { // re-initialize all variables // 重新初始化所有球员状态 angBody = ( angBodyIn == NULL ) ? getGlobalBodyAngle( obj ) : *angBodyIn; angNeck = getGlobalNeckAngle( obj ); pos = ( posIn == NULL ) ? getGlobalPosition ( obj ) : *posIn; vel = ( velIn == NULL ) ? getGlobalVelocity ( obj ) : *velIn; sta = getAgentStamina(); soc.commandType = CMD_ILLEGAL; // predict the ball position after iCycles and from that its velocity // 从球当前的速度预测出球在iCycles周期后的位置以及速度 posBallTmp = predictPosAfterNrCycles( OBJECT_BALL, iCyclesBall ); if( iCyclesBall == 0 ) velBall = getGlobalVelocity( OBJECT_BALL ); else velBall = posBallTmp - posBall; posBall = posBallTmp; // predict the agent position // 预测球员所在的点,并且取得当前球员的点 posPred = predictPosAfterNrCycles( obj, min(iCyclesBall,4), 0 ); posAgent = getGlobalPosition( obj ); // if too far away, we can never reach it and try next cycle // 如果太远了,我们不可能到达那里,尝试更多的周期能否到达 // 或者是球已经出界了,同样通过"continue"可以在循环判断条件时退出循环 if((posPred.getDistanceTo(posBall)-dMaxDist)/getPlayerSpeedMax(obj) > iCyclesBall || isInField( posBall ) == false ) { iCyclesBall++; continue; } // predict our position after the same nr of cycles when intercepting // 预测我们在iCyclesBall周期的截球动作后所在的位置 for( int i = 0; i < iCyclesBall; i++ ) { soc = predictCommandToMoveToPos( obj, posBall, iCyclesBall - i , 2.5, false, &pos, &vel, &angBody ); predictStateAfterCommand( soc, &pos, &vel, &angBody, &angNeck, obj ); } // if in kickable distance, we can reach the ball! // 如果在截球截球的距离以内,我们能到达足球附近! if (pos.getDistanceTo( posBall ) < dMaxDist ) { Log.log( 468, "can intercept ball in %d cycles, dist %f, old %f obj %d", iCyclesBall, pos.getDistanceTo( posBall ), posBall.getDistanceTo( posOldIntercept ), obj ); //计算出的第一个截球点,不仅记录到iMinCyclesBall,还要记录到iFirstBall if( iMinCyclesBall == 100 ) // log first possible interception point iFirstBall = iMinCyclesBall = iCyclesBall; // to get some consistency in the interception point and avoid // too many turns, also keep track of the current possible // interception point. This is the point close to the old // interception point. Two constraints are that the ball has to // have some speed (else it does not really matter where to // intercept) and the ball must be intercepted safely, that is // the ball is close to the body when intercepting. // 去获得一些连续的截球点,并且避免多次的转身,而且保持到当前截球点的轨道。 // 这是一个接近旧的截球点的点。两个限制就是球是必须有速度的而且球必须被安全的接到, // 还有就是截球之后球应该尽量的靠近身体。 if( posBall.getDistanceTo(posOldIntercept) < min( 1.0, dMinOldIntercept ) && pos.getDistanceTo( posBall ) < 0.60*getMaximalKickDist( obj ) && velBall.getMagnitude() > 0.5 ) { Log.log( 468, "update old interception point %d", iCyclesBall ); dBestX = posBall.getX();//记录最佳截球X坐标 iOldIntercept = iCyclesBall;//新的最佳截球点对应的截球周期 dDistanceOfIntercept = pos.getDistanceTo( posBall );//截球后和球的位置 dMinOldIntercept = posBall.getDistanceTo(posOldIntercept);//和上一个计算出的截球点差距 } // determine the safest interception point. This point must be // better than the current intercept, the distance to ball must // be very small after interception and close to the previous // calculated interception point // 如果上面的截球点不是最佳截球点,重新确认一个更安全的截球点。 // 这个点必须要比当前的截球点要好,在截球后和球的距离必须十分小,而且新的点要接近之前算出的截球点。 else if( pos.getDistanceTo( posBall ) < dDistanceOfIntercept && dDistanceOfIntercept > 0.40*getMaximalKickDist( obj ) && ( iCyclesBall <= iMinCyclesBall + 3 || iCyclesBall <= iOldIntercept + 3 ) && fabs( posBall.getY() ) < 32.0 && fabs( posBall.getX() ) < 50.0 ) { iMinCyclesBall = iCyclesBall;//更改最小截球周期 dDistanceOfIntercept = pos.getDistanceTo( posBall );//记录最佳截球后和球距离 Log.log( 468, "safer interception at %d", iMinCyclesBall ); if( iOldIntercept == iMinCyclesBall - 1 )//如果截球周期相差1 { Log.log( 468, "old interception point -> safer" ); iOldIntercept = iMinCyclesBall;//更改最佳截球点对应的截球周期 } } } else Log.log( 468, "cannot intercept ball in %d cycles, dist %f, %f and %f", iCyclesBall, pos.getDistanceTo(posBall), pos.getDistanceTo( posAgent ), posBall.getDistanceTo( posAgent ) - dMaxDist);; //继续循环自增 iCyclesBall++; } Log.log( 463, "first interception point: %d cycles", iFirstBall ); Log.log( 463, "best interception point: %d cycles", iMinCyclesBall ); Log.log( 463, "old interception point %d cycles", iOldIntercept ); // check special situations where we move to special position. // 判断特征状态/局势,我们移动到哪个特征点 // 如果最佳截球点和最快截球点相差不超过2个周期 if( !( iMinCyclesBall > iOldIntercept + 2 ) && iOldIntercept != UnknownIntValue ) { //以最佳截球点为目标 Log.log( 463, "move to old interception point." ); iMinCyclesBall = iOldIntercept; } else { //以最快截球点为目标 Log.log( 463, "move to first intercept" ); iMinCyclesBall = iFirstBall; } //预测截球的位置并记录到日志 posBall = predictPosAfterNrCycles( OBJECT_BALL, iMinCyclesBall ); Log.log( 463, "choose %d cycles", iMinCyclesBall ); logCircle( 463, posBall, 1.0 ); //返回截球周期数 if( iCycles != NULL ) *iCycles = iMinCyclesBall; //记录计算出的截球点,和obj物体随惯性会移动到的位置 posOldIntercept = posBall; posPred = predictPosAfterNrCycles( obj, min(iMinCyclesBall,4), 0 ); //返回截球点 if( posIntercept != NULL ) *posIntercept = posBall; //如果截球周期小于三,并且socClose不是无效的,直接用socClose if( iMinCyclesBall < 3 && ! socClose.isIllegal() ) { Log.log( 463, "do close intercept" ); iMinCyclesBall = 1; soc = socClose; } //本来就已经处于截球成功状态 else if( posPred.getDistanceTo( posBall ) < 0.5 ) { Log.log( 463, "intercept: do not move already close" ); soc = SoccerCommand( CMD_ILLEGAL ); } //否则 else { Log.log( 463, "intercept: move to (%f,%f)", posBall.getX(),posBall.getY()); Log.log( 560, "intercept: move to (%f,%f) in %d cycles", posBall.getX(),posBall.getY(), iMinCyclesBall); //是我们的死球,并且不是门球 if( isDeadBallUs() && !isGoalKickUs()) // do not dash backwards //不向后跑,就是说优先转身,然后跑向 soc = predictCommandToMoveToPos( obj, posBall, iMinCyclesBall, 0 ); else //预测跑向目标点的指令 soc = predictCommandToMoveToPos( obj, posBall, iMinCyclesBall ); } // store the calculated action as a feature // 把计算的结果记录到 feature if( obj == getAgentObjectType() ) setFeature( feature_type, Feature( getTimeLastSeeMessage(), getTimeLastSenseMessage(), getTimeLastHearMessage(), OBJECT_ILLEGAL, getTimeLastSeeMessage().getTime() + iMinCyclesBall, soc ) ); return soc;}/*! This method determines whether a dash command (supplied as the first argument) will result in collision with another player. This is checked by determing the global position after the command and then check whether the positions of one of the other players lies with the player size. Since it cannot be known what kind of action the other player takes in this cycle, it is also difficult to predict what the global position of the player will be in the next cycle. This method therefore assumes the other players have issued a dash with maximum power in the last cycle. \return bool indicating whether dash will result in a collision. */bool WorldModel::isCollisionAfterCommand( SoccerCommand soc ){ VecPosition posPred, velPred; AngDeg ang1, ang2; Stamina sta; predictAgentStateAfterCommand( soc, &posPred, &velPred, &ang1,&ang2,&sta ); velPred /= SS->getPlayerDecay(); VecPosition posBall = predictPosAfterNrCycles( OBJECT_BALL, 1 ); if( soc.commandType == CMD_KICK ) predictBallInfoAfterCommand( soc, &posBall ); double dDist = posPred.getDistanceTo( posBall ) - SS->getPlayerSize() - SS->getBallSize(); Log.log( 510, "check collision dist %f, noise_ball %f noise_me %f", dDist, getBallSpeed()*SS->getBallRand(), velPred.getMagnitude()*SS->getPlayerRand() ); // we could also take into account the error in player movement, but this // is very large, so we would in many cases get a dash if( dDist < getBallSpeed()*SS->getBallRand() ) return true; return false;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -