void Car::applyCollision(const CL_LineSegment2f &p_seg) { static const float DAMAGE_MULT = 0.2f; const float side = -p_seg.point_right_of_line(m_impl->m_position); const CL_Vec2f segVec = p_seg.q - p_seg.p; // need front normal (crash side) CL_Vec2f fnormal(segVec.y, -segVec.x); // right side normal fnormal.normalize(); if (side < 0) { fnormal *= -1; } // move away m_impl->m_position += (fnormal * fabs(m_impl->m_speed)); // calculate collision angle to estaminate speed reduction CL_Angle angleDiff(m_impl->m_phyMoveRot - m_impl->vecToAngle(fnormal)); Workarounds::clAngleNormalize180(&angleDiff); const float colAngleDeg = fabs(angleDiff.to_degrees()) - 90.0f; const float reduction = fabs(1.0f - fabs(colAngleDeg - 90.0f) / 90.0f); // calculate and apply damage const float damage = m_impl->m_speed * reduction * DAMAGE_MULT; m_impl->m_damage = Math::Float::reduce(m_impl->m_damage + damage, 0.0f, 1.0f); cl_log_event(LOG_DEBUG, "damage: %1, total: %2", damage, m_impl->m_damage); // reduce speed m_impl->m_speed -= m_impl->m_speed * reduction; // bounce movement vector and angle away // get mirror point if (m_impl->m_phyMoveVec.length() > 0.01f) { m_impl->m_phyMoveVec.normalize(); const float lengthProj = m_impl->m_phyMoveVec.length() * cos(segVec.angle(m_impl->m_phyMoveVec).to_radians()); const CL_Vec2f mirrorPoint(segVec * (lengthProj / segVec.length())); // invert move vector by mirror point const CL_Vec2f mirrorVec = (m_impl->m_phyMoveVec - mirrorPoint) * -1; m_impl->m_phyMoveVec = mirrorPoint + mirrorVec; // update physics angle m_impl->m_phyMoveRot = m_impl->vecToAngle(m_impl->m_phyMoveVec); } }
CL_Angle CarImpl::vecToAngle(const CL_Vec2f &p_vec) { const static CL_Vec2f ANGLE_ZERO(1.0f, 0.0f); CL_Angle angle = p_vec.angle(ANGLE_ZERO); if (p_vec.y < 0) { angle.set_radians(-angle.to_radians()); } return angle; }