goingthroughspeed.cpp
来自「2002年」· C++ 代码 · 共 352 行
CPP
352 行
#include "goingthroughspeed.h"
#include "serverparam.h"
#include "clientparam.h"
/** Goingthroughspeed, the basic judge pass module that can trust**/
#define MINERROR 0.05f
#define MINCYCLES 5
#define BallMoveDis(speed, time) MoveFormula(speed, time, ServerParam::ball_decay)
float GT_speed_utils::kick_area = ClientParam::reliable_kickarea;
float GT_speed_utils::max_speed = ServerParam::player_speed_max;
double GT_speed_utils::log_ball_decay = log(ServerParam::ball_decay);
void GT_speed_utils::Initialize(){
kick_area = ClientParam::reliable_kickarea;
max_speed = ServerParam::player_speed_max;
log_ball_decay = log(ServerParam::ball_decay);
}
float GT_speed_utils::Player_Intercept_Speed(){
return max_speed;
}
float GT_speed_utils::Player_kickable_area(){
return kick_area;
}
float GT_speed_utils::calc_peakpoint(Vector pos){
if(pos.x <= 0) return 100.0f; //peak point doesn't exist
//use Newton Method to calc the peak point
double z;
double sq, pw;
double f, f_, delta = 1;
int cycles = 0;
double x=pos.x;
do{
sq = sqrt( Sqr(x-pos.x) + Sqr(pos.y) );
z = sq - 1;
pw = pow(ServerParam::ball_decay, -z);
f = (x - pos.x) * x * (1 - ServerParam::ball_decay) - sq * (pw - 1);
f_ = (1-ServerParam::ball_decay) * (2*x-pos.x) + (x-pos.x) * (pw*log_ball_decay - (pw-1)/sq);
delta = f/f_;
x = x - delta;
cycles ++;
}while(fabs(delta) > MINERROR && cycles < 5 && x > 0);
if (fabs(delta)>MINERROR || x<=0){
return ServerParam::pitch_diameter;
}else{
//additional fix to handle special situation.
//sometimes, x is negative
double sx;
if(fabs(pos.y) < CP_kickarea_compensation){
sx = pos.x + sqrt(Sqr(CP_kickarea_compensation)-Sqr(pos.y));
}else{
sx = pos.x;
}
return (float)Max(x, sx);
}
}
/* Criver's version
float GT_speed_utils::calc_peakpoint(Vector pos){
//use Newton Method to calc the peak point
double t = pos.x, tmp1, tmp2, tmp3, tmp4, f, _f;
int cycles = 0;
if (pos.y == 0){
//if y == 0 the function give wrong result
pos.y = 0.0001f;
}
tmp4 = log_ball_decay;
do{
tmp1 = sqrt(Sqr(t -pos.x) + Sqr(pos.y));
tmp2 = (t - pos.x) / tmp1;
tmp3 = pow(ServerParam::ball_decay, tmp1);
f = 1.0 - tmp3 * ( 1.0 - tmp4 * t * tmp2);
_f = tmp4 * ((f - 1.0) * tmp2 + tmp3 * ((2 * t -pos.x ) * tmp1 - t * (t - pos.x) * tmp2) / Sqr(tmp1));
if (f < 0 && _f > 0){
t = (t + pos.x) /2;
}
else{
t = t - f/_f;
}
cycles ++;
}while(fabs(f) > MINERROR && (_f < 0 || f < 0 )&& cycles < 5);
if (fabs(f) > MINERROR)
return ServerParam::pitch_diameter;
return float(t);
}
*/
float GT_speed_utils::calc_spottingspeed(Vector pos, float t, int addcycle){
float cycles;
return calc_spottingspeed(pos, t, cycles, addcycle);
}
float GT_speed_utils::calc_spottingspeed(Vector pos, float t, float& cycles, int addcycle){
//why plus 1 here? --- the player see the ball one cycle after the ball is kicked out
float dist = pos.dist(Vector(t, 0));
if(dist < CP_kickarea_compensation){//when it's in kickarea
cycles = 0;
return ClientParam::infinite_speed; //Modification'll be needed to be compatible with penetrating,
}
cycles = (dist - CP_kickarea_compensation) / ServerParam::player_speed_max ;
cycles += addcycle;
return Min(float(t * (1 - ServerParam::ball_decay) /(1 - pow(ServerParam::ball_decay, cycles))), ClientParam::infinite_speed);
}
float GT_speed_utils::calc_goingthroughspeed(Vector pos, float t){
float peakpoint = calc_peakpoint(pos);
if (t > peakpoint){
return Max(calc_spottingspeed(pos, t), calc_spottingspeed(pos, peakpoint));
}
return calc_spottingspeed(pos, t);
}
float GT_speed_utils::calc_goingthroughspeed(Ray& ballcourse, const Vector& opp, const Line& pline){
ballcourse.Normalize();
float dist = ballcourse.DistanceFromOrigin(opp);
float angle = ballcourse.StrechAngle(opp);
if (pline.SameSlope(Line(ballcourse))){
if (Line(ballcourse).dist2(opp) > pline.dist2(opp)){
//The receiver have better chance for every t
return 0.0f;
}
else{
//The opponent have better chance for every t
return ClientParam::infinite_speed;
}
}
float t = ballcourse.intersection(pline);
if (t < 0) return ClientParam::infinite_speed;
return Min(calc_goingthroughspeed(Polar2Vector(dist, angle), t), ClientParam::infinite_speed);
}
float GT_speed_utils::calc_goalie_spottingspeed(Vector pos, float t){
//why plus 1 here? --- the player see the ball one cycle after the ball is kicked out
float cycles = Max((pos.dist(Vector(t, 0)) - ClientParam::catcharea_compensation) / ServerParam::player_speed_max, 0.0f) + 0.01f;
return Min(float(t * (1 - ServerParam::ball_decay) /(1 - pow(ServerParam::ball_decay, cycles))), ClientParam::infinite_speed);
}
float GT_speed_utils::calc_goalie_goingthroughspeed(Vector pos, float t){
float peakpoint = calc_peakpoint(pos);
if (t > peakpoint){
return Max(calc_goalie_spottingspeed(pos, t), calc_goalie_spottingspeed(pos, peakpoint));
}
return calc_goalie_spottingspeed(pos, t);
}
//coordinates : pos of ball as the origin, direction of ball's movement as the axis x
//startpoint - player's relative pos
//ballspeed - ball's speed
bool GT_speed_utils::calc_interception_solution(Vector startpoint, float ballspeed, Vector& inf_sup){
float t_inf, t_sup, t_closest, t_test, cycles, t_ball, test_ballspeed, conf;
int run_cycles;
t_inf = 0.0f; t_sup = InfCycles;
t_test = t_closest = Max(0.0f, startpoint.x);
run_cycles = 0;
bool is_before_closest_pt;
while(t_sup > t_inf + 2.0f && run_cycles <= 8){
run_cycles ++;
cycles = (float)sqrt(Sqr(t_test - startpoint.x) + Sqr(startpoint.y)) / ServerParam::player_speed_max;
conf = Exp(ServerParam::ball_decay, cycles);
t_ball = ballspeed * (1 - conf) / (1 - ServerParam::ball_decay);
if (t_test == t_closest){
is_before_closest_pt = bool(t_test >= t_ball);
}
if (is_before_closest_pt){
if (t_test > t_ball){
t_sup = t_test;
t_inf = t_ball;
t_test = (t_inf + t_sup) /2;
}
else{
t_inf = t_test;
t_sup = Min(t_ball, t_closest);
t_test = (t_inf + t_sup) /2;
}
}
else{
if (t_test > t_ball){
t_sup = Max(t_ball, t_closest);
t_test = (t_inf + t_sup) /2;
}
else{
t_inf = t_ball;
if (t_sup != InfCycles){
t_test = (t_sup + t_inf) /2;
}
else{
test_ballspeed = ballspeed * conf;
t_test = t_ball + 3.0f * test_ballspeed;
}
}
}
}
inf_sup.x = t_inf;
inf_sup.y = t_sup;
return t_inf < t_sup && t_sup != InfCycles && run_cycles <= 8;
}
void GT_speed_utils::set_intercept_param(float kickable_area, float player_max_speed){
kick_area = kickable_area;
max_speed = player_max_speed;
}
//startpoint - player's pos; ballspeed - ball's initial speed
//return value: Vector r (r.x - distance, r.y- cycles)
Vector GT_speed_utils::calc_closest_it_cycles(const Vector& startpoint, float ballspeed){
Vector inf[3];
unsigned char r = calc_interception_solution(startpoint, ballspeed, inf, true);
return inf[0];
}
int GT_speed_utils::get_closest_it_index(unsigned char state){
if(state & 1)
return 0;
else if(state & 2)
return 1;
else if(state & 4)
return 2;
else
return 0; //shouldn't be here
}
//return value: intercept_state
// Only the last three bits is meaningful, reprensting fore-peak-back three intercept points.
// (Binary) xx1 - fore valid, x1x - peak valid, 1xx - back valid
unsigned char GT_speed_utils::calc_interception_solution(const Vector& startpoint, float ballspeed, Vector* inf, bool onlyclosest){
bool testok;
int cycles;
unsigned char secs = 0;
double fx, fx_;
if(startpoint.x < 0){
testok = 0;
}else{
float testz = ((float)fabs(startpoint.y)-kick_area)/max_speed;
if(testz < 0){
testok = 1;
}else{
if(BallMoveDis(ballspeed, testz) < startpoint.x)
testok = 1;
else
testok = 0;
}
}
double minz, z, tmp, x;
minz = fabs(startpoint.y) - kick_area +0.2;
minz = Max(0.0, minz);
z = (minz + kick_area)/max_speed;
//calculate the nearest intercept point
if(sqrt(Sqr(startpoint.x) + Sqr(startpoint.y)) < kick_area){
//situation 1: the ball has been intercepted here.
inf[0].x = 0.0f; inf[0].y = 0.0f;
secs |= 1;
}else if(testok){
cycles = 0;
fx = 1;
while(cycles < MINCYCLES && fabs(fx) > MINERROR){
x = BallMoveDis(ballspeed, z);
tmp = sqrt(Sqr(max_speed*z+kick_area)-Sqr(startpoint.y));
fx = startpoint.x - tmp - x;
fx_ = - max_speed*(max_speed*z+kick_area)/tmp + ballspeed*pow(ServerParam::ball_decay, z)*log_ball_decay/(1-ServerParam::ball_decay);
z = z - fx/fx_;
if(z < minz) z = minz;
cycles ++;
}
inf[0].x = (float)x; inf[0].y = (float)z;
secs |= 1 ;
}
if(onlyclosest && secs){
return secs;
}
//calculate fatherest intercept point
fx = 1; cycles = 0;
z = Max(z, 30.0);
//if no fore intercept point, we must find a back point
int s_mincycles = testok ? MINCYCLES : 2 * MINCYCLES;
while(cycles < s_mincycles && fabs(fx) > MINERROR){
x = BallMoveDis(ballspeed, z);
tmp = sqrt(Sqr(max_speed*z+kick_area)-Sqr(startpoint.y));
fx = startpoint.x + tmp - x;
fx_ = max_speed*(max_speed*z+kick_area)/tmp + ballspeed*pow(ServerParam::ball_decay, z)*log_ball_decay/(1-ServerParam::ball_decay);
z = z - fx/fx_;
if(z < minz){
if(testok){
break;
}else{
z = minz;
}
}
cycles ++;
}
if(!testok || fabs(fx) < MINERROR){//exist a back point
inf[2].x = (float)x; inf[2].y = (float)z;
secs |= 4;
if(!testok){
float p = calc_peakpoint(startpoint);
if(p < 20.0f && p >= startpoint.x && p < inf[2].x){
z = (sqrt(Sqr(startpoint.x - p) + Sqr(startpoint.y)) - kick_area)/max_speed;
if(z < 1) z=1;
int int_z = int(z);
x = BallMoveDis(ballspeed, int_z);
if(sqrt(Sqr(startpoint.x - x) + Sqr(startpoint.y)) <= max_speed*int_z+kick_area){
inf[1].x = (float)x; inf[1].y = (float)int_z;
secs |= 2;
}else{
int_z ++;
x = BallMoveDis(ballspeed, int_z);
if(sqrt(Sqr(startpoint.x - x) + Sqr(startpoint.y)) <= max_speed*int_z+kick_area){
inf[1].x = (float)x; inf[1].y = (float)int_z;
secs |= 2;
}
}
}
}else{
cycles = 0;
z = minz;
fx = 1;
while(cycles < MINCYCLES && fx > MINERROR){
x = BallMoveDis(ballspeed, z);
tmp = sqrt(Sqr(max_speed*z+kick_area) - Sqr(startpoint.y));
fx = startpoint.x + tmp - x;
fx_ = max_speed + ballspeed*pow(ServerParam::ball_decay, z)*log_ball_decay/(1-ServerParam::ball_decay);
z = z - fx/fx_;
if(z < minz) break;
cycles ++;
}
inf[1].x = (float)x; inf[1].y = (float)z;
secs |= 2;
}
if(onlyclosest){
if(secs & 2){
inf[0] = inf[1];
}else{
inf[0] = inf[2];
}
}
}else{
//shouldn't be here
}
return secs;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?