Imported Upstream version 2.81
[platform/upstream/libbullet.git] / Demos / CharacterDemo / DynamicCharacterController.cpp
1 #include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
2 #include "BulletDynamics/Dynamics/btRigidBody.h"
3 #include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
4 #include "LinearMath/btDefaultMotionState.h"
5 #include "DynamicCharacterController.h"
6
7 DynamicCharacterController::DynamicCharacterController ()
8 {
9         m_rayLambda[0] = 1.0;
10         m_rayLambda[1] = 1.0;
11         m_halfHeight = 1.0;
12         m_turnAngle = 0.0;
13         m_maxLinearVelocity = 10.0;
14         m_walkVelocity = 8.0; // meters/sec
15         m_turnVelocity = 1.0; // radians/sec
16         m_shape = NULL;
17         m_rigidBody = NULL;
18 }
19
20 DynamicCharacterController::~DynamicCharacterController ()
21 {
22 }
23
24 void DynamicCharacterController::setup (btScalar height, btScalar width, btScalar stepHeight)
25 {
26         btVector3 spherePositions[2];
27         btScalar sphereRadii[2];
28         
29         sphereRadii[0] = width;
30         sphereRadii[1] = width;
31         spherePositions[0] = btVector3 (0.0, (height/btScalar(2.0) - width), 0.0);
32         spherePositions[1] = btVector3 (0.0, (-height/btScalar(2.0) + width), 0.0);
33
34         m_halfHeight = height/btScalar(2.0);
35
36         m_shape = new btMultiSphereShape (&spherePositions[0], &sphereRadii[0], 2);
37
38         btTransform startTransform;
39         startTransform.setIdentity ();
40         startTransform.setOrigin (btVector3(0.0, 2.0, 0.0));
41         btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
42         btRigidBody::btRigidBodyConstructionInfo cInfo(1.0, myMotionState, m_shape);
43         m_rigidBody = new btRigidBody(cInfo);
44         // kinematic vs. static doesn't work
45         //m_rigidBody->setCollisionFlags( m_rigidBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
46         m_rigidBody->setSleepingThresholds (0.0, 0.0);
47         m_rigidBody->setAngularFactor (0.0);
48         
49 }
50
51 void DynamicCharacterController::destroy ()
52 {
53         if (m_shape)
54         {
55                 delete m_shape;
56         }
57
58         if (m_rigidBody)
59         {
60                 delete m_rigidBody;
61                 m_rigidBody = 0;
62         }
63 }
64
65 btCollisionObject* DynamicCharacterController::getCollisionObject ()
66 {
67         return m_rigidBody;
68 }
69
70 void DynamicCharacterController::preStep (const btCollisionWorld* collisionWorld)
71 {
72         btTransform xform;
73         m_rigidBody->getMotionState()->getWorldTransform (xform);
74         btVector3 down = -xform.getBasis()[1];
75         btVector3 forward = xform.getBasis()[2];
76         down.normalize ();
77         forward.normalize();
78
79         m_raySource[0] = xform.getOrigin();
80         m_raySource[1] = xform.getOrigin();
81
82         m_rayTarget[0] = m_raySource[0] + down * m_halfHeight * btScalar(1.1);
83         m_rayTarget[1] = m_raySource[1] + forward * m_halfHeight * btScalar(1.1);
84
85         class ClosestNotMe : public btCollisionWorld::ClosestRayResultCallback
86         {
87         public:
88                 ClosestNotMe (btRigidBody* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0))
89                 {
90                         m_me = me;
91                 }
92
93                 virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace)
94                 {
95                         if (rayResult.m_collisionObject == m_me)
96                                 return 1.0;
97
98                         return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace
99                 );
100         }
101         protected:
102                 btRigidBody* m_me;
103         };
104
105         ClosestNotMe rayCallback(m_rigidBody);
106
107         int i = 0;
108         for (i = 0; i < 2; i++)
109         {
110                 rayCallback.m_closestHitFraction = 1.0;
111                 collisionWorld->rayTest (m_raySource[i], m_rayTarget[i], rayCallback);
112                 if (rayCallback.hasHit())
113                 {
114                         m_rayLambda[i] = rayCallback.m_closestHitFraction;
115                 } else {
116                         m_rayLambda[i] = 1.0;
117                 }
118         }
119 }
120
121 void DynamicCharacterController::playerStep (const btCollisionWorld* dynaWorld,btScalar dt,
122                                          int forward,
123                                          int backward,
124                                          int left,
125                                          int right,
126                                          int jump)
127 {
128         btTransform xform;
129         m_rigidBody->getMotionState()->getWorldTransform (xform);
130
131         /* Handle turning */
132         if (left)
133                 m_turnAngle -= dt * m_turnVelocity;
134         if (right)
135                 m_turnAngle += dt * m_turnVelocity;
136
137         xform.setRotation (btQuaternion (btVector3(0.0, 1.0, 0.0), m_turnAngle));
138
139         btVector3 linearVelocity = m_rigidBody->getLinearVelocity();
140         btScalar speed = m_rigidBody->getLinearVelocity().length();
141
142         btVector3 forwardDir = xform.getBasis()[2];
143         forwardDir.normalize ();
144         btVector3 walkDirection = btVector3(0.0, 0.0, 0.0);
145         btScalar walkSpeed = m_walkVelocity * dt;
146
147         if (forward)
148                 walkDirection += forwardDir;
149         if (backward)
150                 walkDirection -= forwardDir;
151
152
153         
154         if (!forward && !backward && onGround())
155         {
156                 /* Dampen when on the ground and not being moved by the player */
157                 linearVelocity *= btScalar(0.2);
158                 m_rigidBody->setLinearVelocity (linearVelocity);
159         } else {
160                 if (speed < m_maxLinearVelocity)
161                 {
162                         btVector3 velocity = linearVelocity + walkDirection * walkSpeed;
163                         m_rigidBody->setLinearVelocity (velocity);
164                 }
165         }
166
167         m_rigidBody->getMotionState()->setWorldTransform (xform);
168         m_rigidBody->setCenterOfMassTransform (xform);
169 }
170
171 bool DynamicCharacterController::canJump () const
172 {
173         return onGround();
174 }
175
176 void DynamicCharacterController::jump ()
177 {
178         if (!canJump())
179                 return;
180
181         btTransform xform;
182         m_rigidBody->getMotionState()->getWorldTransform (xform);
183         btVector3 up = xform.getBasis()[1];
184         up.normalize ();
185         btScalar magnitude = (btScalar(1.0)/m_rigidBody->getInvMass()) * btScalar(8.0);
186         m_rigidBody->applyCentralImpulse (up * magnitude);
187 }
188
189 bool DynamicCharacterController::onGround () const
190 {
191         return m_rayLambda[0] < btScalar(1.0);
192 }
193
194 void DynamicCharacterController::reset ()
195 {
196 }
197 void DynamicCharacterController::warp (const btVector3& origin)
198 {
199 }
200 void DynamicCharacterController::registerPairCacheAndDispatcher (btOverlappingPairCache* pairCache, btCollisionDispatcher* dispatcher)
201 {
202
203 }
204