intercept_util.cpp

来自「2002年」· C++ 代码 · 共 534 行 · 第 1/2 页

CPP
534
字号
/*********************************
Author:	Yaojinyi
Date:	2002-3-1 16:41:16
Description:

Last modifier:	Yaojinyi
Last modification date:	2002-3-1 16:41:16
Note:
*********************************/
#include "intercept_util.h"
#include "serverparam.h"
#include "clientparam.h"
#include "log.h"	

/***********************   Interception   *****************************************/
Intercept_util::Intercept_util(){	
	dash_rate = 0.01f;
	rundash_power = 100.0f;
	max_speed = 1.0f;
	player_decay = 0.4f;
	maxdash_effect = 0.6f;
	kickarea = 1.085f;
	reliable_kickarea = 1.0f;

	adversary_cycles = 100;
}

IT_test_res Intercept_util::interception_test(Ray& ballcourse, Ray& playercourse, float ballspeed, float selffacing, float& distball, InterceptionInfo & inf){
	Vector intersection_pt;
	float distplayer, min_cycles, stretch_angle, dist, conf, speed;

	ballcourse.intersection(playercourse, intersection_pt);
	distball = ballcourse.DistanceFromOrigin(intersection_pt);
	distplayer = playercourse.DistanceFromOrigin(intersection_pt);
	if (!ballcourse.InRightDir(intersection_pt) || !playercourse.InRightDir(intersection_pt)){
		return IT_test_beyond;
	}
	
	stretch_angle = (float)fabs(NormalizeAngle(ballcourse.Dir() - playercourse.Dir()));

	min_cycles = (float)Max(int(distplayer / max_speed), 0);
	conf = Exp(ServerParam::ball_decay, min_cycles);
	distball -= ballspeed * (1 - conf) / (1 - ServerParam::ball_decay);
	distplayer -= max_speed * min_cycles;
	if (distball < 0){
	//go beyond
		dist = (float)sqrt(Sqr(distball) + Sqr(distplayer) + 2 * fabs(distball) * distplayer * Cos(stretch_angle));
		if (dist > reliable_kickarea)
			return IT_test_beyond;
	}
	else{
	//see if it's too far away to wait for
		speed = ballspeed * conf;
		if (distball > (1 + ServerParam::ball_decay + Sqr(ServerParam::ball_decay)) * speed + kickarea + max_speed)
			return IT_test_not_desired;
		dist = (float)sqrt(Sqr(distball) + Sqr(distplayer) - 2 * fabs(distball) * distplayer * Cos(stretch_angle));
		if (dist > reliable_kickarea){
			if (distball - speed < -reliable_kickarea){
				//go beyond this cycle
				return IT_test_beyond;
			}
		}
		if(dist > kickarea)	min_cycles ++;
	}
	inf.IT_angle = selffacing;
	inf.IT_cycles = min_cycles;
	inf.IT_point = intersection_pt;
	inf.IT_is_closeball = false;
	inf.IT_rapidness = max_speed;
	inf.IT_valid = true;
	return IT_test_ok;
}

inline void Intercept_util::InfCycleProcess(float& cycles){
	if (fabs(cycles) > InfCycles || cycles < 0)
		cycles = InfCycles;
}

//cursory calculation 
void Intercept_util::getinterceptioninfo(const Vector& ballpos, const Vector& ballvel, const Vector& startpoint, const Vector& selfvel,  InterceptionInfo& inf){
	//should turn to intercept
	//so calculate directly from next cycle.
	Vector n_ballpos = ballpos + ballvel;
	Vector n_ballvel = ballvel*ServerParam::ball_decay;
	Vector n_playerpos = startpoint + selfvel;

	float ballspeed = n_ballvel.mod();
	float ballangle = n_ballvel.Angle();
	n_playerpos -= n_ballpos;
	n_playerpos = n_playerpos.Rotate(- ballangle);

	float dashmiss = (1-maxdash_effect)/maxdash_effect;
	if(n_playerpos.mod2() < kickarea){
		dashmiss = 0;
	}

	set_intercept_param(kickarea - dashmiss, max_speed);	//reliable_kick_area
	Vector it_inf = calc_closest_it_cycles(n_playerpos, ballspeed);

	inf.IT_valid = true; 
	inf.IT_is_closeball = false;
	inf.IT_rapidness = GT_speed_utils::Player_Intercept_Speed();

	inf.IT_cycles = (float)(int(it_inf.y + 0.99f));	//1 - turn cycle
	InfCycleProcess(inf.IT_cycles);
	it_inf.x = (float)MoveFormula(ballspeed, inf.IT_cycles, ServerParam::ball_decay); 
	Vector rel_it_pos = Vector(it_inf.x, 0);
	inf.IT_point = rel_it_pos.Rotate(ballangle) + n_ballpos;
	inf.IT_cycles += 1.0f;
	inf.IT_angle = (inf.IT_point - startpoint).Angle();
}

