public override ActionSet ComposeActionSet(Reflex reflex, GameActor gameActor)
        {
            ClearActionSet(actionSet);
            UpdateCanBlend(reflex);

            if (!reflex.targetSet.AnyAction)
            {
                return(actionSet);
            }

            SensorTarget target = reflex.targetSet.Nearest;

            if (target != null)
            {
                // Calculate a vector toward target.
                Vector3 value = target.Direction;

                bool apply = reflex.ModifyHeading(gameActor, Modifier.ReferenceFrames.World, ref value);

                if (apply)
                {
                    actionSet.AddAction(Action.AllocTargetLocationAction(reflex, target.Position, autoTurn: true));
                }
            }

            return(actionSet);
        }
        public override ActionSet ComposeActionSet(Reflex reflex, GameActor gameActor)
        {
            ClearActionSet(actionSet);
            UpdateCanBlend(reflex);

            if (!reflex.targetSet.AnyAction)
            {
                return(actionSet);
            }

            if (reflex.targetSet.Count > 0)
            {
                if (reflex.targetSet.CullToFurthest(gameActor, BlockedFrom))
                {
                    // the targetSet is in order by distance
                    SensorTarget target = reflex.targetSet.Furthest;

                    // calculate a vector toward target
                    Vector3 value = target.Direction;

                    bool apply = reflex.ModifyHeading(gameActor, Modifier.ReferenceFrames.World, ref value);

                    if (apply)
                    {
                        // radius should be from object
                        actionSet.AddAttractor(AllocAttractor(target.Range, value, target.GameThing, reflex), 0.4f);
                    }
                }
            }

            return(actionSet);
        }
        public override ActionSet ComposeActionSet(Reflex reflex, GameActor gameActor)
        {
            ClearActionSet(actionSet);
            UpdateCanBlend(reflex);

            if (!reflex.targetSet.AnyAction)
            {
                return(actionSet);
            }

            if (reflex.targetSet.Count > 0)
            {
                // falloff == Avoid, !falloff == Away
                if (falloff)
                {
                    // Avoid.
                    // We want to avoid all actors so we need to loop over the full set.
                    foreach (SensorTarget target in reflex.targetSet)
                    {
                        GameActor targetActor = target.GameThing as GameActor;
                        if (targetActor != null)
                        {
                            actionSet.AddAction(Action.AllocAvoidAction(reflex, targetActor));
                        }
                    }
                }
                else
                {
                    // Away.
                    Vector3 actorPos = gameActor.Movement.Position;
                    Vector3 dir      = Vector3.Zero; // The direction we want to flee.

                    // We want to move away from all actors so we need to loop over the full set.
                    foreach (SensorTarget target in reflex.targetSet)
                    {
                        GameActor targetActor = target.GameThing as GameActor;

                        if (targetActor != null)
                        {
                            Vector3 fromTarget = actorPos - targetActor.Movement.Position;
                            float   dist       = fromTarget.Length();
                            // Normalize fromTarget then divide again by dist.  This gives us a linear
                            // falloff of strength based on distance so that a target that is twice as
                            // close will have twice the weight on the flee direction.
                            dir += fromTarget / dist / dist;
                        }
                    }

                    bool apply = reflex.ModifyHeading(gameActor, Modifier.ReferenceFrames.World, ref dir);

                    if (apply)
                    {
                        dir.Normalize();
                        actionSet.AddAction(Action.AllocVelocityAction(reflex, dir, autoTurn: true));
                    }
                } // end else if falloff
            }     // end if targetSet not empty.

            return(actionSet);
        }
        public override ActionSet ComposeActionSet(Reflex reflex, GameActor gameActor)
        {
            ClearActionSet(movementSet);
            UpdateCanBlend(reflex);

            if (!reflex.targetSet.Action)
            {
                return(movementSet);
            }

            // calculate a vector relative to the camera and input stick
            // see "Game Programming Gems 2", "Classic Super Mario 64 Third-Person Control and Animation"
            //
            Vector2 valueStick = Vector2.Zero;

            if (reflex.targetSet.Param != null && reflex.targetSet.Param is Vector2)
            {
                valueStick = (Vector2)reflex.targetSet.Param;
            }

            Vector3 cameraDir = InGame.inGame.Camera.ViewDir;

            cameraDir.Z = 0.0f;
            if (cameraDir != Vector3.Zero)
            {
                cameraDir.Normalize();
            }

            Vector3 cameraRight = new Vector3(cameraDir.Y, -cameraDir.X, 0.0f);

            Vector3 value = new Vector3((valueStick.X * cameraRight.X) + (valueStick.Y * cameraDir.X),
                                        (valueStick.X * cameraRight.Y) + (valueStick.Y * cameraDir.Y),
                                        0.0f);

            value *= strength;

            bool apply = reflex.ModifyHeading(gameActor, Modifier.ReferenceFrames.World, ref value);

            if (apply)
            {
                if (reflex.Actuator != null &&
                    (reflex.Actuator.category & Actuator.Category.Action) == Actuator.Category.Action)
                {
                    // support it as action even it it supports direction also
                    movementSet.AddActionTarget(AllocEffector(0.0f, value, null, reflex), 0.0f);
                }
                else
                {
                    // radius should be from object
                    movementSet.AddAttractor(AllocEffector(value.Length() * 3.0f, value, null, reflex), 0.0f);
                }
            }

            return(movementSet);
        }
