BOOL CObjectSpace::_RayQuery2 (collide::rq_results& r_dest, const collide::ray_defs& R, collide::rq_callback* CB, LPVOID user_data, collide::test_callback* tb, CObject* ignore_object) { // initialize query r_dest.r_clear (); r_temp.r_clear (); rq_target s_mask = rqtStatic; rq_target d_mask = rq_target( ((R.tgt&rqtObject) ?rqtObject:rqtNone )| ((R.tgt&rqtObstacle)?rqtObstacle:rqtNone )| ((R.tgt&rqtShape) ?rqtShape:rqtNone) ); u32 d_flags = STYPE_COLLIDEABLE|((R.tgt&rqtObstacle)?STYPE_OBSTACLE:0)|((R.tgt&rqtShape)?STYPE_SHAPE:0); // Test static if (R.tgt&s_mask){ xrc.ray_options (R.flags); xrc.ray_query (&Static,R.start,R.dir,R.range); if (xrc.r_count()){ CDB::RESULT* _I = xrc.r_begin(); CDB::RESULT* _E = xrc.r_end (); for (; _I!=_E; _I++) r_temp.append_result(rq_result().set(0,_I->range,_I->id)); } } // Test dynamic if (R.tgt&d_mask){ // Traverse object database g_SpatialSpace->q_ray (r_spatial,0,d_flags,R.start,R.dir,R.range); for (u32 o_it=0; o_it<r_spatial.size(); o_it++){ CObject* collidable = r_spatial[o_it]->dcast_CObject(); if (0==collidable) continue; if (collidable==ignore_object) continue; ICollisionForm* cform = collidable->collidable.model; ECollisionFormType tp = collidable->collidable.model->Type(); if (((R.tgt&(rqtObject|rqtObstacle))&&(tp==cftObject))||((R.tgt&rqtShape)&&(tp==cftShape))){ if (tb&&!tb(R,collidable,user_data))continue; cform->_RayQuery(R,r_temp); } } } if (r_temp.r_count()){ r_temp.r_sort (); collide::rq_result* _I = r_temp.r_begin (); collide::rq_result* _E = r_temp.r_end (); for (; _I!=_E; _I++){ r_dest.append_result(*_I); if (!(CB?CB(*_I,user_data):TRUE)) return r_dest.r_count(); if (R.flags&(CDB::OPT_ONLYNEAREST|CDB::OPT_ONLYFIRST)) return r_dest.r_count(); } } return r_dest.r_count(); }
bool CBulletManager::CalcBullet (collide::rq_results & rq_storage, xr_vector<ISpatial*>& rq_spatial, SBullet* bullet, u32 delta_time) { VERIFY (bullet); float delta_time_sec = float(delta_time)/1000.f; float range = bullet->speed*delta_time_sec; float max_range = bullet->max_dist - bullet->fly_dist; if(range>max_range) range = max_range; //запомнить текущую скорость пули, т.к. в //RayQuery() она может поменяться из-за рикошетов //и столкновений с объектами Fvector cur_dir = bullet->dir; bullet_test_callback_data bullet_data; bullet_data.pBullet = bullet; bullet_data.bStopTracing = true; bullet->flags.ricochet_was = 0; collide::ray_defs RD (bullet->pos, bullet->dir, range, CDB::OPT_CULL, collide::rqtBoth); BOOL result = FALSE; VERIFY (!fis_zero(RD.dir.square_magnitude())); result = Level().ObjectSpace.RayQuery(rq_storage, RD, firetrace_callback, &bullet_data, test_callback, NULL); if (result && bullet_data.bStopTracing) { range = (rq_storage.r_begin()+rq_storage.r_count()-1)->range; } range = _max (EPS_L,range); bullet->flags.skipped_frame = (Device.dwFrame >= bullet->frame_num); if(!bullet->flags.ricochet_was) { //изменить положение пули bullet->pos.mad(bullet->pos, cur_dir, range); bullet->fly_dist += range; if(bullet->fly_dist>=bullet->max_dist) return false; Fbox level_box = Level().ObjectSpace.GetBoundingVolume(); /* if(!level_box.contains(bullet->pos)) return false; */ if(!((bullet->pos.x>=level_box.x1) && (bullet->pos.x<=level_box.x2) && (bullet->pos.y>=level_box.y1) && // (bullet->pos.y<=level_box.y2) && (bullet->pos.z>=level_box.z1) && (bullet->pos.z<=level_box.z2)) ) return false; //изменить скорость и направление ее полета //с учетом гравитации bullet->dir.mul(bullet->speed); Fvector air_resistance = bullet->dir; if (GameID() == GAME_SINGLE) air_resistance.mul(-m_fAirResistanceK*delta_time_sec); else air_resistance.mul(-bullet->air_resistance*(bullet->speed)/(bullet->max_speed)*delta_time_sec); /// Msg("Speed - %f; ar - %f, %f", bullet->dir.magnitude(), air_resistance.magnitude(), air_resistance.magnitude()/bullet->dir.magnitude()*100); bullet->dir.add(air_resistance); bullet->dir.y -= m_fGravityConst*delta_time_sec; bullet->speed = bullet->dir.magnitude(); VERIFY(_valid(bullet->speed)); VERIFY(!fis_zero(bullet->speed)); // by Real Wolf 11.07.2014. R_ASSERT(bullet->speed); //вместо normalize(), чтоб не считать 2 раза magnitude() bullet->dir.x /= bullet->speed; bullet->dir.y /= bullet->speed; bullet->dir.z /= bullet->speed; } if(bullet->speed<m_fMinBulletSpeed) return false; return true; }
BOOL CObjectSpace::_RayQuery (collide::rq_results& r_dest, const collide::ray_defs& R, collide::rq_callback* CB, LPVOID user_data, collide::test_callback* tb, CObject* ignore_object) { #ifdef DEBUG if (R.range<EPS || !_valid(R.range)) Debug.fatal (DEBUG_INFO,"Invalid RayQuery range passed: %f.",R.range); #endif // initialize query r_dest.r_clear (); r_temp.r_clear (); Flags32 sd_test; sd_test.assign (R.tgt); rq_target next_test = R.tgt; rq_result s_res; ray_defs s_rd (R.start,R.dir,R.range,CDB::OPT_ONLYNEAREST|R.flags,R.tgt); ray_defs d_rd (R.start,R.dir,R.range,CDB::OPT_ONLYNEAREST|R.flags,R.tgt); rq_target s_mask = rqtStatic; rq_target d_mask = rq_target( ((R.tgt&rqtObject) ?rqtObject:rqtNone )| ((R.tgt&rqtObstacle)?rqtObstacle:rqtNone )| ((R.tgt&rqtShape) ?rqtShape:rqtNone) ); u32 d_flags = STYPE_COLLIDEABLE|((R.tgt&rqtObstacle)?STYPE_OBSTACLE:0)|((R.tgt&rqtShape)?STYPE_SHAPE:0); s_res.set (0,s_rd.range,-1); do{ if ((R.tgt&s_mask)&&sd_test.is(s_mask)&&(next_test&s_mask)){ s_res.set (0,s_rd.range,-1); // Test static model if (s_rd.range>EPS){ xrc.ray_options (s_rd.flags); xrc.ray_query (&Static,s_rd.start,s_rd.dir,s_rd.range); if (xrc.r_count()){ if (s_res.set_if_less(xrc.r_begin())){ // set new static start & range s_rd.range -= (s_res.range+EPS_L); s_rd.start.mad (s_rd.dir,s_res.range+EPS_L); s_res.range = R.range-s_rd.range-EPS_L; #ifdef DEBUG if (!(fis_zero(s_res.range,EPS) || s_res.range>=0.f)) Debug.fatal(DEBUG_INFO,"Invalid RayQuery static range: %f (%f). /#1/",s_res.range,s_rd.range); #endif } } } if (!s_res.valid()) sd_test.set(s_mask,FALSE); } if ((R.tgt&d_mask)&&sd_test.is_any(d_mask)&&(next_test&d_mask)){ r_temp.r_clear (); if (d_rd.range>EPS){ // Traverse object database g_SpatialSpace->q_ray (r_spatial,0,d_flags,d_rd.start,d_rd.dir,d_rd.range); // Determine visibility for dynamic part of scene for (u32 o_it=0; o_it<r_spatial.size(); o_it++){ CObject* collidable = r_spatial[o_it]->dcast_CObject(); if (0==collidable) continue; if (collidable==ignore_object) continue; ICollisionForm* cform = collidable->collidable.model; ECollisionFormType tp = collidable->collidable.model->Type(); if (((R.tgt&(rqtObject|rqtObstacle))&&(tp==cftObject))||((R.tgt&rqtShape)&&(tp==cftShape))){ if (tb&&!tb(d_rd,collidable,user_data))continue; cform->_RayQuery(d_rd,r_temp); } #ifdef DEBUG if (!((0==r_temp.r_count()) || (r_temp.r_count()&&(fis_zero(r_temp.r_begin()->range, EPS)||(r_temp.r_begin()->range>=0.f))))) Debug.fatal(DEBUG_INFO,"Invalid RayQuery dynamic range: %f (%f). /#2/",r_temp.r_begin()->range,d_rd.range); #endif } } if (r_temp.r_count()){ // set new dynamic start & range rq_result& d_res = *r_temp.r_begin(); d_rd.range -= (d_res.range+EPS_L); d_rd.start.mad(d_rd.dir,d_res.range+EPS_L); d_res.range = R.range-d_rd.range-EPS_L; #ifdef DEBUG if (!(fis_zero(d_res.range,EPS) || d_res.range>=0.f)) Debug.fatal(DEBUG_INFO,"Invalid RayQuery dynamic range: %f (%f). /#3/",d_res.range,d_rd.range); #endif }else{ sd_test.set(d_mask,FALSE); } } if (s_res.valid()&&r_temp.r_count()){ // all test return result if (s_res.range<r_temp.r_begin()->range){ // static nearer BOOL need_calc = CB?CB(s_res,user_data):TRUE; next_test = need_calc?s_mask:rqtNone; r_dest.append_result (s_res); }else{ // dynamic nearer BOOL need_calc = CB?CB(*r_temp.r_begin(),user_data):TRUE; next_test = need_calc?d_mask:rqtNone; r_dest.append_result (*r_temp.r_begin()); } }else if (s_res.valid()) { // only static return result BOOL need_calc = CB?CB(s_res,user_data):TRUE; next_test = need_calc?s_mask:rqtNone; r_dest.append_result (s_res); }else if (r_temp.r_count()) { // only dynamic return result BOOL need_calc = CB?CB(*r_temp.r_begin(),user_data):TRUE; next_test = need_calc?d_mask:rqtNone; r_dest.append_result (*r_temp.r_begin()); }else{ // nothing selected next_test = rqtNone; } if ((R.flags&CDB::OPT_ONLYFIRST)||(R.flags&CDB::OPT_ONLYNEAREST)) break; } while (next_test!=rqtNone) ; return r_dest.r_count () ; }
BOOL CObjectSpace::_RayQuery3 (collide::rq_results& r_dest, const collide::ray_defs& R, collide::rq_callback* CB, LPVOID user_data, collide::test_callback* tb, CObject* ignore_object) { // initialize query r_dest.r_clear (); ray_defs d_rd (R); ray_defs s_rd (R.start,R.dir,R.range,CDB::OPT_ONLYNEAREST|R.flags,R.tgt); rq_target s_mask = rqtStatic; rq_target d_mask = rq_target( ((R.tgt&rqtObject) ?rqtObject:rqtNone )| ((R.tgt&rqtObstacle)?rqtObstacle:rqtNone )| ((R.tgt&rqtShape) ?rqtShape:rqtNone) ); u32 d_flags = STYPE_COLLIDEABLE|((R.tgt&rqtObstacle)?STYPE_OBSTACLE:0)|((R.tgt&rqtShape)?STYPE_SHAPE:0); float d_range = 0.f; do{ r_temp.r_clear (); if (R.tgt&s_mask){ // static test allowed // test static xrc.ray_options (s_rd.flags); xrc.ray_query (&Static,s_rd.start,s_rd.dir,s_rd.range); if (xrc.r_count()) { VERIFY (xrc.r_count()==1); rq_result s_res; s_res.set (0,xrc.r_begin()->range,xrc.r_begin()->id); // update dynamic test range d_rd.range = s_res.range; // set next static start & range s_rd.range -= (s_res.range+EPS_L); s_rd.start.mad (s_rd.dir,s_res.range+EPS_L); s_res.range = R.range-s_rd.range-EPS_L; r_temp.append_result(s_res); }else{ d_rd.range = s_rd.range; } } // test dynamic if (R.tgt&d_mask) { // Traverse object database g_SpatialSpace->q_ray (r_spatial,0,d_flags,d_rd.start,d_rd.dir,d_rd.range); for (u32 o_it=0; o_it<r_spatial.size(); o_it++){ CObject* collidable = r_spatial[o_it]->dcast_CObject(); if (0==collidable) continue; if (collidable==ignore_object) continue; ICollisionForm* cform = collidable->collidable.model; ECollisionFormType tp = collidable->collidable.model->Type(); if (((R.tgt&(rqtObject|rqtObstacle))&&(tp==cftObject))||((R.tgt&rqtShape)&&(tp==cftShape))){ if (tb&&!tb(d_rd,collidable,user_data))continue; u32 r_cnt = r_temp.r_count(); cform->_RayQuery (d_rd,r_temp); for (int k=r_cnt; k<r_temp.r_count(); k++){ rq_result& d_res = *(r_temp.r_begin()+k); d_res.range += d_range; } } } } // set dynamic ray def d_rd.start = s_rd.start; d_range = R.range-s_rd.range; if (r_temp.r_count()){ r_temp.r_sort (); collide::rq_result* _I = r_temp.r_begin (); collide::rq_result* _E = r_temp.r_end (); for (; _I!=_E; _I++){ r_dest.append_result(*_I); if (!(CB?CB(*_I,user_data):TRUE)) return r_dest.r_count(); if (R.flags&CDB::OPT_ONLYFIRST) return r_dest.r_count(); } } if ((R.flags&(CDB::OPT_ONLYNEAREST|CDB::OPT_ONLYFIRST)) && r_dest.r_count()) return r_dest.r_count(); }while(r_temp.r_count()); return r_dest.r_count() ; }