public override void ComposeSensorTargetSet(GameActor gameActor, Reflex reflex) { List <Filter> filters = reflex.Filters; // add normal sightSet of items to the targetset // senseSetIter.Reset(); while (senseSetIter.MoveNext()) { SensorTarget target = (SensorTarget)senseSetIter.Current; bool match = true; bool cursorFilterPresent = false; for (int indexFilter = 0; indexFilter < filters.Count; indexFilter++) { Filter filter = filters[indexFilter] as Filter; ClassificationFilter cursorFilter = filter as ClassificationFilter; if (cursorFilter != null && cursorFilter.classification.IsCursor) { cursorFilterPresent = true; } if (!filter.MatchTarget(reflex, target)) { match = false; break; } } if (match) { if (!target.Classification.IsCursor || cursorFilterPresent) { reflex.targetSet.Add(target); } } } if (ListeningForMusic(filters)) { if (HearMusic(filters)) { SensorTarget sensorTarget = SensorTargetSpares.Alloc(); sensorTarget.Init(gameActor, Vector3.UnitZ, 0.0f); reflex.targetSet.AddOrFree(sensorTarget); } } reflex.targetSet.Action = TestObjectSet(reflex); if (reflex.targetSet.Action) { foreach (SensorTarget targ in reflex.targetSet) { gameActor.AddSoundLine(targ.GameThing); } } }
public override void FinishUpdate(GameActor gameActor) { if (gameActor.ThingBeingHeldByThisActor != null) { // presence is only thing important here SensorTarget target = SensorTargetSpares.Alloc(); target.Init(gameActor, gameActor.ThingBeingHeldByThisActor); senseSet.AddOrFree(target); } }
public void Add(GameThing gameThing, Vector3 direction, float range) { if (sensorTargets.ContainsKey(gameThing.UniqueNum)) { return; } SensorTarget target = SensorTargetSpares.Alloc(); target.Init(gameThing, direction, range); sensorTargets.Add(gameThing.UniqueNum, target.Ref()); dirty = true; }
public override void FinishUpdate(GameActor gameActor) { if (terrainSensor != null) { //if (TouchEdit.HitInfo.TerrainHit) { terrainSensor.OverrideSenseMaterial = TouchEdit.HitInfo.TerrainMaterial; } terrainSensor.FinishUpdate(gameActor); } else { if (TouchEdit.HitInfo.HaveActor) { GameActor touchdActor = TouchEdit.HitInfo.ActorHit; Vector3 actorCenter = Vector3.Transform( gameActor.BoundingSphere.Center, gameActor.Movement.LocalMatrix); Vector3 thingCenter = Vector3.Transform( touchdActor.BoundingSphere.Center, touchdActor.Movement.LocalMatrix); Vector3 direction = thingCenter - actorCenter; float range = direction.Length(); if (range > 0.0f) { direction *= 1.0f / range; // Normalize. } SensorTarget target = SensorTargetSpares.Alloc(); target.Init(touchdActor, direction, range); senseSet.AddOrFree(target); } senseSet.Add(NullActor.Instance, Vector3.Zero, float.MaxValue); } }
public override void ComposeSensorTargetSet(GameActor gameActor, Reflex reflex) { if (terrainSensor != null) { terrainSensor.ComposeSensorTargetSet(gameActor, reflex); } else { List <Filter> filters = reflex.Filters; // The sensor will use the first TouchGestureFilter it finds. Since any given reflex // can only have a single one of these, this works well. TouchGestureFilter gestureFilter = null; TouchButtonFilter buttonFilter = null; GUIButtonFilter guiButtonFilter = null; for (int i = 0; i < filters.Count; i++) { if (filters[i] is TouchGestureFilter) { Debug.Assert(null == gestureFilter); gestureFilter = filters[i] as TouchGestureFilter; } if (filters[i] is TouchButtonFilter) { Debug.Assert(null == buttonFilter); buttonFilter = filters[i] as TouchButtonFilter; } if (filters[i] is GUIButtonFilter) { Debug.Assert(null == guiButtonFilter); guiButtonFilter = filters[i] as GUIButtonFilter; } } //if we don't have a filter, do nothing if (null == gestureFilter && null == buttonFilter && null == guiButtonFilter) { //Debug.Assert(false, "Did not find a touch filter for touch sensor."); return; } // Cause the filter to detect what is under the touch cursor and set that information on the reflex. // MatchAction will be true if the TouchFilter 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 = false; bool notFilter = reflex.Data.FilterExists("filter.not"); bool anythingFilter = reflex.Data.FilterExists("filter.anything"); if (gestureFilter != null) { matchAction = gestureFilter.MatchAction(reflex, out param); } if (buttonFilter != null) { // Make the actual on screen button visible if a reflex contains the touch button filter. //TouchButtons.MakeVisible(buttonFilter.button); matchAction = buttonFilter.MatchAction(reflex, out param); } if (guiButtonFilter != null) { matchAction = guiButtonFilter.MatchAction(reflex, out param); } // Give the anythingFilter a chance to kill the action. if (anythingFilter && reflex.TouchActor == null) { matchAction = false; } // Handle the "Not" filter if (notFilter) { if (matchAction) { matchAction = false; reflex.TouchActor = null; reflex.TouchPosition = null; } else { matchAction = true; } } bool touchCursorTarget = false; // We are moving towards a remembered target position if we're the movement actuator. // We do not require a match on the current frame to continue the movement. // Note, in the presence of a "Not" filter, there is no target to "not move" to, so this // is negated. // Also, support turning toward a remembered position. bool movingToTouchPos = (reflex.actuatorUpid == "actuator.movement" && !notFilter); movingToTouchPos |= (reflex.actuatorUpid == "actuator.turn" && !notFilter); if (movingToTouchPos && (reflex.TouchActor == reflex.Task.GameActor)) { // When moving with touch, going towards oneself doesn't make sense. By discarding // the touch actor and using the terrain position, we have a better definition of this // movement. This allows for small positional corrections around the target's bounding // box as well as letting slide movements that begin on oneself to work. reflex.TouchActor = null; reflex.TouchPosition = TouchEdit.HitInfo.TerrainPosition; } if (matchAction || movingToTouchPos) { bool validTarget = false; SensorTarget target = SensorTargetSpares.Alloc(); // If we have an actor touch target, check if it passes the filters. // If not, null it out. if (reflex.TouchActor != null) { // Create a target. target.Init(reflex.Task.GameActor, reflex.TouchActor); validTarget = true; } else { target.Init(reflex.Task.GameActor, reflex.Task.GameActor); // If we've got a me filter and not TouchActor we've failed. if (reflex.Data.FilterExists("filter.me")) { matchAction = false; } // NOTE: For classification purposes, if the user doesn't touch a particular actor, // we create an 'empty' classification. This is because we need a classification object // in order to do reflexes such as 'tap move blimp -> shoot'. If you don't tap an actor, // it needs to compare the absence of an actor to the blimp. if (reflex.TouchPosition != null) { // We need to add the touch position to the targetSet. target.Classification = new Classification(); target.GameThing = senseSet.Nearest.GameThing; target.Position = reflex.TouchPosition.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.TouchPosition = null; } target.Direction /= target.Range; touchCursorTarget = true; validTarget = true; } else { // We don't have an actor or a position. Only with an action match should we // create a sensor target. if (matchAction) { // Calc a fake position for this target. GameActor actor = reflex.Task.GameActor; Vector3 pos = actor.Movement.Position; target.Classification = new Classification(); target.GameThing = senseSet.Nearest.GameThing; target.Position = pos; target.Direction = target.Position - reflex.Task.GameActor.Movement.Position; target.Range = target.Direction.Length(); target.Direction /= target.Range; validTarget = true; } } } // Test the target against the filters. if (validTarget) { for (int i = 0; i < filters.Count; i++) { if (!(filters[i] is TouchGestureFilter)) { if (!filters[i].MatchTarget(reflex, target) || !filters[i].MatchAction(reflex, out param)) { if (!notFilter) { // Failed a match on one of the filters and we don't have a negation // so null things out and short circuit. reflex.TouchActor = null; validTarget = false; matchAction = false; touchCursorTarget = false; break; } } } } } // If we still have a target, add it to the target set. if (validTarget) { reflex.targetSet.Add(target); } else { // Don't really need this target so free it. SensorTargetSpares.Free(target); } } 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 touch is no longer clicked. reflex.targetSet.ActionMouseTarget = touchCursorTarget; if (matchAction) { bool postProcessCheck = PostProcessAction(matchAction, reflex); if (!postProcessCheck) { // We matched the action, but it failed the post process check (used by "Once" modifier), // so we clear the target set. reflex.targetSet.Clear(); } } } }
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); } }
public void UpdateSensors(BrainCategories category) { UpdateUserControlled(); UpdateIsTurning(); UpdateMouseButtonPresence(); if (IsLeftMouseButtonPresent) { MouseEdit.DisableLeftDrag(); } if (IsRightMouseButtonPresent) { MouseEdit.DisableRightOrbit(); } for (int i = 0; i < reflexes.Count; i++) { Reflex reflex = reflexes[i] as Reflex; reflex.targetSet.Clear(); } if (reflexes.Count > 0) { UpdateGameThingSensors(category); for (int indentationLevel = 0; indentationLevel <= maxReflexIndentation; ++indentationLevel) { // After evaluating root-level reflexes, open up to all sensor categories. if (indentationLevel > 0) { category = BrainCategories.NotSpecified; } for (int i = 0; i < reflexes.Count; i++) { Reflex reflex = reflexes[i]; // Only evaluate reflexes at the current level of indentation. if (reflex.Indentation != indentationLevel) { continue; } // Only evaluate sub-reflexes of parents that evaluated true except // in the case where the reflex actuator is movement based. if (reflex.Parent != null && !reflex.Parent.targetSet.Action) { // Nested reflexes with once modifiers need to clear their "once" state. reflex.ResetOnceModifiers(); // Nested reflexes with active mouse targets should still be acted on // so create valid target and action sets for them. Note that this // only applies to reflexes with a movement actuator. This is so you // can have WHEN MouseLeft DO Move and the result will be that the // bot continues to move toward the target (position or bot) even // after the parent reflex goes false. bool mouseTarget = reflex.MousePosition != null || reflex.MouseActor != null; if (mouseTarget && reflex.IsMovement) { // Create a sensor target set if (reflex.MouseActor != null) { // We need to add the mouse actor to the targetSet. SensorTarget target = SensorTargetSpares.Alloc(); target.Init(reflex.Task.GameActor, reflex.MouseActor); reflex.targetSet.Add(target); } else if (reflex.MousePosition != null) { // We need to add the mouse position to the targetSet. SensorTarget target = SensorTargetSpares.Alloc(); target.GameThing = GameActor; target.Position = reflex.MousePosition.Value; target.Direction = target.Position - reflex.Task.GameActor.Movement.Position; target.Range = target.Direction.Length(); target.Direction /= target.Range; reflex.targetSet.Add(target); } reflex.targetSet.ActionMouseTarget = true; reflex.CreateActionSet(GameActor, 0); } continue; } // Don't evaluate reflexes that don't match the given categories, if any were specified. if ((category != BrainCategories.NotSpecified) && (reflex.Sensor == null || !reflex.Sensor.Categories.Get((int)category))) { continue; } reflex.Update(GameActor, i); } } } }
public override void ComposeSensorTargetSet(GameActor gameActor, Reflex reflex) { List <Filter> filters = reflex.Filters; // If we have a "me" filter we need to look at the ShooterHitSet to // see if anything hit us. if (reflex.Data.HasTile("filter.me")) { SensorTargetSet.Enumerator shooterSetIter = (SensorTargetSet.Enumerator)gameActor.ShooterHitSet.GetEnumerator(); shooterSetIter.Reset(); while (shooterSetIter.MoveNext()) { SensorTarget target = (SensorTarget)shooterSetIter.Current; // Filtering doesn't make much sense since the "target" is me. What // I really want to filter on are the characteristics of the shooter. // Which means I need to know the shooter. SensorTarget shooter = SensorTargetSpares.Alloc(); shooter.Init(target.Shooter, target.Direction, target.Range); shooter.Tag = target.Tag; bool match = true; for (int indexFilter = 0; indexFilter < filters.Count; indexFilter++) { Filter filter = filters[indexFilter] as Filter; // Ignore me filter since it shouldn't be possible to shoot yourself. if (filter.upid != "filter.me") { if (!filter.MatchTarget(reflex, shooter)) { match = false; break; } } } if (match) { reflex.targetSet.Add(target); } } } else { // add sensorSet of items to the targetset senseSetIter.Reset(); while (senseSetIter.MoveNext()) { SensorTarget target = (SensorTarget)senseSetIter.Current; bool match = true; for (int indexFilter = 0; indexFilter < filters.Count; indexFilter++) { Filter filter = filters[indexFilter] as Filter; if (!filter.MatchTarget(reflex, target)) { match = false; break; } } if (match) { reflex.targetSet.Add(target); // Until we enable payloads on the 'shot hit' reflex, leave the target in the hit set // so that it will have the payload from the shoot reflex applied to it. //gameActor.MissileHitSet.Remove(target.GameThing); MissileHitTargetParam param = target.Tag as MissileHitTargetParam; SetUpShotDamage(reflex, param); } } } reflex.targetSet.Action = TestObjectSet(reflex); }