// Filename: CollisionHandlerGravity.cxx // Created by: drose (16Mar02) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE // Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license // along with this source code; you will also find a current copy of // the license at http://etc.cmu.edu/panda3d/docs/license/ . // // To contact the maintainers of this program write to // panda3d-general@lists.sourceforge.net . // //////////////////////////////////////////////////////////////////// #include "collisionHandlerGravity.h" #include "collisionNode.h" #include "collisionEntry.h" #include "config_collide.h" #include "clockObject.h" TypeHandle CollisionHandlerGravity::_type_handle; //////////////////////////////////////////////////////////////////// // Function: CollisionHandlerGravity::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// CollisionHandlerGravity:: CollisionHandlerGravity() { _offset = 0.0f; _airborne_height = 0.0f; _impact_velocity = 0.0f; _gravity = 32.174f; _current_velocity = 0.0f; _max_velocity = 400.0f; } //////////////////////////////////////////////////////////////////// // Function: CollisionHandlerGravity::Destructor // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// CollisionHandlerGravity:: ~CollisionHandlerGravity() { } //////////////////////////////////////////////////////////////////// // Function: CollisionHandlerGravity::set_highest_collision // Access: Protected // Description: // // // // // // //////////////////////////////////////////////////////////////////// float CollisionHandlerGravity:: set_highest_collision(const NodePath &target_node_path, const NodePath &from_node_path, const Entries &entries) { // Get the maximum height for all collisions with this node. // This is really the distance to-the-ground, so it will // be negative when the avatar is above the ground. // Larger values (less negative) are higher elevation (assuming // the avatar is right-side-up (or the ray is plumb)). bool got_max = false; bool got_min = false; float max_height = 0.0f; float min_height = 0.0f; CollisionEntry *highest = NULL; CollisionEntry *lowest = NULL; Entries::const_iterator ei; for (ei = entries.begin(); ei != entries.end(); ++ei) { CollisionEntry *entry = (*ei); nassertr(entry != (CollisionEntry *)NULL, 0.0f); nassertr(from_node_path == entry->get_from_node_path(), 0.0f); if (entry->has_surface_point()) { LPoint3f point = entry->get_surface_point(target_node_path); if (collide_cat.is_debug()) { collide_cat.debug() << "Intersection point detected at " << point << "\n"; } float height = point[2]; if (height < _offset && (!got_max || height > max_height)) { got_max = true; max_height = height; highest = entry; } if (!got_min || height < min_height) { got_min = true; min_height = height; lowest = entry; } } } if (!got_max && got_min) { // We've fallen through the world, but we're also under some walkable // geometry. // Move us up to the lowest surface: got_max = true; max_height = min_height; highest = lowest; } //#*#_has_contact = got_max; #if 0 cout<<"\ncolliding with:\n"; for (Colliding::const_iterator i = _current_colliding.begin(); i != _current_colliding.end(); ++i) { (**i).write(cout, 2); } cout<<"\nhighest:\n"; highest->write(cout, 2); cout< 0.0f || !IS_THRESHOLD_ZERO(adjust, 0.001)) { if (collide_cat.is_debug()) { collide_cat.debug() << "Adjusting height by " << adjust << "\n"; } if (_current_velocity > 0.0f || adjust) { // ...we have a vertical thrust, // ...or the node is above the floor, so it is airborne. float dt = ClockObject::get_global_clock()->get_dt(); // Fyi, the sign of _gravity is reversed. I think it makes the get_*() set_*() // more intuitive to do it this way. float gravity_adjust = _current_velocity * dt + 0.5 * -_gravity * dt * dt; if (adjust > 0.0f) { // ...the node is under the floor, so it has landed. // Keep the adjust to bring us up to the ground and // then add the gravity_adjust to get us airborne: adjust += max(0.0f, gravity_adjust); } else { // ...the node is above the floor, so it is airborne. adjust = max(adjust, gravity_adjust); } _current_velocity -= _gravity * dt; // Record the airborne height in case someone else needs it: _airborne_height = -max_height + adjust; assert(_airborne_height>=0.0f); } if (_airborne_height < 0.001f && _current_velocity < 0.001f) { // ...the node is under the floor, so it has landed. _impact_velocity = _current_velocity; // These values are used by is_on_ground(). _current_velocity = _airborne_height = 0.0f; } else { // ...we're airborne. _current_colliding.clear(); } CPT(TransformState) trans = def._target.get_transform(); LVecBase3f pos = trans->get_pos(); pos[2] += adjust; def._target.set_transform(trans->set_pos(pos)); def.updated_transform(); apply_linear_force(def, LVector3f(0.0f, 0.0f, adjust)); } else { _current_velocity = _airborne_height = 0.0f; if (collide_cat.is_spam()) { collide_cat.spam() << "Leaving height unchanged.\n"; } } } } return okflag; } //////////////////////////////////////////////////////////////////// // Function: CollisionHandlerGravity::apply_linear_force // Access: Protected, Virtual // Description: //////////////////////////////////////////////////////////////////// void CollisionHandlerGravity:: apply_linear_force(ColliderDef &def, const LVector3f &force) { }