//median accurate intercept-solution
void Intercept_util::getinterceptioninfo(const Vector& ballpos, const Vector& ballvel, const Vector& startpoint, const Vector& playervel, float bdfacing, InterceptionInfo &inf){
	if(playervel.mod2() < Sqr(0.1) || fabs(NormalizeAngle(playervel.Angle() -  bdfacing)) > 15 ){
		//Guess: he is not in a prepared state. (it's wrong in few chances)
		getinterceptioninfo( ballpos, ballvel, startpoint, playervel,  inf);
		return;
	}

	float ballspeed = ballvel.mod();
	float ballangle = ballvel.Angle();
	Vector playerpos = startpoint - ballpos;
	playerpos = playerpos.Rotate(- ballangle);

	float dash_miss =(max_speed - playervel.mod() - maxdash_effect)/maxdash_effect ;
	dash_miss = Max(0.0f, Min(dash_miss, 0.7f));
	set_intercept_param(kickarea - dash_miss, max_speed);	//reliable_kick_area
	Vector it_inf = GT_speed_utils::calc_closest_it_cycles(playerpos, ballspeed);

	it_inf.y = (float)(int(it_inf.y + 0.99f));
	it_inf.x = (float)MoveFormula(ballspeed, it_inf.y, ServerParam::ball_decay);

	Vector rel_it_pos = Vector(it_inf.x, 0);
	inf.IT_point = rel_it_pos.Rotate(ballangle) + ballpos;
	inf.IT_angle = (inf.IT_point - startpoint).Angle();

	float angle = NormalizeAngle((rel_it_pos - playerpos).Angle() + ballangle);
	float dist = Max(it_inf.y, kickarea);
	float allow_angle_diff = ASin(Min(kickarea, 0.9f)/dist);

	if(fabs(NormalizeAngle(inf.IT_angle - bdfacing)) < allow_angle_diff){
		//as you see, he doesn't need to turn more.
		inf.IT_valid = true;
		inf.IT_is_closeball = false;
		inf.IT_rapidness = GT_speed_utils::Player_Intercept_Speed();
		inf.IT_cycles = it_inf.y;
	}else{
		//so he has to turn now
		getinterceptioninfo( ballpos, ballvel, startpoint, playervel,  inf);
	}
}

