Add option to change Character Controller capsule origin to start at feet location
This commit is contained in:
@@ -21,6 +21,7 @@ CharacterController::CharacterController(const SpawnParams& params)
|
|||||||
, _upDirection(Vector3::Up)
|
, _upDirection(Vector3::Up)
|
||||||
, _gravityDisplacement(Vector3::Zero)
|
, _gravityDisplacement(Vector3::Zero)
|
||||||
, _nonWalkableMode(NonWalkableModes::PreventClimbing)
|
, _nonWalkableMode(NonWalkableModes::PreventClimbing)
|
||||||
|
, _originMode(OriginModes::CapsuleCenter)
|
||||||
, _lastFlags(CollisionFlags::None)
|
, _lastFlags(CollisionFlags::None)
|
||||||
{
|
{
|
||||||
_contactOffset = 10.0f;
|
_contactOffset = 10.0f;
|
||||||
@@ -35,9 +36,7 @@ void CharacterController::SetRadius(const float value)
|
|||||||
{
|
{
|
||||||
if (value == _radius)
|
if (value == _radius)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_radius = value;
|
_radius = value;
|
||||||
|
|
||||||
UpdateSize();
|
UpdateSize();
|
||||||
UpdateBounds();
|
UpdateBounds();
|
||||||
}
|
}
|
||||||
@@ -51,9 +50,7 @@ void CharacterController::SetHeight(const float value)
|
|||||||
{
|
{
|
||||||
if (value == _height)
|
if (value == _height)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_height = value;
|
_height = value;
|
||||||
|
|
||||||
UpdateSize();
|
UpdateSize();
|
||||||
UpdateBounds();
|
UpdateBounds();
|
||||||
}
|
}
|
||||||
@@ -87,6 +84,23 @@ void CharacterController::SetNonWalkableMode(NonWalkableModes value)
|
|||||||
PhysicsBackend::SetControllerNonWalkableMode(_controller, (int32)value);
|
PhysicsBackend::SetControllerNonWalkableMode(_controller, (int32)value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CharacterController::OriginModes CharacterController::GetOriginMode() const
|
||||||
|
{
|
||||||
|
return _originMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharacterController::SetOriginMode(OriginModes value)
|
||||||
|
{
|
||||||
|
if (_originMode == value)
|
||||||
|
return;
|
||||||
|
_originMode = value;
|
||||||
|
if (_controller)
|
||||||
|
{
|
||||||
|
DeleteController();
|
||||||
|
CreateController();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float CharacterController::GetStepOffset() const
|
float CharacterController::GetStepOffset() const
|
||||||
{
|
{
|
||||||
return _stepOffset;
|
return _stepOffset;
|
||||||
@@ -165,13 +179,23 @@ CharacterController::CollisionFlags CharacterController::SimpleMove(const Vector
|
|||||||
CharacterController::CollisionFlags CharacterController::Move(const Vector3& displacement)
|
CharacterController::CollisionFlags CharacterController::Move(const Vector3& displacement)
|
||||||
{
|
{
|
||||||
CollisionFlags result = CollisionFlags::None;
|
CollisionFlags result = CollisionFlags::None;
|
||||||
if (_controller)
|
if (_controller && !_isUpdatingTransform)
|
||||||
{
|
{
|
||||||
|
// Perform move
|
||||||
const float deltaTime = Time::GetCurrentSafe()->DeltaTime.GetTotalSeconds();
|
const float deltaTime = Time::GetCurrentSafe()->DeltaTime.GetTotalSeconds();
|
||||||
result = (CollisionFlags)PhysicsBackend::MoveController(_controller, _shape, displacement, _minMoveDistance, deltaTime);
|
result = (CollisionFlags)PhysicsBackend::MoveController(_controller, _shape, displacement, _minMoveDistance, deltaTime);
|
||||||
_lastFlags = result;
|
_lastFlags = result;
|
||||||
Vector3 position = PhysicsBackend::GetControllerPosition(_controller) - _center;
|
|
||||||
|
// Update position
|
||||||
|
Vector3 position;
|
||||||
|
if (_originMode == OriginModes::Base)
|
||||||
|
position = PhysicsBackend::GetControllerBasePosition(_controller);
|
||||||
|
else
|
||||||
|
position = PhysicsBackend::GetControllerPosition(_controller);
|
||||||
|
position -= _center;
|
||||||
|
_isUpdatingTransform = true;
|
||||||
SetPosition(position);
|
SetPosition(position);
|
||||||
|
_isUpdatingTransform = false;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -194,10 +218,21 @@ void CharacterController::Resize(float height, float radius)
|
|||||||
Vector3 positionDelta = _upDirection * centerDiff;
|
Vector3 positionDelta = _upDirection * centerDiff;
|
||||||
|
|
||||||
// Change physics position to maintain feet placement (base)
|
// Change physics position to maintain feet placement (base)
|
||||||
Vector3 position = PhysicsBackend::GetControllerPosition(_controller);
|
Vector3 position;
|
||||||
position += positionDelta;
|
switch (_originMode)
|
||||||
_center += positionDelta;
|
{
|
||||||
PhysicsBackend::SetControllerPosition(_controller, position);
|
case OriginModes::CapsuleCenter:
|
||||||
|
position = PhysicsBackend::GetControllerPosition(_controller);
|
||||||
|
position += positionDelta;
|
||||||
|
_center += positionDelta;
|
||||||
|
PhysicsBackend::SetControllerPosition(_controller, position);
|
||||||
|
break;
|
||||||
|
case OriginModes::Base:
|
||||||
|
position = PhysicsBackend::GetControllerBasePosition(_controller);
|
||||||
|
position += positionDelta;
|
||||||
|
PhysicsBackend::SetControllerBasePosition(_controller, position);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Change actor position
|
// Change actor position
|
||||||
_isUpdatingTransform = true;
|
_isUpdatingTransform = true;
|
||||||
@@ -215,7 +250,7 @@ void CharacterController::Resize(float height, float radius)
|
|||||||
void CharacterController::DrawPhysicsDebug(RenderView& view)
|
void CharacterController::DrawPhysicsDebug(RenderView& view)
|
||||||
{
|
{
|
||||||
Quaternion rotation = Quaternion::Euler(90, 0, 0);
|
Quaternion rotation = Quaternion::Euler(90, 0, 0);
|
||||||
const Vector3 position = _transform.LocalToWorld(_center);
|
const Vector3 position = GetControllerPosition();
|
||||||
if (view.Mode == ViewMode::PhysicsColliders)
|
if (view.Mode == ViewMode::PhysicsColliders)
|
||||||
DEBUG_DRAW_CAPSULE(position, rotation, _radius, _height, Color::LightYellow, 0, true);
|
DEBUG_DRAW_CAPSULE(position, rotation, _radius, _height, Color::LightYellow, 0, true);
|
||||||
else
|
else
|
||||||
@@ -225,23 +260,25 @@ void CharacterController::DrawPhysicsDebug(RenderView& view)
|
|||||||
void CharacterController::OnDebugDrawSelected()
|
void CharacterController::OnDebugDrawSelected()
|
||||||
{
|
{
|
||||||
Quaternion rotation = Quaternion::Euler(90, 0, 0);
|
Quaternion rotation = Quaternion::Euler(90, 0, 0);
|
||||||
const Vector3 position = _transform.LocalToWorld(_center);
|
const Vector3 position = GetControllerPosition();
|
||||||
DEBUG_DRAW_WIRE_CAPSULE(position, rotation, _radius, _height, Color::GreenYellow, 0, false);
|
DEBUG_DRAW_WIRE_CAPSULE(position, rotation, _radius, _height, Color::GreenYellow, 0, false);
|
||||||
if (_contactOffset > 0)
|
if (_contactOffset > 0)
|
||||||
DEBUG_DRAW_WIRE_CAPSULE(position, rotation, _radius - _contactOffset, _height, Color::Blue.AlphaMultiplied(0.4f), 0, false);
|
DEBUG_DRAW_WIRE_CAPSULE(position, rotation, _radius - _contactOffset, _height, Color::Blue.AlphaMultiplied(0.4f), 0, false);
|
||||||
#if 0
|
#if 1
|
||||||
// More technical visuals debugging
|
// More technical visuals debugging
|
||||||
if (_controller)
|
if (_controller)
|
||||||
{
|
{
|
||||||
float height, radius;
|
float height, radius;
|
||||||
GetControllerSize(height, radius);
|
GetControllerSize(height, radius);
|
||||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(PhysicsBackend::GetControllerBasePosition(_controller), 5.0f), Color::Red, 0, false);
|
Vector3 base = PhysicsBackend::GetControllerBasePosition(_controller);
|
||||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(PhysicsBackend::GetControllerPosition(_controller), 4.0f), Color::Red, 0, false);
|
Vector3 pos = PhysicsBackend::GetControllerPosition(_controller);
|
||||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(PhysicsBackend::GetControllerPosition(_controller) + Vector3(0, height * 0.5f, 0), 2.0f), Color::Red, 0, false);
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(base, 5.0f), Color::Red, 0, false);
|
||||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(PhysicsBackend::GetControllerPosition(_controller) - Vector3(0, height * 0.5f, 0), 2.0f), Color::Red, 0, false);
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos, 4.0f), Color::Red, 0, false);
|
||||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(PhysicsBackend::GetControllerPosition(_controller) + Vector3(0, height * 0.5f, 0), radius), Color::Red.AlphaMultiplied(0.5f), 0, false);
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos + Vector3(0, height * 0.5f, 0), 2.0f), Color::Red, 0, false);
|
||||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(PhysicsBackend::GetControllerPosition(_controller) - Vector3(0, height * 0.5f, 0), radius), Color::Red.AlphaMultiplied(0.5f), 0, false);
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos - Vector3(0, height * 0.5f, 0), 2.0f), Color::Red, 0, false);
|
||||||
DEBUG_DRAW_WIRE_CYLINDER(PhysicsBackend::GetControllerPosition(_controller), Quaternion::Identity, radius, height, Color::Red.AlphaMultiplied(0.2f), 0, false);
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos + Vector3(0, height * 0.5f, 0), radius), Color::Red.AlphaMultiplied(0.5f), 0, false);
|
||||||
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(pos - Vector3(0, height * 0.5f, 0), radius), Color::Red.AlphaMultiplied(0.5f), 0, false);
|
||||||
|
DEBUG_DRAW_WIRE_CYLINDER(pos, Quaternion::Identity, radius, height, Color::Red.AlphaMultiplied(0.2f), 0, false);
|
||||||
}
|
}
|
||||||
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(position, 3.0f), Color::GreenYellow, 0, false);
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(position, 3.0f), Color::GreenYellow, 0, false);
|
||||||
#else
|
#else
|
||||||
@@ -267,7 +304,10 @@ void CharacterController::CreateController()
|
|||||||
_cachedScale = GetScale().GetAbsolute().MaxValue();
|
_cachedScale = GetScale().GetAbsolute().MaxValue();
|
||||||
float height, radius;
|
float height, radius;
|
||||||
GetControllerSize(height, radius);
|
GetControllerSize(height, radius);
|
||||||
const Vector3 position = _transform.LocalToWorld(_center);
|
Vector3 position = _center;
|
||||||
|
if (_originMode == OriginModes::Base)
|
||||||
|
position += _upDirection * (_height * 0.5f + _radius);
|
||||||
|
position = _transform.LocalToWorld(position);
|
||||||
_controller = PhysicsBackend::CreateController(GetPhysicsScene()->GetPhysicsScene(), this, this, _contactOffset, position, _slopeLimit, (int32)_nonWalkableMode, Material, radius, height, _stepOffset, _shape);
|
_controller = PhysicsBackend::CreateController(GetPhysicsScene()->GetPhysicsScene(), this, this, _contactOffset, position, _slopeLimit, (int32)_nonWalkableMode, Material, radius, height, _stepOffset, _shape);
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
@@ -297,14 +337,25 @@ void CharacterController::UpdateSize() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector3 CharacterController::GetControllerPosition() const
|
||||||
|
{
|
||||||
|
Vector3 position = _center;
|
||||||
|
if (_originMode == OriginModes::Base)
|
||||||
|
position += _upDirection * (_height * 0.5f + _radius);
|
||||||
|
position = _transform.LocalToWorld(position);
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
void CharacterController::GetControllerSize(float& height, float& radius) const
|
void CharacterController::GetControllerSize(float& height, float& radius) const
|
||||||
{
|
{
|
||||||
|
// Use absolute values including scale
|
||||||
height = Math::Abs(_height) * _cachedScale;
|
height = Math::Abs(_height) * _cachedScale;
|
||||||
radius = Math::Abs(_radius) * _cachedScale;
|
radius = Math::Abs(_radius) * _cachedScale;
|
||||||
{
|
|
||||||
// Exclude contact offset around the capsule (otherwise character floats in the air)
|
// Exclude contact offset around the capsule (otherwise character floats in the air)
|
||||||
radius = radius - Math::Max(_contactOffset, 0.0f);
|
radius = radius - Math::Max(_contactOffset, 0.0f);
|
||||||
}
|
|
||||||
|
// Prevent too small controllers
|
||||||
height = Math::Max(height, CC_MIN_SIZE);
|
height = Math::Max(height, CC_MIN_SIZE);
|
||||||
radius = Math::Max(radius, CC_MIN_SIZE);
|
radius = Math::Max(radius, CC_MIN_SIZE);
|
||||||
}
|
}
|
||||||
@@ -319,7 +370,7 @@ void CharacterController::UpdateBounds()
|
|||||||
_cachedScale = GetScale().GetAbsolute().MaxValue();
|
_cachedScale = GetScale().GetAbsolute().MaxValue();
|
||||||
float height, radius;
|
float height, radius;
|
||||||
GetControllerSize(height, radius);
|
GetControllerSize(height, radius);
|
||||||
const Vector3 position = _transform.LocalToWorld(_center);
|
const Vector3 position = GetControllerPosition();
|
||||||
const Vector3 extent(radius, height * 0.5f + radius, radius);
|
const Vector3 extent(radius, height * 0.5f + radius, radius);
|
||||||
_box = BoundingBox(position - extent, position + extent);
|
_box = BoundingBox(position - extent, position + extent);
|
||||||
BoundingSphere::FromBox(_box, _sphere);
|
BoundingSphere::FromBox(_box, _sphere);
|
||||||
@@ -376,7 +427,12 @@ void CharacterController::OnActiveTransformChanged()
|
|||||||
// Change actor transform (but with locking)
|
// Change actor transform (but with locking)
|
||||||
ASSERT(!_isUpdatingTransform);
|
ASSERT(!_isUpdatingTransform);
|
||||||
_isUpdatingTransform = true;
|
_isUpdatingTransform = true;
|
||||||
const Vector3 position = PhysicsBackend::GetControllerPosition(_controller) - _center;
|
Vector3 position;
|
||||||
|
if (_originMode == OriginModes::Base)
|
||||||
|
position = PhysicsBackend::GetControllerBasePosition(_controller);
|
||||||
|
else
|
||||||
|
position = PhysicsBackend::GetControllerPosition(_controller);
|
||||||
|
position -= _center;
|
||||||
SetPosition(position);
|
SetPosition(position);
|
||||||
_isUpdatingTransform = false;
|
_isUpdatingTransform = false;
|
||||||
|
|
||||||
@@ -458,7 +514,10 @@ void CharacterController::OnTransformChanged()
|
|||||||
const Vector3 position = _transform.LocalToWorld(_center);
|
const Vector3 position = _transform.LocalToWorld(_center);
|
||||||
if (!_isUpdatingTransform && _controller)
|
if (!_isUpdatingTransform && _controller)
|
||||||
{
|
{
|
||||||
PhysicsBackend::SetControllerPosition(_controller, position);
|
if (_originMode == OriginModes::Base)
|
||||||
|
PhysicsBackend::SetControllerBasePosition(_controller, position);
|
||||||
|
else
|
||||||
|
PhysicsBackend::SetControllerPosition(_controller, position);
|
||||||
const float scale = GetScale().GetAbsolute().MaxValue();
|
const float scale = GetScale().GetAbsolute().MaxValue();
|
||||||
if (_cachedScale != scale)
|
if (_cachedScale != scale)
|
||||||
UpdateGeometry();
|
UpdateGeometry();
|
||||||
|
|||||||
@@ -41,6 +41,22 @@ public:
|
|||||||
Below = 1 << 2,
|
Below = 1 << 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies how a character controller capsule placement.
|
||||||
|
/// </summary>
|
||||||
|
API_ENUM() enum class OriginModes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Character origin starts at capsule center (including Center offset properly).
|
||||||
|
/// </summary>
|
||||||
|
CapsuleCenter,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Character origin starts at capsule base position aka character feet placement.
|
||||||
|
/// </summary>
|
||||||
|
Base,
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Specifies how a character controller interacts with non-walkable parts.
|
/// Specifies how a character controller interacts with non-walkable parts.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -69,6 +85,7 @@ private:
|
|||||||
Vector3 _upDirection;
|
Vector3 _upDirection;
|
||||||
Vector3 _gravityDisplacement;
|
Vector3 _gravityDisplacement;
|
||||||
NonWalkableModes _nonWalkableMode;
|
NonWalkableModes _nonWalkableMode;
|
||||||
|
OriginModes _originMode;
|
||||||
CollisionFlags _lastFlags;
|
CollisionFlags _lastFlags;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -116,6 +133,17 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
API_PROPERTY() void SetNonWalkableMode(NonWalkableModes value);
|
API_PROPERTY() void SetNonWalkableMode(NonWalkableModes value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the position origin placement mode.
|
||||||
|
/// </summary>
|
||||||
|
API_PROPERTY(Attributes="EditorOrder(216), DefaultValue(OriginModes.CapsuleCenter), EditorDisplay(\"Character Controller\")")
|
||||||
|
OriginModes GetOriginMode() const;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the position origin placement mode.
|
||||||
|
/// </summary>
|
||||||
|
API_PROPERTY() void SetOriginMode(OriginModes value);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the step height. The character will step up a stair only if it is closer to the ground than the indicated value. This should not be greater than the Character Controller’s height or it will generate an error.
|
/// Gets the step height. The character will step up a stair only if it is closer to the ground than the indicated value. This should not be greater than the Character Controller’s height or it will generate an error.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -218,6 +246,7 @@ protected:
|
|||||||
void UpdateSize() const;
|
void UpdateSize() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Vector3 GetControllerPosition() const;
|
||||||
void GetControllerSize(float& height, float& radius) const;
|
void GetControllerSize(float& height, float& radius) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -3155,10 +3155,9 @@ void* PhysicsBackend::CreateController(void* scene, IPhysicsActor* actor, Physic
|
|||||||
desc.material = (PxMaterial*)((PhysicalMaterial*)material->Instance)->GetPhysicsMaterial();
|
desc.material = (PxMaterial*)((PhysicalMaterial*)material->Instance)->GetPhysicsMaterial();
|
||||||
else
|
else
|
||||||
desc.material = DefaultMaterial;
|
desc.material = DefaultMaterial;
|
||||||
const float minSize = 0.001f;
|
desc.height = height;
|
||||||
desc.height = Math::Max(height, minSize);
|
desc.radius = radius;
|
||||||
desc.radius = Math::Max(radius, minSize);
|
desc.stepOffset = Math::Min(stepOffset, desc.height + desc.radius * 2.0f - 0.001f);
|
||||||
desc.stepOffset = Math::Min(stepOffset, desc.height + desc.radius * 2.0f - minSize);
|
|
||||||
auto controllerPhysX = (PxCapsuleController*)scenePhysX->ControllerManager->createController(desc);
|
auto controllerPhysX = (PxCapsuleController*)scenePhysX->ControllerManager->createController(desc);
|
||||||
PxRigidActor* actorPhysX = controllerPhysX->getActor();
|
PxRigidActor* actorPhysX = controllerPhysX->getActor();
|
||||||
ASSERT(actorPhysX && actorPhysX->getNbShapes() == 1);
|
ASSERT(actorPhysX && actorPhysX->getNbShapes() == 1);
|
||||||
@@ -3207,7 +3206,15 @@ void PhysicsBackend::SetControllerStepOffset(void* controller, float value)
|
|||||||
Vector3 PhysicsBackend::GetControllerBasePosition(void* controller)
|
Vector3 PhysicsBackend::GetControllerBasePosition(void* controller)
|
||||||
{
|
{
|
||||||
auto controllerPhysX = (PxCapsuleController*)controller;
|
auto controllerPhysX = (PxCapsuleController*)controller;
|
||||||
return P2C(controllerPhysX->getFootPosition());
|
const Vector3 origin = SceneOrigins[controllerPhysX->getScene()];
|
||||||
|
return P2C(controllerPhysX->getFootPosition()) + origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsBackend::SetControllerBasePosition(void* controller, const Vector3& value)
|
||||||
|
{
|
||||||
|
auto controllerPhysX = (PxCapsuleController*)controller;
|
||||||
|
const Vector3 sceneOrigin = SceneOrigins[controllerPhysX->getScene()];
|
||||||
|
controllerPhysX->setFootPosition(PxExtendedVec3(value.X - sceneOrigin.X, value.Y - sceneOrigin.Y, value.Z - sceneOrigin.Z));
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 PhysicsBackend::GetControllerUpDirection(void* controller)
|
Vector3 PhysicsBackend::GetControllerUpDirection(void* controller)
|
||||||
|
|||||||
@@ -249,6 +249,7 @@ public:
|
|||||||
static void SetControllerNonWalkableMode(void* controller, int32 value);
|
static void SetControllerNonWalkableMode(void* controller, int32 value);
|
||||||
static void SetControllerStepOffset(void* controller, float value);
|
static void SetControllerStepOffset(void* controller, float value);
|
||||||
static Vector3 GetControllerBasePosition(void* controller);
|
static Vector3 GetControllerBasePosition(void* controller);
|
||||||
|
static void SetControllerBasePosition(void* controller, const Vector3& value);
|
||||||
static Vector3 GetControllerUpDirection(void* controller);
|
static Vector3 GetControllerUpDirection(void* controller);
|
||||||
static void SetControllerUpDirection(void* controller, const Vector3& value);
|
static void SetControllerUpDirection(void* controller, const Vector3& value);
|
||||||
static Vector3 GetControllerPosition(void* controller);
|
static Vector3 GetControllerPosition(void* controller);
|
||||||
|
|||||||
Reference in New Issue
Block a user