public override void PreCollisionTestUpdate(GameThing thing)
        {
            Movement        movement        = thing.Movement;
            DesiredMovement desiredMovement = thing.DesiredMovement;

            GameActor.State state = thing.CurrentState;

            //string DebugString = "------------- Debug Fish: "+ thing.CreatableName +" --------------";

            float secs = Time.GameTimeFrameSeconds;

            // Only do movement if we are not being held and active.
            if (state == GameActor.State.Active && thing.ActorHoldingThis == null)
            {
                // Test for grounding.
                float terrainAltitude   = Terrain.GetHeight(movement.Position);
                float waterBaseAltitude = Terrain.GetWaterBase(movement.Position);

                Vector3 waterNormal   = Vector3.UnitZ;
                float   waterAltitude = (waterBaseAltitude > 0) ? Terrain.GetWaterHeightAndNormal(movement.Position, ref waterNormal) : 0.0f;

                // Note that grounded tells us if there's too little water to float.
                // grounded should be false if there's no terrain under the bot.
                float   groundedAmount = terrainAltitude - waterAltitude - (ReScale * HullDraft);
                bool    grounded       = terrainAltitude != 0 && (waterAltitude == 0.0f || groundedAmount > 0.0f);
                Vector3 groundedNormal = grounded ? Terrain.GetNormal(movement.Position) : Vector3.UnitZ;

                // Undo wave offset.
                movement.Position -= new Vector3(0, 0, waveOffset);

                if (!grounded)
                {
                    // Apply DesiredMovement values to current movement.
                    ApplyDesiredMovement(movement, desiredMovement);

                    bodyFlex = movement.RotationZRate / TurningSpeedModifier * 0.5f;
                    float newFlexAmp = MaxRotationRate - Math.Abs(movement.RotationZRate / TurningSpeedModifier);
                    flexAmplitude = MyMath.Lerp(flexAmplitude, newFlexAmp * newFlexAmp, secs);     // Wiggle less when turning.

                    // Apply drag to velocity.
                    ApplyFriction(movement, desiredMovement, applyVertical: true);
                }   // end if not grounded.


                // Now see if we're stuck or hitting shore.
                if (grounded && !(jumping || landing))
                {
                    Vector3 terrainNormal = groundedNormal;

                    // Grounded tells us there's too little water to float, now check if we're
                    // actually touching the ground.
                    float closeToGround = 0.1f;
                    if (movement.Position.Z - hullDraft - terrainAltitude < closeToGround)
                    {
                        // Slide if shallow.
                        if (groundedAmount < 1.0f)
                        {
                            // Slide down hill a bit.
                            terrainNormal.Z    = 0.0f;
                            movement.Position += 10.0f * terrainNormal * secs;
                            movement.Velocity  = 10.0f * terrainNormal * secs;
                        }
                        else
                        {
                            // High and dry
                            movement.Velocity = Vector3.Zero;
                        }
                    }
                    else
                    {
                        // Decay any horizontal velocity.
                        float friction = GameActor.FrictionDecay(Friction, secs);
                        movement.Velocity *= new Vector3(friction, friction, 1);
                    }
                }

                // Move.
                if (state != GameThing.State.Paused)
                {
                    // Apply external force.
                    movement.Velocity += desiredMovement.ExternalForce.GetValueOrDefault() / thing.Mass * secs;

                    movement.Position += movement.Velocity * secs;
                }

                // Adjust pitch based on vertical movement.
                float deltaVZ = movement.Altitude - movement.PrevPosition.Z;
                if (deltaVZ > 0.01f)
                {
                    pitch = MyMath.Lerp(pitch, MaxPitch, secs);
                }
                else if (deltaVZ < -0.01f)
                {
                    pitch = MyMath.Lerp(pitch, -MaxPitch, secs);
                }
                else
                {
                    pitch = MyMath.Lerp(pitch, 0, secs);
                }

                // At the new position,
                //  push bot down due to being above the surface.
                //  push bot up to keep out of mud.
                //  calc waveOffset
                //  calc waveEffect based on how close to surface we are combined with how grounded we are.

                waterBaseAltitude = Terrain.GetWaterBase(movement.Position);
                terrainAltitude   = Terrain.GetHeight(movement.Position);
                waterAltitude     = (waterBaseAltitude > 0) ? Terrain.GetWaterHeightAndNormal(movement.Position, ref waterNormal) : 0.0f;

                // Keep bot out of mud.
                // Calc how deep we are and push us back up.
                // Need to zero out velocity.Z when we do this.
                float inMud = (movement.Position.Z + waveOffset - ReScale * HullDraft) - terrainAltitude;
                if (inMud < 0.0f && terrainAltitude > 0)
                {
                    movement.Position -= new Vector3(0, 0, inMud);
                    movement.Velocity *= new Vector3(1, 1, 0);
                }
                else
                {
                    // Push bot down if too high at surface (or even in the air).
                    // Only apply this if not inMud.
                    if (movement.Position.Z > waterAltitude - MinDepth || terrainAltitude == 0.0f)
                    {
                        movement.Velocity += new Vector3(0, 0, Gravity * secs);
                    }
                }

                // Calc wave effect.  We only want the waves to have an effect when the bot is near
                // the surface.  If grounded, then we want the bot to have a chance to slide back
                // into the water.  If just near the surface, the bot should move with the waves.
                float waveEffect = 0.0f;
                if (grounded)
                {
                    waveEffect = 1.0f - groundedAmount;
                }
                else
                {
                    // Make the waveEffect strongest at the surface and fading to 0 as you go deeper.
                    float maxWaveEffectDepth = 3.0f;
                    float depth = waterBaseAltitude - movement.Position.Z;
                    if (depth > maxWaveEffectDepth)
                    {
                        waveEffect = 0.0f;
                    }
                    else
                    {
                        waveEffect = (maxWaveEffectDepth - depth) / maxWaveEffectDepth;
                    }
                }
                waveEffect = MathHelper.Clamp(waveEffect, 0.0f, 1.0f);
                waveOffset = waveEffect * (waterAltitude - waterBaseAltitude);

                if (grounded)
                {
                    // Blend between ground normal and wave normal.  This allows some minimal
                    // rocking until we're fully grounded.
                    groundedNormal = MyMath.Lerp(groundedNormal, waterNormal, waveEffect);
                    botNormal      = MyMath.Lerp(botNormal, groundedNormal, secs);
                }
                else
                {
                    // Blend between vertical and wave normal.  This allows the waves to
                    // affect the bot more when it's close to the surface.
                    waterNormal = MyMath.Lerp(Vector3.UnitZ, waterNormal, waveEffect);
                    botNormal   = MyMath.Lerp(botNormal, waterNormal, secs);

                    CheckRipples(thing, waveEffect);
                }

                // If in edit mode kill any velocity.
                if (state == GameActor.State.Paused)
                {
                    movement.Velocity = Vector3.Zero;
                }

                // Create a matrix orienting the actor with the surface it's on.
                botNormal.Normalize();
                Vector3 forward = new Vector3(1.0f, 0.0f, 0.0f);
                Vector3 left    = Vector3.Cross(botNormal, forward);
                forward = Vector3.Cross(left, botNormal);
                Matrix local = Matrix.Identity;

                // Ok, this looks strange.  This is because XNA GS assumes Y is up and -Z is forward.  Argh.
                local.Backward = botNormal;
                local.Up       = left;
                local.Right    = forward;

                // Add in Z rotation and pitch.
                local = Matrix.CreateRotationY(-pitch) * Matrix.CreateRotationZ(movement.RotationZ) * local;

                // And translate to the right place.
                local.Translation = movement.Position;

                // Add in wave offset.
                local.M43 = movement.Position.Z + waveOffset;

                // Finally, set the local matrix explicitly
                movement.SetLocalMatrixAndRotation(local, movement.RotationZ);
            } //end of If State == Active && State != Held

            //Debug.WriteLine( DebugString );
        }   // end of PreCollisionTestUpdate()