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

            GameActor.State state = thing.CurrentState;

            float secs = Time.GameTimeFrameSeconds;

            if (state == GameActor.State.Active)
            {
                // Apply DesiredMovement values to current movement.
                ApplyDesiredMovement(movement, desiredMovement);

                float height = 0;
                bool  bounce = CollideWithGround(movement, ref height);

                // Apply external force.
                movement.Velocity += desiredMovement.ExternalForce.GetValueOrDefault() / thing.Mass * secs;

                // Apply drag to velocity.
                ApplyFriction(movement, desiredMovement, applyVertical: true);

                // Apply velocity to position.
                movement.Position += movement.Velocity * secs;
            }
        }
예제 #2
0
        }   // end of SetLoopedAnimationWeights()

        #endregion

        #region Internal

        /// <summary>
        /// Applies the values set by the brain in DesiredMovement to this chassis.
        /// </summary>
        /// <param name="movement"></param>
        /// <param name="desiredMovement"></param>
        public override void ApplyDesiredMovement(Movement movement, DesiredMovement desiredMovement)
        {
            // Apply velocity changes.
            ApplyDesiredVelocityForHover(movement, desiredMovement);

            // Apply rotation changes.
            ApplyDesiredRotation(movement, desiredMovement);
        }   // end of ApplyDesiredMovement()
예제 #3
0
        /// <summary>
        /// Applies the values set by the brain in DesiredMovement to this chassis.
        /// </summary>
        /// <param name="movement"></param>
        /// <param name="desiredMovement"></param>
        public override void ApplyDesiredMovement(Movement movement, DesiredMovement desiredMovement)
        {
            // Apply velocity changes.
            ApplyDesiredVelocityForHover(movement, desiredMovement);

            // Apply vertical movement.
            ApplyDesiredVerticalMovement(movement, desiredMovement);
        }   // end of ApplyDesiredMovement()
예제 #4
0
        public override void PreCollisionTestUpdate(GameThing thing)
        {
            Movement        movement        = thing.Movement;
            DesiredMovement desiredMovement = thing.DesiredMovement;

            GameActor.State state = thing.CurrentState;

            float secs = Time.GameTimeFrameSeconds;

            float waterAltitude = Terrain.GetWaterBase(movement.Position);

            // Only move if active.
            if (state == GameActor.State.Active)
            {
                // Apply DesiredMovement values to current movement.
                ApplyDesiredMovement(movement, desiredMovement);

                float height = 0;
                bool  bounce = CollideWithGround(movement, ref height);

                // Apply external force.
                movement.Velocity += desiredMovement.ExternalForce.GetValueOrDefault() / thing.Mass * secs;

                // Apply drag to velocity.
                ApplyFriction(movement, desiredMovement, applyVertical: true);

                // Apply velocity to position.
                movement.Position += movement.Velocity * secs;

                // Prevent going up steep slopes and have bots slide down slopes.
                if (waterAltitude > 0.0f || !thing.StayAboveWater)
                {
                    Vector3 normal = Terrain.GetNormal(movement.Position);
                    if (normal.Z < slopeThreshold)
                    {
                        Vector3 velocity = movement.Velocity;
                        velocity.X       += normal.X * 10.0f * secs;
                        velocity.Y       += normal.Y * 10.0f * secs;
                        movement.Velocity = velocity;
                    }
                }
                if (waterAltitude > 0.0f)
                {
                    Vector3 collCenter = thing.WorldCollisionCenter;
                    float   collRad    = thing.WorldCollisionRadius;
                    if ((waterAltitude - Terrain.WaveHeight < collCenter.Z + collRad) &&
                        (waterAltitude > collCenter.Z - collRad))
                    {
                        CheckRipples(thing, collRad);
                    }
                }
            } // end of if state is active.
        }     // end of PreCollisionTestUpdate()
예제 #5
0
        }   // end of ApplyDesiredMovement()

        /// <summary>
        /// Applies the values set by the brain in DesiredMovement to this chassis.
        /// Assume the bot is falling so only rotation changes apply.
        /// </summary>
        /// <param name="movement"></param>
        /// <param name="desiredMovement"></param>
        public void ApplyDesiredMovementWhenFalling(Movement movement, DesiredMovement desiredMovement)
        {
            // Apply velocity changes.  Sort of.  We need this to affect the
            // rotation of the bot but, since we're falling, the velocity shouldn't change.
            Vector3 velocity = movement.Velocity;

            ApplyDesiredVelocityForHover(movement, desiredMovement);
            movement.Velocity = velocity;   // Restore saved value.

            // Apply rotation changes.
            ApplyDesiredRotation(movement, desiredMovement);

            // Note that we don't clamp velocity to facing direction here.
            // This means that we can spin in the air without changing our velocity.
        }   // end of ApplyDesiredMovementWhenFalling()
예제 #6
0
        /// <summary>
        /// Applies the values set by the brain in DesiredMovement to this chassis.
        /// </summary>
        /// <param name="movement"></param>
        /// <param name="desiredMovement"></param>
        public override void ApplyDesiredMovement(Movement movement, DesiredMovement desiredMovement)
        {
            // Apply velocity changes.
            ApplyDesiredVelocityForHover(movement, desiredMovement);

            // Apply rotation changes.
            ApplyDesiredRotation(movement, desiredMovement);

            // Clamp velocity to forward/backward.  Don't mess with vertical movement.
            // Calc facing dir without any Z component.
            Vector3 forward = movement.Facing * new Vector3(1, 1, 0);

            forward.Normalize();
            float   dot = Vector3.Dot(forward, movement.Velocity);
            Vector3 vel = dot * forward;

            movement.Velocity = new Vector3(vel.X, vel.Y, movement.Velocity.Z);
        }   // end of ApplyDesiredMovement()
예제 #7
0
        }   // end of SetLoopedAnimationWeights()

        /// <summary>
        /// Applies the values set by the brain in DesiredMovement to this chassis.
        /// </summary>
        /// <param name="movement"></param>
        /// <param name="desiredMovement"></param>
        public override void ApplyDesiredMovement(Movement movement, DesiredMovement desiredMovement)
        {
            // For boats we want them to be able to turn BUT they shouldn't be able
            // to move sideways.  So, we need to calc the rotation as usual but
            // the velocity should only be applied based on the direction the bot
            // is facing.

            // Apply velocity changes.
            ApplyDesiredVelocityForHover(movement, desiredMovement);

            // Apply rotation changes.
            ApplyDesiredRotation(movement, desiredMovement);

            // Clamp velocity to forward/backward.  Don't mess with vertical movement.
            // Calc facing dir without any Z component.
            Vector3 forward = movement.Facing * new Vector3(1, 1, 0);

            forward.Normalize();
            float   dot = Vector3.Dot(forward, movement.Velocity);
            Vector3 vel = dot * forward;

            movement.Velocity = new Vector3(vel.X, vel.Y, movement.Velocity.Z);
        }   // end of ApplyDesiredMovement()
