|
- //
- // Lol Engine
- //
- // Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net>
- // (c) 2009-2012 Benjamin Huet <huet.benjamin@gmail.com>
- // This program is free software; you can redistribute it and/or
- // modify it under the terms of the Do What The Fuck You Want To
- // Public License, Version 2, as published by Sam Hocevar. See
- // http://sam.zoy.org/projects/COPYING.WTFPL for more details.
- //
-
- //
- // The BulletCharacterController class
- // ------------------
- // This class is a equivalent of btKinematicCharacterController, but more useful for Lol.
- //
-
- #if !defined __BULLETCHARACTERCONTROLLER_BULLETCHARACTERCONTROLLER_H__
- #define __BULLETCHARACTERCONTROLLER_BULLETCHARACTERCONTROLLER_H__
-
- #ifdef HAVE_PHYS_USE_BULLET
- #include "core.h"
- #include "EasyPhysics.h"
- //#include "BulletDynamics\Character\btCharacterControllerInterface.h"
- #endif
-
- #define USE_LOL_CTRLR_CHARAC
-
- namespace lol
- {
-
- namespace phys
- {
-
- #ifdef USE_LOL_CTRLR_CHARAC
- #ifdef HAVE_PHYS_USE_BULLET
-
- //SweepCallback used for Swweep Tests.
- class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback
- {
- public:
- ClosestNotMeConvexResultCallback(btCollisionObject* NewMe, const vec3& NewUp, float MinSlopeDot) :
- btCollisionWorld::ClosestConvexResultCallback(LOL2BTU_VEC3(vec3(.0f)), LOL2BTU_VEC3(vec3(.0f))),
- m_me(NewMe),
- m_up(NewUp),
- m_min_slope_dot(MinSlopeDot) { }
-
- virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& ConvexResult, bool NormalInWorld)
- {
- //We hit ourselves, FAIL
- if (ConvexResult.m_hitCollisionObject == m_me)
- return btScalar(1.f);
-
- vec3 WorldHitNomal(.0f);
- if (NormalInWorld)
- WorldHitNomal = BT2LOL_VEC3(ConvexResult.m_hitNormalLocal);
- else //need to transform Normal into worldspace
- {
- btVector3 TmpWorldHitNormal = ConvexResult.m_hitCollisionObject->getWorldTransform().getBasis() * ConvexResult.m_hitNormalLocal;
- WorldHitNomal = BT2LOL_VEC3(TmpWorldHitNormal);
- }
-
- float DotUp = dot(m_up, WorldHitNomal);
- //We hit below the accepted slope_dot, FAIL
- if (DotUp < m_min_slope_dot)
- return btScalar(1.f);
-
- //Continue to next.
- return ClosestConvexResultCallback::addSingleResult(ConvexResult, NormalInWorld);
- }
- protected:
- btCollisionObject* m_me;
- const vec3 m_up;
- float m_min_slope_dot;
- };
-
- ///BulletKinematicCharacterController is an object that supports a sliding motion in a world.
- ///It uses a ghost object and convex sweep test to test for upcoming collisions. This is combined with discrete collision detection to recover from penetrations.
- ///Interaction between btKinematicCharacterController and dynamic rigid bodies needs to be explicity implemented by the user.
- class BulletKinematicCharacterController : public btActionInterface
- {
- public:
- BulletKinematicCharacterController(btPairCachingGhostObject* NewGhostObject, btConvexShape* NewConvexShape, float NewStepHeight, int NewUpAxis=1)
- {
- m_convex_shape = NewConvexShape;
- m_i_up_axis = NewUpAxis;
- m_ghost_object = NewGhostObject;
- m_step_height = NewStepHeight;
-
- m_added_margin = 0.02f;
- m_walk_direction = vec3(.0f, .0f, .0f);
- m_do_gobject_sweep_test = true;
- m_turn_angle = .0f;
- m_use_walk_direction = false; // Should remove walk direction, this doesn't work correctly.
- m_velocity_time_interval = .0f;
- m_vertical_velocity = .0f;
- m_vertical_offset = .0f;
- m_f_gravity = 9.8f * 3.f; // 3G acceleration.
- m_fall_speed = 55.f; // Terminal velocity of a sky diver in m/s.
- m_jump_speed = 10.f; // ?
- m_was_on_ground = false;
- m_was_jumping = false;
- SetMaxSlope(45.f);
- }
- ~BulletKinematicCharacterController() { }
-
- protected:
-
- static vec3* GetUpAxisDirections()
- {
- static vec3 sUpAxisDirection[3] = { vec3(1.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f), vec3(0.0f, 0.0f, 1.0f) };
-
- return sUpAxisDirection;
- }
-
- //--------------------------
- //CONVENIENCE FUNCTIONS
- //--
-
- //Returns the reflection Direction of a ray going 'Direction' hitting a surface with Normal 'Normal' from: http://www-cs-students.stanford.edu/~adityagp/final/node3.html
- vec3 GetReflectedDir(const vec3& Direction, const vec3& Normal)
- {
- return Direction - (2.f * dot(Direction, Normal) * Normal);
- }
- //Returns the portion of 'direction' that is parallel to 'normal'
- vec3 ProjectDirOnNorm(const vec3& Direction, const vec3& Normal)
- {
- return Normal * dot(Direction, Normal);
- }
- //Returns the portion of 'Direction' that is perpindicular to 'Normal'
- vec3 ProjectDirOnNormPerpindicular(const vec3& Direction, const vec3& Normal)
- {
- return Direction - ProjectDirOnNorm(Direction, Normal);
- }
- //Returns Ghost Object. -duh-
- btPairCachingGhostObject* GetGhostObject()
- {
- return m_ghost_object;
- }
-
- //"Real" war functions
- bool RecoverFromPenetration(btCollisionWorld* CollisionWorld);
- void UpdateTargetOnHit(const vec3& hit_normal, float TangentMag = .0f, float NormalMag = 1.f);
- void DoMove(btCollisionWorld* CollisionWorld, const vec3& MoveStep, float DeltaTime);
-
- public:
- ///btActionInterface interface : KEEP IN camelCase
- virtual void updateAction(btCollisionWorld* CollisionWorld, float deltaTime)
- {
- PreStep(CollisionWorld);
- PlayerStep(CollisionWorld, deltaTime);
- }
-
- //not in the interface, but called above
- void PreStep(btCollisionWorld* CollisionWorld);
- void PlayerStep(btCollisionWorld* CollisionWorld, float DeltaTime);
-
- ///btActionInterface interface : KEEP IN camelCase
- void debugDraw(btIDebugDraw* debugDrawer) { }
-
- void SetUpAxis(int NewAxis)
- {
- if (NewAxis < 0)
- NewAxis = 0;
- if (NewAxis > 2)
- NewAxis = 2;
- m_i_up_axis = NewAxis;
- }
-
- //!!!!!! SHOULD DITCH THAT !!!!!!
- //This should probably be called setPositionIncrementPerSimulatorStep.
- //This is neither a Direction nor a velocity, but the amount to
- //increment the position each simulation iteration, regardless
- //of DeltaTime.
- //This call will Reset any velocity set by SetVelocityForTimeInterval().
- virtual void SetWalkDirection(const vec3& walkDirection)
- {
- m_use_walk_direction = true;
- m_walk_direction = walkDirection;
- m_normalized_direction = normalize(m_walk_direction);
- }
-
- //Caller provides a velocity with which the character should MoveStep for
- //the given time period. After the time period, velocity is Reset
- //to zero.
- //This call will Reset any walk Direction set by SetWalkDirection().
- //Negative time intervals will result in no motion.
- virtual void SetVelocityForTimeInterval(const vec3& velocity, float timeInterval)
- {
- m_use_walk_direction = false;
- m_walk_direction = velocity;
- m_normalized_direction = normalize(m_walk_direction);
- m_velocity_time_interval = timeInterval;
- }
-
- //Usefulness ?
- void Reset() { }
- void Warp(const vec3& NewOrigin)
- {
- btTransform NewTransform;
- NewTransform.setIdentity();
- NewTransform.setOrigin(LOL2BTU_VEC3(NewOrigin));
- m_ghost_object->setWorldTransform(NewTransform);
- }
-
- //External Setup
- //--
-
- void SetFallSpeed(float NewFallSpeed) { m_fall_speed = NewFallSpeed; }
- void SetJumpSpeed(float NewJumpSpeed) { m_jump_speed = NewJumpSpeed; }
- void SetMaxJumpHeight(float NewMaxJumpHeight) { m_max_jump_height = NewMaxJumpHeight; }
-
- //Jump logic will go in EasyCC
- bool CanJump() const { return OnGround(); }
- void Jump();
-
- //NewGravity functions
- void SetGravity(float NewGravity) { m_f_gravity = NewGravity; }
- float GetGravity() const { return m_f_gravity; }
-
- //The max slope determines the maximum angle that the controller can walk up.
- //The slope angle is measured in radians.
- void SetMaxSlope(float NewSlopeRadians) { m_max_slope_radians = NewSlopeRadians; m_max_slope_cosine = lol::cos(NewSlopeRadians); }
- float GetMaxSlope() const { return m_max_slope_radians; }
-
- void SetUseGhostSweepTest(bool UseGObjectSweepTest) { m_do_gobject_sweep_test = UseGObjectSweepTest; }
-
- bool OnGround() const { return m_vertical_velocity == .0f && m_vertical_offset == .0f; }
-
- private:
-
- btPairCachingGhostObject* m_ghost_object;
- btConvexShape* m_convex_shape; //is also in m_ghost_object, but it needs to be convex, so we store it here to avoid upcast
-
- //keep track of the contact manifolds
- btManifoldArray m_manifold_array;
-
- float m_half_height;
- float m_velocity_time_interval;
- float m_vertical_velocity;
- float m_vertical_offset;
- float m_fall_speed;
- float m_jump_speed;
- float m_max_jump_height;
- float m_max_slope_radians; // Slope angle that is set (used for returning the exact value)
- float m_max_slope_cosine; // Cosine equivalent of m_max_slope_radians (calculated once when set, for optimization)
- float m_f_gravity;
- float m_turn_angle;
- float m_step_height;
- float m_added_margin;//@todo: remove this and fix the code
-
- ///this is the desired walk Direction, set by the user
- vec3 m_walk_direction;
- vec3 m_normalized_direction;
-
- //some internal variables
- vec3 m_current_position;
- float m_current_step_offset;
- vec3 m_target_position;
-
- vec3 m_touching_normal;
- bool m_touching_contact;
-
- bool m_was_on_ground;
- bool m_was_jumping;
- bool m_do_gobject_sweep_test;
- bool m_use_walk_direction;
- int m_i_up_axis;
-
- //---------------------------------------------------------------------
- //NEW INTERNAL VARS
- //---------------------------------------------------------------------
-
- //Gravity in vec3
- vec3 m_gravity;
-
- //Current Velocity
- vec3 m_velocity;
- };
-
- #endif // HAVE_PHYS_USE_BULLET
- #endif // USE_LOL_CTRLR_CHARAC
-
- } /* namespace phys */
-
- } /* namespace lol */
-
- #endif /* __BULLETCHARACTERCONTROLLER_BULLETCHARACTERCONTROLLER_H__ */
|