private void AIMove(object state) { // block usage if a menu is being displayed if (Map.IsPaused) { return; } // move the AI int index = (int)state; Stopwatch timer = new Stopwatch(); timer.Start(); if (Players[index] is AI) { AI ai = Players[index] as AI; float xdelta = 0; float ydelta = 0; float angle = 0; // the timer is reentrant, so only allow one instance to run if (System.Threading.Interlocked.CompareExchange(ref ai.RunningState, 1, 0) != 0) { return; } if (ai.IsDead) { // drop the current players goodies Map.Drop(ai); ai.SwitchWeapon(); Map.Drop(ai); // stop the timer AITimers[index].Dispose(); return; } // NOTE: Do not apply the ZoomFactor (as it distorts the AI when debugging) - TODO may want to allow this while parachuting // TODO will likely want to translate into a copy of the list with reduced details List <Element> elements = Map.WithinWindow(ai.X, ai.Y, Constants.ProximityViewWidth, Constants.ProximityViewHeight).ToList(); var angleToCenter = Collision.CalculateAngleFromPoint(ai.X, ai.Y, Background.X, Background.Y); var inZone = Background.Damage(ai.X, ai.Y) > 0; if (Constants.CaptureAITrainingData) { // capture what the ai sees AITraining.CaptureBefore(ai, elements, angleToCenter, inZone); } // get action from AI var action = ai.Action(elements, angleToCenter, inZone, ref xdelta, ref ydelta, ref angle); // turn ai.Angle = angle; // perform action bool result = false; Type item = null; switch (action) { case ActionEnum.Drop: item = Map.Drop(ai); result |= (item != null); ai.Feedback(action, item, result); break; case ActionEnum.Pickup: item = Map.Pickup(ai); result |= (item != null); ai.Feedback(action, item, result); break; case ActionEnum.Reload: var reloaded = ai.Reload(); result |= (reloaded == AttackStateEnum.Reloaded); ai.Feedback(action, reloaded, result); break; case ActionEnum.Attack: var attack = Map.Attack(ai); result |= attack == AttackStateEnum.FiredAndKilled || attack == AttackStateEnum.FiredWithContact || attack == AttackStateEnum.MeleeAndKilled || attack == AttackStateEnum.MeleeWithContact; ai.Feedback(action, attack, result); break; case ActionEnum.SwitchWeapon: var swap = ai.SwitchWeapon(); result |= swap; ai.Feedback(action, null, result); break; case ActionEnum.Move: case ActionEnum.None: break; default: throw new Exception("Unknown ai action : " + action); } // have the AI move float oxdelta = xdelta; float oydelta = ydelta; var moved = Map.Move(ai, ref xdelta, ref ydelta); ai.Feedback(ActionEnum.Move, null, moved); // ensure the player stays within the map if (ai.X < 0 || ai.X > Map.Width || ai.Y < 0 || ai.Y > Map.Height) { System.Diagnostics.Debug.WriteLine("Out of bounds"); } if (ai.RecordTraining) { // capture what the ai sees AITraining.CaptureAfter(ai, action, oxdelta, oydelta, angle, action == ActionEnum.None || action == ActionEnum.Move ? moved : result); } // set state back to not running System.Threading.Volatile.Write(ref ai.RunningState, 0); } timer.Stop(); if (timer.ElapsedMilliseconds > 100) { System.Diagnostics.Debug.WriteLine("**AIMove Duration {0} ms", timer.ElapsedMilliseconds); } }
public void KeyPress(char key) { // inputs that are accepted while a menu is displaying if (Map.IsPaused) { switch (key) { // menu case Constants.Esc: HideMenu(); break; } return; } // menu if (key == Constants.Esc) { ShowMenu(); return; } // for training we track the human movements (as the supervised set) if (Human.RecordTraining) { // capture what the user sees List <Element> elements = Map.WithinWindow(Human.X, Human.Y, Constants.ProximityViewWidth, Constants.ProximityViewHeight).ToList(); var angleToCenter = Collision.CalculateAngleFromPoint(Human.X, Human.Y, Background.X, Background.Y); var inZone = Background.Damage(Human.X, Human.Y) > 0; AITraining.CaptureBefore(Human, elements, angleToCenter, inZone); } // handle the user input ActionEnum action = ActionEnum.None; bool result = false; float xdelta = 0; float ydelta = 0; switch (key) { // move case Constants.Down: case Constants.Down2: case Constants.DownArrow: ydelta = 1; break; case Constants.Left: case Constants.Left2: case Constants.LeftArrow: xdelta = -1; break; case Constants.Right: case Constants.Right2: case Constants.RightArrow: xdelta = 1; break; case Constants.Up: case Constants.Up2: case Constants.UpArrow: ydelta = -1; break; case Constants.Switch: action = ActionEnum.SwitchWeapon; result = SwitchWeapon(Human); break; case Constants.Pickup: case Constants.Pickup2: action = ActionEnum.Pickup; result = Pickup(Human); break; case Constants.Drop3: case Constants.Drop2: case Constants.Drop4: case Constants.Drop: action = ActionEnum.Drop; result = Drop(Human); break; case Constants.Reload: case Constants.MiddleMouse: action = ActionEnum.Reload; result = Reload(Human); break; case Constants.Space: case Constants.LeftMouse: action = ActionEnum.Attack; result = Attack(Human); break; case Constants.RightMouse: // use the mouse to move in the direction of the angle float r = (Human.Angle % 90) / 90f; xdelta = 1 * r; ydelta = 1 * (1 - r); if (Human.Angle > 0 && Human.Angle < 90) { ydelta *= -1; } else if (Human.Angle > 180 && Human.Angle <= 270) { xdelta *= -1; } else if (Human.Angle > 270) { ydelta *= -1; xdelta *= -1; } break; } // if a move command, then move if (xdelta != 0 || ydelta != 0) { action = ActionEnum.Move; result = Move(Human, xdelta, ydelta); } // for training we track the human movements (as the supervised set) if (Human.RecordTraining) { // capture the result AITraining.CaptureAfter(Human, action, xdelta, ydelta, Human.Angle, result); } }