예제 #8
0
        public override MovementOutput GetMovement()
        {
            DesiredOutput = DesiredMovement.GetMovement();

            DesiredVelocity = this.Character.velocity + DesiredOutput.linear;

            if (DesiredVelocity.magnitude > MaxSpeed)
            {
                DesiredVelocity.Normalize();
                DesiredVelocity *= MaxSpeed;
            }
            samples.Add(DesiredVelocity);

            for (int i = 0; i < numSamples; i++)
            {
                angle          = Random.Range(0, MathConstants.MATH_2PI);
                magnitude      = Random.Range(0, MaxSpeed);
                velocitySample = MathHelper.ConvertOrientationToVector(angle) * magnitude;
                samples.Add(velocitySample);
            }
            base.Target.velocity = GetBestSample(samples, DesiredVelocity);
            return(base.GetMovement());
        }
예제 #9
0
        /// <summary>
        /// Applies the values set by the brain in DesiredMovement to this chassis.
        /// </summary>
        /// <param name="movement"></param>
        /// <param name="desiredMovement"></param>
        public override void ApplyDesiredMovement(Movement movement, DesiredMovement desiredMovement)
        {
            // Apply velocity changes.
            ApplyDesiredVelocityForHover(movement, desiredMovement);

            // Apply rotation changes.
            ApplyDesiredRotation(movement, desiredMovement);

            // Apply vertical movement.
            ApplyDesiredVerticalMovement(movement, desiredMovement);

            /*
             * // Clamp velocity to prevent side to side motion.
             * if (movement.Velocity.LengthSquared() > 5.0f)
             * {
             *  Vector3 right = Vector3.Cross(movement.Facing, Vector3.UnitZ);
             *  right.Normalize();
             *  float dot = Vector3.Dot(right, movement.Velocity);
             *  // The 0.8 factor just prevents this from clamping down absolutely.
             *  // It give the motion a bit more fluid feel.
             *  movement.Velocity -= 0.8f * dot * right;
             * }
             */
            // Clamp velocity to forward/backward.  Don't mess with vertical movement.
            // Calc facing dir without any Z component.

            /*
             * if (movement.Velocity.LengthSquared() > 5.0f)
             * {
             *  Vector3 forward = movement.Facing * new Vector3(1, 1, 0);
             *  forward.Normalize();
             *  float dot = Vector3.Dot(forward, movement.Velocity);
             *  Vector3 vel = dot * forward;
             *  movement.Velocity = new Vector3(vel.X, vel.Y, movement.Velocity.Z);
             * }
             */
        }   // end of ApplyDesiredMovement()
        }   // end of PreCollisionTestUpdate()

        public override void SetLoopedAnimationWeights(AnimationSet anims, Movement movement, DesiredMovement desiredMovement)
        {
            anims.IdleWeight      = anims.IsOpen ? 1.0f : 0.0f;
            anims.ForwardWeight   = 0.0f;
            anims.BackwardsWeight = 0.0f;
            anims.RightWeight     = 0.0f;
            anims.LeftWeight      = 0.0f;
        }   // end of SetLoopedAnimationWeights()
예제 #11
0
        }   // end of DynamicChassis CollisionResponse()

        /// <summary>
        /// Applies the values set by the brain in DesiredMovement to this chassis.
        /// </summary>
        /// <param name="movement"></param>
        /// <param name="desiredMovement"></param>
        public override void ApplyDesiredMovement(Movement movement, DesiredMovement desiredMovement)
        {
            GameActor actor = Parent as GameActor;

            ApplyDesiredRotation(movement, desiredMovement);
        }   // end of ApplyDesiredMovement()
예제 #12
0
        public override void PreCollisionTestUpdate(GameThing thing)
        {
            Movement        movement        = thing.Movement;
            DesiredMovement desiredMovement = thing.DesiredMovement;

            GameActor.State state = thing.CurrentState;

            UpdateDustEmitter(state);

            // Only do the update if this thing is active and moving.
            if (((state == GameActor.State.Active) || (state == GameThing.State.Dead || state == GameThing.State.Squashed)) &&
                Moving)
            {
                float dt = (float)Time.GameTimeFrameSeconds;


                floating = false;
                inWater  = false;

                // Start with existing values.
                Vector3 position     = movement.Position;
                Vector3 prevPosition = position;
                Vector3 velocity     = movement.Velocity;

                // Are we in water?
                if (Terrain.GetWaterBase(position) > 0.0f)
                {
                    Vector3 surfaceNormal = Vector3.UnitZ;
                    float   waterAlt      = Terrain.GetWaterHeightAndNormal(position, ref surfaceNormal);

                    if (waterAlt > 0)
                    {
                        inWater = true;
                        CheckRipples(thing, velocity, waterAlt);
                    }

                    // Are we in the water?
                    if (position.Z < waterAlt)
                    {
                        // TODO (****) This could be made better by also having
                        // the density control how deep an object floats.

                        // Should we sink or float?
                        if (Density > 1.0f)
                        {
                            // Sink.
                            // Add attenuated gravity.
                            float attenuation = 1.0f - 1.0f / Density;
                            velocity.Z += attenuation * Gravity * dt;
                        }
                        else
                        {
                            // Float.
                            // Add attenuated, inverted gravity.
                            float attenuation = 1.0f - Density;
                            velocity.Z -= attenuation * Gravity * dt;

                            // If we're floating near the surface, have the waves move us a bit.
                            float depth = waterAlt - position.Z;
                            if (depth < 0.5f)
                            {
                                float amp = (0.5f - depth) * 20.0f;
                                velocity.X += surfaceNormal.X * dt * amp;
                                velocity.Y += surfaceNormal.Y * dt * amp;
                                floating    = true;
                            }
                        }

                        // Now attenuate velocity to simulate drag from water.
                        velocity = MyMath.Lerp(velocity, Vector3.Zero, 2.0f * dt);
                    }
                    else
                    {
                        // Not in water.
                        // Add in effect of full gravity.
                        velocity.Z += Gravity * dt;
                    }
                }
                else
                {
                    // No water.
                    // Add in effect of full gravity.
                    velocity.Z += Gravity * dt;
                }

                // Apply external force.
                velocity += desiredMovement.ExternalForce.GetValueOrDefault() / thing.Mass * dt;

                // Update location.
                position.X += velocity.X * dt;
                position.Y += velocity.Y * dt;

                // Push changes back to movement.
                movement.Velocity = velocity;
                movement.Position = position;

                // If we're version 1 or later also do rotation based on brain.
                if (Parent.Version >= 1)
                {
                    ApplyDesiredMovement(movement, desiredMovement);
                }
            }   // end of if moving
            else if (state != GameActor.State.Active &&
                     thing.ActorHoldingThis == null &&
                     state != GameThing.State.Dead &&
                     state != GameThing.State.Squashed &&
                     !Moving)
            {
                // We're not active but we still want to be able to have our height adjusted.
                movement.Altitude = Terrain.GetTerrainAndPathHeight(Top(movement.Position)) + EditHeight;
            }
        }   // end of DynamicPropChassis PreCollisionTestUpdate()
예제 #13
0
        }     // end of PostCollisionTestUpdate()

        /// <summary>
        /// Based on the chassis' internal values, sets the blend values for the
        /// four standard looping animations.
        /// </summary>
        /// <param name="anims"></param>
        public override void SetLoopedAnimationWeights(AnimationSet anims, Movement movement, DesiredMovement desiredMovement)
        {
            StandardSetLoopedAnimationWeights(anims, movement, desiredMovement);
        }   // end of SetLoopedAnimationWeights()
예제 #14
0
        public override void PreCollisionTestUpdate(GameThing thing)
        {
            Movement        movement        = thing.Movement;
            DesiredMovement desiredMovement = thing.DesiredMovement;

            GameActor.State state = thing.CurrentState;

            // Are we being held?
            if (thing.ActorHoldingThis != null)
            {
                grounded = false;
                return;
            }


            float   secs     = Time.GameTimeFrameSeconds;
            Vector3 position = movement.Position;

            Vector3 bow = position + 0.9f * movement.Facing;

            // Test for grounding.
            {
                float waterAltitude   = Terrain.GetWaterHeight(position);
                float terrainAltitude = Terrain.GetTerrainAndPathHeight(Top(position));
                grounded = (terrainAltitude > 0) && (terrainAltitude > waterAltitude - HullDraft);
            }


            if (state == GameActor.State.Active)
            {
                if (!grounded)
                {
                    // Apply DesiredMovement values to current movement.
                    ApplyDesiredMovement(movement, desiredMovement);

                    if (Jump && CanJump() && !jumping && !landing)
                    {
                        startJumpAnimation = true;      // Tell animation to start.
                        jumping            = true;
                        jumpStartTime      = Time.GameTimeTotalSeconds;
                    }
                    Jump = false;

                    if (jumping)
                    {
                        // If the pre delay time has passed, do the jump.
                        if (Time.GameTimeTotalSeconds > jumpStartTime + preJumpDelay)
                        {
                            movement.Velocity += new Vector3(0, 0, effectiveJumpStrength);
                            jumping            = false;
                            landing            = true;
                            lastJumpTime       = Time.GameTimeTotalSeconds;
                        }
                    }

                    // Apply external force.
                    movement.Velocity += desiredMovement.ExternalForce.GetValueOrDefault() / thing.Mass * secs;

                    // Apply drag to velocity.
                    ApplyFriction(movement, desiredMovement, applyVertical: true);

                    // Apply velocity to position.
                    movement.Position += movement.Velocity * secs;
                }   // end if not grounded.
                else
                {
                    // We're grounded but we may be high enough to stil be falling.
                    // Apply velocity to position.
                    movement.Position += movement.Velocity * secs;
                }
            }   // End of if active.
            else
            {
                // Not active but we still want to be able to move vertically
                // if the water level is changing in the editor.
                //movement.Altitude += movement.Velocity.Z * Time.WallClockFrameSeconds;
                //grounded = false;
            }

            // Check for hitting the ground.  Only do this if we're active and not fully grounded.
            if (!grounded && (state != GameActor.State.Dead || state != GameActor.State.Squashed))
            {
                bow = position + 0.9f * movement.Facing;
                float waterBase       = Terrain.GetWaterBase(bow);
                float terrainAltitude = Terrain.GetHeight(bow);
                if (terrainAltitude < waterBase)
                {
                    // Only slide if active.
                    if (state == GameActor.State.Active)
                    {
                        float waterAltitude = Terrain.GetWaterHeight(bow);

                        // Are we hitting ground?  If so, reduce speed and slide back a bit.
                        if (position.Z - hullDraft < terrainAltitude)
                        {
                            // Stuck.
                            speed *= 1.0f - secs;
                            speed  = 0.0f;

                            // Slide down hill a bit.
                            Vector3 terrainNormal = Terrain.GetNormal(movement.Position);
                            terrainNormal.Z    = 0.0f;
                            movement.Position += terrainNormal * 2.0f * secs;
                            movement.Velocity  = terrainNormal;
                        }
                    }
                }
            }   // End of if not grounded or dead.

            velocityZ = movement.Velocity.Z;
        }   // end of PreCollisionTestUpdate()
        //basic movement logic from hover chassis, added velocity using logic from swim chassis for when under water
        public override void PreCollisionTestUpdate(GameThing thing)
        {
            Movement        movement        = thing.Movement;
            DesiredMovement desiredMovement = thing.DesiredMovement;

            GameActor.State state = thing.CurrentState;

            // Are we being held?
            if (thing.ActorHoldingThis != null)
            {
                return;
            }

            float secs = Time.GameTimeFrameSeconds;

            // Calc the height we want to be at.
            float   waterAltitude   = Terrain.GetWaterBase(movement.PrevPosition);
            float   terrainAltitude = 0.0f;
            Vector3 terrainNormal   = Vector3.Zero;

            GetTerrainAltitudeAndNormalFromFeelers(movement, ref terrainAltitude, ref terrainNormal);

            // Heights are distance above ground, not absolute values.
            float heightGoal = EditHeight;
            float floor      = terrainAltitude;

            Vector3 collCenter = thing.WorldCollisionCenter;

            bool underWater = false;

            // Only move if active.
            if (state == GameActor.State.Active)
            {
                // Bounce off ground?
                bool bounce = false;

                // Under water?
                if (waterAltitude > 0 && (waterAltitude - Terrain.WaveHeight) > (collCenter.Z + thing.WorldCollisionRadius))
                {
                    underWater = true;
                }

                float height = movement.Position.Z - Parent.CollisionCenter.Z - Parent.CollisionRadius - floor;

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

                    // If not underwater we should ignore any velocity changes.  We still
                    // need to process them so that we get turning correct.
                    if (!underWater)
                    {
                        // Undo velocity changes.
                        movement.Velocity = movement.PrevVelocity;
                    }

                    bounce = CollideWithGround(movement, ref height);

                    // Create a dust puff when bouncing off dry ground.
                    // TODO (****) This doesn't seem to actually do anything.  As far as I can
                    // tell the CreateDustPuff() call is never called by anything else so it may
                    // not work at all.  May be worth looking into if you're bored some time.

                    /*
                     * if (bounce && waterAltitude == 0)
                     * {
                     *  // Must have bounced on dry ground.  Give a puff
                     *  // of dust if moving fast enough.
                     *  if (Math.Abs(movement.Velocity.Z) > 1.0f)
                     *  {
                     *      ExplosionManager.CreateDustPuff(movement.Position, Parent.CollisionRadius, 1.0f);
                     *  }
                     * }
                     */
                }   // end if BrainMovement

                // Apply external force.
                movement.Velocity += desiredMovement.ExternalForce.GetValueOrDefault() / thing.Mass * secs;

                // Apply drag to velocity.
                if (underWater)
                {
                    ApplyFriction(movement, desiredMovement, applyVertical: true);
                }

                // Lerp pitch based on vertical rate.

                /*
                 * if (desiredMovement.Coasting)
                 * {
                 *  pitch = MyMath.Lerp(pitch, 0, secs);
                 * }
                 * else
                 * {
                 *  float deltaZ = movement.Velocity.Z;
                 *  pitch = MyMath.Lerp(pitch, deltaZ, secs);
                 * }
                 */

                // If not underwater then we should fall to the ground.  If we just hit the ground, skip
                // adding gravity since that will force us too deep into the ground.
                if (!underWater && !bounce)
                {
                    float s0 = (-movement.Velocity.Z + (float)Math.Sqrt(movement.Velocity.Z * movement.Velocity.Z - 4 * Gravity * height)) / (2.0f * Gravity);
                    float s1 = (-movement.Velocity.Z - (float)Math.Sqrt(movement.Velocity.Z * movement.Velocity.Z - 4 * Gravity * height)) / (2.0f * Gravity);
                    float s  = MathHelper.Max(s0, s1);
                    // s will be negative when falling off the edge of the world.
                    if (float.IsNaN(s) || s < 0)
                    {
                        s = secs;
                    }
                    else
                    {
                        s = MathHelper.Min(s, secs);
                    }

                    // Calc affect of gravity using minimum of frame secs or time until we hit the ground.
                    // By using the shorter of the two we help prevent things from getting driven into the ground.
                    Vector3 velocity = movement.Velocity;
                    velocity.Z       += Gravity * s;
                    movement.Velocity = velocity;
                }

                // Apply velocity to position.  We don't do this on the frame where a bounce occurs.  By
                // skipping this frame we help stabilize the behavior on the ground.  The actor sits without bouncing.
                if (!bounce)
                {
                    movement.Position += movement.Velocity * secs;
                }

                // If body is intersecting with water surface, add some splashes/ripples.
                if (waterAltitude != 0)
                {
                    // Test if the collision sphere is breaking the surface of the water.  If we falling in, create a splash.
                    // If we're just cruising along, create ripples.  Note that the extra 1.5f scaling is to make the ripples
                    // appear even if we just get close to the surface.
                    if (movement.Position.Z - Parent.CollisionRadius < waterAltitude && movement.Position.Z + Parent.CollisionRadius * 1.5f > waterAltitude)
                    {
                        CheckSplash(Parent, movement.Position, movement.Velocity);
                        CheckRipples(Parent, Parent.CollisionRadius);
                    }
                }
            }   // end of if state is active.

            // If paused we still want to apply vertical motion
            // so that in edit mode we maintain the correct height.
            if (state == GameThing.State.Paused)
            {
                Vector3 position = movement.Position;
                position.Z        = floor + EditHeight;
                movement.Position = position;
            }
        }   // end of PreCollisionTestUpdate()
