Torque3D Documentation / _generateds / VActorPhysicsController.cpp

VActorPhysicsController.cpp

Engine/source/Verve/VActor/VActorPhysicsController.cpp

More...

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