public override ProgrammingElement Clone() { MouseFilter clone = new MouseFilter(); CopyTo(clone); return(clone); }
public override bool MatchAction(Reflex reflex, out object param) { param = null; GUIButton button = GUIButtonManager.GetButton(color); bool clicked = (null != button) && button.Clicked; if (reflex.Sensor is MouseSensor) { clicked &= button.MouseControlled; MouseFilter mouseFilter = reflex.Data.GetFilterByType(typeof(MouseFilter)) as MouseFilter; if (null != mouseFilter) { switch (mouseFilter.type) { case MouseFilterType.LeftButton: clicked &= button.MouseLeftClick; break; case MouseFilterType.RightButton: clicked &= !button.MouseLeftClick; break; case MouseFilterType.Hover: clicked = button.MouseOver; break; default: clicked = false; break; } } } else { clicked &= !button.MouseControlled; } return(clicked); }
protected void CopyTo(MouseFilter clone) { base.CopyTo(clone); clone.type = this.type; }
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 void ComposeSensorTargetSet(GameActor gameActor, Reflex reflex) { if (terrainSensor != null) { terrainSensor.ComposeSensorTargetSet(gameActor, reflex); } else { List <Filter> filters = reflex.Filters; MouseFilter mouseFilter = reflex.Data.GetFilterByType(typeof(MouseFilter)) as MouseFilter; if (mouseFilter == null) { // TODO this should trigger a hint. You should always have a mouse filter with a mouse sensor. return; } // Cause the filter to detect what is under the mouse cursor and set that information on the reflex. // MatchAction will be true if the MouseFilter passes but then we still need to filter on any other // filters including the ever annoying "not", "me" and "anything" filters. Object param = null; bool matchAction = mouseFilter.MatchAction(reflex, out param); //----------------------------- //GUI Button filter. GUIButtonFilter guiButtonFilter = reflex.Data.GetFilterByType(typeof(GUIButtonFilter)) as GUIButtonFilter; if (null != guiButtonFilter) { matchAction = guiButtonFilter.MatchAction(reflex, out param); } bool notFilter = reflex.Data.FilterExists("filter.not"); bool anythingFilter = reflex.Data.FilterExists("filter.anything"); // Give the anythingFilter a chance to kill the action. if (anythingFilter && reflex.MouseActor == null) { matchAction = false; } bool mouseCursorTarget = false; bool mouseTargetNeeded = false; if (matchAction || reflex.IsMovement) { GameActor mouseActor = reflex.MouseActor; // Preserve this in case we null out the reflex ref and then restore it because of "not". Argh. // If we have an actor mouse target, check if it passes the filters. // If not, null it out. if (reflex.MouseActor != null) { // Create a target. SensorTarget target = SensorTargetSpares.Alloc(); target.Init(reflex.Task.GameActor, reflex.MouseActor); // Test againt the filters. for (int i = 0; i < filters.Count; i++) { if (!filters[i].MatchTarget(reflex, target)) { reflex.MouseActor = null; matchAction = false; } } // Handle "not" filter. if (notFilter) { if (reflex.MouseActor == null) { // Restore MouseActor. reflex.MouseActor = mouseActor; } else { // Killed by the "not" filter. reflex.MouseActor = null; reflex.MousePosition = null; matchAction = false; } } // If we stil have a target, add it to the target set. if (reflex.MouseActor != null) { reflex.targetSet.Add(target); mouseCursorTarget = true; } else { // Don't really need this target so free it. SensorTargetSpares.Free(target); } } else { // No MouseActor case (the mouse click was not on an actor) // If we have any classification filters, then we must have been // looking for an actor. Since we don't have an actor, the // result is false. if (reflex.hasClassificationFitler) { matchAction = false; } // If we've got a me filter and not MouseActor we've failed. if (reflex.hasMeFilter) { matchAction = false; } // MouseActor is null so we didn't click on anything which means that if we have an anything // filter, matchAction should stay false. Unless, of course we also have a notFilter. if (!anythingFilter || notFilter) { // No mouse actor but if we have a "not" or this is a movement toward reflex then the result should be true. // The WHEN Mouse Over DO Turn Toward option is used for mouse-look style controls. // Note that if the reflex is Move Forward we don't want this to trigger. if (notFilter || (reflex.IsMovement && reflex.selectorUpid == "selector.towardclosest") || (reflex.IsMovement && reflex.actuatorUpid == "actuator.turn")) { mouseTargetNeeded = true; matchAction = true; } } } } else { if (notFilter || reflex.IsMovement) { mouseTargetNeeded = true; } } // If MouseActor is null, we may still want to target a position on the ground. //if (reflex.MouseActor == null && !matchAction && reflex.IsMovement) if (mouseTargetNeeded || (reflex.MouseActor == null && matchAction)) { if (reflex.MousePosition != null) { // We need to add the mouse position to the targetSet. SensorTarget target = SensorTargetSpares.Alloc(); target.GameThing = senseSet.Nearest != null ? senseSet.Nearest.GameThing : NullActor.Instance; target.Position = reflex.MousePosition.Value; target.Direction = target.Position - reflex.Task.GameActor.Movement.Position; target.Range = target.Direction.Length(); // If we've arrived at the target position, clear MousePosition. Vector2 dir2d = new Vector2(target.Direction.X, target.Direction.Y); if (dir2d.LengthSquared() < 0.1f) { reflex.MousePosition = null; } target.Direction /= target.Range; reflex.targetSet.Add(target); mouseCursorTarget = true; } else { // Is this a mouse move case? If so translate the param values into // a target the actuator can use. MouseFilter filter = (MouseFilter)reflex.Data.GetFilterByType(typeof(MouseFilter)); if (filter.type == MouseFilterType.Move) { Vector2 position = (Vector2)param; SensorTarget target = SensorTargetSpares.Alloc(); target.GameThing = senseSet.Nearest.GameThing; // Calc fake position. GameActor actor = reflex.Task.GameActor; Vector3 pos = actor.Movement.Position; target.Position = pos; target.Direction = target.Position - reflex.Task.GameActor.Movement.Position; target.Range = target.Direction.Length(); if (target.Range == 0) { target.Direction = Vector3.Zero; } else { target.Direction /= target.Range; } reflex.targetSet.Add(target); reflex.targetSet.Param = position; mouseCursorTarget = true; } } } reflex.targetSet.Action = reflex.targetSet.Count > 0 && TestObjectSet(reflex); reflex.targetSet.Action |= matchAction; // This forces the movement to keep going toward the clicked position/bot // even if the mouse is no longer clicked. reflex.targetSet.ActionMouseTarget = mouseCursorTarget; reflex.targetSet.Action = PostProcessAction(reflex.targetSet.Action, reflex); } }
private void RunActuators() { verbExecutions.SetAll(false); GameActor.Movement.UserControlled = IsUserControlled; // Do not update actuators during pre-game. if (InGame.inGame.PreGameActive) { return; } int initialTaskId = Brain.ActiveTaskId; for (int i = 0; i < reflexes.Count; ++i) { Reflex reflex = reflexes[i] as Reflex; if (reflex.Actuator != null && reflex.targetSet.AnyAction) { if (reflex.Actuator is VerbActuator) { // Ugh, be backward compatible with the old arbitrated verb behavior. VerbActuator verbAct = reflex.Actuator as VerbActuator; // If the verb is exclusive AND we've already seen in then don't process it. if (GameThing.VerbIsExclusive(verbAct.Verb) && verbExecutions.Get((int)verbAct.Verb)) { continue; } else { // This is the first time we've seen the verb so flag it. verbExecutions.Set((int)verbAct.Verb, true); } } // If we have a mouse sensor AND a once modifier then // we want to tag the mouse button with IgnoreUntilReleased. // This makes once work correctly without blocking other // reflexes from seeing the mouse. if (reflex.Sensor is MouseSensor) { OnceModifier om = null; for (int j = 0; j < reflex.Modifiers.Count; j++) { om = reflex.Modifiers[j] as OnceModifier; if (om != null) { break; } } if (om != null) { MouseFilter mf = null; for (int j = 0; j < reflex.Filters.Count; j++) { mf = reflex.Filters[j] as MouseFilter; if (mf != null) { break; } } if (mf != null) { // By setting IgnoreUntilReleased, this prevents another // reflex from being triggered until the mouse is released. switch (mf.type) { case MouseFilterType.LeftButton: MouseInput.Left.IgnoreUntilReleased = true; break; case MouseFilterType.RightButton: MouseInput.Right.IgnoreUntilReleased = true; break; default: // Nothing to see here, move along. break; } } } } reflex.Actuator.Update(reflex); // Stop updating actuators if we switched pages. if (Brain.ActiveTaskId != initialTaskId) { break; } } } }