예제 #16
0
        public override void PreCollisionTestUpdate(GameThing thing)
        {
            Movement        movement        = thing.Movement;
            DesiredMovement desiredMovement = thing.DesiredMovement;

            GameActor.State state = thing.CurrentState;

            float secs = Time.GameTimeFrameSeconds;

            if (state != GameActor.State.Dead || state != GameThing.State.Squashed)
            {
                if (state == GameActor.State.Active)
                {
                    // Only do movement if we are not being held.
                    if (thing.ActorHoldingThis == null)
                    {
                        // Check if we're up in the air.  If so, then we don't kick up
                        // any dust.  We can still turn while in the air but it doesn't
                        // affect the direction we're moving until we hit the ground.
                        float terrainHeight     = Terrain.GetTerrainAndPathHeight(Top(movement.Position));
                        bool  falling           = terrainHeight == 0.0f;
                        float heightAboveGround = movement.Altitude - terrainHeight - MinHeight;

                        if (landing)
                        {
                            // This version doesn't clamp movement to only work forward and backward.
                            ApplyDesiredMovementWhenFalling(movement, desiredMovement);
                        }
                        else
                        {
                            ApplyDesiredMovement(movement, desiredMovement);
                        }

                        // Are we waiting to land?
                        if (landing && movement.Velocity.Z < 0.0f)
                        {
                            // Are we close enough?
                            float predictedHeight = heightAboveGround + movement.Velocity.Z * preLandDelay;
                            if (predictedHeight < CloseToGround)
                            {
                                startLandAnimation = true;
                                landing            = false;
                                if (TerrainDataValid && Feelers != null)
                                {
                                    Foley.PlayCollision(thing, Feelers[0].TerrainMaterialInfo.TerrainType);
                                }
                                else
                                {
                                    Foley.PlayCollision(thing, 0);
                                }
                            }
                        }

                        onGround = heightAboveGround < CloseToGround;
                        onGround = onGround && !falling;
                        if (onGround)
                        {
                            // The bot is on the ground.

                            // Only jump if on the ground and not already jumping.
                            if (Jump && !jumping && !landing)
                            {
                                startJumpAnimation = true;      // Tell animation to start.
                                jumping            = true;
                                jumpStartTime      = Time.GameTimeTotalSeconds;

                                jumpVelocity = new Vector2(movement.Velocity.X, movement.Velocity.Y);
                                float len = jumpVelocity.Length();
                                if (len > 0.1f)
                                {
                                    jumpVelocity /= len;
                                }
                                else
                                {
                                    jumpVelocity = new Vector2(movement.Facing.X, movement.Facing.Y);
                                    jumpVelocity.Normalize();
                                }
                            }
                        }

                        // Always clear jump flag.
                        Jump = false;

                        if (jumping && !landing)
                        {
                            // If the pre delay time has passed, do the jump.
                            if (Time.GameTimeTotalSeconds > jumpStartTime + preJumpDelay)
                            {
                                movement.Velocity += new Vector3(0, 0, effectiveJumpStrength);
                                jumping            = false;
                                landing            = true;
                            }
                        }

                        HandleMovement(movement);

                        // Apply drag to velocity.
                        ApplyFriction(movement, desiredMovement, applyVertical: false);

                        // Apply external force.
                        movement.Velocity += desiredMovement.ExternalForce.GetValueOrDefault() / thing.Mass * secs;

                        // Move due to velocity.
                        movement.Position += movement.Velocity * secs;
                    } // end of if not held.
                }     // end of if active.
            }         // end of if not dead
        }             // end of PreCollisionTestUpdate()
예제 #17
0
        }     // end of PreCollisionTestUpdate()

        public override void PostCollisionTestUpdate(GameThing thing)
        {
            Movement movement = thing.Movement;

            float secs = Time.GameTimeFrameSeconds;

            // Init the target Altitude.  This should only happen the very first time
            // after a reset.  We want to use the bot's initial height as the original
            // target height but at the time the c'tor is called we don't yet know
            // where the bot will be positioned.
            if (startingAltitude == DefaultStartingAltitude)
            {
                startingAltitude = Terrain.GetTerrainAndPathHeight(Top(movement.Position)) + EditHeight;
                if (Parent.StayAboveWater)
                {
                    startingAltitude = Math.Max(startingAltitude, Terrain.GetWaterHeight(movement.Position) + EditHeight);
                }
            }

            //
            // Now handle "automatic" vertical movement.  We want the charactors to try and stay at their
            // startingAltitude.
            //

            // Look at desiredMovement to see if user is actively changing altitude.  If
            // so then adjust startingAltitude to match.
            DesiredMovement desiredMovement    = Parent.DesiredMovement;
            bool            coastingVertically = desiredMovement.CoastingVertically;

            if (!coastingVertically)
            {
                if (desiredMovement.DesiredAltitude.HasValue)
                {
                    startingAltitude = desiredMovement.DesiredAltitude.Value;
                }
                if (desiredMovement.DesiredVerticalSpeed.HasValue)
                {
                    // If we're moving up/down, assume current altitude is the new target.
                    startingAltitude = movement.Altitude;
                }
            }

            // Adjust height for terrain.
            float waterAltitude   = Terrain.GetWaterBase(movement.Position);
            float terrainAltitude = MaxFeelerAltitude(movement, movement.Position, thing.ReScale);
            // altitudeBase is the ground/water we're flying over and basing our height on.
            float altitudeBase = thing.StayAboveWater ? MathHelper.Max(terrainAltitude, waterAltitude) : terrainAltitude;

            float altitudeGoal = altitudeBase + EditHeight;

            altitudeGoal   = Math.Max(altitudeGoal, startingAltitude);
            targetAltitude = 0;

            // Bounce off ground?
            if (movement.Altitude < terrainAltitude)
            {
                BounceOffGround(thing, terrainAltitude, Vector3.UnitZ);
            }

            movement.Altitude = MyMath.Lerp(movement.Altitude, altitudeGoal, 0.1f * 30.0f * secs);

            // Apply this rotation to the actor.  This rotation just makes the character
            // spin.  It has no effect on the heading or facing direction.
            float  angle = movement.RotationZ + (float)Time.GameTimeTotalSeconds * RotationRate;
            Matrix mat   = Matrix.CreateRotationZ(angle);

            mat.Translation = movement.Position;
            // Note that we're just setting the rotation angle back to the
            // original value.  The extra rotation only goes into LocalMatrix.
            movement.SetLocalMatrixAndRotation(mat, movement.RotationZ);
        }   // end of PostCollisionTestUpdate()
