CharacterGame.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  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/arial.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. 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 debug info (physics bodies, bounds, etc).
  323. switch (_drawDebug)
  324. {
  325. case 1:
  326. getPhysicsController()->drawDebug(_scene->getActiveCamera()->getViewProjectionMatrix());
  327. break;
  328. case 2:
  329. _scene->drawDebug(Scene::DEBUG_BOXES);
  330. break;
  331. case 3:
  332. _scene->drawDebug(Scene::DEBUG_SPHERES);
  333. break;
  334. }
  335. _gamepad->draw();
  336. // Draw FPS
  337. _font->start();
  338. char fps[32];
  339. sprintf(fps, "%d", getFrameRate());
  340. _font->drawText(fps, 5, 5, Vector4(1,1,0,1), 20);
  341. _font->finish();
  342. }
  343. void CharacterGame::keyEvent(Keyboard::KeyEvent evt, int key)
  344. {
  345. if (evt == Keyboard::KEY_PRESS)
  346. {
  347. switch (key)
  348. {
  349. case Keyboard::KEY_ESCAPE:
  350. exit();
  351. break;
  352. case Keyboard::KEY_W:
  353. case Keyboard::KEY_CAPITAL_W:
  354. _keyFlags |= NORTH;
  355. _keyFlags &= ~SOUTH;
  356. break;
  357. case Keyboard::KEY_S:
  358. case Keyboard::KEY_CAPITAL_S:
  359. _keyFlags |= SOUTH;
  360. _keyFlags &= ~NORTH;
  361. break;
  362. case Keyboard::KEY_A:
  363. case Keyboard::KEY_CAPITAL_A:
  364. _keyFlags |= WEST;
  365. _keyFlags &= ~EAST;
  366. break;
  367. case Keyboard::KEY_D:
  368. case Keyboard::KEY_CAPITAL_D:
  369. _keyFlags |= EAST;
  370. _keyFlags &= ~WEST;
  371. break;
  372. case Keyboard::KEY_B:
  373. _drawDebug++;
  374. if (_drawDebug > 3)
  375. _drawDebug = 0;
  376. break;
  377. case Keyboard::KEY_SPACE:
  378. jump();
  379. break;
  380. case Keyboard::KEY_SHIFT:
  381. _keyFlags |= RUNNING;
  382. break;
  383. case Keyboard::KEY_M:
  384. case Keyboard::KEY_CAPITAL_M:
  385. _wireframe = !_wireframe;
  386. break;
  387. case Keyboard::KEY_C:
  388. case Keyboard::KEY_CAPITAL_C:
  389. clone();
  390. break;
  391. }
  392. }
  393. else if (evt == Keyboard::KEY_RELEASE)
  394. {
  395. switch (key)
  396. {
  397. case Keyboard::KEY_W:
  398. case Keyboard::KEY_CAPITAL_W:
  399. _keyFlags &= ~NORTH;
  400. break;
  401. case Keyboard::KEY_S:
  402. case Keyboard::KEY_CAPITAL_S:
  403. _keyFlags &= ~SOUTH;
  404. break;
  405. case Keyboard::KEY_A:
  406. case Keyboard::KEY_CAPITAL_A:
  407. _keyFlags &= ~WEST;
  408. break;
  409. case Keyboard::KEY_D:
  410. case Keyboard::KEY_CAPITAL_D:
  411. _keyFlags &= ~EAST;
  412. break;
  413. case Keyboard::KEY_SHIFT:
  414. _keyFlags &= ~RUNNING;
  415. break;
  416. }
  417. }
  418. }
  419. void CharacterGame::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
  420. {
  421. // This should only be called if the gamepad did not handle the touch event.
  422. switch (evt)
  423. {
  424. case Touch::TOUCH_PRESS:
  425. {
  426. _rotateX = x;
  427. }
  428. break;
  429. case Touch::TOUCH_RELEASE:
  430. {
  431. _rotateX = 0;
  432. }
  433. break;
  434. case Touch::TOUCH_MOVE:
  435. {
  436. int deltaX = x - _rotateX;
  437. _rotateX = x;
  438. _character->getNode()->rotateY(-MATH_DEG_TO_RAD(deltaX * 0.5f));
  439. }
  440. break;
  441. default:
  442. break;
  443. }
  444. }
  445. bool CharacterGame::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
  446. {
  447. if (evt == Mouse::MOUSE_PRESS_RIGHT_BUTTON)
  448. {
  449. kick();
  450. return true;
  451. }
  452. return false;
  453. }
  454. void CharacterGame::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad)
  455. {
  456. switch(evt)
  457. {
  458. case Gamepad::CONNECTED_EVENT:
  459. case Gamepad::DISCONNECTED_EVENT:
  460. _gamepad = getGamepad(0);
  461. break;
  462. }
  463. }
  464. void CharacterGame::adjustCamera(float elapsedTime)
  465. {
  466. static float cameraOffset = 0.0f;
  467. PhysicsController* physics = getPhysicsController();
  468. Node* cameraNode = _scene->getActiveCamera()->getNode();
  469. // Reset camera
  470. if (cameraOffset != 0.0f)
  471. {
  472. cameraNode->translateForward(-cameraOffset);
  473. cameraOffset = 0.0f;
  474. }
  475. Vector3 cameraPosition = cameraNode->getTranslationWorld();
  476. Vector3 cameraDirection = cameraNode->getForwardVectorWorld();
  477. cameraDirection.normalize();
  478. // Get focal point of camera (use the resolved world location of the head joint as a focal point)
  479. Vector3 focalPoint(cameraPosition + (cameraDirection * CAMERA_FOCUS_DISTANCE));
  480. Vector3 oldPosition = cameraNode->getTranslationWorld();
  481. PhysicsController::HitResult result;
  482. PhysicsCollisionObject* occlusion = NULL;
  483. do
  484. {
  485. // Perform a ray test to check for camera collisions
  486. if (!physics->sweepTest(cameraNode->getCollisionObject(), focalPoint, &result) || result.object == _character)
  487. break;
  488. occlusion = result.object;
  489. // Step the camera closer to the focal point to resolve the occlusion
  490. float d = cameraNode->getTranslationWorld().distance(result.point);
  491. cameraNode->translateForward(d);
  492. cameraOffset += d;
  493. while (physics->sweepTest(cameraNode->getCollisionObject(), focalPoint, &result) && result.object == occlusion)
  494. {
  495. // Prevent the camera from getting too close to the character.
  496. // Without this check, it's possible for the camera to fly past the character
  497. // and essentially end up in an infinite loop here.
  498. if (cameraNode->getTranslationWorld().distanceSquared(focalPoint) <= 2.0f)
  499. return;
  500. cameraNode->translateForward(0.1f);
  501. cameraOffset += 0.1f;
  502. }
  503. } while (true);
  504. // If the character is closer than 10 world units to the camera, apply transparency to the character so he does not obstruct the view.
  505. if (occlusion)
  506. {
  507. float d = _scene->getActiveCamera()->getNode()->getTranslationWorld().distance(_characterNode->getTranslationWorld());
  508. float alpha = d < 10 ? (d * 0.1f) : 1.0f;
  509. _characterMeshNode->setTag("transparent", alpha < 1.0f ? "true" : NULL);
  510. _materialParameterAlpha->setValue(alpha);
  511. }
  512. else
  513. {
  514. _characterMeshNode->setTag("transparent", NULL);
  515. _materialParameterAlpha->setValue(1.0f);
  516. }
  517. }
  518. void CharacterGame::animationEvent(AnimationClip* clip, AnimationClip::Listener::EventType type)
  519. {
  520. if (clip == _kickClip && !_applyKick)
  521. {
  522. if (_hasBall)
  523. {
  524. _applyKick = true;
  525. releaseBall();
  526. }
  527. }
  528. else
  529. {
  530. clip->crossFade(_currentClip, 150);
  531. }
  532. }
  533. void CharacterGame::clone()
  534. {
  535. Node* clone = _scene->findNode("boycharacter")->clone();
  536. Animation* cloneAnimation = clone->getAnimation();
  537. // Find the current clip and have the clone play that clip repeatedly.
  538. const char* clipId = _currentClip->getId();
  539. if (_jumpClip->isPlaying())
  540. clipId = _jumpClip->getId();
  541. AnimationClip* clip = cloneAnimation->getClip(clipId);
  542. clip->setRepeatCount(AnimationClip::REPEAT_INDEFINITE);
  543. clip->play();
  544. _scene->addNode(clone);
  545. clone->release();
  546. }
  547. void CharacterGame::collisionEvent(PhysicsCollisionObject::CollisionListener::EventType type,
  548. const PhysicsCollisionObject::CollisionPair& collisionPair,
  549. const Vector3& contactPointA,
  550. const Vector3& contactPointB)
  551. {
  552. // objectA -> basketball, only care about collisions between the physics character and the basketball.
  553. if (type == PhysicsCollisionObject::CollisionListener::COLLIDING && collisionPair.objectB == _character)
  554. _hasBall = true;
  555. }
  556. void CharacterGame::grabBall()
  557. {
  558. // Disables physics on the basketball, and increases the size of the character's collison object to include the basketball.
  559. _basketballNode->getCollisionObject()->setEnabled(false);
  560. PhysicsRigidBody::Parameters rbParams;
  561. rbParams.mass = 20.0f;
  562. Vector3 currentVelocity = _character->getCurrentVelocity();
  563. Node* boy = _character->getNode();
  564. boy->setCollisionObject(PhysicsCollisionObject::CHARACTER, PhysicsCollisionShape::capsule(2.9f, 6.0f, Vector3(0.0f, 3.0f, 0.0f), true), &rbParams);
  565. _character = static_cast<PhysicsCharacter*>(boy->getCollisionObject());
  566. _character->setMaxSlopeAngle(0.0f);
  567. _character->setMaxStepHeight(0.0f);
  568. _character->setVelocity(currentVelocity);
  569. }
  570. void CharacterGame::releaseBall()
  571. {
  572. // Decreases the size of the character's collision object and re-enables physics simulation on the basketball.
  573. PhysicsRigidBody::Parameters rbParams;
  574. rbParams.mass = 20.0f;
  575. Vector3 velocity = _character->getCurrentVelocity();
  576. Node* boy = _character->getNode();
  577. boy->setCollisionObject(PhysicsCollisionObject::CHARACTER, PhysicsCollisionShape::capsule(1.2f, 6.0f, Vector3(0.0f, 3.0f, 0.0f), true), &rbParams);
  578. _character = static_cast<PhysicsCharacter*>(boy->getCollisionObject());
  579. _character->setVelocity(velocity);
  580. _character->setMaxSlopeAngle(0.0f);
  581. _character->setMaxStepHeight(0.0f);
  582. PhysicsRigidBody* basketball = (PhysicsRigidBody*) _basketballNode->getCollisionObject();
  583. basketball->setEnabled(true);
  584. }