Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Level_Bullet_Manager.cpp: для обеспечения полета пули по траектории
- // все пули и осколки передаются сюда
- //////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- #include "Level.h"
- #include "Level_Bullet_Manager.h"
- #include "game_cl_base.h"
- #include "Actor.h"
- #include "gamepersistent.h"
- #include "mt_config.h"
- #include "game_cl_base_weapon_usage_statistic.h"
- #include "game_cl_mp.h"
- #include "reward_event_generator.h"
- #include "../Include/xrRender/UIRender.h"
- #include "../Include/xrRender/Kinematics.h"
- #ifdef DEBUG
- # include "debug_renderer.h"
- #endif
- #define HIT_POWER_EPSILON 0.05f
- #define WALLMARK_SIZE 0.04f
- float CBulletManager::m_fMinBulletSpeed = 2.f;
- float const CBulletManager::parent_ignore_distance = 3.f;
- #ifdef DEBUG
- float air_resistance_epsilon = .1f;
- #else // #ifdef DEBUG
- static float const air_resistance_epsilon = .1f;
- #endif // #ifdef DEBUG
- float g_bullet_time_factor = 1.f;
- SBullet::SBullet()
- {
- }
- SBullet::~SBullet()
- {
- }
- void SBullet::Init(const Fvector& position,
- const Fvector& direction,
- float starting_speed,
- float power,
- //. float power_critical,
- float impulse,
- u16 sender_id,
- u16 sendersweapon_id,
- ALife::EHitType e_hit_type,
- float maximum_distance,
- const CCartridge& cartridge,
- float const air_resistance_factor,
- bool SendHit)
- {
- flags._storage = 0;
- bullet_pos = position;
- speed = max_speed = starting_speed;
- VERIFY (speed > 0.f);
- start_position = position;
- start_velocity.mul (direction, starting_speed);
- born_time = Device.dwTimeGlobal;
- life_time = 0.f;
- VERIFY (direction.magnitude() > 0.f);
- dir.normalize (direction);
- hit_param.power = power * cartridge.param_s.kHit;
- hit_param.impulse = impulse * cartridge.param_s.kImpulse;
- max_dist = maximum_distance * cartridge.param_s.kDist;
- fly_dist = 0;
- tracer_start_position = bullet_pos;
- parent_id = sender_id;
- flags.allow_sendhit = SendHit;
- weapon_id = sendersweapon_id;
- hit_type = e_hit_type;
- armor_piercing = cartridge.param_s.kAP;
- air_resistance = cartridge.param_s.kAirRes*air_resistance_factor;
- wallmark_size = cartridge.param_s.fWallmarkSize;
- m_u8ColorID = cartridge.param_s.u8ColorID;
- bullet_material_idx = cartridge.bullet_material_idx;
- VERIFY ( u16(-1) != bullet_material_idx );
- flags.allow_tracer = !!cartridge.m_flags.test(CCartridge::cfTracer);
- flags.allow_ricochet = !!cartridge.m_flags.test(CCartridge::cfRicochet);
- flags.explosive = !!cartridge.m_flags.test(CCartridge::cfExplosive);
- flags.magnetic_beam = !!cartridge.m_flags.test(CCartridge::cfMagneticBeam);
- // flags.skipped_frame = 0;
- init_frame_num = Device.dwFrame;
- targetID = 0;
- density_mode = 0;
- }
- CBulletManager::CBulletManager()
- #if 0//def PROFILE_CRITICAL_SECTIONS
- : m_Lock(MUTEX_PROFILE_ID(CBulletManager))
- # ifdef DEBUG
- ,m_thread_id(GetCurrentThreadId())
- # endif // #ifdef DEBUG
- #else // #ifdef PROFILE_CRITICAL_SECTIONS
- # ifdef DEBUG
- : m_thread_id(GetCurrentThreadId())
- # endif // #ifdef DEBUG
- #endif // #ifdef PROFILE_CRITICAL_SECTIONS
- {
- m_Bullets.clear ();
- m_Bullets.reserve (100);
- }
- CBulletManager::~CBulletManager()
- {
- m_Bullets.clear ();
- m_WhineSounds.clear ();
- m_Events.clear ();
- }
- void CBulletManager::Load ()
- {
- char const * bullet_manager_sect = "bullet_manager";
- if (!IsGameTypeSingle())
- {
- bullet_manager_sect = "mp_bullet_manager";
- }
- m_fTracerWidth = pSettings->r_float(bullet_manager_sect, "tracer_width");
- m_fTracerLengthMax = pSettings->r_float(bullet_manager_sect, "tracer_length_max");
- m_fTracerLengthMin = pSettings->r_float(bullet_manager_sect, "tracer_length_min");
- m_fGravityConst = pSettings->r_float(bullet_manager_sect, "gravity_const");
- m_fAirResistanceK = pSettings->r_float(bullet_manager_sect, "air_resistance_k");
- m_fMinBulletSpeed = pSettings->r_float(bullet_manager_sect, "min_bullet_speed");
- m_fCollisionEnergyMin = pSettings->r_float(bullet_manager_sect, "collision_energy_min");
- m_fCollisionEnergyMax = pSettings->r_float(bullet_manager_sect, "collision_energy_max");
- m_fHPMaxDist = pSettings->r_float(bullet_manager_sect, "hit_probability_max_dist");
- if (pSettings->line_exist(bullet_manager_sect, "bullet_velocity_time_factor"))
- {
- g_bullet_time_factor = pSettings->r_float(bullet_manager_sect, "bullet_velocity_time_factor");
- }
- LPCSTR whine_sounds = pSettings->r_string(bullet_manager_sect, "whine_sounds");
- int cnt = _GetItemCount(whine_sounds);
- xr_string tmp;
- for (int k=0; k<cnt; ++k)
- {
- m_WhineSounds.push_back (ref_sound());
- m_WhineSounds.back().create(_GetItem(whine_sounds,k,tmp),st_Effect,sg_SourceType);
- }
- LPCSTR explode_particles= pSettings->r_string(bullet_manager_sect, "explode_particles");
- cnt = _GetItemCount(explode_particles);
- for (int k=0; k<cnt; ++k)
- m_ExplodeParticles.push_back (_GetItem(explode_particles,k,tmp));
- }
- void CBulletManager::PlayExplodePS( const Fmatrix& xf )
- {
- if ( m_ExplodeParticles.empty() )
- return;
- shared_str const& ps_name = m_ExplodeParticles[Random.randI(0, m_ExplodeParticles.size())];
- CParticlesObject* const ps = CParticlesObject::Create(*ps_name,TRUE);
- ps->UpdateParent (xf,zero_vel);
- GamePersistent().ps_needtoplay.push_back(ps);
- }
- void CBulletManager::PlayWhineSound(SBullet* bullet, CObject* object, const Fvector& pos)
- {
- if (m_WhineSounds.empty()) return;
- if (bullet->m_whine_snd._feedback() != NULL) return;
- if(bullet->hit_type!=ALife::eHitTypeFireWound ) return;
- bullet->m_whine_snd = m_WhineSounds[Random.randI(0, m_WhineSounds.size())];
- bullet->m_whine_snd.play_at_pos (object,pos);
- }
- void CBulletManager::Clear ()
- {
- m_Bullets.clear ();
- m_Events.clear ();
- }
- void CBulletManager::AddBullet(const Fvector& position,
- const Fvector& direction,
- float starting_speed,
- float power,
- //. float power_critical,
- float impulse,
- u16 sender_id,
- u16 sendersweapon_id,
- ALife::EHitType e_hit_type,
- float maximum_distance,
- const CCartridge& cartridge,
- float const air_resistance_factor,
- bool SendHit,
- bool AimBullet)
- {
- VERIFY ( m_thread_id == GetCurrentThreadId() );
- VERIFY (u16(-1)!=cartridge.bullet_material_idx);
- // u32 CurID = Level().CurrentControlEntity()->ID();
- // u32 OwnerID = sender_id;
- m_Bullets.push_back (SBullet());
- SBullet& bullet = m_Bullets.back();
- bullet.Init (position, direction, starting_speed, power, /*power_critical,*/ impulse, sender_id, sendersweapon_id, e_hit_type, maximum_distance, cartridge, air_resistance_factor, SendHit);
- // bullet.frame_num = Device.dwFrame;
- bullet.flags.aim_bullet = AimBullet;
- if (!IsGameTypeSingle())
- {
- if (SendHit)
- Game().m_WeaponUsageStatistic->OnBullet_Fire(&bullet, cartridge);
- game_cl_mp* tmp_cl_game = smart_cast<game_cl_mp*>(&Game());
- if (tmp_cl_game->get_reward_generator())
- tmp_cl_game->get_reward_generator()->OnBullet_Fire(sender_id, sendersweapon_id, position, direction);
- }
- }
- void CBulletManager::UpdateWorkload()
- {
- // VERIFY ( m_thread_id == GetCurrentThreadId() );
- rq_storage.r_clear ();
- u32 const time_delta = Device.dwTimeDelta;
- if (!time_delta)
- return;
- collide::rq_result dummy;
- // this is because of ugly nature of removing bullets
- // when index in vector passed through the tgt_material field
- // and we can remove them only in case when we iterate bullets
- // in the reversed order
- BulletVec::reverse_iterator i = m_Bullets.rbegin();
- BulletVec::reverse_iterator e = m_Bullets.rend();
- for (u16 j=u16(e - i); i != e; ++i, --j) {
- if ( process_bullet( rq_storage, *i, u32(time_delta*g_bullet_time_factor)) )
- continue;
- VERIFY (j > 0);
- RegisterEvent (EVENT_REMOVE, FALSE, &*i, Fvector().set(0, 0, 0), dummy, j - 1);
- }
- }
- static Fvector parabolic_velocity (
- Fvector const& start_velocity,
- Fvector const& gravity,
- float const air_resistance,
- float const time
- )
- {
- return (
- Fvector(start_velocity).mul(
- _max( 0.f, 1.f - air_resistance*time)
- ).mad(
- gravity,
- time
- )
- );
- }
- static Fvector trajectory_velocity (
- Fvector const& start_velocity,
- Fvector const& gravity,
- float const air_resistance,
- float const time
- )
- {
- float const parabolic_time = _max( 0.f, 2.f/air_resistance - air_resistance_epsilon);
- float const fall_down_time = time - parabolic_time;
- // float const fake_velocity = start_velocity*2.f;
- if ( fall_down_time < 0.f ) {
- Fvector const xz_velocity = Fvector().set( start_velocity.x, 0.f, start_velocity.z);
- // this could be since we could fire in different directions
- // for example, vertically into the ground
- if ( !fis_zero(xz_velocity.square_magnitude()) ) {
- return (
- parabolic_velocity(
- start_velocity,
- gravity,
- air_resistance,
- time
- )
- );
- }
- // this fake since our formula doesn't take into account
- // directions correctly
- return (
- Fvector(start_velocity).mad(
- gravity,
- time
- )
- );
- }
- Fvector parabolic_velocity =
- ::parabolic_velocity(
- start_velocity,
- gravity,
- air_resistance,
- parabolic_time
- );
- VERIFY (!fis_zero(air_resistance_epsilon) || fis_zero(_sqr(parabolic_velocity.x) + _sqr(parabolic_velocity.z), EPS_L) );
- return (
- parabolic_velocity.mad(
- gravity,
- fall_down_time
- )
- );
- }
- static Fvector parabolic_position (
- Fvector const& start_position,
- Fvector const& start_velocity,
- Fvector const& gravity,
- float const air_resistance,
- float const time
- )
- {
- float const sqr_t_div_2 = _sqr(time)*.5f;
- return (
- Fvector().mad(
- start_position,
- start_velocity,
- time
- ).mad(
- Fvector(start_velocity).mul(-air_resistance),
- sqr_t_div_2
- ).mad(
- gravity,
- sqr_t_div_2
- )
- );
- }
- //BOOL g_use_new_ballistics = 0;
- #ifdef DEBUG
- float dbg_bullet_time_factor = 1.f;
- #endif
- static Fvector trajectory_position (
- Fvector const& start_position,
- Fvector const& base_start_velocity,
- Fvector const& base_gravity,
- float base_air_resistance,
- float const base_time
- )
- {
- Fvector const & gravity = base_gravity;//g_use_new_ballistics ? Fvector(base_gravity).mul(_sqr(factor)) : base_gravity;
- float const & air_resistance = base_air_resistance;//g_use_new_ballistics ? base_air_resistance*factor : base_air_resistance;
- Fvector const & start_velocity = base_start_velocity;//g_use_new_ballistics ? Fvector(base_start_velocity).mul( factor ) : base_start_velocity;
- float const time = base_time;
- float const parabolic_time = _max( 0.f, 1.f/air_resistance - air_resistance_epsilon);
- float const fall_down_time = time - parabolic_time;
- if ( fall_down_time < 0.f ) {
- Fvector const xz_velocity = Fvector().set( start_velocity.x, 0.f, start_velocity.z);
- if ( !fis_zero(xz_velocity.square_magnitude()) )
- return (
- parabolic_position(
- start_position,
- start_velocity,
- gravity,
- air_resistance,
- time
- )
- );
- return (
- Fvector(start_position).mad (
- start_velocity,
- time
- ).mad(
- gravity,
- _sqr(time)*.5f
- )
- );
- }
- Fvector const parabolic_position =
- ::parabolic_position(
- start_position,
- start_velocity,
- gravity,
- air_resistance,
- parabolic_time
- );
- Fvector const parabolic_velocity =
- ::parabolic_velocity(
- start_velocity,
- gravity,
- air_resistance,
- parabolic_time
- );
- return (
- Fvector(parabolic_position).mad (
- parabolic_velocity,
- fall_down_time
- ).mad(
- gravity,
- _sqr(fall_down_time)*.5f
- )
- );
- }
- inline static float trajectory_max_error_time (
- float const t0,
- float const t1
- )
- {
- return ( (t1 + t0)*.5f );
- // this is correct even in our case
- // y(t) = V0y*t - V0y*ar*t^2/2 - g*t^2/2
- // x(t) = V0x*t - V0x*ar*t^2/2
- }
- static float trajectory_pick_error (
- float const low,
- float const high,
- Fvector const& position,
- Fvector const& velocity,
- Fvector const& gravity,
- float const air_resistance
- )
- {
- float max_error_time = trajectory_max_error_time(low, high);
- Fvector const start = trajectory_position(position, velocity, gravity, air_resistance, low);
- Fvector const target = trajectory_position(position, velocity, gravity, air_resistance, high);
- Fvector const max_error = trajectory_position(position, velocity, gravity, air_resistance, max_error_time);
- Fvector start_to_max_error = Fvector().sub(max_error,start);
- float magnitude = start_to_max_error.magnitude();
- start_to_max_error.mul (1.f/magnitude);
- Fvector start_to_target = Fvector().sub(target,start).normalize();
- float cosine_alpha = _max(-1.f, _min(start_to_max_error.dotproduct(start_to_target), 1.f));
- float sine_alpha = _sqrt(1.f - _sqr(cosine_alpha));
- return (magnitude*sine_alpha);
- }
- static float trajectory_select_pick_gravity (
- SBullet& bullet,
- float start_low,
- float const high,
- Fvector const& gravity,
- float const air_resistance
- )
- {
- float const max_test_distance = bullet.max_dist - bullet.fly_dist;
- float const time_delta = high - start_low;
- float const time_to_fly = Fvector(bullet.start_velocity).mul(time_delta).mad(gravity, _sqr(time_delta)*.5f).magnitude();
- if (time_to_fly <= max_test_distance)
- return (high);
- float const fall_down_velocity_magnitude = bullet.speed;
- float const positive_gravity = -gravity.y;
- float time = (
- _sqrt( _sqr(fall_down_velocity_magnitude) + 2.f*max_test_distance*positive_gravity ) -
- fall_down_velocity_magnitude
- )/positive_gravity;
- VERIFY (time >= 0.f);
- VERIFY (high >= start_low);
- float result = start_low + time;
- clamp (result, start_low, high);
- VERIFY2 ( result <= high, make_string("result[%f], high[%f], start_low[%f], air_resistance[%f]", result, high, start_low, air_resistance) );
- return ( result );
- }
- static float trajectory_select_pick_parabolic (
- SBullet& bullet,
- float const start_low,
- float high,
- Fvector const& gravity,
- float const air_resistance
- )
- {
- float const max_test_distance = bullet.max_dist - bullet.fly_dist;
- Fvector const start = trajectory_position(bullet.start_position, bullet.start_velocity, gravity, air_resistance, start_low);
- float const start_high = high;
- float low = start_low;
- float check_time = high;
- while ( !fsimilar(low, high) ) {
- Fvector const intermediate = trajectory_position(bullet.start_position, bullet.start_velocity, gravity, air_resistance, start_low + (check_time - start_low)*.5f);
- Fvector const target = trajectory_position(bullet.start_position, bullet.start_velocity, gravity, air_resistance, check_time);
- float const distance = start.distance_to(intermediate) + intermediate.distance_to(target);
- if (distance < max_test_distance)
- low = check_time;
- else
- high = check_time;
- check_time = (low + high)*.5f;
- }
- VERIFY ( low <= start_high );
- return (low);
- }
- static bool trajectory_select_pick_ranges(
- float& result,
- SBullet& bullet,
- float const low,
- float const high,
- Fvector const& gravity,
- float const air_resistance
- )
- {
- float const max_test_distance = bullet.max_dist - bullet.fly_dist;
- VERIFY (max_test_distance > 0.f);
- if ( air_resistance*(low + air_resistance_epsilon) >= 1.f ) {
- result = trajectory_select_pick_gravity(bullet, low, high, gravity, air_resistance);
- return (true);
- }
- if ( air_resistance*(high + air_resistance_epsilon) < 1.f ) {
- result = trajectory_select_pick_parabolic(bullet, low, high, gravity, air_resistance);
- return (false);
- }
- float const fall_down_time = _max( 0.f, 1.f/air_resistance - air_resistance_epsilon);
- if ( !fsimilar(fall_down_time, low) ) {
- result = trajectory_select_pick_parabolic(bullet, low, fall_down_time, gravity, air_resistance);
- return (false);
- }
- result = trajectory_select_pick_gravity(bullet, fall_down_time, high, gravity, air_resistance);
- return (false);
- }
- static float trajectory_select_pick_time (
- SBullet& bullet,
- float const start_low,
- float high,
- Fvector const& gravity,
- float const air_resistance
- )
- {
- VERIFY2 ( start_low < high, make_string("start_low[%f] high[%f]", start_low, high) );
- float const start_high = high;
- if (trajectory_select_pick_ranges(high, bullet, start_low, high, gravity, air_resistance)) {
- if (high <= start_high)
- return (high);
- return (start_high);
- }
- float low = start_low;
- float check_time = high;
- float const epsilon = .1f;
- while ( !fsimilar(low, high) ) {
- float distance = trajectory_pick_error(start_low, check_time, bullet.start_position, bullet.start_velocity, gravity, air_resistance);
- if (distance < epsilon)
- low = check_time;
- else
- high = check_time;
- check_time = (low + high)*.5f;
- }
- VERIFY2 (low <= start_high, make_string("low[%f], high[%f]", low, start_high));
- return (low);
- }
- void CBulletManager::add_bullet_point (
- Fvector const& start_position,
- Fvector& previous_position,
- Fvector const& start_velocity,
- Fvector const& gravity,
- float const air_resistance,
- float const current_time
- )
- {
- #ifdef DEBUG
- Fvector const temp = trajectory_position(start_position, start_velocity, gravity, air_resistance, current_time);
- m_bullet_points.push_back (previous_position);
- m_bullet_points.push_back (temp);
- previous_position = temp;
- #endif // #ifdef DEBUG
- }
- static void update_bullet_parabolic (
- SBullet& bullet,
- bullet_test_callback_data& data,
- Fvector const& gravity,
- float const air_resistance
- )
- {
- Fvector xz_projection = Fvector(data.collide_position).sub(bullet.start_position);
- xz_projection.y = 0;
- float const xz_range = xz_projection.magnitude();
- Fvector const xz_velocity = Fvector().set(bullet.start_velocity.x, 0.f, bullet.start_velocity.z);
- VERIFY (air_resistance >= 0.f);
- if ( air_resistance > 0.f ) {
- float value = 2*air_resistance*xz_range/xz_velocity.magnitude();
- clamp (value, 0.f, 1.f);
- VERIFY (value <= 1.f);
- VERIFY (value >= 0.f);
- data.collide_time = (1.f - _sqrt(1.f - value))/air_resistance;
- }
- else
- data.collide_time = xz_range/xz_velocity.magnitude();
- VERIFY (data.collide_time >= 0.f);
- // VERIFY (data.collide_time <= data.high_time);
- // VERIFY (data.collide_time >= bullet.life_time);
- // VERIFY (data.collide_time <= bullet.life_time + Device.fTimeGlobal);
- clamp (data.collide_time, bullet.life_time, data.high_time);
- data.collide_position = trajectory_position(bullet.start_position, bullet.start_velocity, gravity, air_resistance, data.collide_time);
- Fvector const new_velocity = trajectory_velocity(bullet.start_velocity, gravity, air_resistance, data.collide_time);
- bullet.speed = new_velocity.magnitude();
- bullet.dir = Fvector(new_velocity).normalize_safe();
- }
- static void update_bullet_gravitation (
- SBullet& bullet,
- bullet_test_callback_data& data,
- Fvector const& gravity,
- float const air_resistance,
- float const fall_down_time
- )
- {
- Fvector const fall_down_position= trajectory_position(bullet.start_position, bullet.start_velocity, gravity, air_resistance, fall_down_time);
- Fvector const fall_down_velocity= trajectory_velocity(bullet.start_velocity, gravity, air_resistance, fall_down_time);
- VERIFY ( !fis_zero(air_resistance_epsilon) || fis_zero( _sqr(fall_down_velocity.x) + _sqr(fall_down_velocity.z), EPS_L) );
- float const fall_down_velocity_magnitude = fall_down_velocity.magnitude();
- Fvector xz_projection = Fvector(data.collide_position).sub(fall_down_position);
- xz_projection.y = 0;
- float const xz_range = xz_projection.magnitude();
- Fvector const xz_velocity = Fvector().set(fall_down_velocity.x, 0.f, fall_down_velocity.z);
- if ( !fis_zero(xz_velocity.magnitude()) ) {
- data.collide_time = fall_down_time + xz_range/xz_velocity.magnitude();
- VERIFY (data.collide_time >= 0.f);
- // VERIFY (data.collide_time <= data.high_time);
- // VERIFY (data.collide_time >= bullet.life_time);
- // VERIFY (data.collide_time <= bullet.life_time + Device.fTimeGlobal);
- clamp (data.collide_time, bullet.life_time, data.high_time);
- }
- else {
- float const positive_gravity = -gravity.y;
- float const distance = fall_down_position.distance_to(data.collide_position);
- data.collide_time = fall_down_time +
- (
- _sqrt( _sqr(fall_down_velocity_magnitude) + 2.f*distance*positive_gravity ) -
- fall_down_velocity_magnitude
- )/positive_gravity;
- VERIFY (data.collide_time >= 0.f);
- // VERIFY (data.collide_time <= data.high_time);
- // VERIFY (data.collide_time >= bullet.life_time);
- // VERIFY (data.collide_time <= bullet.life_time + Device.fTimeGlobal);
- clamp (data.collide_time, bullet.life_time, data.high_time);
- }
- Fvector const new_velocity = trajectory_velocity(bullet.start_velocity, gravity, air_resistance, data.collide_time);
- bullet.speed = new_velocity.magnitude();
- bullet.dir = Fvector(new_velocity).normalize_safe();
- }
- static void update_bullet (
- SBullet& bullet,
- bullet_test_callback_data& data,
- Fvector const& gravity,
- float const air_resistance
- )
- {
- if ( air_resistance*(bullet.life_time + air_resistance_epsilon) >= 1.f ) {
- update_bullet_gravitation (bullet, data, gravity, air_resistance, _max( 0.f, 1.f/air_resistance - air_resistance_epsilon));
- return;
- }
- Fvector const xz_velocity = Fvector().set( bullet.start_velocity.x, 0.f, bullet.start_velocity.z );
- if ( fis_zero(xz_velocity.square_magnitude()) ) {
- update_bullet_gravitation (bullet, data, gravity, air_resistance, 0.f);
- return;
- }
- update_bullet_parabolic (bullet, data, gravity, air_resistance);
- }
- BOOL CBulletManager::firetrace_callback (collide::rq_result& result, LPVOID params)
- {
- bullet_test_callback_data& data = *(bullet_test_callback_data*)params;
- SBullet& bullet = *data.pBullet;
- Fvector& collide_position = data.collide_position;
- collide_position = Fvector().mad(bullet.bullet_pos, bullet.dir, result.range);
- float const air_resistance = (GameID() == eGameIDSingle) ? Level().BulletManager().m_fAirResistanceK : bullet.air_resistance;
- CBulletManager& bullet_manager = Level().BulletManager();
- Fvector const gravity = { 0.f, -bullet_manager.m_fGravityConst, 0.f };
- update_bullet ( bullet, data, gravity, air_resistance);
- if ( fis_zero(bullet.speed) )
- return (FALSE);
- if ( fis_zero(data.collide_time) )
- return (TRUE);
- //статический объект
- if (!result.O) {
- CDB::TRI const& triangle = *(Level().ObjectSpace.GetStaticTris() + result.element);
- bullet_manager.RegisterEvent(EVENT_HIT, FALSE, &bullet, collide_position, result, triangle.material);
- return (FALSE);
- }
- //динамический объект
- VERIFY ( !(result.O->ID() == bullet.parent_id && bullet.fly_dist < parent_ignore_distance) );
- IKinematics* const kinematics = smart_cast<IKinematics*>(result.O->Visual());
- if (!kinematics)
- return (FALSE);
- CBoneData const& bone_data = kinematics->LL_GetData( (u16)result.element );
- bullet_manager.RegisterEvent ( EVENT_HIT, TRUE, &bullet, collide_position, result, bone_data.game_mtl_idx );
- return (FALSE);
- }
- bool CBulletManager::trajectory_check_error (
- Fvector& previous_position,
- collide::rq_results& storage,
- SBullet& bullet,
- float& low,
- float& high,
- Fvector const& gravity,
- float const air_resistance
- )
- {
- Fvector const& position = bullet.start_position;
- Fvector const& velocity = bullet.start_velocity;
- Fvector const start = trajectory_position(position, velocity, gravity, air_resistance, low);
- Fvector const target = trajectory_position(position, velocity, gravity, air_resistance, high);
- Fvector start_to_target = Fvector().sub(target,start);
- float const distance = start_to_target.magnitude();
- if ( fis_zero(distance) )
- return (true);
- start_to_target.mul ( 1.f/distance );
- bullet_test_callback_data data;
- data.pBullet = •
- #if 1//def DEBUG
- data.high_time = high;
- #endif // #ifdef DEBUG
- bullet.flags.ricochet_was = 0;
- bullet.dir = start_to_target;
- collide::ray_defs RD (start, start_to_target, distance, CDB::OPT_FULL_TEST, collide::rqtBoth);
- BOOL const result = Level().ObjectSpace.RayQuery(storage, RD, CBulletManager::firetrace_callback, &data, CBulletManager::test_callback, NULL);
- if ( !result || (data.collide_time == 0.f) ) {
- add_bullet_point (bullet.start_position, previous_position, bullet.start_velocity, gravity, air_resistance, high);
- return (true);
- }
- add_bullet_point (bullet.start_position, previous_position, bullet.start_velocity, gravity, air_resistance, data.collide_time);
- low = 0.f;
- VERIFY (high >= data.collide_time);
- high -= data.collide_time;
- ++bullet.change_rajectory_count;
- bullet.start_position = data.collide_position;
- bullet.tracer_start_position = bullet.bullet_pos;
- bullet.bullet_pos = data.collide_position;
- bullet.start_velocity = Fvector().mul(bullet.dir, bullet.speed);
- bullet.born_time += iFloor(data.collide_time*1000.f);
- bullet.life_time = 0.f;
- return (false);
- }
- static bool try_update_bullet (SBullet& bullet, Fvector const& gravity, float const air_resistance, float const time)
- {
- Fvector const new_position = trajectory_position(bullet.start_position, bullet.start_velocity, gravity, air_resistance, time);
- bullet.fly_dist += bullet.bullet_pos.distance_to(new_position);
- if (bullet.fly_dist >= bullet.max_dist)
- return (false);
- Fbox const level_box = Level().ObjectSpace.GetBoundingVolume();
- if (
- (bullet.bullet_pos.x < level_box.x1) ||
- (bullet.bullet_pos.x > level_box.x2) ||
- (bullet.bullet_pos.y < level_box.y1) ||
- // (bullet.bullet_pos.y > level_box.y2) ||
- (bullet.bullet_pos.z < level_box.z1) ||
- (bullet.bullet_pos.z > level_box.z2)
- )
- return (false);
- Fvector const new_velocity = trajectory_velocity(bullet.start_velocity, gravity, air_resistance, bullet.life_time);
- bullet.speed = new_velocity.magnitude();
- if ( fis_zero(bullet.speed) )
- return (false);
- bullet.bullet_pos = new_position;
- bullet.dir = Fvector(new_velocity).normalize_safe();
- bullet.life_time = time;
- return (true);
- }
- bool CBulletManager::process_bullet (collide::rq_results & storage, SBullet& bullet, u32 const delta_time)
- {
- float const time_delta = float(delta_time)/1000.f;
- Fvector const gravity = Fvector().set( 0.f, -m_fGravityConst, 0.f);
- float const air_resistance = (GameID() == eGameIDSingle) ? m_fAirResistanceK : bullet.air_resistance;
- bullet.tracer_start_position= bullet.bullet_pos;
- #if 0//def DEBUG
- extern BOOL g_bDrawBulletHit;
- if (g_bDrawBulletHit)
- {
- Msg (
- "free fly velocity: %f",
- trajectory_velocity(
- bullet.start_velocity,
- gravity,
- air_resistance,
- fis_zero(air_resistance) ?
- 0.f :
- (1.f/air_resistance - air_resistance_epsilon)
- ).magnitude()
- );
- }
- #endif
- Fvector const&start_position= bullet.bullet_pos;
- Fvector previous_position = start_position;
- float low = bullet.life_time;
- float high = bullet.life_time + time_delta;
- // Msg ("process_bullet0: low[%f], high[%f]", low, high);
- bullet.change_rajectory_count = 0;
- for (;;) {
- for (;;) {
- if ( bullet.speed < 1.f )
- return (false);
- if ( bullet.change_rajectory_count >= 32 )
- return (false);
- float time = trajectory_select_pick_time(bullet, low, high, gravity, air_resistance);
- if (time == low)
- return (false);
- float safe_time = time;
- VERIFY2 ( safe_time <= high, make_string("safe_time[%f], high[%f]", safe_time, high) );
- if ( !trajectory_check_error(previous_position, storage, bullet, low, time, gravity, air_resistance) ) {
- VERIFY2 ( safe_time >= time, make_string("safe_time[%f], time[%f]", safe_time, time) );
- VERIFY2 ( safe_time <= high, make_string("safe_time[%f], high[%f]", safe_time, high) );
- // clamp (safe_time, time, high);
- high = high - safe_time + time;
- VERIFY2 ( low <= high, make_string("start_low[%f] high[%f]", low, high) );
- if ( fsimilar(low, high) )
- return ( !fis_zero(bullet.speed) );
- break;
- }
- if ( !try_update_bullet(bullet, gravity, air_resistance, time) )
- return (false);
- if ( fsimilar(time, high) )
- return ( true );
- VERIFY2 ( low < high, make_string("start_low[%f] high[%f]", low, high) );
- low = time;
- VERIFY2 ( low < high, make_string("start_low[%f] high[%f]", low, high) );
- }
- if ( fis_zero(bullet.speed) )
- return (false);
- }
- }
- #ifdef DEBUG
- BOOL g_bDrawBulletHit = FALSE;
- #endif
- float SqrDistancePointToSegment(const Fvector& pt, const Fvector& orig, const Fvector& dir)
- {
- Fvector diff; diff.sub(pt,orig);
- float fT = diff.dotproduct(dir);
- if ( fT <= 0.0f ){
- fT = 0.0f;
- }else{
- float fSqrLen= dir.square_magnitude();
- if ( fT >= fSqrLen ){
- fT = 1.0f;
- diff.sub(dir);
- }else{
- fT /= fSqrLen;
- diff.sub(Fvector().mul(dir,fT));
- }
- }
- return diff.square_magnitude();
- }
- void CBulletManager::Render ()
- {
- #ifdef DEBUG
- if (g_bDrawBulletHit && !m_bullet_points.empty()) {
- VERIFY (!(m_bullet_points.size() % 2));
- CDebugRenderer& renderer = Level().debug_renderer();
- Fmatrix sphere = Fmatrix().scale(.05f, .05f, .05f);
- BulletPoints::const_iterator i = m_bullet_points.begin();
- BulletPoints::const_iterator e = m_bullet_points.end();
- for ( ; i != e; i+=2) {
- sphere.c = *i;
- renderer.draw_ellipse (sphere, D3DCOLOR_XRGB(255, 0, 0));
- renderer.draw_line (Fidentity, *i, *(i + 1), D3DCOLOR_XRGB(0, 255, 0));
- sphere.c = *(i + 1);
- renderer.draw_ellipse (sphere, D3DCOLOR_XRGB(255, 0, 0));
- }
- if (m_bullet_points.size() > 32768)
- m_bullet_points.clear_not_free ();
- }
- else
- m_bullet_points.clear_not_free ();
- //0-рикошет
- //1-застрявание пули в материале
- //2-пробивание материала
- if (g_bDrawBulletHit) {
- extern FvectorVec g_hit[];
- FvectorIt it;
- u32 C[3] = {0xffff0000,0xff00ff00,0xff0000ff};
- //RCache.set_xform_world(Fidentity);
- DRender->CacheSetXformWorld(Fidentity);
- for(int i=0; i<3; ++i)
- for(it=g_hit[i].begin();it!=g_hit[i].end();++it){
- Level().debug_renderer().draw_aabb(*it,0.01f,0.01f,0.01f,C[i]);
- }
- }
- #endif
- if(m_BulletsRendered.empty()) return;
- //u32 vOffset = 0 ;
- u32 bullet_num = m_BulletsRendered.size();
- UIRender->StartPrimitive((u32)bullet_num*12, IUIRender::ptTriList, IUIRender::pttLIT);
- for(BulletVecIt it = m_BulletsRendered.begin(); it!=m_BulletsRendered.end(); it++){
- SBullet* bullet = &(*it);
- if(!bullet->flags.allow_tracer)
- continue;
- if (!bullet->CanBeRenderedNow())
- continue;
- Fvector const tracer = Fvector().sub(bullet->bullet_pos, bullet->tracer_start_position);
- float length = tracer.magnitude();
- Fvector const tracer_direction = length >= EPS_L ? Fvector(tracer).mul(1.f/length) : Fvector().set(0.f, 0.f, 1.f);
- if (length < m_fTracerLengthMin)
- continue;
- if (length > m_fTracerLengthMax)
- length = m_fTracerLengthMax;
- float width = m_fTracerWidth;
- float dist2segSqr = SqrDistancePointToSegment(Device.vCameraPosition, bullet->bullet_pos, tracer);
- //---------------------------------------------
- float MaxDistSqr = 1.0f;
- float MinDistSqr = 0.09f;
- if (dist2segSqr < MaxDistSqr)
- {
- if (dist2segSqr < MinDistSqr) dist2segSqr = MinDistSqr;
- width *= _sqrt(dist2segSqr/MaxDistSqr);
- }
- if (Device.vCameraPosition.distance_to_sqr(bullet->bullet_pos)<(length*length))
- {
- length = Device.vCameraPosition.distance_to(bullet->bullet_pos) - 0.3f;
- }
- Fvector center;
- center.mad (bullet->bullet_pos, tracer_direction, -length*.5f);
- bool bActor = false;
- if(Level().CurrentViewEntity())
- {
- bActor = ( bullet->parent_id == Level().CurrentViewEntity()->ID() );
- }
- tracers.Render (bullet->bullet_pos, center, tracer_direction, length, width, bullet->m_u8ColorID, bullet->speed, bActor);
- }
- UIRender->CacheSetCullMode (IUIRender::cmNONE);
- UIRender->CacheSetXformWorld (Fidentity);
- UIRender->SetShader (*tracers.sh_Tracer);
- UIRender->FlushPrimitive ();
- UIRender->CacheSetCullMode (IUIRender::cmCCW);
- }
- void CBulletManager::CommitRenderSet () // @ the end of frame
- {
- m_BulletsRendered = m_Bullets ;
- if (g_mt_config.test(mtBullets)) {
- Device.seqParallel.push_back (fastdelegate::FastDelegate0<>(this,&CBulletManager::UpdateWorkload));
- } else {
- UpdateWorkload ();
- }
- }
- void CBulletManager::CommitEvents () // @ the start of frame
- {
- if (m_Events.size() > 1000)
- Msg ("! too many bullets during single frame: %d", m_Events.size());
- for (u32 _it=0; _it<m_Events.size(); _it++) {
- _event& E = m_Events[_it];
- switch (E.Type)
- {
- case EVENT_HIT:
- {
- if (E.dynamic) DynamicObjectHit (E);
- else StaticObjectHit (E);
- }break;
- case EVENT_REMOVE:
- {
- if (E.bullet.flags.allow_sendhit && GameID() != eGameIDSingle)
- Game().m_WeaponUsageStatistic->OnBullet_Remove(&E.bullet);
- m_Bullets[E.tgt_material] = m_Bullets.back();
- m_Bullets.pop_back();
- }break;
- }
- }
- m_Events.clear_and_reserve () ;
- }
- void CBulletManager::RegisterEvent (EventType Type, BOOL _dynamic, SBullet* bullet, const Fvector& end_point, collide::rq_result& R, u16 tgt_material)
- {
- #if 0//def DEBUG
- if (m_Events.size() > 1000) {
- static bool breakpoint = true;
- if (breakpoint)
- __asm int 3;
- }
- #endif // #ifdef DEBUG
- m_Events.push_back (_event()) ;
- _event& E = m_Events.back() ;
- E.Type = Type ;
- E.bullet = *bullet ;
- switch(Type)
- {
- case EVENT_HIT:
- {
- E.dynamic = _dynamic ;
- E.point = end_point ;
- E.R = R ;
- E.tgt_material = tgt_material ;
- ObjectHit( &E.hit_result, bullet, end_point, R, tgt_material, E.normal );
- if (_dynamic)
- {
- // E.Repeated = (R.O->ID() == E.bullet.targetID);
- // bullet->targetID = R.O->ID();
- E.Repeated = (R.O->ID() == E.bullet.targetID);
- if (GameID() == eGameIDSingle)
- {
- bullet->targetID = R.O->ID();
- }
- else
- {
- if (bullet->targetID != R.O->ID())
- {
- CGameObject* pGO = smart_cast<CGameObject*>(R.O);
- if (!pGO || !pGO->BonePassBullet(R.element))
- bullet->targetID = R.O->ID();
- }
- }
- };
- }break;
- case EVENT_REMOVE:
- {
- E.tgt_material = tgt_material ;
- }break;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement