393 lines
12 KiB
C++
393 lines
12 KiB
C++
// 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();
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|