diff --git a/panda/src/collide/Sources.pp b/panda/src/collide/Sources.pp index 45c4a0e21d..aac22002c6 100644 --- a/panda/src/collide/Sources.pp +++ b/panda/src/collide/Sources.pp @@ -14,6 +14,7 @@ collisionHandler.h \ collisionHandlerEvent.I collisionHandlerEvent.h \ collisionHandlerFloor.I collisionHandlerFloor.h \ + collisionHandlerGravity.I collisionHandlerGravity.h \ collisionHandlerPhysical.I collisionHandlerPhysical.h \ collisionHandlerPusher.I collisionHandlerPusher.h \ collisionHandlerQueue.h \ @@ -36,6 +37,7 @@ collisionHandler.cxx \ collisionHandlerEvent.cxx \ collisionHandlerFloor.cxx \ + collisionHandlerGravity.cxx \ collisionHandlerPhysical.cxx \ collisionHandlerPusher.cxx \ collisionHandlerQueue.cxx \ @@ -57,6 +59,7 @@ collisionHandler.h \ collisionHandlerEvent.I collisionHandlerEvent.h \ collisionHandlerFloor.I collisionHandlerFloor.h \ + collisionHandlerGravity.I collisionHandlerGravity.h \ collisionHandlerPhysical.I collisionHandlerPhysical.h \ collisionHandlerPusher.I collisionHandlerPusher.h \ collisionHandlerQueue.h \ diff --git a/panda/src/collide/collide_composite1.cxx b/panda/src/collide/collide_composite1.cxx index ae366d0fd4..ca96ec2a65 100644 --- a/panda/src/collide/collide_composite1.cxx +++ b/panda/src/collide/collide_composite1.cxx @@ -3,6 +3,7 @@ #include "collisionHandler.cxx" #include "collisionHandlerEvent.cxx" #include "collisionHandlerFloor.cxx" +#include "collisionHandlerGravity.cxx" #include "collisionHandlerPhysical.cxx" #include "collisionHandlerPusher.cxx" #include "collisionHandlerQueue.cxx" diff --git a/panda/src/collide/collisionHandlerFloor.cxx b/panda/src/collide/collisionHandlerFloor.cxx index 839aaffc8a..e9e66291e7 100644 --- a/panda/src/collide/collisionHandlerFloor.cxx +++ b/panda/src/collide/collisionHandlerFloor.cxx @@ -124,7 +124,6 @@ handle_entries() { def.updated_transform(); apply_linear_force(def, LVector3f(0.0f, 0.0f, adjust)); - } else { if (collide_cat.is_spam()) { collide_cat.spam() diff --git a/panda/src/collide/collisionHandlerGravity.I b/panda/src/collide/collisionHandlerGravity.I new file mode 100755 index 0000000000..ef955595b4 --- /dev/null +++ b/panda/src/collide/collisionHandlerGravity.I @@ -0,0 +1,157 @@ +// Filename: CollisionHandlerGravity.I +// Created by: drose (16Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: CollisionHandlerGravity::set_offset +// Access: Public +// Description: Sets the linear offset to add to (or subtract from) +// the highest detected collision point to determine the +// actual height at which to set the collider. +//////////////////////////////////////////////////////////////////// +INLINE void CollisionHandlerGravity:: +set_offset(float offset) { + _offset = offset; +} + +//////////////////////////////////////////////////////////////////// +// Function: CollisionHandlerGravity::get_offset +// Access: Public +// Description: Returns the linear offset to add to (or subtract from) +// the highest detected collision point to determine the +// actual height at which to set the collider. +//////////////////////////////////////////////////////////////////// +INLINE float CollisionHandlerGravity:: +get_offset() const { + return _offset; +} + +//////////////////////////////////////////////////////////////////// +// Function: CollisionHandlerGravity::get_airborne_height +// Access: Public +// Description: Return the height of the object from the ground. +// +// The object might not necessarily be at rest. Use +// is_on_ground() if you want to know whether the +// object is on the ground and at rest. +//////////////////////////////////////////////////////////////////// +INLINE float CollisionHandlerGravity:: +get_airborne_height() const { + return _airborne_height; +} + +//////////////////////////////////////////////////////////////////// +// Function: CollisionHandlerGravity::is_on_ground +// Access: Public +// Description: Is the object at rest? +//////////////////////////////////////////////////////////////////// +INLINE bool CollisionHandlerGravity:: +is_on_ground() const { + // Testing for 0.0f here is not as foolhardy as it may appear. The + // handle_entries() function will set these values to 0.0f if they + // are within a threshold. + return get_airborne_height() == 0.0f && _current_velocity == 0.0f; +} + +//////////////////////////////////////////////////////////////////// +// Function: CollisionHandlerGravity::add_velocity +// Access: Public +// Description: Adds the sepcified amount to the current velocity. +// This is mostly here allow this common operation to +// be faster for scripting, but it's also more concise +// even in cpp. +//////////////////////////////////////////////////////////////////// +INLINE void CollisionHandlerGravity:: +add_velocity(float velocity) { + _current_velocity += velocity; +} + +//////////////////////////////////////////////////////////////////// +// Function: CollisionHandlerGravity::set_velocity +// Access: Public +// Description: Sets the current vertical velocity. +//////////////////////////////////////////////////////////////////// +INLINE void CollisionHandlerGravity:: +set_velocity(float velocity) { + _current_velocity = velocity; +} + +//////////////////////////////////////////////////////////////////// +// Function: CollisionHandlerGravity::get_velocity +// Access: Public +// Description: Gets the current vertical velocity. +// +// Generally, negative values mean the object is in +// free fall; while postive values mean the object has +// vertical thrust. +// +// A zero value does not necessarily mean the object +// on the ground, it may also be weightless and/or at +// the apex of its jump. +// +// See Also: is_on_ground() and get_gravity() +//////////////////////////////////////////////////////////////////// +INLINE float CollisionHandlerGravity:: +get_velocity() const { + return _current_velocity; +} + +//////////////////////////////////////////////////////////////////// +// Function: CollisionHandlerGravity::set_gravity +// Access: Public +// Description: Sets the linear gravity force (always plumb). +//////////////////////////////////////////////////////////////////// +INLINE void CollisionHandlerGravity:: +set_gravity(float gravity) { + _gravity = gravity; +} + +//////////////////////////////////////////////////////////////////// +// Function: CollisionHandlerGravity::get_gravity +// Access: Public +// Description: Gets the linear gravity force (always plumb). +//////////////////////////////////////////////////////////////////// +INLINE float CollisionHandlerGravity:: +get_gravity() const { + return _gravity; +} + +//////////////////////////////////////////////////////////////////// +// Function: CollisionHandlerGravity::set_max_velocity +// Access: Public +// Description: Sets the maximum speed at which the object will be +// allowed to descend towards a floor below it, in units +// per second. Set this to zero to allow it to +// instantly teleport any distance. +//////////////////////////////////////////////////////////////////// +INLINE void CollisionHandlerGravity:: +set_max_velocity(float max_velocity) { + _max_velocity = max_velocity; +} + +//////////////////////////////////////////////////////////////////// +// Function: CollisionHandlerGravity::get_max_velocity +// Access: Public +// Description: Retrieves the maximum speed at which the object will +// be allowed to descend towards a floor below it, in +// units per second. See set_max_velocity(). +//////////////////////////////////////////////////////////////////// +INLINE float CollisionHandlerGravity:: +get_max_velocity() const { + return _max_velocity; +} diff --git a/panda/src/collide/collisionHandlerGravity.cxx b/panda/src/collide/collisionHandlerGravity.cxx new file mode 100755 index 0000000000..41a70fc859 --- /dev/null +++ b/panda/src/collide/collisionHandlerGravity.cxx @@ -0,0 +1,175 @@ +// Filename: CollisionHandlerGravity.cxx +// Created by: drose (16Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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; + _gravity = 32.174f; + _current_velocity = 0.0f; + _max_velocity = 400.0f; +} + +//////////////////////////////////////////////////////////////////// +// Function: CollisionHandlerGravity::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +CollisionHandlerGravity:: +~CollisionHandlerGravity() { +} + +//////////////////////////////////////////////////////////////////// +// Function: CollisionHandlerGravity::handle_entries +// Access: Protected, Virtual +// Description: Called by the parent class after all collisions have +// been detected, this manages the various collisions +// and moves around the nodes as necessary. +// +// The return value is normally true, but it may be +// false to indicate the CollisionTraverser should +// disable this handler from being called in the future. +//////////////////////////////////////////////////////////////////// +bool CollisionHandlerGravity:: +handle_entries() { + bool okflag = true; + + FromEntries::const_iterator fi; + for (fi = _from_entries.begin(); fi != _from_entries.end(); ++fi) { + const NodePath &from_node_path = (*fi).first; + const Entries &entries = (*fi).second; + + Colliders::iterator ci; + ci = _colliders.find(from_node_path); + if (ci == _colliders.end()) { + // Hmm, someone added a CollisionNode to a traverser and gave + // it this CollisionHandler pointer--but they didn't tell us + // about the node. + collide_cat.error() + << get_type() << " doesn't know about " + << from_node_path << ", disabling.\n"; + okflag = false; + } else { + ColliderDef &def = (*ci).second; + { + // Get the maximum height for all collisions with this node. + bool got_max = false; + float max_height = 0.0f; + + Entries::const_iterator ei; + for (ei = entries.begin(); ei != entries.end(); ++ei) { + CollisionEntry *entry = (*ei); + nassertr(entry != (CollisionEntry *)NULL, false); + nassertr(from_node_path == entry->get_from_node_path(), false); + + if (entry->has_surface_point()) { + LPoint3f point = entry->get_surface_point(def._target); + if (collide_cat.is_debug()) { + collide_cat.debug() + << "Intersection point detected at " << point << "\n"; + } + + float height = point[2]; + if (!got_max || height > max_height) { + got_max = true; + max_height = height; + } + } + } + + // Now set our height accordingly. + float adjust = max_height + _offset; + if (_current_velocity > 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 < -0.001f) { + // ...we have a vertical thrust, + // ...or the node is above the floor, so it is airborne. + float dt = min(ClockObject::get_global_clock()->get_dt(), 0.1f); + // The sign in this equation is reversed from normal. This is + // because _current_velocity is a scaler and the equation normally + // has a vector. I suppose the sign of _gravity could have been + // reversed, but 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; + } + + if (_airborne_height < 0.001f && _current_velocity < 0.001f) { + // ...the node is under the floor, so it has landed. + // These values are used by is_on_ground(). + _current_velocity = _airborne_height = 0.0f; + } + + 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) { +} diff --git a/panda/src/collide/collisionHandlerGravity.h b/panda/src/collide/collisionHandlerGravity.h new file mode 100755 index 0000000000..bd5b339411 --- /dev/null +++ b/panda/src/collide/collisionHandlerGravity.h @@ -0,0 +1,91 @@ +// Filename: CollisionHandlerGravity.h +// Created by: drose (16Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, 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://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef CollisionHandlerGravity_H +#define CollisionHandlerGravity_H + +#include "pandabase.h" + +#include "collisionHandlerPhysical.h" + +/////////////////////////////////////////////////////////////////// +// Class : CollisionHandlerGravity +// Description : A specialized kind of CollisionHandler that sets the +// Z height of the collider to a fixed linear offset +// from the highest detected collision point each frame. +// It's intended to implement walking around on a floor +// of varying height by casting a ray down from the +// avatar's head. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA CollisionHandlerGravity : public CollisionHandlerPhysical { +PUBLISHED: + CollisionHandlerGravity(); + virtual ~CollisionHandlerGravity(); + + INLINE void set_offset(float offset); + INLINE float get_offset() const; + + INLINE float get_airborne_height() const; + INLINE bool is_on_ground() const; + + INLINE void add_velocity(float velocity); + INLINE void set_velocity(float velocity); + INLINE float get_velocity() const; + + INLINE void set_gravity(float gravity); + INLINE float get_gravity() const; + + INLINE void set_max_velocity(float max_vel); + INLINE float get_max_velocity() const; + +protected: + virtual bool handle_entries(); + virtual void apply_linear_force(ColliderDef &def, const LVector3f &force); + +private: + float _offset; + float _airborne_height; + float _gravity; + float _current_velocity; + float _max_velocity; + + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + CollisionHandlerPhysical::init_type(); + register_type(_type_handle, "CollisionHandlerGravity", + CollisionHandlerPhysical::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "CollisionHandlerGravity.I" + +#endif + + +