/** * The problem with this is that it doesn't really know if it's already performed turnaround, * and has no hysteresis, so it ends up wobbling its ass a lot, decelerating much more slowly * than it should be able to, and overshooting the target. * * Also for reasons I can't figure out, it only accelerates for about the first third of the trajectory, * instead of until halfway as it should. */ void SimpleShipMovementController::step(RocketShip& ship, point2 target) { // Angular tolerance within which directions are considered equivalent. const plane_angle direction_slop = ship.side_thruster_acceleration() * pow<2>(0.25*seconds); ship.stop_turning(); ship.thrust_off(); vec2<length> r = target - ship.position(); unit_vec2 rhat(r); vec2<velocity> dr = ship.velocity(); acceleration dv = ship.main_thruster_acceleration(); // Not sure WTF these expressions mean physically, but it's the result of hours of screwing around and seems to produce nice results. unit_vec2 thrust_direction_towards(rhat*fudge_direction_ratio_ - dr.rejection(r)*((1-fudge_direction_ratio_)*second/meter)); unit_vec2 thrust_direction_away(-rhat*fudge_direction_ratio_ - dr.rejection(r)*((1-fudge_direction_ratio_)*second/meter)); time_interval time_to_target = r.magnitude() / dr.scalar_projection(r); time_interval time_to_stop = dr.scalar_projection(r) / dv; //plane_angle turnaround_delta_a = angle_difference(thrust_direction_away.angle(), ship.heading() + M_PI*radians); //time_interval maximum_turnaround_time = .75*seconds; // FIXME: pull this number from somewhere other than my ass //time_to_stop -= maximum_turnaround_time*(fabs(turnaround_delta_a) / (M_PI*radians)); // is this really linear wrt delta_a? /* if(fabs(turnaround_delta_a) > direction_slop) { time_to_stop -= maximum_turnaround_time*(fabs(turnaround_delta_a) / (M_PI*radians)); } */ unit_vec2 thrust_direction(0,0); if(time_to_target < 0*seconds || time_to_stop < time_to_target) { // Before turnaround - thrust towards the target. thrust_direction = thrust_direction_towards; } else { // After turnaround - thrust away from the target. thrust_direction = thrust_direction_away; } point_at(ship, thrust_direction); // Thrust if heading within tolerance if(fabs(angle_difference(thrust_direction.angle(), ship.heading())) < direction_slop) { ship.thrust_on(); } // Finally, ship.update_forces(); }
void bonesManipulation::SetMotion(CBoneInstance *bone, u8 axis, float target_yaw, float r_speed, u32 t) { int index = -1; // найти бону bone в m_Bones for (u32 i=0; i<m_Bones.size(); ++i) { if ((m_Bones[i].bone == bone) && (m_Bones[i].axis == axis)) { index = i; break; } } R_ASSERT(-1 != index); m_Bones[index].params.target_yaw = target_yaw; m_Bones[index].params.r_speed = r_speed; m_Bones[index].params.dist_yaw = angle_difference(target_yaw,m_Bones[index].params.cur_yaw); if (t > freeze_time) freeze_time = t; bActive = true; in_return_state = false; time_started = 0; }
void CControlRotationJump::stop_at_once() { m_time = m_man->animation().motion_time(m_right_side ? m_data.anim_stop_rs : m_data.anim_stop_ls, m_object->Visual()); // set angular speed in exclusive force mode SControlDirectionData *ctrl_data_dir = (SControlDirectionData*)m_man->data(this, ControlCom::eControlDir); VERIFY (ctrl_data_dir); float target_yaw; if (m_data.flags.is(SControlRotationJumpData::eRotateOnce) && m_object->EnemyMan.get_enemy()) { // if rotate once so rotate to enemy Fvector dir_to_enemy; dir_to_enemy.sub (m_object->EnemyMan.get_enemy()->Position(), m_object->Position()); dir_to_enemy.normalize (); target_yaw = angle_normalize(-dir_to_enemy.getH()); } else { target_yaw = angle_normalize(-m_object->Direction().getH() + (m_right_side ? m_data.turn_angle : -m_data.turn_angle)); } ctrl_data_dir->heading.target_angle = target_yaw; float cur_yaw; m_man->direction().get_heading (cur_yaw, target_yaw); ctrl_data_dir->heading.target_speed = angle_difference(cur_yaw,target_yaw)/ m_time; ctrl_data_dir->linear_dependency = false; VERIFY (!fis_zero(ctrl_data_dir->heading.target_speed)); m_stage = eStop; // start new animation SControlAnimationData *ctrl_data = (SControlAnimationData*)m_man->data(this, ControlCom::eControlAnimation); VERIFY (ctrl_data); ctrl_data->global.motion = m_right_side ? m_data.anim_stop_rs : m_data.anim_stop_ls; ctrl_data->global.actual = false; }
MotionID CStalkerAnimationManager::legs_move_animation () { m_no_move_actual = false; stalker_movement_manager_smart_cover &movement = object().movement(); VERIFY ( (movement.body_state() == eBodyStateStand) || (movement.mental_state() != eMentalStateFree) ); if (eMentalStateDanger != movement.mental_state()) { m_target_speed = movement.speed(eMovementDirectionForward); m_last_non_zero_speed = m_target_speed; return ( m_data_storage->m_part_animations.A[ body_state() ].m_movement.A[ movement.movement_type() ].A[ eMovementDirectionForward ].A[ 1 ] ); } float yaw,pitch; object().sight().GetDirectionAngles(yaw,pitch); yaw = angle_normalize_signed(-yaw);; legs_process_direction (yaw); float body_current = movement.body_orientation().current.yaw; bool left = left_angle(yaw,body_current); float test_angle_forward = right_forward_angle; float test_angle_backward = left_forward_angle; if (left) { test_angle_forward = left_forward_angle; test_angle_backward = right_forward_angle; } test_angle_backward = PI - test_angle_backward; EMovementDirection speed_direction; float difference = angle_difference(yaw,body_current); if (difference <= test_angle_forward) speed_direction = eMovementDirectionForward; else { if (difference > test_angle_backward) speed_direction = eMovementDirectionBackward; else { if (left) speed_direction = eMovementDirectionLeft; else speed_direction = eMovementDirectionRight; } } if (m_previous_speed_direction != speed_direction) { if (m_change_direction_time < Device.dwTimeGlobal) m_change_direction_time = Device.dwTimeGlobal; if (!legs_switch_factor()) { m_previous_speed = 0.f; m_target_speed = 0.f; } m_previous_speed_direction = speed_direction; } m_target_speed = movement.speed(speed_direction); m_last_non_zero_speed = m_target_speed; return ( m_data_storage->m_part_animations.A[ body_state() ].m_movement.A[ movement.movement_type() ].A[ speed_direction ].A[ 0 ] ); }
double hexbright::difference_from_down() { int light_axis[3] = {0, -100, 0}; return (angle_difference(dot_product(light_axis, down_vector), 100, 100)); }
void CBaseMonster::HitEntity(const CEntity *pEntity, float fDamage, float impulse, Fvector &dir, ALife::EHitType hit_type, bool draw_hit_marks) { if (!g_Alive()) return; if (!pEntity || pEntity->getDestroy()) return; if (!EnemyMan.get_enemy()) return; if (EnemyMan.get_enemy() == pEntity) { Fvector position_in_bone_space; position_in_bone_space.set(0.f,0.f,0.f); // перевод из локальных координат в мировые вектора направления импульса Fvector hit_dir; XFORM().transform_dir (hit_dir,dir); hit_dir.normalize (); CEntity *pEntityNC = const_cast<CEntity*>(pEntity); VERIFY (pEntityNC); NET_Packet l_P; SHit HS; HS.GenHeader(GE_HIT, pEntityNC->ID()); // u_EventGen (l_P,GE_HIT, pEntityNC->ID()); HS.whoID = (ID()); // l_P.w_u16 (ID()); HS.weaponID = (ID()); // l_P.w_u16 (ID()); HS.dir = (hit_dir); // l_P.w_dir (hit_dir); HS.power = (fDamage); // l_P.w_float (fDamage); HS.boneID = (smart_cast<IKinematics*>(pEntityNC->Visual())->LL_GetBoneRoot());// l_P.w_s16 (smart_cast<IKinematics*>(pEntityNC->Visual())->LL_GetBoneRoot()); HS.p_in_bone_space = (position_in_bone_space); // l_P.w_vec3 (position_in_bone_space); HS.impulse = (impulse); // l_P.w_float (impulse); HS.hit_type = hit_type; // l_P.w_u16 ( u16(ALife::eHitTypeWound) ); HS.Write_Packet(l_P); u_EventSend (l_P); if (pEntityNC == Actor() && draw_hit_marks) { START_PROFILE("BaseMonster/Animation/HitEntity"); SDrawStaticStruct* s = CurrentGameUI()->AddCustomStatic("monster_claws", false); float h1,p1; Device.vCameraDirection.getHP (h1,p1); Fvector hd = hit_dir; hd.mul (-1); float d = -h1 + hd.getH (); s->wnd()->SetHeading (d); Fvector2 wnd_pos = s->wnd()->GetWndPos(); wnd_pos.y += 400.0f*_cos(d); wnd_pos.x += 500.0f*_sin(d); s->wnd()->SetWndPos(wnd_pos); STOP_PROFILE; //SetAttackEffector (); float time_to_lock = fDamage * MAX_LOCK_TIME; clamp (time_to_lock, 0.f, MAX_LOCK_TIME); Actor()->lock_accel_for (int(time_to_lock * 1000)); ////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////// CEffectorCam* ce = Actor()->Cameras().GetCamEffector((ECamEffectorType)effBigMonsterHit); if(!ce) { const shared_str& eff_sect = pSettings->r_string(cNameSect(), "actor_hit_effect"); if(eff_sect.c_str()) { int id = -1; Fvector cam_pos,cam_dir,cam_norm; Actor()->cam_Active()->Get (cam_pos,cam_dir,cam_norm); cam_dir.normalize_safe (); dir.normalize_safe (); float ang_diff = angle_difference (cam_dir.getH(), dir.getH()); Fvector cp; cp.crossproduct (cam_dir,dir); bool bUp =(cp.y>0.0f); Fvector cross; cross.crossproduct (cam_dir, dir); VERIFY (ang_diff>=0.0f && ang_diff<=PI); float _s1 = PI_DIV_8; float _s2 = _s1+PI_DIV_4; float _s3 = _s2+PI_DIV_4; float _s4 = _s3+PI_DIV_4; if(ang_diff<=_s1){ id = 2; }else { if(ang_diff>_s1 && ang_diff<=_s2){ id = (bUp)?5:7; }else if(ang_diff>_s2 && ang_diff<=_s3){ id = (bUp)?3:1; }else if(ang_diff>_s3 && ang_diff<=_s4){ id = (bUp)?4:6; }else if(ang_diff>_s4){ id = 0; }else{ VERIFY(0); } } string64 sect_name; xr_sprintf (sect_name,"%s_%d",eff_sect.c_str(), id); AddEffector (Actor(), effBigMonsterHit, sect_name, fDamage); } } ////////////////////////////////////////////////////////////////////////// } Morale.on_attack_success(); m_time_last_attack_success = Device.dwTimeGlobal; } }
void CActor::HitSignal(float perc, Fvector& vLocalDir, CObject* who, s16 element) { if (g_Alive()) { // stop-motion if (character_physics_support()->movement()->Environment()==CPHMovementControl::peOnGround || character_physics_support()->movement()->Environment()==CPHMovementControl::peAtWall) { Fvector zeroV; zeroV.set (0,0,0); character_physics_support()->movement()->SetVelocity(zeroV); } // check damage bone Fvector D; XFORM().transform_dir(D,vLocalDir); float yaw, pitch; D.getHP(yaw,pitch); CKinematicsAnimated *tpKinematics = smart_cast<CKinematicsAnimated*>(Visual()); VERIFY(tpKinematics); #pragma todo("Dima to Dima : forward-back bone impulse direction has been determined incorrectly!") MotionID motion_ID = m_anims->m_normal.m_damage[iFloor(tpKinematics->LL_GetBoneInstance(element).get_param(1) + (angle_difference(r_model_yaw + r_model_yaw_delta,yaw) <= PI_DIV_2 ? 0 : 1))]; float power_factor = perc/100.f; clamp(power_factor,0.f,1.f); VERIFY(motion_ID.valid()); tpKinematics->PlayFX(motion_ID,power_factor); } }
void CActor::HitMark (float P, Fvector dir, CObject* who, s16 element, Fvector position_in_bone_space, float impulse, ALife::EHitType hit_type) { // hit marker if ( (hit_type==ALife::eHitTypeFireWound||hit_type==ALife::eHitTypeWound_2) && g_Alive() && Local() && /*(this!=who) && */(Level().CurrentEntity()==this) ) { HUD().Hit(0, P, dir); { CEffectorCam* ce = Cameras().GetCamEffector((ECamEffectorType)effFireHit); if(!ce) { int id = -1; Fvector cam_pos,cam_dir,cam_norm; cam_Active()->Get (cam_pos,cam_dir,cam_norm); cam_dir.normalize_safe (); dir.normalize_safe (); float ang_diff = angle_difference (cam_dir.getH(), dir.getH()); Fvector cp; cp.crossproduct (cam_dir,dir); bool bUp =(cp.y>0.0f); Fvector cross; cross.crossproduct (cam_dir, dir); VERIFY (ang_diff>=0.0f && ang_diff<=PI); float _s1 = PI_DIV_8; float _s2 = _s1+PI_DIV_4; float _s3 = _s2+PI_DIV_4; float _s4 = _s3+PI_DIV_4; if(ang_diff<=_s1){ id = 2; }else if(ang_diff>_s1 && ang_diff<=_s2){ id = (bUp)?5:7; }else if(ang_diff>_s2 && ang_diff<=_s3){ id = (bUp)?3:1; }else if(ang_diff>_s3 && ang_diff<=_s4){ id = (bUp)?4:6; }else if(ang_diff>_s4){ id = 0; }else{ VERIFY(0); } string64 sect_name; sprintf(sect_name,"effector_fire_hit_%d",id); AddEffector(this, effFireHit, sect_name, P/100.0f); } } } }
bool CControlJump::can_jump(CObject *target) { const bool aggressive_jump = m_object->can_use_agressive_jump(target); if ( m_time_next_allowed != 0 ) { // in aggressive mode we can jump after 1/3 of m_delay_after_jump if ( m_time_next_allowed - (int)aggressive_jump*(2*m_delay_after_jump/3) > Device.dwTimeGlobal) { return false; } } Fvector source_position = m_object->Position (); Fvector target_position; target->Center (target_position); // проверка на dist float dist = source_position.distance_to(target_position); // in aggressive mode we can jump from distance >= 1 const float test_min_distance = aggressive_jump ? _min(1.f, m_min_distance) : m_min_distance; if ( (dist < test_min_distance) || (dist > m_max_distance) ) return false; // получить вектор направлени¤ и его мир угол float dir_yaw = Fvector().sub(target_position, source_position).getH(); dir_yaw = angle_normalize(-dir_yaw); // проверка на angle float yaw_current, yaw_target; m_object->control().direction().get_heading(yaw_current, yaw_target); if (angle_difference(yaw_current, dir_yaw) > m_max_angle) return false; // check if target on the same floor etc if (_abs(target_position.y-source_position.y) > m_max_height) return false; // проверка prepare if (!is_flag(SControlJumpData::ePrepareSkip) && !is_flag(SControlJumpData::eGlideOnPrepareFailed)) { if (!is_flag(SControlJumpData::ePrepareInMove)) { VERIFY(m_data.state_prepare.motion.valid()); } else { VERIFY(m_data.state_prepare_in_move.motion.valid()); VERIFY(m_data.state_prepare_in_move.velocity_mask != u32(-1)); // try to trace distance according to prepare animation bool good_trace_res = false; // get animation time float time = m_man->animation().motion_time(m_data.state_prepare_in_move.motion, m_object->Visual()); // set acceleration and velocity SVelocityParam &vel = m_object->move().get_velocity(m_data.state_prepare_in_move.velocity_mask); float dist = time * vel.velocity.linear; // check nodes in direction Fvector target_point; target_point.mad(m_object->Position(), m_object->Direction(), dist); if (m_man->path_builder().accessible(target_point)) { // нода в пр¤мой видимости? m_man->path_builder().restrictions().add_border(m_object->Position(), target_point); u32 node = ai().level_graph().check_position_in_direction(m_object->ai_location().level_vertex_id(),m_object->Position(),target_point); m_man->path_builder().restrictions().remove_border(); if (ai().level_graph().valid_vertex_id(node) && m_man->path_builder().accessible(node)) good_trace_res = true; } if (!good_trace_res) { // cannot prepare in move, so check if can prepare in stand state if (!m_data.state_prepare.motion.valid()) return false; } } } return true; }
void CControlRotationJump::build_line_second() { if (!m_object->EnemyMan.get_enemy()) { m_man->notify (ControlCom::eventRotationJumpEnd, 0); return; } // set acceleration and velocity m_target_velocity = m_start_velocity; m_start_velocity = 0; // get animation time m_time = m_man->animation().motion_time(m_right_side ? m_data.anim_run_rs : m_data.anim_run_ls, m_object->Visual()); // acceleration m_accel = (m_target_velocity - m_start_velocity) / m_time; // path distance m_dist = (m_target_velocity*m_target_velocity - m_start_velocity*m_start_velocity) / (2*m_accel); // set angular speed in exclusive force mode SControlDirectionData *ctrl_data_dir = (SControlDirectionData*)m_man->data(this, ControlCom::eControlDir); VERIFY (ctrl_data_dir); Fvector dir_to_enemy; dir_to_enemy.sub (m_object->EnemyMan.get_enemy()->Position(), m_object->Position()); dir_to_enemy.normalize (); float target_yaw = dir_to_enemy.getH(); target_yaw = angle_normalize(-target_yaw); ctrl_data_dir->heading.target_angle = target_yaw; float cur_yaw; m_man->direction().get_heading (cur_yaw, target_yaw); ctrl_data_dir->heading.target_speed = angle_difference(cur_yaw,target_yaw)/ m_time; ctrl_data_dir->linear_dependency = false; VERIFY (!fis_zero(ctrl_data_dir->heading.target_speed)); // Velocity mask u32 velocity_mask = MonsterMovement::eVelocityParameterStand | MonsterMovement::eVelocityParameterRunNormal; m_stage = eRun; Fvector target_position; target_position.mad(m_object->Position(), dir_to_enemy, m_dist); if (!m_man->build_path_line(this, target_position, u32(-1), velocity_mask)) { m_man->notify (ControlCom::eventRotationJumpEnd, 0); } else { // enable path SControlPathBuilderData *ctrl_path = (SControlPathBuilderData*)m_man->data(this, ControlCom::eControlPath); VERIFY (ctrl_path); ctrl_path->enable = true; m_man->lock (this, ControlCom::eControlPath); SControlMovementData *ctrl_move = (SControlMovementData*)m_man->data(this, ControlCom::eControlMovement); VERIFY (ctrl_move); ctrl_move->velocity_target = m_target_velocity; ctrl_move->acc = m_accel; // start new animation SControlAnimationData *ctrl_data = (SControlAnimationData*)m_man->data(this, ControlCom::eControlAnimation); VERIFY (ctrl_data); ctrl_data->global.motion = m_right_side ? m_data.anim_run_rs : m_data.anim_run_ls; ctrl_data->global.actual = false; } }
void CHelicopter::MoveStep() { Fvector dir, pathDir; float desired_H = m_movement.currPathH; float desired_P; if(m_movement.type != eMovNone) { float dist = m_movement.currP.distance_to(m_movement.desiredPoint); dir.sub(m_movement.desiredPoint,m_movement.currP); dir.normalize_safe(); pathDir = dir; dir.getHP(desired_H, desired_P); float speed_ = _min(m_movement.GetSpeedInDestPoint(), GetMaxVelocity() ); static float ang = pSettings->r_float (cNameSect(),"magic_angle"); if(m_movement.curLinearSpeed>GetMaxVelocity() || angle_difference(m_movement.currPathH,desired_H)>ang) m_movement.curLinearAcc = -m_movement.LinearAcc_bk; else m_movement.curLinearAcc = GetCurrAcc( m_movement.curLinearSpeed, speed_, dist*0.95f, m_movement.LinearAcc_fw, -m_movement.LinearAcc_bk); angle_lerp (m_movement.currPathH, desired_H, m_movement.GetAngSpeedHeading(m_movement.curLinearSpeed), STEP); angle_lerp (m_movement.currPathP, desired_P, m_movement.GetAngSpeedPitch(m_movement.curLinearSpeed), STEP); dir.setHP(m_movement.currPathH, m_movement.currPathP); float vp = m_movement.curLinearSpeed*STEP+(m_movement.curLinearAcc*STEP*STEP)/2.0f; m_movement.currP.mad (dir, vp); m_movement.curLinearSpeed += m_movement.curLinearAcc*STEP; static bool aaa = false; if(aaa) Log("1-m_movement.curLinearSpeed=",m_movement.curLinearSpeed); clamp(m_movement.curLinearSpeed,0.0f,1000.0f); if(aaa) Log("2-m_movement.curLinearSpeed=",m_movement.curLinearSpeed); } else { //go stopping if( !fis_zero(m_movement.curLinearSpeed) ) { m_movement.curLinearAcc = -m_movement.LinearAcc_bk; float vp = m_movement.curLinearSpeed*STEP+(m_movement.curLinearAcc*STEP*STEP)/2.0f; dir.setHP(m_movement.currPathH, m_movement.currPathP); dir.normalize_safe(); m_movement.currP.mad (dir, vp); m_movement.curLinearSpeed += m_movement.curLinearAcc*STEP; clamp(m_movement.curLinearSpeed,0.0f,1000.0f); // clamp(m_movement.curLinearSpeed,0.0f,m_movement.maxLinearSpeed); } else { m_movement.curLinearAcc = 0.0f; m_movement.curLinearSpeed = 0.0f; } }; if( m_body.b_looking_at_point) { Fvector desired_dir; desired_dir.sub(m_body.looking_point, m_movement.currP ).normalize_safe(); float center_desired_H,tmp_P; desired_dir.getHP(center_desired_H, tmp_P); angle_lerp (m_body.currBodyHPB.x, center_desired_H, m_movement.GetAngSpeedHeading(m_movement.curLinearSpeed), STEP); } else { angle_lerp (m_body.currBodyHPB.x, m_movement.currPathH, m_movement.GetAngSpeedHeading(m_movement.curLinearSpeed), STEP); } float needBodyP = -m_body.model_pitch_k*m_movement.curLinearSpeed; if(m_movement.curLinearAcc < 0) needBodyP*=-1; angle_lerp (m_body.currBodyHPB.y, needBodyP, m_body.model_angSpeedPitch, STEP); float sign; Fvector cp; cp.crossproduct (pathDir,dir); (cp.y>0.0)?sign=1.0f:sign=-1.0f; float ang_diff = angle_difference (m_movement.currPathH, desired_H); float needBodyB = -ang_diff*sign*m_body.model_bank_k*m_movement.curLinearSpeed; angle_lerp (m_body.currBodyHPB.z, needBodyB, m_body.model_angSpeedBank, STEP); XFORM().setHPB(m_body.currBodyHPB.x,m_body.currBodyHPB.y,m_body.currBodyHPB.z); XFORM().translate_over(m_movement.currP); }
double move_contact_object(int object, double angle, double max_dist, bool solid_only) { enigma::object_collisions* const inst1 = ((enigma::object_collisions*)enigma::instance_event_iterator->inst); if (inst1->sprite_index == -1 && (inst1->mask_index == -1)) { return -4; } const double x = inst1->x, y = inst1->y; if (collide_inst_inst(object, solid_only, true, x, y) != NULL) { return 0; } const double DMIN = 1, DMAX = 1000; // Arbitrary max for non-positive values, 1000 fits with other implementations. const double contact_distance = DMIN; double mid_dist = max_dist; // mid_dist is used for the subtraction part. if (max_dist <= 0) { // Use the arbitrary max for non-positive values. max_dist = DMAX; } mid_dist = max_dist; const double radang = (fmod(fmod(angle, 360) + 360, 360))*(M_PI/180.0); const double sin_angle = sin(radang), cos_angle = cos(radang); // Subtraction. const int quad = int(angle/90.0); const bbox_rect_t &box = inst1->$bbox_relative(); const double x1 = inst1->x, y1 = inst1->y, xscale1 = inst1->image_xscale, yscale1 = inst1->image_yscale, ia1 = inst1->image_angle; int left1, top1, right1, bottom1; get_border(&left1, &right1, &top1, &bottom1, box.left, box.top, box.right, box.bottom, x1, y1, xscale1, yscale1, ia1); for (enigma::iterator it = enigma::fetch_inst_iter_by_int(object); it; ++it) { const enigma::object_collisions* inst2 = (enigma::object_collisions*)*it; if (inst2->sprite_index == -1 && (inst2->mask_index == -1)) continue; if (inst2->id == inst1->id || (solid_only && !inst2->solid)) continue; const bbox_rect_t &box2 = inst2->$bbox_relative(); const double x2 = inst2->x, y2 = inst2->y, xscale2 = inst2->image_xscale, yscale2 = inst2->image_yscale, ia2 = inst2->image_angle; int left2, top2, right2, bottom2; get_border(&left2, &right2, &top2, &bottom2, box2.left, box2.top, box2.right, box2.bottom, x2, y2, xscale2, yscale2, ia2); if (right2 >= left1 && bottom2 >= top1 && left2 <= right1 && top2 <= bottom1) { mid_dist = DMIN; break; } switch (quad) { case 0: if ((left2 > right1 || top1 > bottom2) && angle_difference(point_direction(right1, bottom1, left2, top2),angle) >= 0 && angle_difference(point_direction(left1, top1, right2, bottom2),angle) <= 0) { if (angle_difference(point_direction(right1, top1, left2, bottom2),angle) > 0) { mid_dist = min(mid_dist, (top1 - bottom2 - contact_distance)/sin_angle); } else { mid_dist = min(mid_dist, (left2 - right1 - contact_distance)/cos_angle); } } break; case 1: if ((left1 > right2 || top1 > bottom2) && angle_difference(point_direction(left1, bottom1, right2, top2),angle) <= 0 && angle_difference(point_direction(right1, top1, left2, bottom2),angle) >= 0) { if (angle_difference(point_direction(left1, top1, right2, bottom2),angle) > 0) { mid_dist = min(mid_dist, (right2 - left1 + contact_distance)/cos_angle); } else { mid_dist = min(mid_dist, (top1 - bottom2 - contact_distance)/sin_angle); } } break; case 2: if ((left1 > right2 || top2 > bottom1) && angle_difference(point_direction(right1, bottom1, left2, top2),angle) <= 0 && angle_difference(point_direction(left1, top1, right2, bottom2),angle) >= 0) { if (angle_difference(point_direction(left1, bottom1, right2, top2),angle) > 0) { mid_dist = min(mid_dist, (bottom1 - top2 + contact_distance)/sin_angle); } else { mid_dist = min(mid_dist, (right2 - left1 + contact_distance)/cos_angle); } } break; case 3: if ((left2 > right1 || top2 > bottom1) && angle_difference(point_direction(right1, top1, left2, bottom2),angle) <= 0 && angle_difference(point_direction(left1, bottom1, right2, top2),angle) >= 0) { if (angle_difference(point_direction(right1, bottom1, left2, top2),angle) > 0) { mid_dist = min(mid_dist, (left2 - right1 - contact_distance)/cos_angle); } else { mid_dist = min(mid_dist, (bottom1 - top2 + contact_distance)/sin_angle); } } break; } } double current_dist = DMIN; { // Avoid moving to position which isn't free. mid_dist is not guaranteed to indicate a free position. double next_x = x + mid_dist*cos_angle; double next_y = y - mid_dist*sin_angle; if (collide_inst_inst(object, solid_only, true, next_x, next_y) == NULL) { inst1->x = next_x; inst1->y = next_y; current_dist = mid_dist; } } // Subtraction end. for (; current_dist <= max_dist; current_dist++) { const double next_x = x + current_dist*cos_angle; const double next_y = y - current_dist*sin_angle; if (collide_inst_inst(object, solid_only, true, next_x, next_y) != NULL) { current_dist--; break; } else { inst1->x = next_x; inst1->y = next_y; } } return current_dist; }
void CControlDirection::update_frame() { pitch_correction (); SRotationEventData event_data; event_data.angle = 0; bool heading_similar = false; bool pitch_similar = false; // difference float diff = angle_difference(m_pitch.current_angle, m_data.pitch.target_angle) * 4.0f; clamp(diff, PI_DIV_6, 5 * PI_DIV_6); m_data.pitch.target_speed = m_pitch.current_speed = diff; // поправка угловой скорости в соответствии с текущей и таргетовой линейной скоростями // heading speed correction if (!fis_zero(m_man->movement().velocity_current()) && !fis_zero(m_man->movement().velocity_target()) && m_data.linear_dependency) m_heading.current_speed = m_data.heading.target_speed * m_man->movement().velocity_current() / (m_man->movement().velocity_target() + EPS_L); else velocity_lerp (m_heading.current_speed, m_data.heading.target_speed, m_heading.current_acc, m_object->client_update_fdelta()); m_heading.current_angle = angle_normalize(m_heading.current_angle); m_data.heading.target_angle = angle_normalize(m_data.heading.target_angle); if (fsimilar(m_heading.current_angle, m_data.heading.target_angle)) heading_similar = true; angle_lerp(m_heading.current_angle, m_data.heading.target_angle, m_heading.current_speed, m_object->client_update_fdelta()); if (!heading_similar && fsimilar(m_heading.current_angle, m_data.heading.target_angle)) { event_data.angle |= SRotationEventData::eHeading; } // update pitch velocity_lerp (m_pitch.current_speed, m_data.pitch.target_speed, m_pitch.current_acc, m_object->client_update_fdelta()); m_pitch.current_angle = angle_normalize_signed (m_pitch.current_angle); m_data.pitch.target_angle = angle_normalize_signed (m_data.pitch.target_angle); if (fsimilar(m_pitch.current_angle, m_data.pitch.target_angle)) pitch_similar = true; angle_lerp (m_pitch.current_angle, m_data.pitch.target_angle, m_pitch.current_speed, m_object->client_update_fdelta()); if (!pitch_similar && fsimilar(m_pitch.current_angle, m_data.pitch.target_angle)) { event_data.angle |= SRotationEventData::ePitch; } // set m_man->path_builder().m_body.speed = m_heading.current_speed; m_man->path_builder().m_body.current.yaw = m_heading.current_angle; m_man->path_builder().m_body.target.yaw = m_heading.current_angle; m_man->path_builder().m_body.current.pitch = m_pitch.current_angle; m_man->path_builder().m_body.target.pitch = m_pitch.current_angle; // save object position Fvector P = m_object->Position(); // set angles if(!m_object->animation_movement_controlled()) m_object->XFORM().setHPB (-m_man->path_builder().m_body.current.yaw,-m_man->path_builder().m_body.current.pitch,0); // restore object position m_object->Position() = P; // if there is an event if (event_data.angle) m_man->notify(ControlCom::eventRotationEnd, &event_data); }