Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Single player character collisions #3049

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions source/main/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ CVar* sim_no_self_collisions;
CVar* sim_gearbox_mode;
CVar* sim_soft_reset_mode;
CVar* sim_quickload_dialog;
CVar* sim_character_collisions;

// Multiplayer
CVar* mp_state;
Expand Down
1 change: 1 addition & 0 deletions source/main/Application.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ extern CVar* sim_no_self_collisions;
extern CVar* sim_gearbox_mode;
extern CVar* sim_soft_reset_mode;
extern CVar* sim_quickload_dialog;
extern CVar* sim_character_collisions;

// Multiplayer
extern CVar* mp_state;
Expand Down
105 changes: 95 additions & 10 deletions source/main/gameplay/Character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,15 +145,19 @@ void Character::update(float dt)

// Trigger script events and handle mesh (ground) collision
Vector3 query = position;
App::GetGameContext()->GetTerrain()->GetCollisions()->collisionCorrect(&query);
if (App::GetGameContext()->GetTerrain()->GetCollisions()->collisionCorrect(&query))
{
m_inertia = false;
}

// Auto compensate minor height differences
float depth = calculate_collision_depth(position);
if (depth > 0.0f)
float terrain_depth = calculate_collision_depth(position);
if (terrain_depth > 0.0f)
{
m_can_jump = true;
m_character_v_speed = std::max(0.0f, m_character_v_speed);
position.y += std::min(depth, 2.0f * dt);
position.y += std::min(terrain_depth, 2.0f * dt);
m_inertia = false;
}

// Submesh "collision"
Expand All @@ -173,16 +177,77 @@ void Character::update(float dt)
if (result.first && result.second < 1.8f)
{
depth = std::max(depth, result.second);
if (depth > 0 && m_contacting_actor == nullptr) // check fresh contacting actor also, prevents knockbacks with multiple actors that have node position overlapping
{
// first contact - initialize 'last' values to avoid big knockbacks
Vector3 cab_position = CalcCabAveragePos(actor, i);
m_last_vehicle_position = cab_position;
m_last_vehicle_rotation = Ogre::Radian(actor->getRotation());
m_last_contacting_cab = i;
m_contacting_actor = actor;
}
m_contacting_cab = i;
}
}

if (depth > 0)
{
m_can_jump = true;
m_character_v_speed = std::max(0.0f, m_character_v_speed);
position.y += std::min(depth, 0.05f);
}

if (m_contacting_actor != nullptr)
{
int motion_cab = -1;
if (m_contacting_cab == m_last_contacting_cab) // we're on the same cab - just get it's current pos.
{
motion_cab = m_contacting_cab;
}
else // we're on different cab - use current position of the previous cab.
{
motion_cab = m_last_contacting_cab;
}
Vector3 cab_position = CalcCabAveragePos(m_contacting_actor, motion_cab);
m_vehicle_position = cab_position;
m_vehicle_rotation = Ogre::Radian(m_contacting_actor->getRotation());

if (App::sim_character_collisions->getBool() && App::mp_state->getEnum<MpState>() != MpState::CONNECTED)
{
position += (m_vehicle_position - m_last_vehicle_position);
this->setRotation(m_character_rotation + (m_vehicle_rotation - m_last_vehicle_rotation));
}

m_inertia = true;
m_inertia_position = (m_vehicle_position - m_last_vehicle_position);
m_inertia_rotation = (m_vehicle_rotation - m_last_vehicle_rotation);
}
else if (m_inertia)
{
if (App::sim_character_collisions->getBool() && App::mp_state->getEnum<MpState>() != MpState::CONNECTED)
{
position += m_inertia_position;
this->setRotation(m_character_rotation + m_inertia_rotation);
}
}
}
else if (m_contacting_actor != nullptr && !m_contacting_actor->ar_bounding_box.contains(position)) // we lost contact, reset contacting actor
{
m_contacting_actor = nullptr;
}
}
if (depth > 0.0f)
{
m_can_jump = true;
m_character_v_speed = std::max(0.0f, m_character_v_speed);
position.y += std::min(depth, 0.05f);
}

if (m_contacting_cab == m_last_contacting_cab)
{
m_last_vehicle_position = m_vehicle_position;
}
else if (m_contacting_actor != nullptr) // we used last_contacting_cab's position for the motion, but we'll need contacting_cab's position next frame.
{
Vector3 cab_position = CalcCabAveragePos(m_contacting_actor, m_contacting_cab);
m_last_vehicle_position = cab_position;
}
m_last_contacting_cab = m_contacting_cab;
m_last_vehicle_rotation = m_vehicle_rotation;
}

// Obstacle detection
Expand Down Expand Up @@ -214,6 +279,7 @@ void Character::update(float dt)
position.y = pheight;
m_character_v_speed = 0.0f;
m_can_jump = true;
m_inertia = false;
}