예제 #18
0
        public override void PreCollisionTestUpdate(GameThing thing)
        {
            Movement        movement        = thing.Movement;
            DesiredMovement desiredMovement = thing.DesiredMovement;

            GameActor.State state = thing.CurrentState;

            if (thing.ActorHoldingThis != null)
            {
                return;
            }

            float secs = Time.GameTimeFrameSeconds;

            // Only move if active.
            if (state == GameActor.State.Active)
            {
                if (AllowBrainMovement)
                {
                    // Apply DesiredMovement values to current movement.
                    ApplyDesiredMovement(movement, desiredMovement);
                }

                // Apply external force.
                movement.Velocity += desiredMovement.ExternalForce.GetValueOrDefault() / thing.Mass * secs;

                // Apply drag to velocity.
                ApplyFriction(movement, desiredMovement, applyVertical: false);

                // Create local copies to work on.  Will be copied back to movement below.
                Vector3 velocity = movement.Velocity;
                Vector3 position = movement.Position;

                // Apply velocity to position.movement.
                position += velocity * secs;

                if (Jump && CanJump())
                {
                    // If we've already jumped but not yet landed or double-jumped,
                    // see if we're allowed to double jump.
                    if (landing && !doubleJumping)
                    {
                        // Look for the vertical velocity to be slow as an
                        // indicator of the top of the arc.
                        if (Math.Abs(velocity.Z) < 0.15f)
                        {
                            doubleJumping = true;
                            velocity.Z   += 1.5f * effectiveJumpStrength;
                        }
                    }
                    else if (!landing && !jumping)
                    {
                        startJumpAnimation = true;      // Tell animation to start.
                        jumping            = true;
                        jumpStartTime      = Time.GameTimeTotalSeconds;
                    }
                }
                Jump = false;

                if (jumping)
                {
                    // If the pre delay time has passed, do the jump.
                    if (Time.GameTimeTotalSeconds > jumpStartTime + preJumpDelay)
                    {
                        velocity.Z  += effectiveJumpStrength;
                        jumping      = false;
                        landing      = true;
                        lastJumpTime = Time.GameTimeTotalSeconds;
                    }
                }

                // Copy changes back to movement.
                movement.Position = position;
                movement.Velocity = velocity;
            }   // end of if state is active.

            //
            // Balance hover force with gravity so that chassis stays at the right height.
            // Note that we use the previous position for this since we "know" it's valid.
            //
            {
                // Create local copies to work on.  Will be copied back to movement below.
                Vector3 velocity     = movement.Velocity;
                Vector3 position     = movement.Position;
                Vector3 prevPosition = movement.PrevPosition;

                // Calc the height we want to be at.
                float   waterAltitude   = Terrain.GetWaterBase(prevPosition);
                float   terrainAltitude = 0.0f;
                Vector3 terrainNormal   = Vector3.Zero;

                GetTerrainAltitudeAndNormalFromFeelers(movement, ref terrainAltitude, ref terrainNormal);

                // Heights are distance above ground, not absolute values.
                float heightGoal = EditHeight;
                float floor      = 0.0f; // Level we're hovering over.
                bool  overWater  = false;
                if (thing.StayAboveWater)
                {
                    if (waterAltitude > terrainAltitude)
                    {
                        floor     = waterAltitude;
                        overWater = true;

                        if (!landing)
                        {
                            /// Only apply ripples if we are _not_ in the middle
                            /// of a jump.
                            CheckRipples(thing, thing.CollisionRadius);
                        }
                    }
                    else
                    {
                        floor = terrainAltitude;
                    }
                }
                else
                {
                    floor = terrainAltitude;

                    /// Look to see if we are intersecting the water surface,
                    /// and if so kick off some ripples.
                    Vector3 collCenter = thing.WorldCollisionCenter;
                    float   collRad    = thing.WorldCollisionRadius;
                    if ((waterAltitude - Terrain.WaveHeight < collCenter.Z + collRad) &&
                        (waterAltitude > collCenter.Z - collRad))
                    {
                        CheckRipples(thing, collRad * 1.5f);
                    }
                }
                // If there's no terrain or we're already falling, just let the bot fall.
                // Compare against -1 to ensure that we can't get pushed through the ground.
                if (floor == 0.0f || position.Z - MinHeight < -1.0f)
                {
                    floor = float.MinValue;
                }
                float curHeight = position.Z - floor;

                // Are we waiting to land?
                if (landing)
                {
                    // Are we close enough?
                    float predictedHeight = curHeight + velocity.Z * preLandDelay;
                    if (predictedHeight < heightGoal)
                    {
                        startLandAnimation = true;
                        landing            = false;
                        doubleJumping      = false;
                    }
                }

                /*
                 * // Did we bounce into the ground?
                 * if (curHeight < MinHeight)
                 * {
                 *  position.Z = floor + MinHeight;     // Move back to above ground.
                 *  velocity.Z = Math.Max(velocity.Z, 0.1f);
                 *
                 *  // TODO (****) Bump sound and dust cloud?
                 * }
                 * else
                 */
                {
                    float ratio = heightGoal / curHeight;
                    if (float.IsNaN(ratio))
                    {
                        ratio = 0.0f;
                    }

                    float hoverEffect = ratio * -Gravity;

                    float lift = hoverEffect + Gravity;

                    // Clamp lift to limits.
                    if (lift > 0.0f)
                    {
                        // Clamp to maximum acceleration up.  Allow vertical acceleration to be 10x the
                        // normal linear acceleration.  This will help keep bots out of the ground.
                        lift = 10.0f * MathHelper.Clamp(lift, 0, MaxLinearAcceleration * LinearAccelerationModifier);
                    }
                    else
                    {
                        // Clamp to gravity down.
                        lift = MathHelper.Clamp(lift, Gravity, 0);
                    }

                    float deltaZ = lift * secs;

                    velocity.Z *= (1.0f - secs);    // Damp vertical velocity.
                    velocity.Z += deltaZ;

                    // If lift > 0 clamp the upward velocity to the max allowed without overshoot.
                    if (lift > 0)
                    {
                        float d     = heightGoal - curHeight;
                        float t     = (float)Math.Sqrt(Math.Abs(2.0f * d / Gravity));
                        float speed = -t * Gravity;
                        velocity.Z = Math.Min(velocity.Z, speed);
                    }

                    // Did we bounce off the ground?
                    if (curHeight < 0.0f)
                    {
                        // Move position back above ground.
                        position.Z -= curHeight;
                        // Make sure we're moving up, not down.  Also apply some agressive damping.
                        // This prevents hover chassis bots from getting too bouncy if they are
                        // too close to the ground.
                        velocity.Z = (float)Math.Abs(velocity.Z) * CoefficientOfRestitution * 0.2f;
                    }
                }

                // Add in effect of slope.
                if (!overWater && Moving)
                {
                    // Attenuate SlopeAttenuation based on how high we are.  Basically, if
                    // we're way up in the air, ignore slopes.
                    float slopeFactor = SlopeAttenuation;

                    if (curHeight > EditHeight)
                    {
                        if (curHeight > EditHeight * 2.0f)
                        {
                            // Too high, ignore slope.
                            slopeFactor = 0.0f;
                        }
                        else
                        {
                            slopeFactor *= 1.0f - (curHeight - EditHeight) / EditHeight;
                        }
                    }

                    if (slopeFactor > 0)
                    {
                        // Translate any change in height to a change in velocity.
                        float deltaZ = prevPosition.Z - position.Z;
                        float deltaV = (float)Math.Sqrt(Math.Abs(2.0f * Gravity * deltaZ));

                        // Always have a minimal deltaV.  This causes things to start
                        // sliding downhill if not moving.
                        deltaV = Math.Max(deltaV, 0.01f);

                        // Get direction apply new velocity.
                        terrainNormal.Z = 0.0f;
                        velocity       += slopeFactor * deltaV * terrainNormal;
                    }
                }

                // Apply vertical velocity to position.
                position.Z += velocity.Z * secs;

                // Copy changes back to movement.
                movement.Velocity = velocity;
                movement.Position = position;
            }
        }   // end of PreCollisionTestUpdate()