Exemple #5
0
        public override ActionSet ComposeActionSet(Reflex reflex, GameActor gameActor)
        {
            ClearActionSet(actionSet);
            UpdateCanBlend(reflex);

            if (!reflex.targetSet.AnyAction)
            {
                return(actionSet);
            }

            float angle = (float)Math.Acos(gameActor.Movement.Facing.X);

            if (gameActor.Movement.Facing.Y < 0.0f)
            {
                angle = MathHelper.TwoPi - angle;
            }
            angle += MathHelper.PiOver4; // rotate 45
            angle  = (angle + (float)Math.PI * 2.0f) % ((float)Math.PI * 2.0f);

            // calculate a vector toward target
            Vector3 value = new Vector3();

            value.X = (float)Math.Cos(angle);
            value.Y = (float)Math.Sin(angle);
            value.Z = 0.0f;
            value  *= 0.001f; // remove any forward velocity


            bool apply = reflex.ModifyHeading(gameActor, Modifier.ReferenceFrames.World, ref value);

            if (apply)
            {
                // radius should be from object
                actionSet.AddAttractor(Action.AllocAttractor(0.0f, value, null, reflex), 0.0f);
            }

            // unused // this.used = false; // will get reset if truely used
            return(actionSet);
        }
        public override ActionSet ComposeActionSet(Reflex reflex, GameActor gameActor)
        {
            ClearActionSet(actionSet);
            UpdateCanBlend(reflex);

            if (!reflex.targetSet.AnyAction)
            {
                return(actionSet);
            }

            Vector2 valueStick = defaultStickVector;

            if (reflex.targetSet.Param != null && reflex.targetSet.Param is Vector2)
            {
                // Read the gamepad input
                valueStick = (Vector2)reflex.targetSet.Param;
            }

            Vector3 actorDir = gameActor.Movement.Heading;

            actorDir.Z = 0;

            // The direction we want to be moving.
            Vector3 targetDirection = Vector3.Zero;

            bool isForwardSel = this.Categories.Get((int)BrainCategories.ForwardSelector);

            Vector3 cameraRight = new Vector3(actorDir.Y, -actorDir.X, 0.0f);

            targetDirection = new Vector3((valueStick.X * cameraRight.X) + (valueStick.Y * actorDir.X),
                                          (valueStick.X * cameraRight.Y) + (valueStick.Y * actorDir.Y),
                                          0.0f);

            // We used to normalize here but that makes movement binary instead of analog, ie
            // it acts as if the stick is fully over all the time instead of allowing for
            // finer control.

            /*
             * value.Normalize();
             * // If value was 0,0,0 we'll get NaNs when we normalize so check for this
             * // and restore valid values for value.  (sorry, couldn't resist)
             * if (float.IsNaN(value.X))
             * {
             *  value = Vector3.Zero;
             * }
             */

            targetDirection *= strength;

            bool absoluteDirection = false;

            // See if the modifiers want to give us an absolute direction.
            Vector3 modifiedDirection = Vector3.Zero;
            bool    apply             = reflex.ModifyHeading(gameActor, Modifier.ReferenceFrames.World, ref modifiedDirection);

            if (apply && modifiedDirection != Vector3.Zero)
            {
                // Yes, we have an absolute direction. We still need to apply the non-frame modifiers (speed, color, etc)
                float stickPower = targetDirection.Length();
                targetDirection = modifiedDirection;
                if (stickPower != 0)
                {
                    targetDirection *= stickPower;
                }
                apply             = reflex.ModifyHeading(gameActor, Modifier.ReferenceFrames.Local, ref targetDirection);
                absoluteDirection = true;
            }
            else
            {
                // No absolute direction given, we'll use the input given to us by the brain.
                apply = reflex.ModifyHeading(gameActor, Modifier.ReferenceFrames.World, ref targetDirection);
            }

            if (apply)
            {
                // TODO (****) Move all the Rover specific stuff to the Rover class.  None of this should be here.
                // SGI_MOD also apply the speed modifier for hills for the Rover
                Boku.SimWorld.Chassis.RoverChassis RovChassis = gameActor.Chassis as Boku.SimWorld.Chassis.RoverChassis;
                if (RovChassis != null)
                {
                    RovChassis.ModifyHeading(ref targetDirection);
                }

                if (!reflex.IsUserControlled)
                {
                    if (absoluteDirection)
                    {
                        actionSet.AddAction(Action.AllocVelocityAction(reflex, targetDirection, autoTurn: true));
                    }
                    else
                    {
                        // Move Forward
                        // TODO (****) Is this controllable by stick?  If so, 1.0 should be replaced by stick value.
                        actionSet.AddAction(Action.AllocSpeedAction(reflex, 1.0f));
                    }
                }
                else
                {
                    // If this actor is user controlled, we need to rotate the heading to make it camera relative.
                    // Unless the direction given is an absolute one, like "North".
                    // Note, we need to test for Zero here otherwise we add an action even if the user isn't giving
                    // any inputs.
                    if (targetDirection != Vector3.Zero)
                    {
                        if (!absoluteDirection && !isForwardSel && reflex.Task.IsUserControlled)
                        {
                            Matrix mat = Matrix.CreateRotationZ(InGame.inGame.Camera.Rotation - gameActor.Movement.RotationZ);
                            targetDirection = Vector3.TransformNormal(targetDirection, mat);
                        }

                        actionSet.AddAction(Action.AllocVelocityAction(reflex, targetDirection, autoTurn: true));
                    }
                }
            }

            return(actionSet);
        }
        public override ActionSet ComposeActionSet(Reflex reflex, GameActor gameActor)
        {
            ClearActionSet(actionSet);
            //UpdateCanBlend(reflex);

            if (!reflex.targetSet.AnyAction)
            {
                return(actionSet);
            }

            TurnModifier         turnMod         = reflex.GetModifierByType(typeof(TurnModifier)) as TurnModifier;
            GamePadStickFilter   stickFilt       = reflex.Data.GetFilterByType(typeof(GamePadStickFilter)) as GamePadStickFilter;
            GamePadTriggerFilter triggerFilt     = reflex.Data.GetFilterByType(typeof(GamePadTriggerFilter)) as GamePadTriggerFilter;
            MouseFilter          mouseFilt       = reflex.Data.GetFilterByType(typeof(MouseFilter)) as MouseFilter;
            TouchGestureFilter   touchFilt       = reflex.Data.GetFilterByType(typeof(TouchGestureFilter)) as TouchGestureFilter;
            KeyBoardKeyFilter    keyBoardKeyFilt = reflex.Data.GetFilterByType(typeof(KeyBoardKeyFilter)) as KeyBoardKeyFilter;

            // Will be modified depending on stick or trigger position.
            float speedModifier = 1.0f;

            //
            // Start by looking at the input filters to attenuate speed.
            //

            if (stickFilt != null)
            {
                // Note that we take the sign into account further below.
                // For now, just get the magnitude.
                speedModifier *= (float)Math.Abs(stickFilt.stickPosition.X);
            }
            else if (triggerFilt != null)
            {
                speedModifier *= triggerFilt.triggerValue;
            }
            else if (mouseFilt != null)
            {
                // Note that we take the sign into account further below.
                // For now, just get the magnitude.
                speedModifier *= Math.Abs(mouseFilt.ScreenPosition.X);
            }
            else if (touchFilt != null)
            {
                if (touchFilt.type == TouchGestureFilterType.Rotate)
                {
                    reflex.Task.GameActor.Chassis.WasTouchRotated = true;
                }
            }

            // Decide if we're turning toward a particular direction or
            // setting a turn rate.  Note, this will miss some cases
            // that we clean up further down.  The failure is rooted
            // in TurnModifier if you want to go fix it.  :-)

            Vector3 desiredHeading = Vector3.Zero;
            float   targetHeading  = 0;

            // See if the modifiers want to give us an absolute direction.
            reflex.ModifyHeading(gameActor, Modifier.ReferenceFrames.World, ref desiredHeading);
            targetHeading = MyMath.ZRotationFromDirection(desiredHeading);

            // If we have a desiredHeading, use that, else assume we're just turning.
            if (desiredHeading != Vector3.Zero)
            {
                // We were given an absolute direction, use it.
                actionSet.AddActionTarget(Action.AllocHeadingAction(reflex, targetHeading, speedModifier));
            }
            else
            {
                // Determine which relative direction we should use.
                TurnModifier.TurnDirections direction = TurnModifier.TurnDirections.None;

                if (turnMod != null)
                {
                    // If a turn modifier was specified, use its direction.
                    direction = turnMod.direction;
                }
                else if (stickFilt != null)
                {
                    // No turn modifier but we have a gamepad stick, use it to determine turn direction.
                    direction = stickFilt.stickPosition.X > 0 ? TurnModifier.TurnDirections.Right : TurnModifier.TurnDirections.Left;
                }
                else if (triggerFilt != null)
                {
                    // No turn modifier but we have a gamepad trigger, use it to determine turn direction.
                    // Basically this automatically maps left trigger to left turn and right trigger to right turn.
                    direction = triggerFilt.trigger == GamePadTriggerFilter.GamePadTrigger.LeftTrigger ? TurnModifier.TurnDirections.Left : TurnModifier.TurnDirections.Right;
                }
                else if (mouseFilt != null)
                {
                    // No turn modifier but we do have mouse input.
                    direction = mouseFilt.ScreenPosition.X > 0 ? TurnModifier.TurnDirections.Right : TurnModifier.TurnDirections.Left;
                    // This scaling by 2 has no real justification except
                    // that it matches the magnitude of the original code
                    // so this is more compatible with older games.
                    speedModifier *= 2.0f;
                }
                else if (touchFilt != null)
                {
                    // No turn modifier but we do have touch input.
                    if (touchFilt.type == TouchGestureFilterType.Rotate)
                    {
                        if (touchFilt.DeltaRotation < 0)
                        {
                            direction = TurnModifier.TurnDirections.Left;
                        }
                        else if (touchFilt.DeltaRotation > 0)
                        {
                            direction = TurnModifier.TurnDirections.Right;
                        }
                    }
                    else if (touchFilt.type == TouchGestureFilterType.Tap)
                    {
                        direction = TurnModifier.TurnDirections.Toward;
                    }
                }
                else if (keyBoardKeyFilt != null)
                {
                    if (reflex.targetSet != null)
                    {
                        Vector2 dir = (Vector2)(reflex.targetSet.Param);
                        if (dir.X == 1)
                        {
                            direction = TurnModifier.TurnDirections.Right;
                        }
                        else if (dir.X == -1)
                        {
                            direction = TurnModifier.TurnDirections.Left;
                        }
                    }
                }
                else
                {
                    // Nothing exists that would help us decide which way we should turn, choose left.
                    // This could be the user programming WHEN DO Turn
                    direction = TurnModifier.TurnDirections.Left;
                }

                // Calculate the new direction we want to face.
                switch (direction)
                {
                // Turn to our left.
                case TurnModifier.TurnDirections.Left:
                {
                    float angle = 0.0f;

                    if (touchFilt != null && touchFilt.type == TouchGestureFilterType.Rotate)
                    {
                        angle = gameActor.Movement.RotationZ + Math.Abs(touchFilt.DeltaRotation);
                    }
                    else
                    {
                        angle = gameActor.Movement.RotationZ + MathHelper.PiOver2;
                    }
                    desiredHeading = new Vector3((float)Math.Cos(angle), (float)Math.Sin(angle), 0);

                    actionSet.AddActionTarget(Action.AllocTurnSpeedAction(reflex, speedModifier), 0);
                }
                break;

                // Turn to our right.
                case TurnModifier.TurnDirections.Right:
                {
                    float angle = 0.0f;

                    if (touchFilt != null && touchFilt.type == TouchGestureFilterType.Rotate)
                    {
                        angle = gameActor.Movement.RotationZ - Math.Abs(touchFilt.DeltaRotation);
                    }
                    else
                    {
                        angle = gameActor.Movement.RotationZ - MathHelper.PiOver2;
                    }

                    desiredHeading = new Vector3((float)Math.Cos(angle), (float)Math.Sin(angle), 0);

                    actionSet.AddActionTarget(Action.AllocTurnSpeedAction(reflex, -speedModifier), 0);
                }
                break;

                // Turn to face the direction we are moving.
                case TurnModifier.TurnDirections.Forward:
                {
                    float angle = MyMath.ZRotationFromDirection(gameActor.Movement.Velocity);
                    desiredHeading = new Vector3((float)Math.Cos(angle), (float)Math.Sin(angle), 0);

                    actionSet.AddActionTarget(Action.AllocHeadingAction(reflex, targetHeading, speedModifier));
                }
                break;

                // Turn to face the sensed object.
                case TurnModifier.TurnDirections.Toward:
                    // We're probably here because of WHEN Mouse Left DO Turn Toward.
                    // This is another case where we want a Heading Action.
                    if (reflex.targetSet.Nearest != null)
                    {
                        speedModifier = 1;

                        // If we're doing mouse-look (WHEN Mouse Over DO Turn Toward) try
                        // and create a bit of a dead-zone in the middle.
                        bool mouseOver = false;
                        foreach (Filter f in reflex.Filters)
                        {
                            MouseFilter mf = f as MouseFilter;
                            if (mf != null && mf.type == MouseFilterType.Hover)
                            {
                                mouseOver = true;
                                break;
                            }
                        }

                        desiredHeading = reflex.targetSet.Nearest.Direction;
                        targetHeading  = MyMath.ZRotationFromDirection(desiredHeading);

                        // If mouseOver, calc damping to slow down turning when already looking
                        // in the direction we want.  This helps make it less twitchy.
                        float dampingFactor = 1.0f;
                        if (mouseOver)
                        {
                            float dot = Vector3.Dot(desiredHeading, gameActor.Movement.Heading);

                            float deadzoneAngle = 0.96f;
                            float dampzoneAngle = 0.9f;

                            // If very close to center, just treat as zero.
                            if (dot > deadzoneAngle)
                            {
                                dampingFactor = 0;
                            }
                            else if (dot > dampzoneAngle)
                            {
                                // Not in center, but close so damp turning.
                                // The closer we are to already looking in the correct direction, increase damping.
                                dampingFactor = MyMath.RemapRange(dot, deadzoneAngle, dampzoneAngle, 0, 1);
                                // Smooth the result to flatten out the center.
                                dampingFactor = MyMath.SmoothStep(0, 1, dampingFactor);
                            }
                        }

                        actionSet.AddActionTarget(Action.AllocHeadingAction(reflex, targetHeading, dampingFactor * speedModifier));
                    }
                    break;
                }
            }

            return(actionSet);
        }   // end of ComposeActionSet()
        public override ActionSet ComposeActionSet(Reflex reflex, GameActor gameActor)
        {
            ClearActionSet(actionSet);
            UpdateCanBlend(reflex);

            if (!reflex.targetSet.AnyAction)
            {
                return(actionSet);
            }

            Vector3   direction = Vector3.Zero; // This is either the direction to the nearest target or, if no target, the direction we want (forward, etc).
            GameThing gameThing = null;
            float     range     = 0.0f;

            // TODO (****) This was causing a null ref in the "Green Ghost V Looper" level
            // when the user pressed the mouse button to launch a wisp.  In that case the
            // targetSet has 1 element in it but it's not "valid" so it never goes into
            // the nearestTargets list, hence targetSet.Nearest is null.
            // Note I also pulled the Finalize call out of the if statement since Finialize(sic)
            // is what creates the nearestTargets list.
            // Still need to investigate the underlying cause.
            // Turns out to be an issue with Ghost.  Ghosted objects are "ignored" so not valid
            // for the Nearest list.  Should probably rethink how invisible and ghosted work.

            if (reflex.targetSet.Nearest != null && !(reflex.targetSet.Nearest.GameThing is NullActor))
            {
                // We have a "real" target.
                // The targetSet is in order by distance.
                // Pick the nearest member of the target set.
                SensorTarget target = reflex.targetSet.Nearest;

                direction = target.Direction;
                gameThing = target.GameThing;
                range     = target.Range;
            }
            else
            {
                // No explicit target.
                // This handles the case of WHEN GamePad AButton DO Shoot
                // where instead of having a target we just have a direction.
                if (reflex.targetSet.Param != null && reflex.targetSet.Param is Vector2)
                {
                    direction = new Vector3((Vector2)reflex.targetSet.Param, 0.0f);
                }
                else
                {
                    direction = Vector3.Zero;
                }
                gameThing = null;
                range     = 1.0f;
            }

            bool apply = reflex.ModifyHeading(gameActor, Modifier.ReferenceFrames.World, ref direction);

            if (apply)
            {
                // TODO (****) Probably need a TargetObject Action.
                // radius should be from object
                actionSet.AddActionTarget(Action.AllocAttractor(range, direction, gameThing, reflex), 0.4f);
            }

            return(actionSet);
        }
        public override ActionSet ComposeActionSet(Reflex reflex, GameActor gameActor)
        {
            ClearActionSet(actionSet);
            UpdateCanBlend(reflex);

            if (!reflex.targetSet.AnyAction)
            {
                return(actionSet);
            }

            Vector2 valueStick = Vector2.Zero;

            if (reflex.targetSet.Param != null && reflex.targetSet.Param is Vector2)
            {
                // Read the gamepad input
                valueStick = (Vector2)reflex.targetSet.Param;

                // Flip gamepad axes for buttons and triggers, since they report in the y-axis.
                foreach (Filter filter in reflex.Filters)
                {
                    if (filter is GamePadButtonFilter || filter is GamePadTriggerFilter)
                    {
                        valueStick = new Vector2(valueStick.Y, -valueStick.X);
                    }
                }

                valueStick.Y = 0;
            }
            else
            {
                valueStick = new Vector2(0.75f, 0);
            }

            // Pass stick value to modifiers (quickly, slowly, left, right, etc)
            Vector3 stick3d = new Vector3(valueStick.X, 0, 0);
            bool    apply   = reflex.ModifyHeading(gameActor, Modifier.ReferenceFrames.Local, ref stick3d);

            if (apply)
            {
                float strength = stick3d.Length();

                Vector3 velocity = new Vector3(gameActor.Movement.Velocity.X, gameActor.Movement.Velocity.Y, 0);

                float angle = 0;

                float maxAngle = MathHelper.Pi / 2.01f;

                // Special handling of the "toward" turn modifier, since it doesn't have enough information to know
                // which way "toward" actually is for an actor.
                if (reflex.targetSet.Nearest != null && reflex.HasModifier("modifier.turntoward"))
                {
                    SensorTarget target = reflex.targetSet.Nearest;

                    Vector3 toTarget = target.Direction;
                    toTarget.Z = 0;
                    toTarget.Normalize();

                    angle = MyMath.ZRotationFromDirection(toTarget);

                    Vector3 unit = new Vector3((float)Math.Cos(angle), (float)Math.Sin(angle), 0);

                    // radius should be from object
                    actionSet.AddAttractor(Action.AllocAttractor(target.Range, unit * 0.001f, target.GameThing, reflex, specialInstruction: BaseAction.SpecialInstruction.MatchVectorScale | BaseAction.SpecialInstruction.EnforceMinScale), 0.4f);
                }
                else
                {
                    // Dampen sensitivity for small stick movements.
                    strength *= strength;

                    if (strength > 0.001f)
                    {
                        // Scale the strength so that the speed modifiers have a visible effect.
                        strength *= 0.3f;

                        // See if the modifiers want to give us an absolute direction in which to turn.
                        Vector3 modifiedDirection = Vector3.Zero;
                        reflex.ModifyHeading(gameActor, Modifier.ReferenceFrames.World, ref modifiedDirection);

                        if (modifiedDirection != Vector3.Zero)
                        {
                            // Yes, we have an absolute turn direction.
                            angle = MyMath.ZRotationFromDirection(modifiedDirection);

                            // Check to see whether we're already facing this direction.
                            if (Math.Abs(angle - gameActor.Movement.RotationZ) < 0.001f)
                            {
                                apply = false;
                            }

                            // Put the angle into the local reference frame so that the code below can act on it.
                            // The actor's rotation will be added back in later.
                            angle -= gameActor.Movement.RotationZ;
                        }
                        else
                        {
                            // For relative turning angle, start with the max angle possible in the desired direction. It will be
                            // reduced according to stick input strength in the code below.
                            angle = maxAngle * -Math.Sign(stick3d.X);
                        }

                        if (apply)
                        {
                            // If the actor is moving very slow or standing still, then build a turn vector who's angle
                            // is derived from the strength of the stick input.
                            angle = angle * strength;

                            // Put the angle into the world reference frame.
                            angle += gameActor.Movement.RotationZ;

                            // cap it within 0-pi*2;
                            angle = (angle + MathHelper.TwoPi) % (MathHelper.TwoPi);

                            Vector3 unit = new Vector3((float)Math.Cos(angle), (float)Math.Sin(angle), 0);

                            // radius should be from object; none in this case
                            actionSet.AddAttractor(Action.AllocAttractor(1.0f, unit * 0.001f, null, reflex, specialInstruction: BaseAction.SpecialInstruction.MatchVectorScale | BaseAction.SpecialInstruction.EnforceMinScale), 0.0f);
                        }
                    }
                }
            } // apply

            return(actionSet);
        }