// water stuff
Expand Down Expand Up @@ -373,6 +439,12 @@ void Character::update(float dt)
}
else if (m_actor_coupling) // The character occupies a vehicle or machine
{
// Submesh collision - Prevent knockbacks on vehicle exit
if (m_contacting_actor != nullptr)
{
m_contacting_actor = nullptr;
}

// Animation
float angle = m_actor_coupling->ar_hydro_dir_wheel_display * -1.0f; // not getSteeringAngle(), but this, as its smoothed
float anim_time_pos = ((angle + 1.0f) * 0.5f) * m_driving_anim_length;
Expand All @@ -398,6 +470,19 @@ void Character::update(float dt)
#endif // USE_SOCKETW
}

Ogre::Vector3 Character::CalcCabAveragePos(ActorPtr actor, int cab_index)
{
int tmpv = actor->ar_collcabs[cab_index] * 3;
Vector3 a = actor->ar_nodes[actor->ar_cabs[tmpv + 0]].AbsPosition;
Vector3 b = actor->ar_nodes[actor->ar_cabs[tmpv + 1]].AbsPosition;
Vector3 c = actor->ar_nodes[actor->ar_cabs[tmpv + 2]].AbsPosition;
Vector3 result;
result.x = (a.x + b.x + c.x) / 3;
result.y = (a.y + b.y + c.y) / 3;
result.z = (a.z + b.z + c.z) / 3;
return result;
}

void Character::move(Vector3 offset)
{
m_character_position += offset; //ASYNCSCENE OLD m_character_scenenode->translate(offset);
Expand Down
15 changes: 14 additions & 1 deletion source/main/gameplay/Character.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,19 @@ class Character
Ogre::Timer m_net_timer;
unsigned long m_net_last_update_time;
GfxCharacter* m_gfx_character;

// Collision with actor:
Ogre::Vector3 m_vehicle_position;
Ogre::Radian m_vehicle_rotation;
Ogre::Vector3 m_last_vehicle_position;
Ogre::Radian m_last_vehicle_rotation;
bool m_inertia = false;
Ogre::Vector3 m_inertia_position;
Ogre::Radian m_inertia_rotation;
ActorPtr m_contacting_actor;
int m_contacting_cab;
int m_last_contacting_cab;
Ogre::Vector3 CalcCabAveragePos(ActorPtr actor, int cab_index);
};

/// @} // addtogroup Character
Expand All @@ -105,7 +118,7 @@ struct GfxCharacter
Ogre::UTFString simbuf_net_username;
bool simbuf_is_remote;
int simbuf_color_number;
ActorPtr simbuf_actor_coupling;
ActorPtr simbuf_actor_coupling;
std::string simbuf_anim_name;
float simbuf_anim_time; // Intentionally left empty = forces initial update.
};
Expand Down
6 changes: 6 additions & 0 deletions source/main/gui/panels/GUI_TopMenubar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,12 @@ void TopMenubar::Update()
DrawGCheckbox(App::mp_pseudo_collisions, _LC("TopMenubar", "Collisions"));
DrawGCheckbox(App::mp_hide_net_labels, _LC("TopMenubar", "Hide labels"));
}
if (App::mp_state->getEnum<MpState>() != MpState::CONNECTED)
{
ImGui::Separator();
ImGui::TextColored(GRAY_HINT_TEXT, "%s", _LC("TopMenubar", "Miscellaneous:"));
DrawGCheckbox(App::sim_character_collisions, _LC("TopMenubar", "Character collisions"));
}
ImGui::PopItemWidth();
m_open_menu_hoverbox_min = menu_pos;
m_open_menu_hoverbox_max.x = menu_pos.x + ImGui::GetWindowWidth();
Expand Down
1 change: 1 addition & 0 deletions source/main/system/CVar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ void Console::cVarSetupBuiltins()
App::sim_gearbox_mode = this->cVarCreate("sim_gearbox_mode", "GearboxMode", CVAR_ARCHIVE | CVAR_TYPE_INT);
App::sim_soft_reset_mode = this->cVarCreate("sim_soft_reset_mode", "", CVAR_TYPE_BOOL, "false");
App::sim_quickload_dialog = this->cVarCreate("sim_quickload_dialog", "", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "true");
App::sim_character_collisions = this->cVarCreate("sim_character_collisions", "CharacterCollisions", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false");

App::mp_state = this->cVarCreate("mp_state", "", CVAR_TYPE_INT, "0"/*(int)MpState::DISABLED*/);
App::mp_join_on_startup = this->cVarCreate("mp_join_on_startup", "Auto connect", CVAR_ARCHIVE | CVAR_TYPE_BOOL, "false");
Expand Down