VActorPhysicsController.cpp
Engine/source/Verve/VActor/VActorPhysicsController.cpp
Public Variables
Detailed Description
Public Variables
const U32 sCollisionMask
const U32 sGroundCollisionMask
const U32 sMoveCollisionMask
1 2//----------------------------------------------------------------------------- 3// Verve 4// Copyright (C) 2014 - Violent Tulip 5// 6// Permission is hereby granted, free of charge, to any person obtaining a copy 7// of this software and associated documentation files (the "Software"), to 8// deal in the Software without restriction, including without limitation the 9// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10// sell copies of the Software, and to permit persons to whom the Software is 11// furnished to do so, subject to the following conditions: 12// 13// The above copyright notice and this permission notice shall be included in 14// all copies or substantial portions of the Software. 15// 16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22// IN THE SOFTWARE. 23//----------------------------------------------------------------------------- 24#include "VActorPhysicsController.h" 25 26#include "VActor.h" 27#include "VActorData.h" 28#include "VActorPhysicsStates.h" 29 30#include "Verve/VPath/VPath.h" 31 32#include "collision/clippedPolyList.h" 33#include "collision/earlyOutPolyList.h" 34#include "collision/extrudedPolyList.h" 35#include "core/stream/bitStream.h" 36#include "environment/waterObject.h" 37 38//----------------------------------------------------------------------------- 39 40static const U32 sGroundCollisionMask = ( StaticObjectType | StaticShapeObjectType | TerrainObjectType ); 41static const U32 sMoveCollisionMask = ( PlayerObjectType | VehicleObjectType ); 42static const U32 sCollisionMask = ( sGroundCollisionMask | sMoveCollisionMask ); 43 44//----------------------------------------------------------------------------- 45 46VActorPhysicsController::VActorPhysicsController( void ) : 47 mObject( NULL ), 48 mMountedPath( NULL ), 49 mPhysicsState( 0 ), 50 mControlState( k_NullControlState ), 51 mMoveState( k_NullMove ), 52 mVelocity( VectorF::Zero ), 53 mGravity( 0.f, 0.f, -9.8f ), 54 mOnGround(false) 55{ 56 // Void. 57} 58 59VActorPhysicsController::~VActorPhysicsController( void ) 60{ 61 // Clear Object. 62 clearObject(); 63} 64 65 66 67 68//----------------------------------------------------------------------------- 69// 70// Initialisation Methods. 71// 72//----------------------------------------------------------------------------- 73 74//----------------------------------------------------------------------------- 75// 76// VActorPhysicsController::initPhysicsController(); 77// 78// Initialise the physics table and setup the interface between the Controller 79// and the reference object. 80// 81//----------------------------------------------------------------------------- 82bool VActorPhysicsController::initPhysicsController( VActor *pObject ) 83{ 84 // Valid Object? 85 if ( !pObject ) 86 { 87 // Assert & Quit. 88 AssertFatal( false, "VActorPhysicsController::initPhysicsController() - Invalid Object Specified." ); 89 return false; 90 } 91 92 // Set Object. 93 mObject = pObject; 94 // Register for Actor Events. 95 mObject->getEventSignal().notify( this, &VActorPhysicsController::onActorEvent ); 96 97 // Set Table's Reference. 98 mPhysicsStateTable.setObject( pObject ); 99 100 // Init the Convex Box. 101 mConvex.init( pObject ); 102 103 // Reset Interp. 104 mInterpController.resetDelta( pObject->getTransform() ); 105 106 // Validate. 107 return initPhysicsTable(); 108} 109 110//----------------------------------------------------------------------------- 111// 112// VActorPhysicsController::initPhysicsTable(); 113// 114// Register the available physics states which this controller may utilize. 115// 116//----------------------------------------------------------------------------- 117bool VActorPhysicsController::initPhysicsTable( void ) 118{ 119 // Valid Object? 120 if ( !isValidObject() ) 121 { 122 // No, Quit Now. 123 return false; 124 } 125 126 // Clear the Table. 127 mPhysicsStateTable.clear(); 128 129 // Fetch Sequence List. 130 VActorData::tPhysicsStateVector *stateList = getObjectDataBlock()->getPhysicsStateList(); 131 132 // Initialise the Physics States. 133 for ( VActorData::tPhysicsStateVector::iterator itr = stateList->begin(); 134 itr != stateList->end(); 135 itr++ ) 136 { 137 // Fetch Sequence Definition. 138 const VActorData::sPhysicsState &physState = ( *itr ); 139 140 // Valid State? 141 if ( physState.State ) 142 { 143 // Register State. 144 mPhysicsStateTable.registerState( physState.State, physState.Priority ); 145 } 146 } 147 148 // Sort the Table. 149 mPhysicsStateTable.sort(); 150 151 // Valid. 152 return true; 153} 154 155 156 157 158//----------------------------------------------------------------------------- 159// 160// Accessor Methods 161// 162//----------------------------------------------------------------------------- 163 164//----------------------------------------------------------------------------- 165// 166// VActorPhysicsController::isValidObject(); 167// 168// Do we have a valid reference object? 169// 170//----------------------------------------------------------------------------- 171bool VActorPhysicsController::isValidObject( void ) 172{ 173 return ( mObject && mObject->getDataBlock() ); 174} 175 176//----------------------------------------------------------------------------- 177// 178// VActorPhysicsController::getObject(); 179// 180// Return the reference object. 181// 182//----------------------------------------------------------------------------- 183VActor *VActorPhysicsController::getObject( void ) 184{ 185 return mObject; 186} 187 188//----------------------------------------------------------------------------- 189// 190// VActorPhysicsController::getObjectDataBlock(); 191// 192// Get the Actor Data for the reference object. 193// 194//----------------------------------------------------------------------------- 195VActorData *VActorPhysicsController::getObjectDataBlock( void ) 196{ 197 // Valid Object? 198 if ( !mObject ) 199 { 200 // No. 201 return NULL; 202 } 203 204 // Return DataBlock. 205 return mObject->getDataBlock(); 206} 207 208//----------------------------------------------------------------------------- 209// 210// VActorPhysicsController::clearObject(); 211// 212// Clear the reference object. Note that this should *never* be called outside 213// of the controller's destructor! 214// 215//----------------------------------------------------------------------------- 216void VActorPhysicsController::clearObject( void ) 217{ 218 // Valid Object? 219 if ( !mObject ) 220 { 221 // No. 222 return; 223 } 224 225 // Clear Notify. 226 mObject->getEventSignal().remove( this, &VActorPhysicsController::onActorEvent ); 227 228 // Clear Object. 229 mObject = NULL; 230 231 // Clear Table. 232 mPhysicsStateTable.setObject( NULL ); 233 mPhysicsStateTable.clear(); 234} 235 236//----------------------------------------------------------------------------- 237// 238// VActorPhysicsController::getControlState(); 239// 240// Get the current Control State. 241// 242//----------------------------------------------------------------------------- 243const U32 VActorPhysicsController::getControlState( void ) 244{ 245 return mControlState; 246} 247 248//----------------------------------------------------------------------------- 249// 250// VActorPhysicsController::clearControlState( pControlState ); 251// 252// Clear the Control State of a particular mask. 253// 254//----------------------------------------------------------------------------- 255void VActorPhysicsController::clearControlState( const U32 &pControlState ) 256{ 257 mControlState &= ( ~pControlState ); 258} 259 260//----------------------------------------------------------------------------- 261// 262// VActorPhysicsController::setControlState( pControlState ); 263// 264// Set the Control State. 265// 266//----------------------------------------------------------------------------- 267void VActorPhysicsController::setControlState( const U32 &pControlState ) 268{ 269 mControlState = pControlState; 270} 271 272//----------------------------------------------------------------------------- 273// 274// VActorPhysicsController::isMoving(); 275// 276// Is the Actor currently Moving? 277// 278//----------------------------------------------------------------------------- 279const bool VActorPhysicsController::isMoving( void ) 280{ 281 return ( !mIsZero( getVelocity().lenSquared() ) ); 282} 283 284//----------------------------------------------------------------------------- 285// 286// VActorPhysicsController::isMoving( pMoveState ); 287// 288// Is the Actor currently moving with the desired state? 289// 290//----------------------------------------------------------------------------- 291const bool VActorPhysicsController::isMoving( const U32 &pMoveState ) 292{ 293 // Moving? 294 return ( ( getMoveState() & pMoveState ) && isMoving() ); 295} 296 297//----------------------------------------------------------------------------- 298// 299// VActorPhysicsController::getMoveState(); 300// 301// Get the current Move State. 302// 303//----------------------------------------------------------------------------- 304const U32 VActorPhysicsController::getMoveState( void ) 305{ 306 // Return Move State. 307 return mMoveState; 308} 309 310//----------------------------------------------------------------------------- 311// 312// VActorPhysicsController::clearMoveState( pMoveState ); 313// 314// Clear the Move State of a particular mask. 315// 316//----------------------------------------------------------------------------- 317void VActorPhysicsController::clearMoveState( const U32 &pMoveState ) 318{ 319 // Set Move State. 320 mMoveState &= ( ~pMoveState ); 321} 322 323//----------------------------------------------------------------------------- 324// 325// VActorPhysicsController::setMoveState( pMoveState ); 326// 327// Set the Move State. 328// 329//----------------------------------------------------------------------------- 330void VActorPhysicsController::setMoveState( const U32 &pMoveState ) 331{ 332 // Set Move State. 333 mMoveState = pMoveState; 334} 335 336//----------------------------------------------------------------------------- 337// 338// VActorPhysicsController::isPathing(); 339// 340// Is the Actor Pathing? 341// 342//----------------------------------------------------------------------------- 343const bool VActorPhysicsController::isPathing( void ) 344{ 345 // Valid Object? 346 if ( !isValidObject() ) 347 { 348 // No. 349 return false; 350 } 351 352 return ( mMountedPath != NULL ); 353} 354 355//----------------------------------------------------------------------------- 356// 357// VActorPhysicsController::getPathObject(); 358// 359// Get the Path Object the Actor is mounted to. 360// 361//----------------------------------------------------------------------------- 362VPath *VActorPhysicsController::getPathObject( void ) 363{ 364 // Valid Object? 365 if ( !isValidObject() ) 366 { 367 // No. 368 return NULL; 369 } 370 371 return mMountedPath; 372} 373 374//----------------------------------------------------------------------------- 375// 376// VActorPhysicsController::isOnGround(); 377// 378// Is the Actor On the Ground? 379// 380//----------------------------------------------------------------------------- 381const bool VActorPhysicsController::isOnGround( void ) 382{ 383 // Valid Objects? 384 if ( !isValidObject() ) 385 { 386 // No. 387 return false; 388 } 389 390 // On Ground? 391 return ( mOnGround && mGroundObject && !isInWater() ); 392} 393 394//----------------------------------------------------------------------------- 395// 396// VActorPhysicsController::isInAir(); 397// 398// Is the Actor in the Air? 399// 400//----------------------------------------------------------------------------- 401const bool VActorPhysicsController::isInAir( void ) 402{ 403 // Valid Objects? 404 if ( !isValidObject() ) 405 { 406 // No. 407 return false; 408 } 409 410 // In Air? 411 return ( !isOnGround() && !isInWater() ); 412} 413 414//----------------------------------------------------------------------------- 415// 416// VActorPhysicsController::isInWater(); 417// 418// Is the Actor in the Water? 419// 420//----------------------------------------------------------------------------- 421const bool VActorPhysicsController::isInWater( void ) 422{ 423 // Valid Objects? 424 if ( !isValidObject() || !getWaterObject() ) 425 { 426 // No. 427 return false; 428 } 429 430 // Submerged? 431 return ( ( mObject->getWaterCoverage() + POINT_EPSILON ) >= mObject->getDataBlock()->getSumbergeCoverage() ); 432} 433 434//----------------------------------------------------------------------------- 435// 436// VActorPhysicsController::getWaterObject(); 437// 438// Get the current Water Object the Actor is in. 439// 440//----------------------------------------------------------------------------- 441WaterObject *VActorPhysicsController::getWaterObject( void ) 442{ 443 // Valid Object? 444 if ( !isValidObject() ) 445 { 446 // No. 447 return NULL; 448 } 449 450 return mObject->getCurrentWaterObject(); 451} 452 453//----------------------------------------------------------------------------- 454// 455// VActorPhysicsController::getTransform(); 456// 457// Get the Actor's Transform. 458// 459//----------------------------------------------------------------------------- 460MatrixF VActorPhysicsController::getTransform( void ) 461{ 462 // Valid Object? 463 if ( !isValidObject() ) 464 { 465 // No. 466 return MatrixF::Identity; 467 } 468 469 // Return Transform. 470 return mObject->getTransform(); 471} 472 473//----------------------------------------------------------------------------- 474// 475// VActorPhysicsController::setTransform( pTransform ); 476// 477// Set the Actor's Transform. 478// 479//----------------------------------------------------------------------------- 480void VActorPhysicsController::setTransform( const MatrixF &pTransform ) 481{ 482 // Valid Object? 483 if ( !isValidObject() ) 484 { 485 // No. 486 return; 487 } 488 489 // Apply Transform. 490 mObject->setTransform( pTransform ); 491} 492 493//----------------------------------------------------------------------------- 494// 495// VActorPhysicsController::getPosition(); 496// 497// Get the Actor's Position. 498// 499//----------------------------------------------------------------------------- 500Point3F VActorPhysicsController::getPosition( void ) 501{ 502 // Valid Object? 503 if ( !isValidObject() ) 504 { 505 // No. 506 return Point3F::Zero; 507 } 508 509 // Return Position. 510 return mObject->getPosition(); 511} 512 513//----------------------------------------------------------------------------- 514// 515// VActorPhysicsController::setPosition( pPosition ); 516// 517// Set the Actor's Position. 518// 519//----------------------------------------------------------------------------- 520void VActorPhysicsController::setPosition( const Point3F &pPosition ) 521{ 522 // Valid Object? 523 if ( !isValidObject() ) 524 { 525 // No. 526 return; 527 } 528 529 // Apply Position. 530 mObject->setPosition( pPosition ); 531} 532 533//----------------------------------------------------------------------------- 534// 535// VActorPhysicsController::applyGravity( pElapsedTime ); 536// 537// Apply gravity for the elapsed period. 538// 539//----------------------------------------------------------------------------- 540void VActorPhysicsController::applyGravity( const F32 &pElapsedTime ) 541{ 542 // Get Velocity. 543 VectorF velocity = getVelocity(); 544 // Add Tick Gravity. 545 velocity += getGravity() * pElapsedTime; 546 // Apply. 547 setVelocity( velocity ); 548} 549 550//----------------------------------------------------------------------------- 551// 552// VActorPhysicsController::getVelocity(); 553// 554// Get the Actor's Velocity. 555// 556//----------------------------------------------------------------------------- 557VectorF VActorPhysicsController::getVelocity( void ) 558{ 559 // Valid Object? 560 if ( !isValidObject() ) 561 { 562 // No. 563 return VectorF::Zero; 564 } 565 566 // Return Velocity. 567 return mVelocity; 568} 569 570//----------------------------------------------------------------------------- 571// 572// VActorPhysicsController::setVelocity( pVelocity ); 573// 574// Set the Actor's Velocity. 575// 576//----------------------------------------------------------------------------- 577void VActorPhysicsController::setVelocity( const VectorF &pVelocity ) 578{ 579 // Set Velocity. 580 mVelocity = pVelocity; 581} 582 583 584 585 586//----------------------------------------------------------------------------- 587// 588// Physics Methods 589// 590//----------------------------------------------------------------------------- 591 592//----------------------------------------------------------------------------- 593// 594// VActorPhysicsController::update( pDelta, pMove ); 595// 596// ... 597// 598//----------------------------------------------------------------------------- 599void VActorPhysicsController::update( const F32 &pDelta, const Move *pMove ) 600{ 601 // Valid Objects? 602 if ( !isValidObject() ) 603 { 604 // No, Quit Now. 605 return; 606 } 607 608 // Pre-tick Update. 609 preTickUpdate( pDelta ); 610 611 // Integrate Tick Update. 612 integrateTickUpdate( pDelta, pMove ); 613 614 // Post-tick Update. 615 postTickUpdate( pDelta ); 616} 617 618//----------------------------------------------------------------------------- 619// 620// VActorPhysicsController::preTickUpdate( pDelta ); 621// 622// ... 623// 624//----------------------------------------------------------------------------- 625void VActorPhysicsController::preTickUpdate( const F32 &pDelta ) 626{ 627 // Pop Delta. 628 mInterpController.popDelta(); 629 630 switch( mControlState ) 631 { 632 case k_PathControlState : 633 { 634 AssertFatal( isPathing(), "VActorPhysicsController::preTickUpdate() - Invalid Path State." ); 635 636 // Fetch Mount Velocity. 637 const VectorF &mountVelocity = mMountedPath->getMountVelocity( mObject->getMountNode() ); 638 639 // Use X & Y Velocity. 640 VectorF velocity = getVelocity(); 641 velocity.x = mountVelocity.x; 642 velocity.y = mountVelocity.y; 643 644 // Apply Updates. 645 setVelocity( velocity ); 646 647 } break; 648 } 649 650 // Update Move State. 651 updateMoveState(); 652} 653 654//----------------------------------------------------------------------------- 655// 656// VActorPhysicsController::integrateTickUpdate( pDelta, pMove ); 657// 658// ... 659// 660//----------------------------------------------------------------------------- 661void VActorPhysicsController::integrateTickUpdate( const F32 &pDelta, const Move *pMove ) 662{ 663 // Update Collision Set. 664 updateWorkingCollisionSet(); 665 // Ground Ground Status. 666 updateGroundStatus(); 667 668 // Execute Physics Table. 669 VActorPhysicsState *physState = dynamic_cast<VActorPhysicsState*>( mPhysicsStateTable.execute() ); 670 // Assert. 671 AssertFatal( physState, "VActorPhysicsController::update() - Invalid Physics State in the Table." ); 672 673 // Process the State. 674 physState->processTick( mObject, pDelta, pMove ); 675 676 // Process Collisions. 677 processCollisions(); 678} 679 680//----------------------------------------------------------------------------- 681// 682// VActorPhysicsController::postTickUpdate( pDelta ); 683// 684// ... 685// 686//----------------------------------------------------------------------------- 687void VActorPhysicsController::postTickUpdate( const F32 &pDelta ) 688{ 689 switch( mControlState ) 690 { 691 case k_PathControlState : 692 { 693 AssertFatal( isPathing(), "VActorPhysicsController::postTickUpdate() - Invalid Path State." ); 694 695 // Fetch Mount Transform. 696 MatrixF transform; 697 mMountedPath->getMountTransform( mObject->getMountNode(), getTransform(), &transform ); 698 // Fetch Mount Position. 699 const Point3F &mountPosition = transform.getPosition(); 700 701 // Update X & Y Position. 702 Point3F position = getPosition(); 703 position.x = mountPosition.x; 704 position.y = mountPosition.y; 705 706 // In Water? 707 bool underWater = false; 708 if ( isInWater() ) 709 { 710 // Fetch Body of Water. 711 WaterObject *waterBody = getWaterObject(); 712 713 // Fetch Surface Position. 714 const F32 &waterSurfacePosition = waterBody->getSurfaceHeight( Point2F( position.x, position.y ) ); 715 // Fetch Submersion Position. 716 const F32 sumbersionPosition = waterSurfacePosition - ( mObject->getWorldBox().len_z() * mObject->getDataBlock()->getSumbergeCoverage() ); 717 718 // Choose a Z Value. 719 // Note: This is done so that the Actor will either path under the 720 // water, or it will swim along the water's surface. 721 position.z = getMin( mountPosition.z, sumbersionPosition ); 722 723 // Under Water? 724 underWater = ( position.z < sumbersionPosition ); 725 } 726 727 // Under Water? 728 if ( !underWater ) 729 { 730 // Fetch Y Column. 731 VectorF forwardVector; 732 transform.getColumn( 1, &forwardVector ); 733 734 // Determine Angle. 735 const F32 &angle = -mAtan2( -forwardVector.x, forwardVector.y ); 736 737 // Reset Transform. 738 transform.set( EulerF( 0.f, 0.f, angle ) ); 739 740 // In the air? 741 if ( !isOnGround() ) 742 { 743 // Apply z-axis force. 744 position.z += ( getVelocity().z * pDelta ); 745 } 746 } 747 748 // Update Transform. 749 transform.setPosition( position ); 750 751 // Apply Update. 752 setTransform( transform ); 753 754 } break; 755 756 default : 757 { 758 // Fetch Transform. 759 MatrixF transform = getTransform(); 760 761 // Determine the Post-Tick Position. 762 Point3F postTickPosition = getPosition() + ( getVelocity() * pDelta ); 763 // Set the Post Tick Position. 764 transform.setPosition( postTickPosition ); 765 766 // Apply the Transform. 767 setTransform( transform ); 768 769 } break; 770 } 771 772 // Push Delta. 773 mInterpController.pushDelta( getTransform() ); 774} 775 776 777 778 779//----------------------------------------------------------------------------- 780// 781// VActorPhysicsController::interpolateTick( pDelta ); 782// 783// ... 784// 785//----------------------------------------------------------------------------- 786void VActorPhysicsController::interpolateTick( const F32 &pDelta ) 787{ 788 // Fetch Interpolated Transform. 789 const MatrixF transform = mInterpController.getTransform( pDelta ); 790 // Apply Render Transform. 791 mObject->setRenderTransform( transform ); 792} 793 794 795 796 797//----------------------------------------------------------------------------- 798// 799// VActorPhysicsController::updateWorkingCollisionSet(); 800// 801// ... 802// 803//----------------------------------------------------------------------------- 804void VActorPhysicsController::updateWorkingCollisionSet() 805{ 806 // Contstruct Bounding Box. 807 const Box3F boundingBox = mConvex.getBoundingBox( getTransform(), mObject->getScale() ); 808 809 // Determine Sweep Vector. 810 const VectorF sweepVector = ( getVelocity() * TickSec ); 811 812 // Construct Swept Box. 813 Box3F sweptBox = boundingBox; 814 sweptBox.minExtents.setMin( boundingBox.minExtents + sweepVector ); 815 sweptBox.maxExtents.setMax( boundingBox.maxExtents + sweepVector ); 816 817 // Update Collision List. 818 mObject->disableCollision(); 819 mConvex.updateWorkingList( sweptBox, sCollisionMask ); 820 mObject->enableCollision(); 821} 822 823 824 825 826//----------------------------------------------------------------------------- 827// 828// VActorPhysicsController::updateMoveState(); 829// 830// ... 831// 832//----------------------------------------------------------------------------- 833void VActorPhysicsController::updateMoveState( void ) 834{ 835 switch( mControlState ) 836 { 837 case k_PathControlState : 838 { 839 AssertFatal( isPathing(), "VActorPhysicsController::updateMoveState() - Invalid Path State." ); 840 841 // Update Move State. 842 VPathObject *pathObject = mMountedPath->getPathObject( mObject ); 843 if ( !pathObject->isActive() ) 844 { 845 // Idle. 846 setMoveState( k_NullMove ); 847 } 848 else 849 { 850 // Set Movement Direction. 851 setMoveState( ( pathObject->isForward() ) ? k_ForwardMove : k_BackwardMove ); 852 } 853 854 } break; 855 856 default : 857 { 858 // Set Idle. 859 setMoveState( k_NullMove ); 860 861 } break; 862 } 863} 864 865 866 867 868//----------------------------------------------------------------------------- 869// 870// VActorPhysicsController::clearGroundStatus(); 871// 872// ... 873// 874//----------------------------------------------------------------------------- 875void VActorPhysicsController::clearGroundStatus( void ) 876{ 877 // Clear Grounding. 878 mOnGround = false; 879 mGroundObject = NULL; 880 mGroundNormal.zero(); 881} 882 883//----------------------------------------------------------------------------- 884// 885// VActorPhysicsController::updateGroundStatus(); 886// 887// ... 888// 889//----------------------------------------------------------------------------- 890void VActorPhysicsController::updateGroundStatus( void ) 891{ 892 // Submerged? 893 if ( isInWater() ) 894 { 895 // Clear Ground Status. 896 clearGroundStatus(); 897 return; 898 } 899 900 // Check for Grounding. 901 SceneObject *groundObject; 902 Point3F groundPoint; 903 VectorF groundNormal; 904 if ( !findGroundContact( groundObject, groundPoint, groundNormal ) ) 905 { 906 // Clear Ground Status. 907 clearGroundStatus(); 908 return; 909 } 910 911 // Tidy up the Contact Position. 912 // Note: This basically "clamps" the Actor to the surface of the ground 913 // object. 914 const Point3F objPosition = getPosition(); 915 setPosition( objPosition - Point3F( 0.f, 0.f, ( objPosition.z - groundPoint.z ) ) ); 916 917 // Clear Z-Axis Velocity. 918 mVelocity.z = 0.f; 919 920 // Store Details. 921 mOnGround = true; 922 mGroundObject = groundObject; 923 mGroundNormal = groundNormal; 924} 925 926//----------------------------------------------------------------------------- 927// 928// VActorPhysicsController::findGroundContact( pContactObject, pContactPoint, pContactNormal ); 929// 930// ... 931// 932//----------------------------------------------------------------------------- 933bool VActorPhysicsController::findGroundContact( SceneObject *&pContactObject, Point3F &pContactPoint, VectorF &pContactNormal ) 934{ 935 // Setup Collision List. 936 static CollisionList sCollisionList; 937 sCollisionList.clear(); 938 939 static Polyhedron sBoxPolyhedron; 940 static ExtrudedPolyList sExtrudedPolyList; 941 942 // Fetch Max Step Height. 943 const F32 stepHeight = mObject->getDataBlock()->getMaxStepHeight(); 944 945 // Determine Positions. 946 const Point3F preTickPosition = getPosition() + Point3F( 0.f, 0.f, stepHeight ); 947 const VectorF preTickVelocity = getVelocity() + mGravity - VectorF( 0.f, 0.f, stepHeight / TickSec ); 948 const Point3F postTickPosition = preTickPosition + ( preTickVelocity * TickSec ); 949 const VectorF postTickVector = postTickPosition - preTickPosition; 950 951 // Construct Scaled Box. 952 Box3F scaledBox = mObject->getObjBox(); 953 scaledBox.minExtents.convolve( mObject->getScale() ); 954 scaledBox.maxExtents.convolve( mObject->getScale() ); 955 956 // Setup Polyherdron. 957 MatrixF collisionMatrix( true ); 958 collisionMatrix.setPosition( preTickPosition ); 959 sBoxPolyhedron.buildBox( collisionMatrix, scaledBox ); 960 961 // Setup Extruded Poly List. 962 sExtrudedPolyList.extrude( sBoxPolyhedron, postTickVector ); 963 sExtrudedPolyList.setVelocity( preTickVelocity ); 964 sExtrudedPolyList.setCollisionList( &sCollisionList ); 965 966 // Construct World Convex Box & Adjust for Sweep. 967 Box3F convexBox = scaledBox; 968 getTransform().mul( convexBox ); 969 convexBox.minExtents += postTickVector; 970 convexBox.maxExtents += postTickVector; 971 972 // Build List of Contacts. 973 CollisionWorkingList &rList = mConvex.getWorkingList(); 974 for ( CollisionWorkingList *pList = rList.wLink.mNext; pList != &rList; pList = pList->wLink.mNext ) 975 { 976 Convex *convexShape = pList->mConvex; 977 978 // Ground Object? 979 if ( !( convexShape->getObject()->getTypeMask() & sGroundCollisionMask ) ) 980 { 981 // No, Continue. 982 continue; 983 } 984 985 // Overlap? 986 const Box3F &collisionConvexBox = convexShape->getBoundingBox(); 987 if ( convexBox.isOverlapped( collisionConvexBox ) ) 988 { 989 // Build Contact Information. 990 convexShape->getPolyList( &sExtrudedPolyList ); 991 } 992 } 993 994 // Valid Collision? 995 if ( sCollisionList.getCount() == 0 || sCollisionList.getTime() < 0.f || sCollisionList.getTime() > 1.f ) 996 { 997 // No, Quit Now. 998 return false; 999 } 1000 1001 // Use First Collision. 1002 Collision *collision = &sCollisionList[0]; 1003 1004 // More Collisions? 1005 if ( sCollisionList.getCount() > 1 ) 1006 { 1007 // Check for Better Contacts. 1008 for ( Collision *cp = ( collision + 1 ); cp != ( collision + sCollisionList.getCount() ); cp++ ) 1009 { 1010 if ( cp->faceDot > collision->faceDot ) 1011 { 1012 // Use this One. 1013 collision = cp; 1014 } 1015 } 1016 } 1017 1018 // Set Properties. 1019 pContactObject = collision->object; 1020 //pContactPoint = collision->point; 1021 pContactPoint = ( preTickPosition + ( preTickVelocity * TickSec * sCollisionList.getTime() ) ); 1022 pContactNormal = collision->normal; 1023 1024 // Valid Contact. 1025 return true; 1026} 1027 1028 1029 1030 1031//----------------------------------------------------------------------------- 1032// 1033// VActorPhysicsController::processCollisions(); 1034// 1035// ... 1036// 1037//----------------------------------------------------------------------------- 1038void VActorPhysicsController::processCollisions( void ) 1039{ 1040 // Find & Resolve Collisions. 1041 Collision *collision; 1042 if ( findCollision( collision ) ) 1043 { 1044 // Solve the Collision. 1045 solveCollision( collision ); 1046 } 1047} 1048 1049//----------------------------------------------------------------------------- 1050// 1051// VActorPhysicsController::findCollision( pCollision ); 1052// 1053// ... 1054// 1055//----------------------------------------------------------------------------- 1056bool VActorPhysicsController::findCollision( Collision *&pCollision ) 1057{ 1058 // Setup Collision List. 1059 static CollisionList sCollisionList; 1060 sCollisionList.clear(); 1061 1062 static Polyhedron sBoxPolyhedron; 1063 static ExtrudedPolyList sExtrudedPolyList; 1064 1065 // Determine Positions. 1066 const Point3F preTickPosition = getPosition(); 1067 const VectorF preTickVelocity = getVelocity(); 1068 const Point3F postTickPosition = preTickPosition + ( preTickVelocity * TickSec ); 1069 const VectorF postTickVector = postTickPosition - preTickPosition; 1070 1071 // Construct Scaled Box. 1072 Box3F scaledBox = mObject->getObjBox(); 1073 scaledBox.minExtents.convolve( mObject->getScale() ); 1074 scaledBox.maxExtents.convolve( mObject->getScale() ); 1075 1076 // Setup Polyherdron. 1077 MatrixF collisionMatrix( true ); 1078 collisionMatrix.setPosition( preTickPosition ); 1079 sBoxPolyhedron.buildBox( collisionMatrix, scaledBox ); 1080 1081 // Setup Extruded Poly List. 1082 sExtrudedPolyList.extrude( sBoxPolyhedron, postTickVector ); 1083 sExtrudedPolyList.setVelocity( preTickVelocity ); 1084 sExtrudedPolyList.setCollisionList( &sCollisionList ); 1085 1086 // Construct World Convex Box & Adjust for Sweep. 1087 Box3F convexBox = scaledBox; 1088 getTransform().mul( convexBox ); 1089 convexBox.minExtents += postTickVector; 1090 convexBox.maxExtents += postTickVector; 1091 1092 // Determine the Collision Mask. 1093 const U32 collisionMask = ( isInWater() ) ? ( sGroundCollisionMask | sMoveCollisionMask ) : sMoveCollisionMask; 1094 1095 // Build List of Contacts. 1096 CollisionWorkingList &rList = mConvex.getWorkingList(); 1097 for ( CollisionWorkingList *pList = rList.wLink.mNext; pList != &rList; pList = pList->wLink.mNext ) 1098 { 1099 Convex *convexShape = pList->mConvex; 1100 1101 // Valid Collision Target? 1102 if ( !( convexShape->getObject()->getTypeMask() & collisionMask ) ) 1103 { 1104 // No, Continue. 1105 continue; 1106 } 1107 1108 // Overlap? 1109 const Box3F &collisionConvexBox = convexShape->getBoundingBox(); 1110 if ( convexBox.isOverlapped( collisionConvexBox ) ) 1111 { 1112 // Build Contact Information. 1113 convexShape->getPolyList( &sExtrudedPolyList ); 1114 } 1115 } 1116 1117 // Valid Collision? 1118 if ( sCollisionList.getCount() == 0 || sCollisionList.getTime() > 1.f ) 1119 { 1120 // No, Quit Now. 1121 return false; 1122 } 1123 1124 // Use First Collision. 1125 Collision *collision = &sCollisionList[0]; 1126 1127 // More Collisions? 1128 if ( sCollisionList.getCount() > 1 ) 1129 { 1130 // Check for Better Contacts. 1131 for ( Collision *cp = ( collision + 1 ); cp != ( collision + sCollisionList.getCount() ); cp++ ) 1132 { 1133 if ( cp->faceDot > collision->faceDot ) 1134 { 1135 // Use this One. 1136 collision = cp; 1137 } 1138 } 1139 } 1140 1141 // Store Reference. 1142 pCollision = collision; 1143 1144 // Valid Collision. 1145 return true; 1146} 1147 1148//----------------------------------------------------------------------------- 1149// 1150// VActorPhysicsController::solveCollision( pCollision ); 1151// 1152// ... 1153// 1154//----------------------------------------------------------------------------- 1155void VActorPhysicsController::solveCollision( Collision *pCollision ) 1156{ 1157 // Fetch Velocity. 1158 VectorF velocity = getVelocity(); 1159 // Resolve Collision. 1160 velocity -= ( pCollision->normal * mDot( getVelocity(), pCollision->normal ) ); 1161 1162 // Pathing? 1163 if ( isPathing() ) 1164 { 1165 // Clear X & Y Velocity Adjustments. 1166 // Note: This means that any collisions made during pathing will not 1167 // be solved, unless they only affect Z position. It is up to the 1168 // user to construct Paths which avoid obsticles! 1169 velocity.x = velocity.y = 0.f; 1170 } 1171 1172 // Set Velocity. 1173 setVelocity( velocity ); 1174} 1175 1176 1177 1178 1179//----------------------------------------------------------------------------- 1180// 1181// Update Methods 1182// 1183//----------------------------------------------------------------------------- 1184 1185//----------------------------------------------------------------------------- 1186// 1187// VActorPhysicsController::onActorEvent( pEvent ); 1188// 1189// ... 1190// 1191//----------------------------------------------------------------------------- 1192void VActorPhysicsController::onActorEvent( const VActor::eEventType &pEvent ) 1193{ 1194 switch( pEvent ) 1195 { 1196 case VActor::k_MountEvent : 1197 { 1198 // Set Control State. 1199 setControlState( k_PathControlState ); 1200 1201 // Store Path. 1202 mMountedPath = dynamic_cast<VPath*>( mObject->getObjectMount() ); 1203 1204 } break; 1205 1206 case VActor::k_UnmountEvent : 1207 { 1208 // Clear Control State. 1209 clearControlState( k_PathControlState ); 1210 1211 // Clear Path. 1212 mMountedPath = NULL; 1213 // Clear X & Y Velocity. 1214 setVelocity( VectorF( 0.f, 0.f, mVelocity.z ) ); 1215 1216 } break; 1217 } 1218} 1219 1220//----------------------------------------------------------------------------- 1221// 1222// VActorPhysicsController::packUpdate( pConnection, pMask, pStream ); 1223// 1224// ... 1225// 1226//----------------------------------------------------------------------------- 1227U32 VActorPhysicsController::packUpdate( NetConnection *pConnection, U32 pMask, BitStream *pStream ) 1228{ 1229 // Return Mask. 1230 U32 retMask = 0; 1231 1232 // Valid Object? 1233 if ( !pStream->writeFlag( isValidObject() ) ) 1234 { 1235 return retMask; 1236 } 1237 1238 // Write Move? 1239 const bool writeMove = ( pMask & VActor::MoveMask ) && !isPathing(); 1240 if ( pStream->writeFlag( writeMove ) ) 1241 { 1242 // Write Position. 1243 const Point3F &position = getPosition(); 1244 pStream->write( position.x ); 1245 pStream->write( position.y ); 1246 pStream->write( position.z ); 1247 } 1248 1249 return retMask; 1250} 1251 1252//----------------------------------------------------------------------------- 1253// 1254// VActorPhysicsController::unpackUpdate( pConnection, pStream ); 1255// 1256// ... 1257// 1258//----------------------------------------------------------------------------- 1259void VActorPhysicsController::unpackUpdate( NetConnection *pConnection, BitStream *pStream ) 1260{ 1261 // Valid Object? 1262 if ( !pStream->readFlag() ) 1263 { 1264 return; 1265 } 1266 1267 // Read Move? 1268 if ( pStream->readFlag() ) 1269 { 1270 // Read Position. 1271 Point3F position; 1272 pStream->read( &position.x ); 1273 pStream->read( &position.y ); 1274 pStream->read( &position.z ); 1275 1276 // Apply. 1277 setPosition( position ); 1278 } 1279} 1280