예제 #19
0
        }   // end of PreCollisionTestUpdate()

        public override void SetLoopedAnimationWeights(AnimationSet anims, Movement movement, DesiredMovement desiredMovement)
        {
            float idleWeight      = 0.0f;
            float forwardWeight   = 0.0f;
            float backwardsWeight = 0.0f;
            float rightWeight     = 0.0f;
            float leftWeight      = 0.0f;

            // For the sub and fish the forward and backward animations
            // are used for dive and surface so look at the pitch value
            // and assign weights from that.

            if (pitch > 0)
            {
                // Surfacing
                backwardsWeight = Math.Min(pitch / maxPitch, 1.0f);;
            }
            else
            {
                forwardWeight = Math.Max(-pitch / maxPitch, -1.0f);
            }

            // Blend left/right animations based only soley on current rotation rate.
            {
                // Both the current rotation and the desired rotation are
                // in the range 0..2pi so shift into -pi..pi range to make
                // the comparison easier.
                float delta = movement.RotationZRate;
                if (delta > 0.0f)
                {
                    rightWeight = Math.Min(delta / MathHelper.PiOver2, 1.0f);
                }
                else
                {
                    leftWeight = Math.Min(-delta / MathHelper.PiOver2, 1.0f);
                }
            }

            // Bias weights toward either full or off with a 10% flat area.
            forwardWeight = MyMath.SmoothStep(0.1f, 0.9f, forwardWeight);
            rightWeight   = MyMath.SmoothStep(0.1f, 0.9f, rightWeight);
            leftWeight    = MyMath.SmoothStep(0.1f, 0.9f, leftWeight);

            // Adjust weights to sum to 1.0.
            float total = forwardWeight + backwardsWeight + rightWeight + leftWeight;

            if (total > 1.0f)
            {
                forwardWeight   /= total;
                backwardsWeight /= total;
                leftWeight      /= total;
                rightWeight     /= total;
            }
            else
            {
                // Fill in with idle.
                idleWeight = 1.0f - total;
            }

            // Set resulting weights on animation set.
            anims.IdleWeight      = idleWeight;
            anims.ForwardWeight   = forwardWeight;
            anims.BackwardsWeight = backwardsWeight;
            anims.RightWeight     = rightWeight;
            anims.LeftWeight      = leftWeight;
        }   // end of SetLoopedAnimationWeights()
        public override void PostCollisionTestUpdate(GameThing thing)
        {
            Movement movement = thing.Movement;

            GameActor.State state = thing.CurrentState;

            float secs = Time.GameTimeFrameSeconds;

            if (state == GameActor.State.Active)
            {
                // Init the target Altitude.  This should only happen the very first time
                // after a reset.  We want to use the bot's initial height as the original
                // target height but at the time the c'tor is called we don't yet know
                // where the bot will be positioned.
                if (startingAltitude == DefaultStartingAltitude)
                {
                    startingAltitude = Terrain.GetTerrainAndPathHeight(Top(movement.Position)) + EditHeight;
                    if (Parent.StayAboveWater)
                    {
                        startingAltitude = Math.Max(startingAltitude, Terrain.GetWaterHeight(movement.Position) + EditHeight);
                    }
                }

                //
                // Now handle "automatic" vertical movement.  We want the charactors to try and stay at their
                // startingAltitude.
                //

                // Look at desiredMovement to see if user is actively changing altitude.  If
                // so then adjust startingAltitude to match.
                DesiredMovement desiredMovement    = Parent.DesiredMovement;
                bool            coastingVertically = desiredMovement.CoastingVertically;

                if (!coastingVertically)
                {
                    if (desiredMovement.DesiredAltitude.HasValue)
                    {
                        startingAltitude = desiredMovement.DesiredAltitude.Value;
                    }
                    if (desiredMovement.DesiredVerticalSpeed.HasValue)
                    {
                        // If we're moving up/down, assume currentl altitude is the new target.
                        startingAltitude = movement.Altitude;
                    }
                }

                //
                // From here down is "old" code (pre movement refactor) that still seems to have
                // the right feel so just leave it.
                //

                // Calc the min height so that we don't hit the ground (or water).
                // Do some look-ahead so we better handle cliffs.
                float lookAheadHeight = Terrain.GetTerrainAndPathHeight(Top(movement.Position + movement.Facing * 3.0f));
                float terrainHeight   = Terrain.GetTerrainAndPathHeight(Top(movement.Position));
                float waterHeight     = Terrain.GetWaterBase(movement.Position);

                if (waterHeight > 0)
                {
                    CheckRipples(thing, waterHeight);
                }

                float minimumHeight = MathHelper.Max(terrainHeight, lookAheadHeight);
                if (thing.StayAboveWater)
                {
                    minimumHeight = MathHelper.Max(minimumHeight, waterHeight);
                }
                minimumHeight += MinHeight;
                minimumHeight += VerticalStoppingDistance();

                bool tooLow  = movement.Altitude < minimumHeight;
                bool tooHigh = movement.Altitude > maxAltitude;

                float goalAltitude = Math.Max(startingAltitude, minimumHeight);
                if (targetAltitude > 0)
                {
                    goalAltitude   = Math.Max(minimumHeight, targetAltitude);
                    targetAltitude = 0;
                }

                // Add a bit of a dead zone around the target altitude.
                float targetCushion = 0.5f;

                if (tooLow || movement.Altitude < goalAltitude - targetCushion)
                {
                    // have increased acceleration upward when near ground.
                    float scaleFactor = tooLow ? 2.0f : 1.0f;

                    // Accelerate upward.
                    deltaAltitude += maxVerticalAcceleration * scaleFactor * secs * VerticalSpeedMultiplier;
                    // Clamp
                    if (deltaAltitude > maxVerticalSpeed * VerticalSpeedMultiplier)
                    {
                        deltaAltitude = maxVerticalSpeed * VerticalSpeedMultiplier;
                    }
                }
                else if (tooHigh || movement.Altitude > goalAltitude + targetCushion)
                {
                    // Accelerate downward.
                    deltaAltitude -= maxVerticalAcceleration * secs * VerticalSpeedMultiplier;
                    // Clamp
                    if (deltaAltitude < -maxVerticalSpeed * 0.7f * VerticalSpeedMultiplier)
                    {
                        deltaAltitude = -maxVerticalSpeed * 0.7f * VerticalSpeedMultiplier;
                    }
                }
                else
                {
                    // If not going up or down, damp out vertical acceleration.
                    deltaAltitude *= 1.0f - secs;
                }

                movement.Altitude += deltaAltitude * secs;
            }   // end of if active
            else
            {
                // Still need to adjust the height if in edit mode.
                float terrainHeight = Terrain.GetTerrainAndPathHeight(Top(movement.Position));
                if (thing.StayAboveWater)
                {
                    float waterHeight = Terrain.GetWaterBase(movement.Position);
                    terrainHeight = MathHelper.Max(terrainHeight, waterHeight);
                }
                terrainHeight    += EditHeight;
                movement.Altitude = terrainHeight;
            }
        }   // end of PreCollisionTestUpdate()
