CharacterGame.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  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), _drawDebug(0), _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/common/arial40.gpb");
  32. // Load scene.
  33. _scene = Scene::load("res/common/scene.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. Node* lightNode = scene->findNode("sun");
  67. material->getParameter("u_ambientColor")->bindValue(scene, &Scene::getAmbientColor);
  68. material->getParameter("u_lightColor")->bindValue(lightNode->getLight(), &Light::getColor);
  69. material->getParameter("u_lightDirection")->bindValue(lightNode, &Node::getForwardVectorView);
  70. }
  71. }
  72. void CharacterGame::initializeCharacter()
  73. {
  74. Node* node = _scene->findNode("boycharacter");
  75. // Store the physics character object.
  76. _character = static_cast<PhysicsCharacter*>(node->getCollisionObject());
  77. // Store character nodes.
  78. _characterNode = node->findNode("boyScale");
  79. _characterMeshNode = _scene->findNode("boymesh");
  80. _characterShadowNode = _scene->findNode("boyshadow");
  81. // Get the basketball node.
  82. _basketballNode = _scene->findNode("basketball");
  83. _basketballNode->getCollisionObject()->addCollisionListener(this);
  84. _floorLevel = _basketballNode->getTranslationY();
  85. // Store the alpha material parameter from the character's model.
  86. _materialParameterAlpha = _characterMeshNode->getModel()->getMaterial()->getTechniqueByIndex(0)->getPassByIndex(0)->getParameter("u_modulateAlpha");
  87. // Load character animations.
  88. _animation = node->getAnimation("animations");
  89. _animation->createClips("res/common/boy.animation");
  90. _jumpClip = _animation->getClip("jump");
  91. _jumpClip->addListener(this, _jumpClip->getDuration() - 250);
  92. _kickClip = _animation->getClip("kick");
  93. _kickClip->addListener(this, _kickClip->getDuration() - 250); // when to cross fade
  94. _kickClip->addListener(this, 416); // when to turn on _isKicking.
  95. // Start playing the idle animation when we load.
  96. play("idle", true);
  97. }
  98. void CharacterGame::finalize()
  99. {
  100. SAFE_RELEASE(_scene);
  101. SAFE_RELEASE(_font);
  102. SAFE_DELETE_ARRAY(_buttonPressed);
  103. }
  104. void CharacterGame::drawSplash(void* param)
  105. {
  106. clear(CLEAR_COLOR_DEPTH, Vector4(0, 0, 0, 1), 1.0f, 0);
  107. SpriteBatch* batch = SpriteBatch::create("res/logo_powered_white.png");
  108. batch->start();
  109. 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);
  110. batch->finish();
  111. SAFE_DELETE(batch);
  112. }
  113. bool CharacterGame::drawScene(Node* node, bool transparent)
  114. {
  115. if (node->getModel() && (transparent == node->hasTag("transparent")))
  116. node->getModel()->draw(_wireframe);
  117. return true;
  118. }
  119. void CharacterGame::play(const char* id, bool repeat, float speed)
  120. {
  121. AnimationClip* clip = _animation->getClip(id);
  122. // Set clip properties
  123. clip->setSpeed(speed);
  124. clip->setRepeatCount(repeat ? AnimationClip::REPEAT_INDEFINITE : 1);
  125. // Is the clip already playing?
  126. if (clip == _currentClip && clip->isPlaying())
  127. return;
  128. if (_jumpClip->isPlaying() || _kickClip->isPlaying())
  129. {
  130. _currentClip = clip;
  131. return;
  132. }
  133. // If a current clip is playing, crossfade into the new one
  134. if (_currentClip && _currentClip->isPlaying())
  135. {
  136. _currentClip->crossFade(clip, 150);
  137. }
  138. else
  139. {
  140. clip->play();
  141. }
  142. _currentClip = clip;
  143. }
  144. void CharacterGame::jump()
  145. {
  146. if (isOnFloor() && !_kickClip->isPlaying())
  147. {
  148. play("jump", false, 0.55f);
  149. _character->jump(3.0f);
  150. }
  151. }
  152. void CharacterGame::kick()
  153. {
  154. if (!_jumpClip->isPlaying())
  155. play("kick", false, 1.75f);
  156. _kicking = true;
  157. }
  158. bool CharacterGame::isOnFloor() const
  159. {
  160. return (std::fabs(_character->getCurrentVelocity().y) < MATH_EPSILON);
  161. }
  162. void CharacterGame::update(float elapsedTime)
  163. {
  164. if (_applyKick)
  165. {
  166. // apply impulse from kick.
  167. Vector3 impulse(-_characterNode->getForwardVectorWorld());
  168. impulse.normalize();
  169. impulse.y = 1.0f; // add some lift to kick
  170. impulse.scale(16.6f); //scale the impulse.
  171. ((PhysicsRigidBody*)_basketballNode->getCollisionObject())->applyImpulse(impulse);
  172. _hasBall = false;
  173. _applyKick = false;
  174. }
  175. if (!_kickClip->isPlaying())
  176. _kicking = false;
  177. if (_gamepad->isButtonDown(Gamepad::BUTTON_A))
  178. {
  179. if (_buttonPressed[BUTTON_1])
  180. {
  181. _buttonPressed[BUTTON_1] = false;
  182. // Jump while the gamepad button is being pressed
  183. jump();
  184. }
  185. }
  186. else
  187. {
  188. _buttonPressed[BUTTON_1] = true;
  189. }
  190. if (_gamepad->isButtonDown(Gamepad::BUTTON_B))
  191. {
  192. if (_buttonPressed[BUTTON_2])
  193. {
  194. _buttonPressed[BUTTON_2] = false;
  195. kick();
  196. }
  197. }
  198. else
  199. {
  200. _buttonPressed[BUTTON_2] = true;
  201. }
  202. _currentDirection.set(Vector2::zero());
  203. if (!_kicking)
  204. {
  205. if (_gamepad->getJoystickCount() > 0)
  206. {
  207. _gamepad->getJoystickValues(0, &_currentDirection);
  208. }
  209. }
  210. if (_gamepad->getJoystickCount() > 1)
  211. {
  212. Vector2 out;
  213. _gamepad->getJoystickValues(1, &out);
  214. _character->getNode()->rotateY(-MATH_DEG_TO_RAD(out.x * 2.0f));
  215. }
  216. if (_currentDirection.isZero())
  217. {
  218. // Construct direction vector from keyboard input
  219. if (_keyFlags & NORTH)
  220. _currentDirection.y = 1;
  221. else if (_keyFlags & SOUTH)
  222. _currentDirection.y = -1;
  223. else
  224. _currentDirection.y = 0;
  225. if (_keyFlags & EAST)
  226. _currentDirection.x = 1;
  227. else if (_keyFlags & WEST)
  228. _currentDirection.x = -1;
  229. else
  230. _currentDirection.x = 0;
  231. _currentDirection.normalize();
  232. if ((_keyFlags & RUNNING) == 0)
  233. _currentDirection *= 0.5f;
  234. }
  235. // Update character animation and velocity
  236. if (_currentDirection.isZero())
  237. {
  238. play("idle", true);
  239. _character->setVelocity(Vector3::zero());
  240. }
  241. else
  242. {
  243. bool running = (_currentDirection.lengthSquared() > 0.75f);
  244. float speed = running ? RUN_SPEED : WALK_SPEED;
  245. play(running ? "running" : "walking", true, 1.0f);
  246. // Orient the character relative to the camera so he faces the direction we want to move.
  247. const Matrix& cameraMatrix = _scene->getActiveCamera()->getNode()->getWorldMatrix();
  248. Vector3 cameraRight, cameraForward;
  249. cameraMatrix.getRightVector(&cameraRight);
  250. cameraMatrix.getForwardVector(&cameraForward);
  251. // Get the current forward vector for the mesh node (negate it since the character was modelled facing +z)
  252. Vector3 currentHeading(-_characterNode->getForwardVectorWorld());
  253. // Construct a new forward vector for the mesh node
  254. Vector3 newHeading(cameraForward * _currentDirection.y + cameraRight * _currentDirection.x);
  255. // Compute the rotation amount based on the difference between the current and new vectors
  256. float angle = atan2f(newHeading.x, newHeading.z) - atan2f(currentHeading.x, currentHeading.z);
  257. if (angle > MATH_PI)
  258. angle -= MATH_PIX2;
  259. else if (angle < -MATH_PI)
  260. angle += MATH_PIX2;
  261. angle *= (float)elapsedTime * 0.001f * MATH_PIX2;
  262. _characterNode->rotate(Vector3::unitY(), angle);
  263. // Update the character's velocity
  264. Vector3 velocity = -_characterNode->getForwardVectorWorld();
  265. velocity.normalize();
  266. velocity *= speed;
  267. _character->setVelocity(velocity);
  268. }
  269. // Adjust camera to avoid it from being obstructed by walls and objects in the scene.
  270. adjustCamera(elapsedTime);
  271. // Project the character's shadow node onto the surface directly below him.
  272. PhysicsController::HitResult hitResult;
  273. Vector3 v = _character->getNode()->getTranslationWorld();
  274. if (getPhysicsController()->rayTest(Ray(Vector3(v.x, v.y + 1.0f, v.z), Vector3(0, -1, 0)), 100.0f, &hitResult, NULL))
  275. _characterShadowNode->setTranslation(Vector3(hitResult.point.x, hitResult.point.y + 0.1f, hitResult.point.z));
  276. if (_hasBall)
  277. {
  278. // This is the first time entering this block of code if the basketball is still enabled.
  279. // Disable physics on basketball, and create a bigger collision object around the boy to include the ball.
  280. // This will ensure the boy cannot walk through walls/objects with the basketball.
  281. PhysicsRigidBody* basketball = (PhysicsRigidBody*)_basketballNode->getCollisionObject();
  282. if (basketball->isEnabled())
  283. grabBall();
  284. // Capture the basketball's old position, and then calculate the basketball's new position in front of the character
  285. _oldBallPosition = _basketballNode->getTranslationWorld();
  286. Vector3 characterForwardVector(_characterNode->getForwardVectorWorld());
  287. Vector3 translation(_characterNode->getTranslationWorld() + characterForwardVector.normalize() * -2.2f);
  288. translation.y = _floorLevel;
  289. // Calculates rotation to be applied to the basketball.
  290. Vector3 rotationVector(0.0f, -_basketballNode->getBoundingSphere().radius, 0.0f);
  291. Vector3::cross(rotationVector, _oldBallPosition - translation, &rotationVector);
  292. if (!rotationVector.isZero())
  293. {
  294. Matrix m;
  295. _basketballNode->getWorldMatrix().transpose(&m);
  296. Vector3 rotNorm;
  297. m.transformVector(rotationVector, &rotNorm);
  298. rotNorm.normalize();
  299. _basketballNode->rotate(rotNorm, rotationVector.length());
  300. }
  301. _basketballNode->setTranslation(translation.x, _floorLevel, translation.z);
  302. }
  303. }
  304. void CharacterGame::render(float elapsedTime)
  305. {
  306. // Clear the color and depth buffers.
  307. clear(CLEAR_COLOR_DEPTH, Vector4(0.41f, 0.48f, 0.54f, 1.0f), 1.0f, 0);
  308. // Draw our scene, with separate passes for opaque and transparent objects.
  309. _scene->visit(this, &CharacterGame::drawScene, false);
  310. _scene->visit(this, &CharacterGame::drawScene, true);
  311. // Draw debug info (physics bodies, bounds, etc).
  312. switch (_drawDebug)
  313. {
  314. case 1:
  315. getPhysicsController()->drawDebug(_scene->getActiveCamera()->getViewProjectionMatrix());
  316. break;
  317. case 2:
  318. _scene->drawDebug(Scene::DEBUG_BOXES);
  319. break;
  320. case 3:
  321. _scene->drawDebug(Scene::DEBUG_SPHERES);
  322. break;
  323. }
  324. _gamepad->draw();
  325. // Draw FPS
  326. _font->start();
  327. char fps[32];
  328. sprintf(fps, "%d", getFrameRate());
  329. _font->drawText(fps, 5, 5, Vector4(1,1,0,1), 20);
  330. _font->finish();
  331. }
  332. void CharacterGame::keyEvent(Keyboard::KeyEvent evt, int key)
  333. {
  334. if (evt == Keyboard::KEY_PRESS)
  335. {
  336. switch (key)
  337. {
  338. case Keyboard::KEY_ESCAPE:
  339. exit();
  340. break;
  341. case Keyboard::KEY_W:
  342. case Keyboard::KEY_CAPITAL_W:
  343. _keyFlags |= NORTH;
  344. _keyFlags &= ~SOUTH;
  345. break;
  346. case Keyboard::KEY_S:
  347. case Keyboard::KEY_CAPITAL_S:
  348. _keyFlags |= SOUTH;
  349. _keyFlags &= ~NORTH;
  350. break;
  351. case Keyboard::KEY_A:
  352. case Keyboard::KEY_CAPITAL_A:
  353. _keyFlags |= WEST;
  354. _keyFlags &= ~EAST;
  355. break;
  356. case Keyboard::KEY_D:
  357. case Keyboard::KEY_CAPITAL_D:
  358. _keyFlags |= EAST;
  359. _keyFlags &= ~WEST;
  360. break;
  361. case Keyboard::KEY_B:
  362. _drawDebug++;
  363. if (_drawDebug > 3)
  364. _drawDebug = 0;
  365. break;
  366. case Keyboard::KEY_SPACE:
  367. jump();
  368. break;
  369. case Keyboard::KEY_SHIFT:
  370. _keyFlags |= RUNNING;
  371. break;
  372. case Keyboard::KEY_M:
  373. case Keyboard::KEY_CAPITAL_M:
  374. _wireframe = !_wireframe;
  375. break;
  376. case Keyboard::KEY_C:
  377. case Keyboard::KEY_CAPITAL_C:
  378. clone();
  379. break;
  380. }
  381. }
  382. else if (evt == Keyboard::KEY_RELEASE)
  383. {
  384. switch (key)
  385. {
  386. case Keyboard::KEY_W:
  387. case Keyboard::KEY_CAPITAL_W:
  388. _keyFlags &= ~NORTH;
  389. break;
  390. case Keyboard::KEY_S:
  391. case Keyboard::KEY_CAPITAL_S:
  392. _keyFlags &= ~SOUTH;
  393. break;
  394. case Keyboard::KEY_A:
  395. case Keyboard::KEY_CAPITAL_A:
  396. _keyFlags &= ~WEST;
  397. break;
  398. case Keyboard::KEY_D:
  399. case Keyboard::KEY_CAPITAL_D:
  400. _keyFlags &= ~EAST;
  401. break;
  402. case Keyboard::KEY_SHIFT:
  403. _keyFlags &= ~RUNNING;
  404. break;
  405. }
  406. }
  407. }
  408. void CharacterGame::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
  409. {
  410. // This should only be called if the gamepad did not handle the touch event.
  411. switch (evt)
  412. {
  413. case Touch::TOUCH_PRESS:
  414. {
  415. _rotateX = x;
  416. }
  417. break;
  418. case Touch::TOUCH_RELEASE:
  419. {
  420. _rotateX = 0;
  421. }
  422. break;
  423. case Touch::TOUCH_MOVE:
  424. {
  425. int deltaX = x - _rotateX;
  426. _rotateX = x;
  427. _character->getNode()->rotateY(-MATH_DEG_TO_RAD(deltaX * 0.5f));
  428. }
  429. break;
  430. default:
  431. break;
  432. }
  433. }
  434. bool CharacterGame::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
  435. {
  436. if (evt == Mouse::MOUSE_PRESS_RIGHT_BUTTON)
  437. {
  438. kick();
  439. return true;
  440. }
  441. return false;
  442. }
  443. void CharacterGame::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad)
  444. {
  445. switch(evt)
  446. {
  447. case Gamepad::CONNECTED_EVENT:
  448. case Gamepad::DISCONNECTED_EVENT:
  449. _gamepad = getGamepad(0);
  450. break;
  451. }
  452. }
  453. void CharacterGame::adjustCamera(float elapsedTime)
  454. {
  455. static float cameraOffset = 0.0f;
  456. PhysicsController* physics = getPhysicsController();
  457. Node* cameraNode = _scene->getActiveCamera()->getNode();
  458. // Reset camera
  459. if (cameraOffset != 0.0f)
  460. {
  461. cameraNode->translateForward(-cameraOffset);
  462. cameraOffset = 0.0f;
  463. }
  464. Vector3 cameraPosition = cameraNode->getTranslationWorld();
  465. Vector3 cameraDirection = cameraNode->getForwardVectorWorld();
  466. cameraDirection.normalize();
  467. // Get focal point of camera (use the resolved world location of the head joint as a focal point)
  468. Vector3 focalPoint(cameraPosition + (cameraDirection * CAMERA_FOCUS_DISTANCE));
  469. Vector3 oldPosition = cameraNode->getTranslationWorld();
  470. PhysicsController::HitResult result;
  471. PhysicsCollisionObject* occlusion = NULL;
  472. do
  473. {
  474. // Perform a ray test to check for camera collisions
  475. if (!physics->sweepTest(cameraNode->getCollisionObject(), focalPoint, &result) || result.object == _character)
  476. break;
  477. occlusion = result.object;
  478. // Step the camera closer to the focal point to resolve the occlusion
  479. float d = cameraNode->getTranslationWorld().distance(result.point);
  480. cameraNode->translateForward(d);
  481. cameraOffset += d;
  482. while (physics->sweepTest(cameraNode->getCollisionObject(), focalPoint, &result) && result.object == occlusion)
  483. {
  484. // Prevent the camera from getting too close to the character.
  485. // Without this check, it's possible for the camera to fly past the character
  486. // and essentially end up in an infinite loop here.
  487. if (cameraNode->getTranslationWorld().distanceSquared(focalPoint) <= 2.0f)
  488. return;
  489. cameraNode->translateForward(0.1f);
  490. cameraOffset += 0.1f;
  491. }
  492. } while (true);
  493. // If the character is closer than 10 world units to the camera, apply transparency to the character so he does not obstruct the view.
  494. if (occlusion)
  495. {
  496. float d = _scene->getActiveCamera()->getNode()->getTranslationWorld().distance(_characterNode->getTranslationWorld());
  497. float alpha = d < 10 ? (d * 0.1f) : 1.0f;
  498. _characterMeshNode->setTag("transparent", alpha < 1.0f ? "true" : NULL);
  499. _materialParameterAlpha->setValue(alpha);
  500. }
  501. else
  502. {
  503. _characterMeshNode->setTag("transparent", NULL);
  504. _materialParameterAlpha->setValue(1.0f);
  505. }
  506. }
  507. void CharacterGame::animationEvent(AnimationClip* clip, AnimationClip::Listener::EventType type)
  508. {
  509. if (clip == _kickClip && !_applyKick)
  510. {
  511. if (_hasBall)
  512. {
  513. _applyKick = true;
  514. releaseBall();
  515. }
  516. }
  517. else
  518. {
  519. clip->crossFade(_currentClip, 150);
  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. }