46 void Actor::CalcForcesEulerCompute(
bool doUpdate,
int num_steps)
49 this->UpdateBoundingBoxes();
50 this->CalcEventBoxes();
52 this->CalcAircraftForces(doUpdate);
54 this->CalcBuoyance(doUpdate);
55 this->CalcDifferentials();
56 this->CalcWheels(doUpdate, num_steps);
57 this->CalcShocks(doUpdate, num_steps);
59 this->CalcCommands(doUpdate);
61 this->CalcTruckEngine(doUpdate);
63 this->CalcBeams(doUpdate);
64 this->CalcCabCollisions();
66 this->CalcForceFeedback(doUpdate);
69 void Actor::CalcForceFeedback(
bool doUpdate)
75 m_force_sensors.Reset();
78 if (ar_current_cinecam != -1)
80 m_force_sensors.accu_body_forces += ar_nodes[ar_camera_node_pos[ar_current_cinecam]].Forces;
85 beam_t* beam = &ar_beams[hydrobeam.hb_beam_index];
88 m_force_sensors.accu_hydros_forces += hydrobeam.hb_speed * beam->
refL * beam->
stress;
94 void Actor::CalcMouse()
98 Vector3 dir = m_mouse_grab_pos - ar_nodes[m_mouse_grab_node].AbsPosition;
99 ar_nodes[m_mouse_grab_node].Forces += m_mouse_grab_move_force * dir;
103 void Actor::CalcAircraftForces(
bool doUpdate)
110 for (
int i = 0; i < ar_num_aeroengines; i++)
111 if (ar_aeroengines[i])
112 ar_aeroengines[i]->updateForces(
PHYSICS_DT, doUpdate);
115 for (
int i = 0; i < ar_num_screwprops; i++)
116 if (ar_screwprops[i])
117 ar_screwprops[i]->updateForces(doUpdate);
120 for (
int i = 0; i < ar_num_wings; i++)
122 ar_wings[i].fa->updateForces();
125 void Actor::CalcFuseDrag()
127 if (m_fusealge_airfoil && m_fusealge_width > 0.0f)
129 Vector3 wind = -m_fusealge_front->Velocity;
130 float wspeed = wind.length();
131 Vector3 axis = m_fusealge_front->RelPosition - m_fusealge_back->RelPosition;
132 float s = axis.length() * m_fusealge_width;
134 float v = axis.getRotationTo(wind).w;
136 if (v < 1.0 && v > -1.0)
138 m_fusealge_airfoil->getparams(aoa, 1.0, 0.0, &cz, &cx, &cm);
141 float altitude = m_fusealge_front->AbsPosition.y;
142 float sea_level_pressure = 101325;
143 float airpressure = sea_level_pressure *
approx_pow(1.0 - 0.0065 * altitude / 288.1, 5.24947);
144 float airdensity = airpressure * 0.0000120896f;
147 ar_fusedrag = ((cx * s + m_fusealge_width * m_fusealge_width * 0.5) * 0.5 * airdensity * wspeed / ar_num_nodes) * wind;
151 void Actor::CalcBuoyance(
bool doUpdate)
155 for (
int i = 0; i < ar_num_buoycabs; i++)
157 int tmpv = ar_buoycabs[i] * 3;
158 m_buoyance->computeNodeForce(&ar_nodes[ar_cabs[tmpv]], &ar_nodes[ar_cabs[tmpv + 1]], &ar_nodes[ar_cabs[tmpv + 2]], doUpdate == 1, ar_buoycab_types[i]);
163 void Actor::CalcDifferentials()
165 if (ar_engine && m_num_proped_wheels > 0)
167 float torque = ar_engine->GetTorque() / m_num_proped_wheels;
168 if (m_has_axles_section)
172 for (
int i = 0; i < ar_num_wheels; i++)
174 if (ar_wheels[i].wh_propulsed && !ar_wheels[i].wh_is_detached)
175 ar_wheels[i].wh_torque += torque;
179 int num_axle_diffs = (m_transfer_case && m_transfer_case->tr_4wd_mode) ? m_num_axle_diffs + 1 : m_num_axle_diffs;
182 for (
int i = 0; i < num_axle_diffs; i++)
184 int a_1 = m_axle_diffs[i]->di_idx_1;
185 int a_2 = m_axle_diffs[i]->di_idx_2;
186 wheel_t* axle_1_wheels[2] = {&ar_wheels[m_wheel_diffs[a_1]->di_idx_1], &ar_wheels[m_wheel_diffs[a_1]->di_idx_2]};
187 wheel_t* axle_2_wheels[2] = {&ar_wheels[m_wheel_diffs[a_2]->di_idx_1], &ar_wheels[m_wheel_diffs[a_2]->di_idx_2]};
188 if (axle_1_wheels[0]->wh_is_detached && axle_1_wheels[1]->wh_is_detached)
193 if (axle_2_wheels[0]->wh_is_detached && axle_2_wheels[1]->wh_is_detached)
199 for (
int i = 0; i < m_num_wheel_diffs; i++)
201 wheel_t* axle_wheels[2] = {&ar_wheels[m_wheel_diffs[i]->di_idx_1], &ar_wheels[m_wheel_diffs[i]->di_idx_2]};
202 if (axle_wheels[0]->wh_is_detached) axle_wheels[0]->
wh_speed = axle_wheels[1]->
wh_speed;
203 if (axle_wheels[1]->wh_is_detached) axle_wheels[1]->
wh_speed = axle_wheels[0]->
wh_speed;
208 for (
int i = 0; i < num_axle_diffs; i++)
210 int a_1 = m_axle_diffs[i]->di_idx_1;
211 int a_2 = m_axle_diffs[i]->di_idx_2;
213 Ogre::Real axle_torques[2] = {0.0f, 0.0f};
217 (ar_wheels[m_wheel_diffs[a_1]->di_idx_1].wh_speed + ar_wheels[m_wheel_diffs[a_1]->di_idx_2].wh_speed) * 0.5f,
218 (ar_wheels[m_wheel_diffs[a_2]->di_idx_1].wh_speed + ar_wheels[m_wheel_diffs[a_2]->di_idx_2].wh_speed) * 0.5f
220 m_axle_diffs[i]->di_delta_rotation,
221 {axle_torques[0], axle_torques[1]},
222 ar_wheels[m_wheel_diffs[a_1]->di_idx_1].wh_torque + ar_wheels[m_wheel_diffs[a_1]->di_idx_2].wh_torque +
223 ar_wheels[m_wheel_diffs[a_2]->di_idx_1].wh_torque + ar_wheels[m_wheel_diffs[a_2]->di_idx_2].wh_torque,
227 m_axle_diffs[i]->CalcAxleTorque(diff_data);
231 ar_wheels[m_wheel_diffs[a_1]->di_idx_1].wh_torque = diff_data.
out_torque[0] * 0.5f;
232 ar_wheels[m_wheel_diffs[a_1]->di_idx_2].wh_torque = diff_data.
out_torque[0] * 0.5f;
233 ar_wheels[m_wheel_diffs[a_2]->di_idx_1].wh_torque = diff_data.
out_torque[1] * 0.5f;
234 ar_wheels[m_wheel_diffs[a_2]->di_idx_2].wh_torque = diff_data.
out_torque[1] * 0.5f;
239 for (
int i = 0; i < m_num_wheel_diffs; i++)
241 Ogre::Real axle_torques[2] = {0.0f, 0.0f};
242 wheel_t* axle_wheels[2] = {&ar_wheels[m_wheel_diffs[i]->di_idx_1], &ar_wheels[m_wheel_diffs[i]->di_idx_2]};
247 m_wheel_diffs[i]->di_delta_rotation,
248 {axle_torques[0], axle_torques[1]},
253 m_wheel_diffs[i]->CalcAxleTorque(diff_data);
257 ar_wheels[m_wheel_diffs[i]->di_idx_1].wh_torque = diff_data.
out_torque[0];
258 ar_wheels[m_wheel_diffs[i]->di_idx_2].wh_torque = diff_data.
out_torque[1];
262 void Actor::CalcWheels(
bool doUpdate,
int num_steps)
268 if (alb_timer >= alb_pulse_time)
271 alb_pulse_state = !alb_pulse_state;
273 if (tc_timer >= tc_pulse_time)
276 tc_pulse_state = !tc_pulse_state;
279 m_antilockbrake =
false;
280 m_tractioncontrol =
false;
282 ar_wheel_spin = 0.0f;
283 ar_wheel_speed = 0.0f;
285 for (
int i = 0; i < ar_num_wheels; i++)
289 ar_wheels[i].debug_rpm = 0.0f;
290 ar_wheels[i].debug_torque = 0.0f;
291 ar_wheels[i].debug_vel = Vector3::ZERO;
292 ar_wheels[i].debug_slip = Vector3::ZERO;
293 ar_wheels[i].debug_force = Vector3::ZERO;
294 ar_wheels[i].debug_scaled_cforce = Vector3::ZERO;
297 if (ar_wheels[i].wh_is_detached)
300 float relspeed = ar_nodes[0].Velocity.dotProduct(getDirection());
301 float curspeed = fabs(relspeed);
302 float wheel_slip = fabs(ar_wheels[i].wh_speed - relspeed) / std::max(1.0f, curspeed);
305 if (tc_mode && fabs(ar_wheels[i].wh_torque) > 0.0f && fabs(ar_wheels[i].wh_speed) > curspeed && wheel_slip > 0.25f)
309 ar_wheels[i].wh_tc_coef = curspeed / fabs(ar_wheels[i].wh_speed);
310 ar_wheels[i].wh_tc_coef = pow(ar_wheels[i].wh_tc_coef, tc_ratio);
312 float tc_coef = pow(ar_wheels[i].wh_tc_coef, std::min(std::abs(ar_wheels[i].wh_speed) / 5.0f, 1.0f));
313 ar_wheels[i].wh_torque *= tc_coef;
314 m_tractioncontrol =
true;
318 ar_wheels[i].wh_tc_coef = 1.0f;
321 if (ar_wheels[i].wh_braking != wheel_t::BrakeCombo::NONE)
324 float abrake = ar_brake_force * ar_brake;
328 if (ar_parking_brake && (ar_wheels[i].wh_braking != wheel_t::BrakeCombo::FOOT_ONLY))
330 hbrake = m_handbrake_force;
335 if ((ar_wheels[i].wh_speed < 20.0f)
336 && (((ar_wheels[i].wh_braking == wheel_t::BrakeCombo::FOOT_HAND_SKID_LEFT) && (ar_hydro_dir_state > 0.0f))
337 || ((ar_wheels[i].wh_braking == wheel_t::BrakeCombo::FOOT_HAND_SKID_RIGHT) && (ar_hydro_dir_state < 0.0f))))
339 dbrake = ar_brake_force * abs(ar_hydro_dir_state);
342 if (abrake != 0.0 || dbrake != 0.0 || hbrake != 0.0)
344 float adbrake = abrake + dbrake;
347 if (alb_mode && curspeed > alb_minspeed && curspeed > fabs(ar_wheels[i].wh_speed) && (adbrake > 0.0f) && wheel_slip > 0.25f)
351 ar_wheels[i].wh_alb_coef = fabs(ar_wheels[i].wh_speed) / curspeed;
352 ar_wheels[i].wh_alb_coef = pow(ar_wheels[i].wh_alb_coef, alb_ratio);
354 adbrake *= ar_wheels[i].wh_alb_coef;
355 m_antilockbrake =
true;
358 float force = -ar_wheels[i].wh_avg_speed * ar_wheels[i].wh_radius * ar_wheels[i].wh_mass /
PHYSICS_DT;
359 force -= ar_wheels[i].wh_last_retorque;
361 if (ar_wheels[i].wh_speed > 0)
362 ar_wheels[i].wh_torque += Math::Clamp(force, -(adbrake + hbrake), 0.0f);
364 ar_wheels[i].wh_torque += Math::Clamp(force, 0.0f, +(adbrake + hbrake));
368 ar_wheels[i].wh_alb_coef = 1.0f;
372 ar_wheels[i].debug_torque += ar_wheels[i].wh_torque / (float)num_steps;
375 Vector3 axis = (ar_wheels[i].wh_axis_node_1->RelPosition - ar_wheels[i].wh_axis_node_0->RelPosition).normalisedCopy();
376 float axis_precalc = ar_wheels[i].wh_torque / (Real)(ar_wheels[i].wh_num_nodes);
378 float expected_wheel_speed = ar_wheels[i].wh_speed;
379 ar_wheels[i].wh_speed = 0.0f;
381 Real contact_counter = 0.0f;
382 Vector3 slip = Vector3::ZERO;
383 Vector3 force = Vector3::ZERO;
384 for (
int j = 0; j < ar_wheels[i].wh_num_nodes; j++)
386 node_t* outer_node = ar_wheels[i].wh_nodes[j];
387 node_t* inner_node = (j % 2) ? ar_wheels[i].wh_axis_node_1 : ar_wheels[i].wh_axis_node_0;
390 float inverted_rlen = 1.0f / radius.length();
392 if (ar_wheels[i].wh_propulsed == 2)
397 Vector3 dir = axis.crossProduct(radius) * inverted_rlen;
398 ar_wheels[i].wh_nodes[j]->Forces += dir * axis_precalc * inverted_rlen;
399 ar_wheels[i].wh_speed += (outer_node->
Velocity - inner_node->
Velocity).dotProduct(dir);
401 if (ar_wheels[i].wh_nodes[j]->nd_has_ground_contact || ar_wheels[i].wh_nodes[j]->nd_has_mesh_contact)
403 contact_counter += 1.0f;
404 float force_ratio = ar_wheels[i].wh_nodes[j]->nd_last_collision_force.length();
405 slip += ar_wheels[i].wh_nodes[j]->nd_last_collision_slip * force_ratio;
406 force += ar_wheels[i].wh_nodes[j]->nd_last_collision_force;
409 if (contact_counter > 0.0f && !force.isZeroLength())
411 slip /= force.length();
412 slip /= contact_counter;
413 force /= contact_counter;
414 Vector3 normal = force.normalisedCopy();
415 Vector3 v = ar_wheels[i].wh_axis_node_0->Velocity.midPoint(ar_wheels[i].wh_axis_node_1->Velocity);
416 Vector3 vel = v - v.dotProduct(normal) * normal;
417 ar_wheels[i].debug_vel += vel / (float)num_steps;
418 ar_wheels[i].debug_slip += slip / (float)num_steps;
419 ar_wheels[i].debug_force += force / (float)num_steps;
422 ar_wheels[i].wh_speed /= (Real)ar_wheels[i].wh_num_nodes;
423 ar_wheels[i].wh_net_rp += (ar_wheels[i].wh_speed / ar_wheels[i].wh_radius) *
PHYSICS_DT;
425 ar_wheels[i].wh_avg_speed = ar_wheels[i].wh_avg_speed * 0.99 + ar_wheels[i].wh_speed * 0.1;
426 ar_wheels[i].debug_rpm +=
RAD_PER_SEC_TO_RPM * ar_wheels[i].wh_speed / ar_wheels[i].wh_radius / (float)num_steps;
427 if (ar_wheels[i].wh_propulsed == 1)
429 float speedacc = ar_wheels[i].wh_speed / (float)m_num_proped_wheels;
430 ar_wheel_speed += speedacc;
431 ar_wheel_spin += speedacc / ar_wheels[i].wh_radius;
434 expected_wheel_speed += ((ar_wheels[i].wh_last_torque / ar_wheels[i].wh_radius) / ar_wheels[i].wh_mass) *
PHYSICS_DT;
435 ar_wheels[i].wh_last_retorque = ar_wheels[i].wh_mass * (ar_wheels[i].wh_speed - expected_wheel_speed) /
PHYSICS_DT;
438 Vector3 rradius = ar_wheels[i].wh_arm_node->RelPosition - ar_wheels[i].wh_near_attach_node->RelPosition;
439 Vector3 radius = Plane(axis, ar_wheels[i].wh_near_attach_node->RelPosition).projectVector(rradius);
440 float offset = (rradius - radius).length();
441 Real rlen = radius.normalise();
443 if (rlen > 0.01 && offset * 2.0f < rlen && fabs(ar_wheels[i].wh_torque) > 0.01f)
445 Vector3 cforce = axis.crossProduct(radius);
447 cforce *= (0.5f * ar_wheels[i].wh_torque / rlen) * (1.0f - ((offset * 2.0f) / rlen));
448 ar_wheels[i].wh_arm_node->Forces -= cforce;
449 ar_wheels[i].wh_near_attach_node->Forces += cforce;
450 ar_wheels[i].debug_scaled_cforce += cforce / m_total_mass / (float)num_steps;
453 ar_wheels[i].wh_last_torque = ar_wheels[i].wh_torque;
454 ar_wheels[i].wh_torque = 0.0f;
457 ar_avg_wheel_speed = ar_avg_wheel_speed * 0.995 + ar_wheel_speed * 0.005;
466 if (!m_antilockbrake)
475 if (!m_tractioncontrol)
486 float distance_driven = fabs(ar_wheel_speed *
PHYSICS_DT);
487 m_odometer_total += distance_driven;
488 m_odometer_user += distance_driven;
491 void Actor::CalcShocks(
bool doUpdate,
int num_steps)
494 if (this->ar_has_active_shocks && m_stabilizer_shock_request)
496 if ((m_stabilizer_shock_request == 1 && m_stabilizer_shock_ratio < 0.1) || (m_stabilizer_shock_request == -1 && m_stabilizer_shock_ratio > -0.1))
497 m_stabilizer_shock_ratio = m_stabilizer_shock_ratio + (float)m_stabilizer_shock_request *
PHYSICS_DT *
STAB_RATE;
498 for (
int i = 0; i < ar_num_shocks; i++)
502 ar_beams[ar_shocks[i].beamid].L = ar_beams[ar_shocks[i].beamid].refL * (1.0 + m_stabilizer_shock_ratio);
504 ar_beams[ar_shocks[i].beamid].L = ar_beams[ar_shocks[i].beamid].refL * (1.0 - m_stabilizer_shock_ratio);
508 if (this->ar_has_active_shocks && doUpdate)
510 m_stabilizer_shock_sleep -=
PHYSICS_DT * num_steps;
512 float roll = asin(GetCameraRoll().dotProduct(Vector3::UNIT_Y));
514 if (fabs(roll) > 0.2)
516 m_stabilizer_shock_sleep = -1.0;
518 if (fabs(roll) > 0.01 && m_stabilizer_shock_sleep < 0.0)
520 if (roll > 0.0 && m_stabilizer_shock_request != -1)
522 m_stabilizer_shock_request = 1;
524 else if (roll < 0.0 && m_stabilizer_shock_request != 1)
526 m_stabilizer_shock_request = -1;
530 m_stabilizer_shock_request = 0;
531 m_stabilizer_shock_sleep = 3.0;
536 m_stabilizer_shock_request = 0;
539 if (m_stabilizer_shock_request && fabs(m_stabilizer_shock_ratio) < 0.1)
546 void Actor::CalcHydros()
549 if (ar_hydro_dir_state != 0 || ar_hydro_dir_command != 0)
551 if (!ar_hydro_speed_coupling)
556 float diff = ar_hydro_dir_command - ar_hydro_dir_state;
557 float rate = std::exp(-std::min(std::abs(diff), 1.0f) / sensitivity) * diff;
558 ar_hydro_dir_state += (10.0f / smoothing) *
PHYSICS_DT * rate;
562 if (ar_hydro_dir_command != 0)
566 float rate = std::max(1.2f, 30.0f / (10.0f));
567 if (ar_hydro_dir_state > ar_hydro_dir_command)
575 float rate = std::max(1.2f, 30.0f / (10.0f + std::abs(ar_wheel_speed / 2.0f)));
576 if (ar_hydro_dir_state > ar_hydro_dir_command)
583 if (ar_hydro_dir_state > dirdelta)
584 ar_hydro_dir_state -= dirdelta;
585 else if (ar_hydro_dir_state < -dirdelta)
586 ar_hydro_dir_state += dirdelta;
588 ar_hydro_dir_state = 0;
592 if (ar_hydro_aileron_state != 0 || ar_hydro_aileron_command != 0)
594 if (ar_hydro_aileron_command != 0)
596 if (ar_hydro_aileron_state > ar_hydro_aileron_command)
602 if (ar_hydro_aileron_state > delta)
603 ar_hydro_aileron_state -= delta;
604 else if (ar_hydro_aileron_state < -delta)
605 ar_hydro_aileron_state += delta;
607 ar_hydro_aileron_state = 0;
610 if (ar_hydro_rudder_state != 0 || ar_hydro_rudder_command != 0)
612 if (ar_hydro_rudder_command != 0)
614 if (ar_hydro_rudder_state > ar_hydro_rudder_command)
621 if (ar_hydro_rudder_state > delta)
622 ar_hydro_rudder_state -= delta;
623 else if (ar_hydro_rudder_state < -delta)
624 ar_hydro_rudder_state += delta;
626 ar_hydro_rudder_state = 0;
629 if (ar_hydro_elevator_state != 0 || ar_hydro_elevator_command != 0)
631 if (ar_hydro_elevator_command != 0)
633 if (ar_hydro_elevator_state > ar_hydro_elevator_command)
639 if (ar_hydro_elevator_state > delta)
640 ar_hydro_elevator_state -= delta;
641 else if (ar_hydro_elevator_state < -delta)
642 ar_hydro_elevator_state += delta;
644 ar_hydro_elevator_state = 0;
647 const int num_hydros =
static_cast<int>(ar_hydros.size());
648 for (
int i = 0; i < num_hydros; ++i)
658 if (ar_wheel_speed < 12.0f)
659 cstate += ar_hydro_dir_state * (12.0f - ar_wheel_speed) / 12.0f;
664 cstate += ar_hydro_dir_state;
669 cstate += ar_hydro_aileron_state;
674 cstate += ar_hydro_rudder_state;
679 cstate += ar_hydro_elevator_state;
684 cstate -= ar_hydro_aileron_state;
689 cstate -= ar_hydro_rudder_state;
694 cstate -= ar_hydro_elevator_state;
708 this->CalcAnimators(hydrobeam, cstate, div);
714 cstate /= (float)div;
719 ar_hydro_dir_wheel_display = cstate;
721 float factor = 1.0 - cstate * hydrobeam.
hb_speed;
726 if (factor < 1.0f - ar_beams[beam_idx].shortbound)
727 factor = 1.0f - ar_beams[beam_idx].shortbound;
728 if (factor > 1.0f + ar_beams[beam_idx].longbound)
729 factor = 1.0f + ar_beams[beam_idx].longbound;
737 void Actor::CalcCommands(
bool doUpdate)
739 if (m_has_command_beams)
742 bool requested =
false;
747 ar_engine_hydraulics_ready = ar_engine->GetEngineRpm() > ar_engine->getIdleRPM() * 0.95f;
749 ar_engine_hydraulics_ready =
true;
752 float crankfactor = 1.0f;
754 crankfactor = ar_engine->GetCrankFactor();
762 for (
int j = 0; j < (int)ar_command_key[i].beams.size(); j++)
764 ar_command_key[i].beams[j].cmb_state->auto_move_lock =
false;
770 float oldValue = ar_command_key[i].commandValue;
772 ar_command_key[i].commandValue = std::max(ar_command_key[i].playerInputValue, ar_command_key[i].triggerInputValue);
774 ar_command_key[i].triggerInputValue = 0.0f;
776 if (ar_command_key[i].commandValue > 0.01f && oldValue < 0.01f)
779 ar_command_key[i].commandValueState = 1;
781 else if (ar_command_key[i].commandValue < 0.01f && oldValue > 0.01f)
784 ar_command_key[i].commandValueState = -1;
787 for (
int j = 0; j < (int)ar_command_key[i].beams.size(); j++)
789 if (ar_command_key[i].commandValue >= 0.5)
791 ar_command_key[i].beams[j].cmb_state->auto_move_lock =
true;
792 if (ar_command_key[i].beams[j].cmb_is_autocentering)
794 ar_command_key[i].beams[j].cmb_state->auto_moving_mode = 0;
803 bool requestpower =
false;
804 for (
int j = 0; j < (int)ar_command_key[i].beams.size(); j++)
810 if (bbeam > ar_num_beams)
815 crankfactor = std::min(crankfactor, 1.0f);
817 float v = ar_command_key[i].commandValue;
818 int& vst = ar_command_key[i].commandValueState;
824 if (ar_beams[bbeam].refL == 0 || ar_beams[bbeam].L == 0)
827 float current = (ar_beams[bbeam].L / ar_beams[bbeam].refL);
832 cmd_beam.
cmb_state->auto_moving_mode = 0;
836 int mode = cmd_beam.
cmb_state->auto_moving_mode;
840 cmd_beam.
cmb_state->auto_moving_mode = -1;
842 cmd_beam.
cmb_state->auto_moving_mode = 1;
845 if (mode != 0 && mode != cmd_beam.
cmb_state->auto_moving_mode)
848 cmd_beam.
cmb_state->auto_moving_mode = 0;
853 if (ar_beams[bbeam].refL != 0 && ar_beams[bbeam].L != 0)
855 float clen = ar_beams[bbeam].L / ar_beams[bbeam].refL;
858 float dl = ar_beams[bbeam].L;
865 cmd_beam.
cmb_state->pressed_center_mode =
true;
866 cmd_beam.
cmb_state->auto_moving_mode = 0;
870 cmd_beam.
cmb_state->pressed_center_mode =
false;
875 bool key = (v > 0.5);
876 if (bbeam_dir * cmd_beam.
cmb_state->auto_moving_mode <= 0 && key)
878 cmd_beam.
cmb_state->auto_moving_mode = bbeam_dir * 1;
880 else if (cmd_beam.
cmb_state->auto_moving_mode == bbeam_dir * 1 && !key)
882 cmd_beam.
cmb_state->auto_moving_mode = bbeam_dir * 2;
884 else if (cmd_beam.
cmb_state->auto_moving_mode == bbeam_dir * 2 && key)
886 cmd_beam.
cmb_state->auto_moving_mode = bbeam_dir * 3;
888 else if (cmd_beam.
cmb_state->auto_moving_mode == bbeam_dir * 3 && !key)
890 cmd_beam.
cmb_state->auto_moving_mode = 0;
894 v = ar_command_key[i].command_inertia.CalcCmdKeyDelay(v,
PHYSICS_DT);
896 if (bbeam_dir * cmd_beam.
cmb_state->auto_moving_mode > 0)
899 if (cmd_beam.
cmb_needs_engine && ((ar_engine && !ar_engine->isRunning()) || !ar_engine_hydraulics_ready))
939 dl = fabs(dl - ar_beams[bbeam].L);
949 cmd_beam.
cmb_state->auto_moving_mode = 0;
954 for (
int j = 0; j < (int)ar_command_key[i].rotators.size(); j++)
957 int rota = std::abs(ar_command_key[i].rotators[j]) - 1;
959 if (ar_rotators[rota].needs_engine && ((ar_engine && !ar_engine->isRunning()) || !ar_engine_hydraulics_ready))
962 v = ar_command_key[i].rotator_inertia.CalcCmdKeyDelay(ar_command_key[i].commandValue,
PHYSICS_DT);
964 if (v > 0.0f && ar_rotators[rota].engine_coupling > 0.0f)
969 if (ar_rotators[rota].engine_coupling > 0.0f)
972 if (ar_command_key[i].rotators[j] > 0)
973 ar_rotators[rota].angle += ar_rotators[rota].rate * v * cf *
PHYSICS_DT;
975 ar_rotators[rota].angle -= ar_rotators[rota].rate * v * cf *
PHYSICS_DT;
977 if (doUpdate || v != 0.0f)
979 ar_rotators[rota].debug_rate = ar_rotators[rota].rate * v * cf;
988 ar_engine->SetHydroPumpWork(work);
989 ar_engine->SetEnginePriming(requested);
998 float pump_rpm = 660.0f * (1.0f - (work / (float)active) / 100.0f);
1008 for (
int i = 0; i < ar_num_rotators; i++)
1011 Vector3 ax1 = ar_nodes[ar_rotators[i].axis1].RelPosition;
1012 Vector3 ax2 = ar_nodes[ar_rotators[i].axis2].RelPosition;
1013 Vector3 axis = ax1 - ax2;
1016 Plane pl = Plane(axis, 0);
1018 ar_rotators[i].debug_aerror = 0;
1019 for (
int k = 0; k < 2; k++)
1022 Vector3 ref1 = pl.projectVector(ax1 - ar_nodes[ar_rotators[i].nodes1[k]].RelPosition);
1023 Vector3 ref2 = pl.projectVector(ax2 - ar_nodes[ar_rotators[i].nodes2[k]].RelPosition);
1024 float ref1len = ref1.normalise();
1025 float ref2len = ref2.normalise();
1027 Vector3 th1 = Quaternion(Radian(ar_rotators[i].angle + Math::HALF_PI), axis) * ref1;
1029 float aerror = asin(th1.dotProduct(ref2));
1030 ar_rotators[i].debug_aerror += 0.5f * aerror;
1032 float rigidity = ar_rotators[i].force;
1033 Vector3 dir1 = ref1.crossProduct(axis);
1034 Vector3 dir2 = ref2.crossProduct(axis);
1037 if (ref1len <= ar_rotators[i].tolerance)
1039 if (ref2len <= ar_rotators[i].tolerance)
1042 ar_nodes[ar_rotators[i].nodes1[k ]].Forces += (aerror * ref1len * rigidity) * dir1;
1043 ar_nodes[ar_rotators[i].nodes2[k ]].Forces -= (aerror * ref2len * rigidity) * dir2;
1045 ar_nodes[ar_rotators[i].nodes1[k + 2]].Forces -= (aerror * ref1len * rigidity) * dir1;
1046 ar_nodes[ar_rotators[i].nodes2[k + 2]].Forces += (aerror * ref2len * rigidity) * dir2;
1052 void Actor::CalcTies()
1055 for (std::vector<tie_t>::iterator it = ar_ties.begin(); it != ar_ties.end(); it++)
1062 if (it->ti_beam->refL == 0 || it->ti_beam->L == 0)
1065 float clen = it->ti_beam->L / it->ti_beam->refL;
1066 if (clen > it->ti_min_length)
1068 it->ti_beam->L *= (1.0 - it->ti_contract_speed *
PHYSICS_DT / it->ti_beam->L);
1073 it->ti_tying =
false;
1077 if (fabs(it->ti_beam->stress) > it->ti_max_stress)
1079 it->ti_tying =
false;
1083 void Actor::CalcTruckEngine(
bool doUpdate)
1087 ar_engine->UpdateEngineSim(
PHYSICS_DT, doUpdate);
1091 void Actor::CalcReplay()
1093 if (m_replay_handler && m_replay_handler->isValid())
1095 m_replay_handler->onPhysicsStep();
1099 bool Actor::CalcForcesEulerPrepare(
bool doUpdate)
1101 if (m_ongoing_reset)
1103 if (ar_physics_paused)
1105 if (ar_state != ActorState::LOCAL_SIMULATED)
1112 rq->
alr_type = ActorLinkingRequestType::HOOK_ACTION;
1128 msg <<
" (index: " << node->
pos <<
")";
1134 msg <<
"It was between nodes ";
1141 void Actor::CalcBeams(
bool trigger_hooks)
1143 for (
int i = 0; i < ar_num_beams; i++)
1145 if (!ar_beams[i].bm_disabled && !ar_beams[i].bm_inter_actor)
1148 Vector3 dis = ar_beams[i].p1->RelPosition - ar_beams[i].p2->RelPosition;
1150 Real dislen = dis.squaredLength();
1153 dislen *= inverted_dislen;
1156 Real difftoBeamL = dislen - ar_beams[i].L;
1158 Real k = ar_beams[i].k;
1159 Real d = ar_beams[i].d;
1162 float v = (ar_beams[i].p1->Velocity - ar_beams[i].p2->Velocity).dotProduct(dis) * inverted_dislen;
1164 if (ar_beams[i].bounded ==
SHOCK1)
1166 float interp_ratio = 0.0f;
1169 if (difftoBeamL > ar_beams[i].longbound * ar_beams[i].L)
1170 interp_ratio = difftoBeamL - ar_beams[i].longbound * ar_beams[i].L;
1171 else if (difftoBeamL < -ar_beams[i].shortbound * ar_beams[i].L)
1172 interp_ratio = -difftoBeamL - ar_beams[i].shortbound * ar_beams[i].L;
1174 if (interp_ratio != 0.0f)
1183 tspring = ar_beams[i].shock->sbd_spring;
1184 tdamp = ar_beams[i].shock->sbd_damp;
1187 k += (tspring - k) * interp_ratio;
1188 d += (tdamp - d) * interp_ratio;
1191 else if (ar_beams[i].bounded ==
TRIGGER)
1193 this->CalcTriggers(i, difftoBeamL, trigger_hooks);
1195 else if (ar_beams[i].bounded ==
SHOCK2)
1197 this->CalcShocks2(i, difftoBeamL, k, d, v);
1199 else if (ar_beams[i].bounded ==
SHOCK3)
1201 this->CalcShocks3(i, difftoBeamL, k, d, v);
1205 if (difftoBeamL > 0.0f)
1210 if (ar_beams[i].longbound > 0.0f)
1213 break_limit = ar_beams[i].longbound;
1217 if (difftoBeamL > ar_beams[i].L * break_limit)
1219 ar_beams[i].bm_broken =
true;
1220 ar_beams[i].bm_disabled =
true;
1221 if (m_beam_break_debug_enabled)
1224 msg <<
"[RoR|Diag] XXX Support-Beam " << i <<
" limit extended and broke. "
1225 <<
"Length: " << difftoBeamL <<
" / max. Length: " << (ar_beams[i].L*break_limit) <<
". ";
1232 else if (ar_beams[i].bounded ==
ROPE)
1234 if (difftoBeamL < 0.0f)
1241 if (trigger_hooks && ar_beams[i].bounded && ar_beams[i].bm_type ==
BEAM_HYDRO)
1243 ar_beams[i].debug_k = k * std::abs(difftoBeamL);
1244 ar_beams[i].debug_d = d * std::abs(v);
1245 ar_beams[i].debug_v = std::abs(v);
1248 float slen = -k * difftoBeamL - d * v;
1249 ar_beams[i].stress = slen;
1252 float len = std::abs(slen);
1253 if (len > ar_beams[i].minmaxposnegstress)
1255 if (ar_beams[i].bm_type ==
BEAM_NORMAL && ar_beams[i].bounded !=
SHOCK1 && k != 0.0f)
1258 if (slen > ar_beams[i].maxposstress && difftoBeamL < 0.0f)
1260 Real yield_length = ar_beams[i].maxposstress / k;
1261 Real deform = difftoBeamL + yield_length * (1.0f - ar_beams[i].plastic_coef);
1262 Real Lold = ar_beams[i].L;
1263 ar_beams[i].L += deform;
1265 slen = slen - (slen - ar_beams[i].maxposstress) * 0.5f;
1267 if (ar_beams[i].L > 0.0f && Lold > ar_beams[i].L)
1269 ar_beams[i].maxposstress *= Lold / ar_beams[i].L;
1270 ar_beams[i].minmaxposnegstress = std::min(ar_beams[i].maxposstress, -ar_beams[i].maxnegstress);
1271 ar_beams[i].minmaxposnegstress = std::min(ar_beams[i].minmaxposnegstress, ar_beams[i].strength);
1276 if (m_beam_deform_debug_enabled)
1279 msg <<
"[RoR|Diag] YYY Beam " << i <<
" just deformed with extension force "
1280 << len <<
" / " << ar_beams[i].strength <<
". ";
1285 else if (slen < ar_beams[i].maxnegstress && difftoBeamL > 0.0f)
1287 Real yield_length = ar_beams[i].maxnegstress / k;
1288 Real deform = difftoBeamL + yield_length * (1.0f - ar_beams[i].plastic_coef);
1289 Real Lold = ar_beams[i].L;
1290 ar_beams[i].L += deform;
1291 slen = slen - (slen - ar_beams[i].maxnegstress) * 0.5f;
1293 if (Lold > 0.0f && ar_beams[i].L > Lold)
1295 ar_beams[i].maxnegstress *= ar_beams[i].L / Lold;
1296 ar_beams[i].minmaxposnegstress = std::min(ar_beams[i].maxposstress, -ar_beams[i].maxnegstress);
1297 ar_beams[i].minmaxposnegstress = std::min(ar_beams[i].minmaxposnegstress, ar_beams[i].strength);
1299 ar_beams[i].strength -= deform * k;
1300 if (m_beam_deform_debug_enabled)
1303 msg <<
"[RoR|Diag] YYY Beam " << i <<
" just deformed with extension force "
1304 << len <<
" / " << ar_beams[i].strength <<
". ";
1312 if (len > ar_beams[i].strength)
1322 if (!((ar_beams[i].p1->nd_cab_node && GetNumActiveConnectedBeams(ar_beams[i].p1->pos) < 3) || (ar_beams[i].p2->nd_cab_node && GetNumActiveConnectedBeams(ar_beams[i].p2->pos) < 3)))
1325 ar_beams[i].bm_broken =
true;
1326 ar_beams[i].bm_disabled =
true;
1328 if (m_beam_break_debug_enabled)
1331 msg <<
"[RoR|Diag] XXX Beam " << i <<
" just broke with force " << len <<
" / " << ar_beams[i].strength <<
". ";
1338 if (ar_beams[i].detacher_group > 0)
1341 for (
int j = 0; j < ar_num_beams; j++)
1345 if (abs(ar_beams[j].detacher_group) == ar_beams[i].detacher_group)
1347 ar_beams[j].bm_broken =
true;
1348 ar_beams[j].bm_disabled =
true;
1349 if (m_beam_break_debug_enabled)
1352 "Deleting Detacher BeamID: " +
TOSTRING(j) +
", Detacher Group: " +
TOSTRING(ar_beams[i].detacher_group)+
", actor ID: " +
TOSTRING(ar_instance_id));
1359 if (wheeldetacher.wd_detacher_group == ar_beams[i].detacher_group)
1361 ar_wheels[wheeldetacher.wd_wheel_id].wh_is_detached =
true;
1362 if (m_beam_break_debug_enabled)
1365 "Detaching wheel ID: " +
TOSTRING(wheeldetacher.wd_wheel_id) +
", Detacher Group: " +
TOSTRING(ar_beams[i].detacher_group)+
", actor ID: " +
TOSTRING(ar_instance_id));
1373 ar_beams[i].strength = 2.0f * ar_beams[i].minmaxposnegstress;
1377 for (
int mk = 0; mk < ar_num_buoycabs; mk++)
1379 int tmpv = ar_buoycabs[mk] * 3;
1380 if (ar_buoycab_types[mk] == Buoyance::BUOY_DRAGONLY)
1382 if ((ar_beams[i].p1 == &ar_nodes[ar_cabs[tmpv]] || ar_beams[i].p1 == &ar_nodes[ar_cabs[tmpv + 1]] || ar_beams[i].p1 == &ar_nodes[ar_cabs[tmpv + 2]]) &&
1383 (ar_beams[i].p2 == &ar_nodes[ar_cabs[tmpv]] || ar_beams[i].p2 == &ar_nodes[ar_cabs[tmpv + 1]] || ar_beams[i].p2 == &ar_nodes[ar_cabs[tmpv + 2]]))
1385 m_buoyance->sink =
true;
1393 f *= (slen * inverted_dislen);
1394 ar_beams[i].p1->Forces += f;
1395 ar_beams[i].p2->Forces -= f;
1400 void Actor::CalcBeamsInterActor()
1402 for (
int i = 0; i < static_cast<int>(ar_inter_beams.size()); i++)
1404 if (!ar_inter_beams[i]->bm_disabled && ar_inter_beams[i]->bm_inter_actor)
1407 Vector3 dis = ar_inter_beams[i]->p1->AbsPosition - ar_inter_beams[i]->p2->AbsPosition;
1409 Real dislen = dis.squaredLength();
1412 dislen *= inverted_dislen;
1415 Real difftoBeamL = dislen - ar_inter_beams[i]->L;
1417 Real k = ar_inter_beams[i]->k;
1418 Real d = ar_inter_beams[i]->d;
1420 if (ar_inter_beams[i]->bounded ==
ROPE && difftoBeamL < 0.0f)
1427 Vector3 v = ar_inter_beams[i]->p1->Velocity - ar_inter_beams[i]->p2->Velocity;
1429 float slen = -k * (difftoBeamL) - d * v.dotProduct(dis) * inverted_dislen;
1430 ar_inter_beams[i]->stress = slen;
1433 float len = std::abs(slen);
1434 if (len > ar_inter_beams[i]->minmaxposnegstress)
1436 if (ar_inter_beams[i]->bm_type ==
BEAM_NORMAL && ar_inter_beams[i]->bounded !=
SHOCK1 && k != 0.0f)
1439 if (slen > ar_inter_beams[i]->maxposstress && difftoBeamL < 0.0f)
1441 Real yield_length = ar_inter_beams[i]->maxposstress / k;
1442 Real deform = difftoBeamL + yield_length * (1.0f - ar_inter_beams[i]->plastic_coef);
1443 Real Lold = ar_inter_beams[i]->L;
1444 ar_inter_beams[i]->L += deform;
1445 ar_inter_beams[i]->L = std::max(
MIN_BEAM_LENGTH, ar_inter_beams[i]->L);
1446 slen = slen - (slen - ar_inter_beams[i]->maxposstress) * 0.5f;
1448 if (ar_inter_beams[i]->L > 0.0f && Lold > ar_inter_beams[i]->L)
1450 ar_inter_beams[i]->maxposstress *= Lold / ar_inter_beams[i]->L;
1451 ar_inter_beams[i]->minmaxposnegstress = std::min(ar_inter_beams[i]->maxposstress, -ar_inter_beams[i]->maxnegstress);
1452 ar_inter_beams[i]->minmaxposnegstress = std::min(ar_inter_beams[i]->minmaxposnegstress, ar_inter_beams[i]->strength);
1457 if (m_beam_deform_debug_enabled)
1460 msg <<
"[RoR|Diag] YYY Beam " << i <<
" just deformed with extension force "
1461 << len <<
" / " << ar_inter_beams[i]->strength <<
". ";
1466 else if (slen < ar_inter_beams[i]->maxnegstress && difftoBeamL > 0.0f)
1468 Real yield_length = ar_inter_beams[i]->maxnegstress / k;
1469 Real deform = difftoBeamL + yield_length * (1.0f - ar_inter_beams[i]->plastic_coef);
1470 Real Lold = ar_inter_beams[i]->L;
1471 ar_inter_beams[i]->L += deform;
1472 slen = slen - (slen - ar_inter_beams[i]->maxnegstress) * 0.5f;
1474 if (Lold > 0.0f && ar_inter_beams[i]->L > Lold)
1476 ar_inter_beams[i]->maxnegstress *= ar_inter_beams[i]->L / Lold;
1477 ar_inter_beams[i]->minmaxposnegstress = std::min(ar_inter_beams[i]->maxposstress, -ar_inter_beams[i]->maxnegstress);
1478 ar_inter_beams[i]->minmaxposnegstress = std::min(ar_inter_beams[i]->minmaxposnegstress, ar_inter_beams[i]->strength);
1480 ar_inter_beams[i]->strength -= deform * k;
1481 if (m_beam_deform_debug_enabled)
1484 msg <<
"[RoR|Diag] YYY Beam " << i <<
" just deformed with extension force "
1485 << len <<
" / " << ar_inter_beams[i]->strength <<
". ";
1493 if (len > ar_inter_beams[i]->strength)
1503 if (!((ar_inter_beams[i]->p1->nd_cab_node && GetNumActiveConnectedBeams(ar_inter_beams[i]->p1->pos) < 3) || (ar_inter_beams[i]->p2->nd_cab_node && GetNumActiveConnectedBeams(ar_inter_beams[i]->p2->pos) < 3)))
1506 ar_inter_beams[i]->bm_broken =
true;
1507 ar_inter_beams[i]->bm_disabled =
true;
1509 if (m_beam_break_debug_enabled)
1512 msg <<
"Beam " << i <<
" just broke with force " << len <<
" / " << ar_inter_beams[i]->strength <<
". ";
1519 ar_inter_beams[i]->strength = 2.0f * ar_inter_beams[i]->minmaxposnegstress;
1526 f *= (slen * inverted_dislen);
1527 ar_inter_beams[i]->p1->Forces += f;
1528 ar_inter_beams[i]->p2->Forces -= f;
1533 void Actor::CalcNodes()
1537 m_water_contact =
false;
1539 for (
NodeNum_t i = 0; i < ar_num_nodes; i++)
1542 if (!ar_nodes[i].nd_no_ground_contact)
1544 Vector3 oripos = ar_nodes[i].AbsPosition;
1547 ar_nodes[i].nd_has_ground_contact = contacted;
1548 if (ar_nodes[i].nd_has_ground_contact || ar_nodes[i].nd_has_mesh_contact)
1550 ar_last_fuzzy_ground_model = ar_nodes[i].nd_last_collision_gm;
1554 ar_nodes[i].RelPosition += ar_nodes[i].AbsPosition - oripos;
1558 if (i == ar_main_camera_node_pos)
1561 m_camera_gforces_accu += ar_nodes[i].Forces / ar_nodes[i].mass;
1565 if (!ar_nodes[i].nd_immovable)
1567 ar_nodes[i].Velocity += ar_nodes[i].Forces / ar_nodes[i].mass *
PHYSICS_DT;
1568 ar_nodes[i].RelPosition += ar_nodes[i].Velocity *
PHYSICS_DT;
1569 ar_nodes[i].AbsPosition = ar_origin;
1570 ar_nodes[i].AbsPosition += ar_nodes[i].RelPosition;
1576 ar_nodes[i].Forces = Vector3(0, ar_nodes[i].mass * gravity, 0);
1578 Real approx_speed =
approx_sqrt(ar_nodes[i].Velocity.squaredLength());
1581 if (approx_speed > 6860 && !m_ongoing_reset)
1585 rq->
amr_type = ActorModifyRequest::Type::RESET_ON_SPOT;
1587 m_ongoing_reset =
true;
1590 if (m_fusealge_airfoil)
1593 ar_nodes[i].Forces += ar_fusedrag;
1595 else if (!ar_disable_aerodyn_turbulent_drag)
1599 Vector3 drag = -defdragxspeed * ar_nodes[i].Velocity;
1601 Real maxtur = defdragxspeed * approx_speed * 0.005f;
1603 ar_nodes[i].Forces += drag;
1608 const bool is_under_water = water->IsUnderWater(ar_nodes[i].AbsPosition);
1611 m_water_contact =
true;
1612 if (ar_num_buoycabs == 0)
1615 ar_nodes[i].Forces -= (
DEFAULT_WATERDRAG * approx_speed) * ar_nodes[i].Velocity;
1617 ar_nodes[i].Forces += ar_nodes[i].buoyancy * Vector3::UNIT_Y;
1620 if (i == ar_cinecam_node[0] && ar_engine)
1622 ar_engine->StopEngine();
1625 ar_nodes[i].nd_under_water = is_under_water;
1630 void Actor::CalcEventBoxes()
1639 m_potential_eventboxes.clear();
1645 bool has_collision =
false;
1646 bool do_callback_enter =
true;
1647 bool do_callback_exit =
false;
1648 auto itor = m_active_eventboxes.begin();
1649 while (itor != m_active_eventboxes.end())
1651 if (itor->first == cbox)
1658 itor = m_active_eventboxes.erase(itor);
1660 do_callback_enter =
false;
1661 do_callback_exit =
true;
1674 for (
NodeNum_t i = 0; i < ar_num_nodes; i++)
1679 do_callback_exit =
false;
1681 m_active_eventboxes.push_back(std::make_pair(cbox, i));
1683 if (do_callback_enter)
1700 if (do_callback_exit)
1709 void Actor::CalcHooks()
1712 for (std::vector<hook_t>::iterator it = ar_hooks.begin(); it != ar_hooks.end(); it++)
1715 it->hk_timer = std::max(0.0f, it->hk_timer -
PHYSICS_DT);
1717 if (it->hk_lock_node && it->hk_locked ==
PRELOCK)
1719 if (it->hk_beam->L < it->hk_min_length)
1727 if (it->hk_beam->L > it->hk_lockspeed && fabs(it->hk_beam->stress) < it->hk_maxforce)
1729 it->hk_beam->L = (it->hk_beam->L - it->hk_lockspeed);
1733 if (fabs(it->hk_beam->stress) < it->hk_maxforce)
1735 it->hk_beam->L = 0.001f;
1741 if (it->hk_nodisable)
1751 rq->
alr_type = ActorLinkingRequestType::HOOK_ACTION;
1762 void Actor::CalcRopes()
1764 for (
auto r : ar_ropes)
1766 if (r.rp_locked ==
LOCKED && r.rp_locked_ropable)
1768 auto locked_node = r.rp_locked_ropable->node;
1769 r.rp_beam->p2->AbsPosition = locked_node->AbsPosition;
1770 r.rp_beam->p2->RelPosition = locked_node->AbsPosition - ar_origin;
1771 r.rp_beam->p2->Velocity = locked_node->Velocity;
1772 locked_node->Forces += r.rp_beam->p2->Forces;
1773 r.rp_beam->p2->Forces = Vector3::ZERO;