예제 #21
0
        public override void PreCollisionTestUpdate(GameThing thing)
        {
            Movement        movement        = thing.Movement;
            DesiredMovement desiredMovement = thing.DesiredMovement;

            GameActor.State state = thing.CurrentState;

            float secs = Time.GameTimeFrameSeconds;

            Vector3 waterNormal   = Vector3.UnitZ;
            float   waterAltitude = Terrain.GetWaterHeightAndNormal(movement.Position, ref waterNormal);

            // Only move if active.
            if (state == GameActor.State.Active)
            {
                movement.RotationZRate = rotationRate;

                // Now that we've updated the rotation rate, apply this to the actual rotation.
                //movement.Rotation += movement.RotationRate * secs;

                // Apply DesiredMovement values to current movement.
                ApplyDesiredMovement(movement, desiredMovement);

                float height = 0;
                bool  bounce = CollideWithGround(movement, ref height);

                // Apply external force.
                movement.Velocity += desiredMovement.ExternalForce.GetValueOrDefault() / thing.Mass * secs;

                // Apply drag to velocity.
                ApplyFriction(movement, desiredMovement, applyVertical: true);

                // Apply velocity to position.
                movement.Position += movement.Velocity * secs;

                // If not moving, and on a slope (or a wave), give a nudge.
                if (movement.Speed < 0.1f)
                {
                    Vector3 normal = Vector3.UnitZ;
                    if (waterAltitude > 0)
                    {
                        normal = waterNormal;
                    }
                    else
                    {
                        normal = Terrain.GetNormal(movement.Position);
                    }

                    if (normal.Z < slopeThreshold)
                    {
                        Vector3 velocity = movement.Velocity;
                        velocity.X       += normal.X * 10.0f * secs;
                        velocity.Y       += normal.Y * 10.0f * secs;
                        movement.Velocity = velocity;
                    }
                }

                if (waterAltitude > 0.0f)
                {
                    Vector3 collCenter = thing.WorldCollisionCenter;
                    float   collRad    = thing.WorldCollisionRadius;
                    if ((waterAltitude - Terrain.WaveHeight < collCenter.Z + collRad) &&
                        (waterAltitude > collCenter.Z - collRad))
                    {
                        CheckRipples(thing, collRad);
                    }
                }
            } // end of if state is active.
        }     // end of PreCollisionTestUpdate()
예제 #22
0
        }     // end of PreCollisionTestUpdate()

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

            GameActor.State state = thing.CurrentState;

            // Zero out the vertical velocity, the puck ignores it.

            Vector3 velocity = movement.Velocity;
            Vector3 position = movement.Position;
            float   secs     = Time.GameTimeFrameSeconds;

            // Only zero out velocity.Z if we're not trying to adjust vertical.
            if (desiredMovement.CoastingVertically)
            {
                velocity.Z = 0;
            }
            else
            {
                // If we're actively moving up/down, we need to adjust height offset.
                thing.HeightOffset += velocity.Z * secs;
            }

            // Adjust height for terrain.  We do this outside of the check for Active
            // so that we stay at the right height if we're being dragged around.
            // Note that for the position we use the max Z of the current and previous
            // positions.  This way we can always detect the ground without getting
            // pushed through it.
            if (position.Z < movement.PrevPosition.Z)
            {
                position.Z = movement.PrevPosition.Z;
            }
            float   terrainAltitude = 0.0f;
            Vector3 terrainNormal   = Vector3.UnitZ;

            // Feelers aren't valid in edit mode.
            if (state == GameThing.State.Paused)
            {
                terrainAltitude = Terrain.GetTerrainAndPathHeight(Top(position));
            }
            else
            {
                GetTerrainAltitudeAndNormalFromFeelers(movement, ref terrainAltitude, ref terrainNormal);
            }

            Vector3 waterNormal   = Vector3.UnitZ;
            float   waterAltitude = Terrain.GetWaterHeightAndNormal(movement.Position, ref waterNormal);

            // Decide what the altitude and normal is under us.
            float   baseAltitude = 0.0f;
            Vector3 baseNormal   = Vector3.UnitZ;

            if (thing.StayAboveWater)
            {
                if (terrainAltitude > waterAltitude)
                {
                    baseAltitude = terrainAltitude;
                    baseNormal   = terrainNormal;
                }
                else
                {
                    baseAltitude = waterAltitude;
                    baseNormal   = waterNormal;
                }
            }
            else
            {
                baseAltitude = terrainAltitude;
                baseNormal   = terrainNormal;
            }

            if (waterAltitude > 0)
            {
                CheckRipples(thing, waterAltitude);
            }

            // If nothing is there or we're already under the terrain, let the bot fall.
            if (baseAltitude == 0.0f || position.Z < 0.0f)
            {
                speedDown         += Gravity * secs;
                movement.Altitude += speedDown * secs;
            }
            else
            {
                float heightGoal = EditHeight + baseAltitude;

                heightGoal = Math.Max(heightGoal, targetAltitude);

                float t = Math.Min(0.2f * 30.0f * MovementSpeedModifier * secs, 1.0f);
                movement.Altitude = MyMath.Lerp(movement.Altitude, heightGoal, t);

                // Ensure we don't go under ground.
                if (movement.Altitude < baseAltitude)
                {
                    movement.Altitude = baseAltitude;
                }
            }

            if (state == GameThing.State.Active)
            {
                // Translate any change in height to a change in velocity but only do so if actually over terrain
                // and at low altitude, and not touching the ground, and not moving upward.

                if (terrainAltitude > 0.0f && position.Z > 0.0f && !impactingFloor)
                {
                    float deltaZ = movement.Position.Z - movement.PrevPosition.Z;

                    if (deltaZ != 0.0f)
                    {
                        float deltaV = (float)Math.Sqrt(Math.Abs(2.0f * Gravity * deltaZ));

                        // Get direction apply new velocity.
                        baseNormal.Z = 0.0f;
                        velocity    += deltaV * baseNormal;
                    }
                }

                // If the puck has impacted the ground, reduce lateral velocity
                if (impactingFloor)
                {
                    velocity.X *= 0.9f * secs;
                    velocity.Y *= 0.9f * secs;
                }

                // Apply the continuous rotational effect.
                // Apply this rotation to the actor.  This rotation just makes the character
                // spin.  It has no effect on the heading or facing direction.
                float  angle = movement.RotationZ + (float)Time.GameTimeTotalSeconds * RotationRate;
                Matrix mat   = Matrix.CreateRotationZ(angle);
                mat.Translation = movement.Position;
                // Note that we're just setting the rotation angle back to the
                // original value.  The extra rotation only goes into LocalMatrix.
                movement.SetLocalMatrixAndRotation(mat, movement.RotationZ);
            }

            // If moving too fast, damp down a bit, but only if we have a target velocity.
            // If there isn't one, just let it move freely.
            float speed = velocity.Length();

            if (speed > 0 && desiredMovement.DesiredVelocity != null && speed > desiredMovement.MaxSpeed)
            {
                float delta = (speed - desiredMovement.MaxSpeed) * secs;
                velocity *= (1 - delta);
            }

            movement.Velocity = velocity;

            // The puck has no real "heading" which is used for Move Forward.
            // To make movement work correctly, force heading to match the
            // current moving direction.
            // We can't set heading directly so set z rotation.
            // Note that this causes the visual rotation to glitch on bouncing
            // but at least the overall physical behaviour is correct.
            movement.RotationZ = MyMath.ZRotationFromDirection(velocity);
        }   // end of PuckChassis PostCollisionTestUpdate()
