CharacterGame.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. #include "CharacterGame.h"
  2. // Declare our game instance
  3. CharacterGame game;
  4. // Input flags
  5. #define NORTH 1
  6. #define SOUTH 2
  7. #define EAST 4
  8. #define WEST 8
  9. #define RUNNING 16
  10. // Character defines
  11. #define WALK_SPEED 5.0f
  12. #define STRAFE_SPEED 1.5f
  13. #define RUN_SPEED 15.0f
  14. #define CAMERA_FOCUS_DISTANCE 16.0f
  15. #define BUTTON_1 0
  16. #define BUTTON_2 1
  17. CharacterGame::CharacterGame()
  18. : _font(NULL), _scene(NULL), _character(NULL), _characterNode(NULL), _characterMeshNode(NULL), _characterShadowNode(NULL), _basketballNode(NULL),
  19. _animation(NULL), _currentClip(NULL), _jumpClip(NULL), _kickClip(NULL), _rotateX(0), _materialParameterAlpha(NULL),
  20. _keyFlags(0), _physicsDebug(false), _wireframe(false), _hasBall(false), _applyKick(false), _gamepad(NULL)
  21. {
  22. _buttonPressed = new bool[2];
  23. }
  24. void CharacterGame::initialize()
  25. {
  26. // Enable multi-touch (only affects devices that support multi-touch).
  27. setMultiTouch(true);
  28. // Display the gameplay splash screen for at least 1 second.
  29. displayScreen(this, &CharacterGame::drawSplash, NULL, 1000L);
  30. // Load the font.
  31. _font = Font::create("res/ui/arial.gpb");
  32. // Load scene.
  33. _scene = Scene::load("res/common/sample.scene");
  34. // Update the aspect ratio for our scene's camera to match the current device resolution.
  35. _scene->getActiveCamera()->setAspectRatio(getAspectRatio());
  36. // Initialize the physics character.
  37. initializeCharacter();
  38. // Create a collision object for the ceiling.
  39. Node* ceiling = _scene->addNode("ceiling");
  40. ceiling->setTranslationY(14.5f);
  41. PhysicsRigidBody::Parameters rbParams;
  42. rbParams.mass = 0.0f;
  43. rbParams.friction = 0.5f;
  44. rbParams.restitution = 0.75f;
  45. rbParams.linearDamping = 0.025f;
  46. rbParams.angularDamping = 0.16f;
  47. ceiling->setCollisionObject(PhysicsCollisionObject::RIGID_BODY, PhysicsCollisionShape::box(Vector3(49.5f, 1.0f, 49.5f)), &rbParams);
  48. // Initialize scene.
  49. _scene->visit(this, &CharacterGame::initializeScene);
  50. _gamepad = getGamepad(0);
  51. }
  52. bool CharacterGame::initializeScene(Node* node)
  53. {
  54. Model* model = node->getModel();
  55. if (model && model->getMaterial())
  56. {
  57. initializeMaterial(_scene, node, model->getMaterial());
  58. }
  59. return true;
  60. }
  61. void CharacterGame::initializeMaterial(Scene* scene, Node* node, Material* material)
  62. {
  63. // Bind light shader parameters to dynamic objects only
  64. if (node->hasTag("dynamic"))
  65. {
  66. material->getParameter("u_ambientColor")->bindValue(scene, &Scene::getAmbientColor);
  67. Node* lightNode = scene->findNode("sun");
  68. if (lightNode)
  69. {
  70. material->getParameter("u_directionalLightColor[0]")->bindValue(lightNode->getLight(), &Light::getColor);
  71. material->getParameter("u_directionalLightDirection[0]")->bindValue(lightNode, &Node::getForwardVectorView);
  72. }
  73. }
  74. }
  75. void CharacterGame::initializeCharacter()
  76. {
  77. Node* node = _scene->findNode("boycharacter");
  78. // Store the physics character object.
  79. _character = static_cast<PhysicsCharacter*>(node->getCollisionObject());
  80. // Store character nodes.
  81. _characterNode = node->findNode("boyScale");
  82. _characterMeshNode = _scene->findNode("boymesh");
  83. _characterShadowNode = _scene->findNode("boyshadow");
  84. // Get the basketball node.
  85. _basketballNode = _scene->findNode("basketball");
  86. _basketballNode->getCollisionObject()->addCollisionListener(this);
  87. _floorLevel = _basketballNode->getTranslationY();
  88. // Store the alpha material parameter from the character's model.
  89. _materialParameterAlpha = _characterMeshNode->getModel()->getMaterial()->getTechniqueByIndex(0)->getPassByIndex(0)->getParameter("u_modulateAlpha");
  90. // Load character animations.
  91. _animation = node->getAnimation("animations");
  92. _animation->createClips("res/common/boy.animation");
  93. _jumpClip = _animation->getClip("jump");
  94. _jumpClip->addListener(this, _jumpClip->getDuration() - 250);
  95. _kickClip = _animation->getClip("kick");
  96. // when to cross fade
  97. _kickClip->addListener(this, _kickClip->getDuration() - 250);
  98. // when to turn on _isKicking.
  99. _kickClip->addListener(this, 416);
  100. // Start playing the idle animation when we load.
  101. play("idle", true);
  102. }
  103. void CharacterGame::finalize()
  104. {
  105. SAFE_RELEASE(_scene);
  106. SAFE_RELEASE(_font);
  107. SAFE_DELETE_ARRAY(_buttonPressed);
  108. }
  109. void CharacterGame::drawSplash(void* param)
  110. {
  111. clear(CLEAR_COLOR_DEPTH, Vector4(0, 0, 0, 1), 1.0f, 0);
  112. SpriteBatch* batch = SpriteBatch::create("res/logo_powered_white.png");
  113. batch->start();
  114. batch->draw(getWidth() * 0.5f, getHeight() * 0.5f, 0.0f, 512.0f, 512.0f, 0.0f, 1.0f, 1.0f, 0.0f, Vector4::one(), true);
  115. batch->finish();
  116. SAFE_DELETE(batch);
  117. }
  118. bool CharacterGame::drawScene(Node* node, bool transparent)
  119. {
  120. if (node->getModel() && (transparent == node->hasTag("transparent")))
  121. node->getModel()->draw(_wireframe);
  122. return true;
  123. }
  124. void CharacterGame::play(const char* id, bool repeat, float speed)
  125. {
  126. AnimationClip* clip = _animation->getClip(id);
  127. // Set clip properties
  128. clip->setSpeed(speed);
  129. clip->setRepeatCount(repeat ? AnimationClip::REPEAT_INDEFINITE : 1);
  130. // Is the clip already playing?
  131. if (clip == _currentClip && clip->isPlaying())
  132. return;
  133. if (_jumpClip->isPlaying() || _kickClip->isPlaying())
  134. {
  135. _currentClip = clip;
  136. return;
  137. }
  138. // If a current clip is playing, crossfade into the new one
  139. if (_currentClip && _currentClip->isPlaying())
  140. {
  141. _currentClip->crossFade(clip, 150);
  142. }
  143. else
  144. {
  145. clip->play();
  146. }
  147. _currentClip = clip;
  148. }
  149. void CharacterGame::jump()
  150. {
  151. if (isOnFloor() && !_kickClip->isPlaying())
  152. {
  153. play("jump", false, 0.55f);
  154. _character->jump(3.0f);
  155. }
  156. }
  157. void CharacterGame::kick()
  158. {
  159. if (!_jumpClip->isPlaying())
  160. play("kick", false, 1.75f);
  161. _kicking = true;
  162. }
  163. bool CharacterGame::isOnFloor() const
  164. {
  165. return (std::fabs(_character->getCurrentVelocity().y) < MATH_EPSILON);
  166. }
  167. void CharacterGame::update(float elapsedTime)
  168. {
  169. if (_applyKick)
  170. {
  171. // apply impulse from kick.
  172. Vector3 impulse(-_characterNode->getForwardVectorWorld());
  173. impulse.normalize();
  174. // add some lift to kick
  175. impulse.y = 1.0f;
  176. //scale the impulse.
  177. impulse.scale(16.6f);
  178. ((PhysicsRigidBody*)_basketballNode->getCollisionObject())->applyImpulse(impulse);
  179. _hasBall = false;
  180. _applyKick = false;
  181. }
  182. if (!_kickClip->isPlaying())
  183. _kicking = false;
  184. if (_gamepad->isButtonDown(Gamepad::BUTTON_A))
  185. {
  186. if (_buttonPressed[BUTTON_1])
  187. {
  188. _buttonPressed[BUTTON_1] = false;
  189. // Jump while the gamepad button is being pressed
  190. jump();
  191. }
  192. }
  193. else
  194. {
  195. _buttonPressed[BUTTON_1] = true;
  196. }
  197. if (_gamepad->isButtonDown(Gamepad::BUTTON_B))
  198. {
  199. if (_buttonPressed[BUTTON_2])
  200. {
  201. _buttonPressed[BUTTON_2] = false;
  202. kick();
  203. }
  204. }
  205. else
  206. {
  207. _buttonPressed[BUTTON_2] = true;
  208. }
  209. _currentDirection.set(Vector2::zero());
  210. if (!_kicking)
  211. {
  212. if (_gamepad->getJoystickCount() > 0)
  213. {
  214. _gamepad->getJoystickValues(0, &_currentDirection);
  215. }
  216. }
  217. if (_gamepad->getJoystickCount() > 1)
  218. {
  219. Vector2 out;
  220. _gamepad->getJoystickValues(1, &out);
  221. _character->getNode()->rotateY(-MATH_DEG_TO_RAD(out.x * 2.0f));
  222. }
  223. if (_currentDirection.isZero())
  224. {
  225. // Construct direction vector from keyboard input
  226. if (_keyFlags & NORTH)
  227. _currentDirection.y = 1;
  228. else if (_keyFlags & SOUTH)
  229. _currentDirection.y = -1;
  230. else
  231. _currentDirection.y = 0;
  232. if (_keyFlags & EAST)
  233. _currentDirection.x = 1;
  234. else if (_keyFlags & WEST)
  235. _currentDirection.x = -1;
  236. else
  237. _currentDirection.x = 0;
  238. _currentDirection.normalize();
  239. if ((_keyFlags & RUNNING) == 0)
  240. _currentDirection *= 0.5f;
  241. }
  242. // Update character animation and velocity
  243. if (_currentDirection.isZero())
  244. {
  245. play("idle", true);
  246. _character->setVelocity(Vector3::zero());
  247. }
  248. else
  249. {
  250. bool running = (_currentDirection.lengthSquared() > 0.75f);
  251. float speed = running ? RUN_SPEED : WALK_SPEED;
  252. play(running ? "running" : "walking", true, 1.0f);
  253. // Orient the character relative to the camera so he faces the direction we want to move.
  254. const Matrix& cameraMatrix = _scene->getActiveCamera()->getNode()->getWorldMatrix();
  255. Vector3 cameraRight, cameraForward;
  256. cameraMatrix.getRightVector(&cameraRight);
  257. cameraMatrix.getForwardVector(&cameraForward);
  258. // Get the current forward vector for the mesh node (negate it since the character was modelled facing +z)
  259. Vector3 currentHeading(-_characterNode->getForwardVectorWorld());
  260. // Construct a new forward vector for the mesh node
  261. Vector3 newHeading(cameraForward * _currentDirection.y + cameraRight * _currentDirection.x);
  262. // Compute the rotation amount based on the difference between the current and new vectors
  263. float angle = atan2f(newHeading.x, newHeading.z) - atan2f(currentHeading.x, currentHeading.z);
  264. if (angle > MATH_PI)
  265. angle -= MATH_PIX2;
  266. else if (angle < -MATH_PI)
  267. angle += MATH_PIX2;
  268. angle *= (float)elapsedTime * 0.001f * MATH_PIX2;
  269. _characterNode->rotate(Vector3::unitY(), angle);
  270. // Update the character's velocity
  271. Vector3 velocity = -_characterNode->getForwardVectorWorld();
  272. velocity.normalize();
  273. velocity *= speed;
  274. _character->setVelocity(velocity);
  275. }
  276. // Adjust camera to avoid it from being obstructed by walls and objects in the scene.
  277. adjustCamera(elapsedTime);
  278. // Project the character's shadow node onto the surface directly below him.
  279. PhysicsController::HitResult hitResult;
  280. Vector3 v = _character->getNode()->getTranslationWorld();
  281. if (getPhysicsController()->rayTest(Ray(Vector3(v.x, v.y + 1.0f, v.z), Vector3(0, -1, 0)), 100.0f, &hitResult, NULL))
  282. {
  283. _characterShadowNode->setTranslation(Vector3(hitResult.point.x, hitResult.point.y + 0.1f, hitResult.point.z));
  284. }
  285. if (_hasBall)
  286. {
  287. // This is the first time entering this block of code if the basketball is still enabled.
  288. // Disable physics on basketball, and create a bigger collision object around the boy to include the ball.
  289. // This will ensure the boy cannot walk through walls/objects with the basketball.
  290. PhysicsRigidBody* basketball = (PhysicsRigidBody*)_basketballNode->getCollisionObject();
  291. if (basketball->isEnabled())
  292. {
  293. grabBall();
  294. }
  295. // Capture the basketball's old position, and then calculate the basketball's new position in front of the character
  296. _oldBallPosition = _basketballNode->getTranslationWorld();
  297. Vector3 characterForwardVector(_characterNode->getForwardVectorWorld());
  298. Vector3 translation(_characterNode->getTranslationWorld() + characterForwardVector.normalize() * -2.2f);
  299. translation.y = _floorLevel;
  300. // Calculates rotation to be applied to the basketball.
  301. Vector3 rotationVector(0.0f, -_basketballNode->getBoundingSphere().radius, 0.0f);
  302. Vector3::cross(rotationVector, _oldBallPosition - translation, &rotationVector);
  303. if (!rotationVector.isZero())
  304. {
  305. Matrix m;
  306. _basketballNode->getWorldMatrix().transpose(&m);
  307. Vector3 rotNorm;
  308. m.transformVector(rotationVector, &rotNorm);
  309. rotNorm.normalize();
  310. _basketballNode->rotate(rotNorm, rotationVector.length());
  311. }
  312. _basketballNode->setTranslation(translation.x, _floorLevel, translation.z);
  313. }
  314. }
  315. void CharacterGame::render(float elapsedTime)
  316. {
  317. // Clear the color and depth buffers.
  318. clear(CLEAR_COLOR_DEPTH, Vector4(0.41f, 0.48f, 0.54f, 1.0f), 1.0f, 0);
  319. // Draw our scene, with separate passes for opaque and transparent objects.
  320. _scene->visit(this, &CharacterGame::drawScene, false);
  321. _scene->visit(this, &CharacterGame::drawScene, true);
  322. // Draw physics debug
  323. if (_physicsDebug)
  324. getPhysicsController()->drawDebug(_scene->getActiveCamera()->getViewProjectionMatrix());
  325. _gamepad->draw();
  326. // Draw FPS
  327. _font->start();
  328. char fps[32];
  329. sprintf(fps, "%d", getFrameRate());
  330. _font->drawText(fps, 5, 5, Vector4(1,1,0,1), 20);
  331. _font->finish();
  332. }
  333. void CharacterGame::keyEvent(Keyboard::KeyEvent evt, int key)
  334. {
  335. if (evt == Keyboard::KEY_PRESS)
  336. {
  337. switch (key)
  338. {
  339. case Keyboard::KEY_ESCAPE:
  340. exit();
  341. break;
  342. case Keyboard::KEY_W:
  343. case Keyboard::KEY_CAPITAL_W:
  344. _keyFlags |= NORTH;
  345. _keyFlags &= ~SOUTH;
  346. break;
  347. case Keyboard::KEY_S:
  348. case Keyboard::KEY_CAPITAL_S:
  349. _keyFlags |= SOUTH;
  350. _keyFlags &= ~NORTH;
  351. break;
  352. case Keyboard::KEY_A:
  353. case Keyboard::KEY_CAPITAL_A:
  354. _keyFlags |= WEST;
  355. _keyFlags &= ~EAST;
  356. break;
  357. case Keyboard::KEY_D:
  358. case Keyboard::KEY_CAPITAL_D:
  359. _keyFlags |= EAST;
  360. _keyFlags &= ~WEST;
  361. break;
  362. case Keyboard::KEY_B:
  363. _physicsDebug = !_physicsDebug;
  364. break;
  365. case Keyboard::KEY_SPACE:
  366. jump();
  367. break;
  368. case Keyboard::KEY_SHIFT:
  369. _keyFlags |= RUNNING;
  370. break;
  371. case Keyboard::KEY_M:
  372. case Keyboard::KEY_CAPITAL_M:
  373. _wireframe = !_wireframe;
  374. break;
  375. case Keyboard::KEY_C:
  376. case Keyboard::KEY_CAPITAL_C:
  377. clone();
  378. break;
  379. }
  380. }
  381. else if (evt == Keyboard::KEY_RELEASE)
  382. {
  383. switch (key)
  384. {
  385. case Keyboard::KEY_W:
  386. case Keyboard::KEY_CAPITAL_W:
  387. _keyFlags &= ~NORTH;
  388. break;
  389. case Keyboard::KEY_S:
  390. case Keyboard::KEY_CAPITAL_S:
  391. _keyFlags &= ~SOUTH;
  392. break;
  393. case Keyboard::KEY_A:
  394. case Keyboard::KEY_CAPITAL_A:
  395. _keyFlags &= ~WEST;
  396. break;
  397. case Keyboard::KEY_D:
  398. case Keyboard::KEY_CAPITAL_D:
  399. _keyFlags &= ~EAST;
  400. break;
  401. case Keyboard::KEY_SHIFT:
  402. _keyFlags &= ~RUNNING;
  403. break;
  404. }
  405. }
  406. }
  407. void CharacterGame::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
  408. {
  409. // This should only be called if the gamepad did not handle the touch event.
  410. switch (evt)
  411. {
  412. case Touch::TOUCH_PRESS:
  413. {
  414. _rotateX = x;
  415. }
  416. break;
  417. case Touch::TOUCH_RELEASE:
  418. {
  419. _rotateX = 0;
  420. }
  421. break;
  422. case Touch::TOUCH_MOVE:
  423. {
  424. int deltaX = x - _rotateX;
  425. _rotateX = x;
  426. _character->getNode()->rotateY(-MATH_DEG_TO_RAD(deltaX * 0.5f));
  427. }
  428. break;
  429. default:
  430. break;
  431. }
  432. }
  433. bool CharacterGame::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
  434. {
  435. if (evt == Mouse::MOUSE_PRESS_RIGHT_BUTTON)
  436. {
  437. kick();
  438. return true;
  439. }
  440. return false;
  441. }
  442. void CharacterGame::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad)
  443. {
  444. switch(evt)
  445. {
  446. case Gamepad::CONNECTED_EVENT:
  447. case Gamepad::DISCONNECTED_EVENT:
  448. _gamepad = getGamepad(0);
  449. break;
  450. }
  451. }
  452. void CharacterGame::adjustCamera(float elapsedTime)
  453. {
  454. static float cameraOffset = 0.0f;
  455. PhysicsController* physics = getPhysicsController();
  456. Node* cameraNode = _scene->getActiveCamera()->getNode();
  457. // Reset camera
  458. if (cameraOffset != 0.0f)
  459. {
  460. cameraNode->translateForward(-cameraOffset);
  461. cameraOffset = 0.0f;
  462. }
  463. Vector3 cameraPosition = cameraNode->getTranslationWorld();
  464. Vector3 cameraDirection = cameraNode->getForwardVectorWorld();
  465. cameraDirection.normalize();
  466. // Get focal point of camera (use the resolved world location of the head joint as a focal point)
  467. Vector3 focalPoint(cameraPosition + (cameraDirection * CAMERA_FOCUS_DISTANCE));
  468. Vector3 oldPosition = cameraNode->getTranslationWorld();
  469. PhysicsController::HitResult result;
  470. PhysicsCollisionObject* occlusion = NULL;
  471. do
  472. {
  473. // Perform a ray test to check for camera collisions
  474. if (!physics->sweepTest(cameraNode->getCollisionObject(), focalPoint, &result) || result.object == _character)
  475. break;
  476. occlusion = result.object;
  477. // Step the camera closer to the focal point to resolve the occlusion
  478. float d = cameraNode->getTranslationWorld().distance(result.point);
  479. cameraNode->translateForward(d);
  480. cameraOffset += d;
  481. while (physics->sweepTest(cameraNode->getCollisionObject(), focalPoint, &result) && result.object == occlusion)
  482. {
  483. // Prevent the camera from getting too close to the character.
  484. // Without this check, it's possible for the camera to fly past the character
  485. // and essentially end up in an infinite loop here.
  486. if (cameraNode->getTranslationWorld().distanceSquared(focalPoint) <= 2.0f)
  487. return;
  488. cameraNode->translateForward(0.1f);
  489. cameraOffset += 0.1f;
  490. }
  491. } while (true);
  492. // If the character is closer than 10 world units to the camera, apply transparency to the character so he does not obstruct the view.
  493. if (occlusion)
  494. {
  495. float d = _scene->getActiveCamera()->getNode()->getTranslationWorld().distance(_characterNode->getTranslationWorld());
  496. float alpha = d < 10 ? (d * 0.1f) : 1.0f;
  497. _characterMeshNode->setTag("transparent", alpha < 1.0f ? "true" : NULL);
  498. _materialParameterAlpha->setValue(alpha);
  499. }
  500. else
  501. {
  502. _characterMeshNode->setTag("transparent", NULL);
  503. _materialParameterAlpha->setValue(1.0f);
  504. }
  505. }
  506. void CharacterGame::animationEvent(AnimationClip* clip, AnimationClip::Listener::EventType type)
  507. {
  508. if (clip == _kickClip && !_applyKick)
  509. {
  510. _keyFlags = 0;
  511. if (_hasBall)
  512. {
  513. _applyKick = true;
  514. releaseBall();
  515. }
  516. }
  517. else
  518. {
  519. clip->crossFade(_currentClip, 100);
  520. }
  521. }
  522. void CharacterGame::clone()
  523. {
  524. Node* clone = _scene->findNode("boycharacter")->clone();
  525. Animation* cloneAnimation = clone->getAnimation();
  526. // Find the current clip and have the clone play that clip repeatedly.
  527. const char* clipId = _currentClip->getId();
  528. if (_jumpClip->isPlaying())
  529. clipId = _jumpClip->getId();
  530. AnimationClip* clip = cloneAnimation->getClip(clipId);
  531. clip->setRepeatCount(AnimationClip::REPEAT_INDEFINITE);
  532. clip->play();
  533. _scene->addNode(clone);
  534. clone->release();
  535. }
  536. void CharacterGame::collisionEvent(PhysicsCollisionObject::CollisionListener::EventType type,
  537. const PhysicsCollisionObject::CollisionPair& collisionPair,
  538. const Vector3& contactPointA,
  539. const Vector3& contactPointB)
  540. {
  541. // objectA -> basketball, only care about collisions between the physics character and the basketball.
  542. if (type == PhysicsCollisionObject::CollisionListener::COLLIDING && collisionPair.objectB == _character)
  543. _hasBall = true;
  544. }
  545. void CharacterGame::grabBall()
  546. {
  547. // Disables physics on the basketball, and increases the size of the character's collison object to include the basketball.
  548. _basketballNode->getCollisionObject()->setEnabled(false);
  549. PhysicsRigidBody::Parameters rbParams;
  550. rbParams.mass = 20.0f;
  551. Vector3 currentVelocity = _character->getCurrentVelocity();
  552. Node* boy = _character->getNode();
  553. boy->setCollisionObject(PhysicsCollisionObject::CHARACTER, PhysicsCollisionShape::capsule(2.9f, 6.0f, Vector3(0.0f, 3.0f, 0.0f), true), &rbParams);
  554. _character = static_cast<PhysicsCharacter*>(boy->getCollisionObject());
  555. _character->setMaxSlopeAngle(0.0f);
  556. _character->setMaxStepHeight(0.0f);
  557. _character->setVelocity(currentVelocity);
  558. }
  559. void CharacterGame::releaseBall()
  560. {
  561. // Decreases the size of the character's collision object and re-enables physics simulation on the basketball.
  562. PhysicsRigidBody::Parameters rbParams;
  563. rbParams.mass = 20.0f;
  564. Vector3 velocity = _character->getCurrentVelocity();
  565. Node* boy = _character->getNode();
  566. boy->setCollisionObject(PhysicsCollisionObject::CHARACTER, PhysicsCollisionShape::capsule(1.2f, 6.0f, Vector3(0.0f, 3.0f, 0.0f), true), &rbParams);
  567. _character = static_cast<PhysicsCharacter*>(boy->getCollisionObject());
  568. _character->setVelocity(velocity);
  569. _character->setMaxSlopeAngle(0.0f);
  570. _character->setMaxStepHeight(0.0f);
  571. PhysicsRigidBody* basketball = (PhysicsRigidBody*) _basketballNode->getCollisionObject();
  572. basketball->setEnabled(true);
  573. }