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 + -
显示快捷键?