예제 #23
0
        }   // end of PuckChassis PostCollisionTestUpdate()

        public override void SetLoopedAnimationWeights(AnimationSet anims, Movement movement, DesiredMovement desiredMovement)
        {
            float forward = movement.Speed / MaxSpeed;

            anims.IdleWeight      = 1.0f - forward;
            anims.ForwardWeight   = forward;
            anims.BackwardsWeight = 0.0f;
            anims.RightWeight     = 0.0f;
            anims.LeftWeight      = 0.0f;
        }   // end of SetLoopedAnimationWeights()
        }   // end of PreCollisionTestUpdate()

        public override void SetLoopedAnimationWeights(AnimationSet anims, Movement movement, DesiredMovement desiredMovement)
        {
            float idleWeight     = 0.0f;
            float forwardWeight  = 0.0f;
            float backwardWeight = 0.0f;
            float leftWeight     = 0.0f;
            float rightWeight    = 0.0f;

            // Blend animations based only on relationship between
            // actual facing direction and desired heading.  This
            // ignores current speed or rotation rate.
            if (desiredMovement.DesiredVelocity.HasValue || desiredMovement.DesiredTargetLocation.HasValue)
            {
                Vector3 facing          = movement.Facing;
                Vector3 desiredVelocity = facing;  // Value will be overwritten.

                if (desiredMovement.DesiredVelocity.HasValue)
                {
                    // Trying to move in explicit direction.
                    desiredVelocity = desiredMovement.DesiredVelocity.Value;
                }

                if (desiredMovement.DesiredTargetLocation.HasValue)
                {
                    // Trying to move toward target.
                    desiredVelocity = desiredMovement.DesiredTargetLocation.Value - movement.Position;
                }

                desiredVelocity.Normalize();
                if (!float.IsNaN(desiredVelocity.X))
                {
                    forwardWeight = Math.Max(0.0f, Vector3.Dot(desiredVelocity, facing));

                    Vector3 right = Vector3.Cross(facing, Vector3.UnitZ);
                    right.Normalize();

                    rightWeight = Math.Max(0.0f, Vector3.Dot(right, desiredVelocity));
                    leftWeight  = Math.Max(0.0f, Vector3.Dot(-right, desiredVelocity));
                }
            }
            else if (desiredMovement.DesiredRotationAngle.HasValue || desiredMovement.DesiredRotationRate.HasValue)
            {
                // If we aren't setting values based on velocity changes, maybe set them based on turning.
                float curHeading     = movement.RotationZ;
                float desiredHeading = curHeading;  // Value will be overwritten.

                if (desiredMovement.DesiredRotationAngle.HasValue)
                {
                    desiredHeading = desiredMovement.DesiredRotationAngle.Value;
                }

                if (desiredMovement.DesiredRotationRate.HasValue)
                {
                    desiredHeading = curHeading + Math.Sign(desiredMovement.DesiredRotationRate.Value);
                }

                float delta = curHeading - desiredHeading;
                delta = MathHelper.WrapAngle(delta);
                if (delta > 0.0f)
                {
                    rightWeight = Math.Min(delta / MathHelper.PiOver2, 1.0f);
                }
                else
                {
                    leftWeight = Math.Min(-delta / MathHelper.PiOver2, 1.0f);
                }
            }

            // Bias weights toward either full or off with a 10% flat area.
            forwardWeight = MyMath.SmoothStep(0.1f, 0.9f, forwardWeight);
            rightWeight   = MyMath.SmoothStep(0.1f, 0.9f, rightWeight);
            leftWeight    = MyMath.SmoothStep(0.1f, 0.9f, leftWeight);

            // Adjust weights to sum to 1.0.
            float total = forwardWeight + rightWeight + leftWeight;

            if (total > 1.0f)
            {
                forwardWeight /= total;
                leftWeight    /= total;
                rightWeight   /= total;
            }
            else
            {
                // Fill in with idle.
                idleWeight = 1.0f - total;

                // If there's any idle, see how much of it should be wind.
                if (idleWeight > 0.0f)
                {
                    // For this chassis we assume that the backwards animation represents wind.
                    float wind = Fx.ShaderGlobals.WindAt(movement.Position);

                    if (wind > idleWeight)
                    {
                        backwardWeight = idleWeight;
                        idleWeight     = 0.0f;
                    }
                    else
                    {
                        backwardWeight = wind;
                        idleWeight     = idleWeight - wind;
                    }
                }
            }

            // Set resulting weights on animation set.
            anims.IdleWeight      = idleWeight;
            anims.ForwardWeight   = forwardWeight;
            anims.BackwardsWeight = backwardWeight;
            anims.RightWeight     = rightWeight;
            anims.LeftWeight      = leftWeight;
        }   // end of SetLoopedAnimationWeights()
예제 #25
0
        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()