// Filename: physxController.cxx // Created by: enn0x (24Sep09) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE // Copyright (c) Carnegie Mellon University. All rights reserved. // // All use of this software is subject to the terms of the revised BSD // license. You should have received a copy of this license along // with this source code in a file named "LICENSE." // //////////////////////////////////////////////////////////////////// #include "event.h" #include "eventQueue.h" #include "eventParameter.h" #include "physxController.h" #include "physxManager.h" #include "physxActor.h" #include "physxBoxController.h" #include "physxCapsuleController.h" TypeHandle PhysxController::_type_handle; //////////////////////////////////////////////////////////////////// // Function: PhysxController::release // Access: Published // Description: //////////////////////////////////////////////////////////////////// void PhysxController:: release() { nassertv(_error_type == ET_ok); NxControllerManager *cm = get_actor()->get_scene()->cm(); unlink(); cm->releaseController(*ptr()); } //////////////////////////////////////////////////////////////////// // Function: PhysxController::factory // Access: Public // Description: //////////////////////////////////////////////////////////////////// PhysxController *PhysxController:: factory(NxControllerType controllerType) { switch (controllerType) { case NX_CONTROLLER_BOX: return new PhysxBoxController(); case NX_CONTROLLER_CAPSULE: return new PhysxCapsuleController(); } physx_cat.error() << "Unknown controller type.\n"; return NULL; } //////////////////////////////////////////////////////////////////// // Function: PhysxController::get_actor // Access: Published // Description: Retrieves the actor which this controller is // associated with. //////////////////////////////////////////////////////////////////// PhysxActor *PhysxController:: get_actor() const { nassertr(_error_type == ET_ok, NULL); return (PhysxActor *)(ptr()->getActor()->userData); } //////////////////////////////////////////////////////////////////// // Function: PhysxController::set_pos // Access: Published // Description: Sets the position of the controller is global // space. This can be used for initial placement or // for teleporting the character. //////////////////////////////////////////////////////////////////// void PhysxController:: set_pos(const LPoint3f &pos) { nassertv(_error_type == ET_ok); ptr()->setPosition(PhysxManager::point3_to_nxExtVec3(pos)); } //////////////////////////////////////////////////////////////////// // Function: PhysxController::get_pos // Access: Published // Description: Retruns the position of the controller is global // space. //////////////////////////////////////////////////////////////////// LPoint3f PhysxController:: get_pos() const { nassertr(_error_type == ET_ok, LPoint3f::zero()); return PhysxManager::nxExtVec3_to_point3(ptr()->getPosition()); } //////////////////////////////////////////////////////////////////// // Function: PhysxController::set_sharpness // Access: Published // Description: Sharpness is used to smooth motion with a feedback // filter, having a value between 0 (so smooth it // doesn't move) and 1 (no smoothing = unfiltered // motion). Sharpness can ease the motion curve when // the auto-step feature is used with boxes. // Default value is 1.0. //////////////////////////////////////////////////////////////////// void PhysxController:: set_sharpness(float sharpness) { nassertv(_error_type == ET_ok); nassertv(sharpness > 0.0f); nassertv(sharpness <= 1.0f); _sharpness = sharpness; } //////////////////////////////////////////////////////////////////// // Function: PhysxController::get_sharpness // Access: Published // Description: Returns the sharpness used to ease the motion curve // when the auto-step feature is used. // Default value is 1.0. //////////////////////////////////////////////////////////////////// float PhysxController:: get_sharpness() const { nassertr(_error_type == ET_ok, 0.0f); return _sharpness; } //////////////////////////////////////////////////////////////////// // Function: PhysxController::set_collision // Access: Published // Description: Enable/Disable collisions for this controller and // actor. //////////////////////////////////////////////////////////////////// void PhysxController:: set_collision(bool enable) { nassertv(_error_type == ET_ok); ptr()->setCollision(enable); } //////////////////////////////////////////////////////////////////// // Function: PhysxController::set_min_distance // Access: Published // Description: Sets the the minimum travelled distance to consider // when moving the controller. If travelled distance // is smaller, the character doesn't move. This is // used to stop the recursive motion algorithm when // remaining distance to travel is small. // The default value is 0.0001. //////////////////////////////////////////////////////////////////// void PhysxController:: set_min_distance(float min_dist) { nassertv(_error_type == ET_ok); nassertv(min_dist > 0.0f); _min_dist = min_dist; } //////////////////////////////////////////////////////////////////// // Function: PhysxController::set_step_offset // Access: Published // Description: Sets the step height/offset for the controller. //////////////////////////////////////////////////////////////////// void PhysxController:: set_step_offset(float offset) { nassertv(_error_type == ET_ok); nassertv(offset > 0.0f); ptr()->setStepOffset(offset); } //////////////////////////////////////////////////////////////////// // Function: PhysxController::set_global_speed // Access: Published // Description: Sets the linear speed of the controller in global // space. //////////////////////////////////////////////////////////////////// void PhysxController:: set_global_speed(const LVector3f &speed) { nassertv(_error_type == ET_ok); nassertv_always(!speed.is_nan()); _speed = NxVec3(speed.get_x(), speed.get_y(), speed.get_z()); } //////////////////////////////////////////////////////////////////// // Function: PhysxController::set_local_speed // Access: Published // Description: Sets the linear speed of the controller in local // coordinates. //////////////////////////////////////////////////////////////////// void PhysxController:: set_local_speed(const LVector3f &speed) { nassertv(_error_type == ET_ok); nassertv_always(!speed.is_nan()); NodePath np = get_actor()->get_node_path(); nassertv(!np.is_empty()); NxQuat q = ptr()->getActor()->getGlobalOrientationQuat(); NxVec3 s = NxVec3(speed.get_x(), speed.get_y(), speed.get_z()); _speed = (q * _up_quat_inv).rot(s); } //////////////////////////////////////////////////////////////////// // Function: PhysxController::set_omega // Access: Published // Description: Sets the angular velocity (degrees per second) // of the controller. The angular velocity is used to // compute the new heading when updating the // controller. //////////////////////////////////////////////////////////////////// void PhysxController:: set_omega(float omega) { nassertv(_error_type == ET_ok); _omega = omega; } //////////////////////////////////////////////////////////////////// // Function: PhysxController::set_h // Access: Published // Description: Sets the heading of the controller is global // space. Note: only heading is supported. Pitch and // roll are constrained by PhysX in order to alyways // keep the character upright. //////////////////////////////////////////////////////////////////// void PhysxController:: set_h(float heading) { nassertv(_error_type == ET_ok); _heading = heading; NxQuat q(_heading, _up_vector); ptr()->getActor()->moveGlobalOrientationQuat(_up_quat * q); } //////////////////////////////////////////////////////////////////// // Function: PhysxController::get_h // Access: Published // Description: Returns the heading of the controller in global // space. //////////////////////////////////////////////////////////////////// float PhysxController:: get_h() const { nassertr(_error_type == ET_ok, 0.0f); return _heading; } //////////////////////////////////////////////////////////////////// // Function: PhysxController::report_scene_changed // Access: Published // Description: The character controller uses caching in order to // speed up collision testing, this caching can not // detect when static objects have changed in the // scene. You need to call this method when such // changes have been made. //////////////////////////////////////////////////////////////////// void PhysxController:: report_scene_changed() { nassertv(_error_type == ET_ok); ptr()->reportSceneChanged(); } //////////////////////////////////////////////////////////////////// // Function: PhysxController::update_controller // Access: Public // Description: //////////////////////////////////////////////////////////////////// void PhysxController:: update_controller(float dt) { nassertv(_error_type == ET_ok); // Speed NxU32 mask = 0xFFFFFFFF; NxU32 collision_flags; NxVec3 gravity; ptr()->getActor()->getScene().getGravity(gravity); NxVec3 d = (_speed + gravity) * dt; NxReal heightDelta = get_jump_height(dt, gravity); if (heightDelta != 0.0f) { ((_up_axis == NX_Z) ? d.z : d.y) += heightDelta; } ptr()->move(d, mask, _min_dist, collision_flags, _sharpness); if (collision_flags & NXCC_COLLISION_DOWN) { stop_jump(); } // Omega if (_omega != 0.0f) { NxReal delta = _omega * dt; _heading += delta; NxQuat q(_heading, _up_vector); ptr()->getActor()->moveGlobalOrientationQuat(_up_quat * q); } // Reset speed and omega _speed.zero(); _omega = 0.0f; } //////////////////////////////////////////////////////////////////// // Function: PhysxController::get_jump_height // Access: Private // Description: //////////////////////////////////////////////////////////////////// NxReal PhysxController:: get_jump_height(float dt, NxVec3 &gravity) { if (_jumping == false) { return 0.0f; } _jump_time += dt; float G = (_up_axis == NX_Z) ? gravity.z : gravity.y; float h = 2.0f * G * _jump_time * _jump_time + _jump_v0 * _jump_time; return (h - G) * dt; } //////////////////////////////////////////////////////////////////// // Function: PhysxController::start_jump // Access: Published // Description: Enters the jump mode. The parameter is the intial // upward velocity of the character. //////////////////////////////////////////////////////////////////// void PhysxController:: start_jump(float v0) { nassertv(_error_type == ET_ok); if (_jumping == true) { return; } _jumping = true; _jump_time = 0.0f; _jump_v0 = v0; } //////////////////////////////////////////////////////////////////// // Function: PhysxController::stop_jump // Access: Published // Description: Leaves the jump mode. This method is automatically // called if a ground collision is detected. Usually // users need not call this method. //////////////////////////////////////////////////////////////////// void PhysxController:: stop_jump() { nassertv(_error_type == ET_ok); if (_jumping == false) { return; } _jumping = false; //NxVec3 v = ptr()->getActor()->getLinearVelocity(); //double velocity = (_up_axis == NX_Z) ? v.z : v.y; Event *event = new Event("physx-controller-down"); event->add_parameter(EventParameter(this)); //event->add_parameter(EventParameter(velocity)); EventQueue::get_global_event_queue()->queue_event(event); }