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