Exemple #10
0
        public override ActionSet ComposeActionSet(Reflex reflex, GameActor gameActor)
        {
            ClearActionSet(actionSet);
            UpdateCanBlend(reflex);

            if (!reflex.targetSet.AnyAction)
            {
                return(actionSet);
            }

            // The targetSet is in order by distance use the closest one.
            // Should be null if 0 count in target set.
            SensorTarget target = reflex.targetSet.Nearest;

            if (target != null && !(target.GameThing is NullActor))
            {
                // calculate a vector toward target
                Vector3 toTarget = target.Position - gameActor.Movement.Position;

                float targetZ = target.GameThing.WorldCollisionCenter.Z;
                float deltaZ  = targetZ - gameActor.WorldCollisionCenter.Z;

                toTarget.Z = 0;
                float dist = toTarget.Length();

                float targetRadius = 0;
                if (target.GameThing != null && !(target.GameThing is NullActor))
                {
                    targetRadius = target.GameThing.BoundingSphere.Radius;
                }
                float radius = targetRadius + gameActor.BoundingSphere.Radius;
                radius  = Math.Max(radius, 1.0f);
                radius *= 8.0f * radiusScale;
                radius *= (1.0f + escapeRadius);

                Vector3 toTargetUnit = Vector3.Normalize(toTarget);

                // Calculate the desired angle relative to the vector toward target.
                float localTheta;
                if (dist > radius)
                {
                    localTheta = (float)Math.Cos(radius / dist);
                }
                else
                {
                    localTheta = -(float)Math.Cos(dist / radius * Math.PI * 0.5);
                }

                // Get the vector from the local desired angle.
                Vector3 localDir = new Vector3(
                    (float)Math.Cos(localTheta),
                    (float)Math.Sin(localTheta),
                    0);

                // Scale the local vector by the strength setting from CardSpace.
                localDir *= strength;

                // Modify the local vector (left, right, quickly, slowly, etc).
                bool apply = reflex.ModifyHeading(gameActor, Modifier.ReferenceFrames.Local, ref localDir);

                if (apply)
                {
                    // Because CCW is considered "left".
                    if (CCW)
                    {
                        localDir.X *= -1;
                    }

                    // Get the modified desired angle.
                    localTheta = MyMath.ZRotationFromDirection(localDir);

                    // Combine with the rotation of vector toward target relative to the actor.
                    float thetaToTarget = MyMath.ZRotationFromDirection(toTargetUnit);
                    float finalTheta    = thetaToTarget + localTheta - MathHelper.PiOver2;

                    // cap it within 0-pi*2;
                    finalTheta = (finalTheta + MathHelper.TwoPi) % (MathHelper.TwoPi);

                    if (controlZ &&
                        (gameActor.Chassis is FloatInAirChassis ||
                         gameActor.Chassis is SwimChassis ||
                         gameActor.Chassis is SaucerChassis))
                    {
                        gameActor.Chassis.TargetAltitude = targetZ;
                    }
                    else
                    {
                        deltaZ = 0;
                    }

                    // Build a heading vector in world space.
                    Vector3 finalDir = new Vector3(
                        (float)Math.Cos(finalTheta),
                        (float)Math.Sin(finalTheta),
                        deltaZ);

                    finalDir.Normalize();

                    CheckEscape(reflex, gameActor, target.Position, target.GameThing, finalDir);

                    finalDir *= localDir.Length();

                    actionSet.AddAction(Action.AllocVelocityAction(reflex, finalDir, autoTurn: true));
                }
            }

            return(actionSet);
        }