bool Intercept_util::getcloseballinterceptioninfo(Vector selfpos, Vector ballpos, Vector selfvel, Vector ballvel, float selffacing, InterceptionInfo &inf, bool testonly){
//more sophisticated design can be added here, compare onlydashintercept with turn intercept
	float dashpow;
	if(testonly){
		safecloseit = false;
	}else{
		noturn_cycles = -1;
	}
	float cycles = (float)OnlyDashIntercept(IT_closeball_max_cycles, selfpos, ballpos, selfvel, ballvel, selffacing, dashpow, testonly);
	if (cycles >= 0){
	//Only dashs will do
	//patches
		if (cycles == 2 && getball_dist > 0.85f && !testonly){
			InterceptionInfo t_inf;
			float back_getball_dist = getball_dist;
			int turn_cycles = TurnDashIntercept(3, selfpos, ballpos, selfvel, ballvel, selffacing, t_inf);
			if (turn_cycles > 0 && t_inf.IT_cycles <= 3 
				&& (t_inf.IT_cycles <= 2 || t_inf.IT_cycles < adversary_cycles)
				&& (back_getball_dist - getball_dist > 0.15f)){
				inf = t_inf;
				DoLog("patches applyed---turn dash %.2f, %.2f", back_getball_dist, getball_dist);
				return true;
			}
		}

		DoLog(LOG_IT, "(close_ball) Only dash %.2f", cycles);
		inf.IT_is_closeball = true;
		inf.IT_dashpow = dashpow;
		inf.IT_angle = IT_dash_angle; // disable turn
		inf.IT_valid = true;
		inf.IT_cycles = cycles;
		inf.IT_point = ballpos +ballvel * (1 - Exp(ServerParam::ball_decay, cycles)) / (1 - ServerParam::ball_decay);
		return true;
	}
	if(cycles <= -2 && !testonly && safecloseit){
		noturn_cycles = IT_closeball_max_cycles - (int)cycles - 1;
	}  
//dash backwards
	cycles = (float)OnlyDashIntercept(3, selfpos, ballpos, selfvel, ballvel, selffacing + 180, dashpow, testonly);
	if ( cycles >= 0){
	//Only dashs will do
			//Only dashs will do
	//patches
		if (cycles == 2 && getball_dist > 0.85f && !testonly){
			InterceptionInfo t_inf;
			float back_getball_dist = getball_dist;
			int turn_cycles = TurnDashIntercept(3, selfpos, ballpos, selfvel, ballvel, selffacing, t_inf);
			if (turn_cycles > 0 && t_inf.IT_cycles <= 3 && getball_dist < back_getball_dist
				&& (t_inf.IT_cycles <= 2 || t_inf.IT_cycles < adversary_cycles)){
				inf = t_inf;
				DoLog("patches applyed---turn dash");
				return true;
			}
		}
		DoLog(LOG_IT, "(close_ball) backward Only dash %.2f", cycles);
		inf.IT_is_closeball = true;
		inf.IT_dashpow = -dashpow;
		inf.IT_angle = IT_dash_angle; // disable turn
		inf.IT_valid = true;
		inf.IT_cycles = cycles;
		inf.IT_point = ballpos +ballvel * (1 - Exp(ServerParam::ball_decay, cycles)) / (1 - ServerParam::ball_decay);
		return true;
	}
//if turn angle changes little, please
	cycles = (float)TurnDashIntercept(IT_closeball_max_cycles, selfpos, ballpos, selfvel, ballvel, selffacing, inf);
	if (cycles != -1){
		return true;
	}
	
	DoLog(LOG_IT, "No CloseBall");
	return false;
}

bool Intercept_util::OneCycleIntercept(Vector selfpos, Vector ballpos, Vector selfvel, Vector ballvel, float selfbodyfacing, float& dashpow, bool testonly){
	float min_dist, maxdasheffect, kickable_area;

	dashpow = 2 * ServerParam::max_power;	

	Vector ballrelpos = ballpos + ballvel- selfpos - selfvel;
	
	ballrelpos = ballrelpos.Rotate( - selfbodyfacing);
	
	if (testonly)
		kickable_area = reliable_kickarea;
	else
		kickable_area = kickarea;

	if (fabs(ballrelpos.y) > kickable_area) return false;
	maxdasheffect = maxdash_effect;
	if (ballrelpos.mod2() > Sqr(kickable_area + maxdasheffect)) return false;

	DoLog(LOG_IT, "(LastCycle) (%.2f %.2f) testonly %d", ballrelpos.x, ballrelpos.y, testonly);
	
	if (maxdasheffect > fabs(ballrelpos.x)){
		getball_dist = (float)fabs(ballrelpos.y);
		if (testonly)
			return true;
		
		if (fabs(ballrelpos.y) >= ClientParam::desired_kickarea){
			dashpow = float(fabs(ballrelpos.x) / dash_rate);
		}
		else{
		//There are two solutions, choose the one that is more robust
			float solution[2], dist[2];
			int final_solution = 0;
			solution[0] = float(fabs(ballrelpos.x) - sqrt(Sqr(ClientParam::desired_kickarea) - Sqr(ballrelpos.y)));
			solution[1] = 2 * (float)fabs(ballrelpos.x) - solution[0];
			pose_limitation(solution[0], -maxdasheffect, maxdasheffect);
			solution[1] = Min(solution[1], maxdasheffect);
			dist[0] = float(sqrt(Sqr(solution[0] - fabs(ballrelpos.x)) + Sqr(ballrelpos.y)));
			dist[1] = float(sqrt(Sqr(solution[1] - fabs(ballrelpos.x)) + Sqr(ballrelpos.y)));
			if (dist[0] < ClientParam::collision_threshold || dist[1] < ClientParam::collision_threshold){
				//if one solution leads to a collision, choose the bigger one
				if (dist[0] > dist[1])

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?