/// <summary> /// Called from the Arena, when a bot calls the Arena.Cannon() method /// /// The Cannon() function fires a missile heading a specified range and direction. /// Cannon() returns 1 (true) if a missile was fired, or 0 (false) if the cannon is reloading. /// Degree is forced into the range 0-359 as in Scan() and Drive(). /// Range can be 0-700, with greater ranges truncated to 700. /// /// Examples: /// degree = 45; // set a direction to test /// if ((range=Scan(robot, degree, 2)) > 0) // see if a target is there /// Cannon(robot, degree, range); // fire a missile /// </summary> /// <param name="robot"></param> /// <param name="degree"></param> /// <param name="range"></param> /// <returns></returns> public bool FireCannon(Robot robot, int degree, int range) { degree = Arena.DegreeTo360(degree); if (range < 0) { range = 0; } if (range > 700) { range = 700; } BotAssembly bot = Bots.Find(botAssembly => botAssembly.Id == robot.Id); if (bot.MissilesInFlight < MaxMissles) { bot.MissilesInFlight++; Missiles.Add(new Missile { Id = robot.Id, Speed = 100, Location = new PointF { X = bot.Location.X, Y = bot.Location.Y }, Direction = degree, Range = range }); return(true); } return(false); }
/// <summary> /// Called from the Arena, when a bot calls the Arena.Scan() method /// /// The Scan() function invokes the robot's scanner, at a specified degree and resolution. /// Scan() returns 0 if no robots are within the scan range or a positive integer representing /// the range to the closest robot. Degree should be within the range 0-359, otherwise degree /// is forced into 0-359 by a modulo 360 operation, and made positive if necessary. /// Resolution controls the scanner's sensing resolution, up to +/- 10 degrees. /// /// Examples: /// range = Scan(robot, 45, 0); // scan 45, with no variance /// range = Scan(robot, 365, 10); // scans the range from 355 to 15 /// </summary> /// <param name="robot"></param> /// <param name="degree"></param> /// <param name="resolution"></param> /// <returns></returns> public int Scan(Robot robot, int degree, int resolution) { degree = Arena.DegreeTo360(degree); if (resolution < 0) { resolution = 0; } if (resolution > MaxScanResolution) { resolution = MaxScanResolution; } // Get the BotAssembly of the given robot from our list of robots BotAssembly botAssembly = Bots.Find(ba => ba.Id == robot.Id); // Update these for display botAssembly.ScanDirection = degree; botAssembly.ScanResolution = resolution; // Iterate all bots (Max of 4 bots in the game) foreach (var bot in Bots) { // As long as it is not the given robot if (bot != botAssembly) { // Plot a course from this bot to the given methods bot int course = Arena.PlotCourse((int)bot.Location.X, (int)bot.Location.Y, (int)botAssembly.Location.X, (int)botAssembly.Location.Y); // Given the Scan resolution ( +/- 10 degrees maximum ) is there a bot out there? int degStart = Arena.DegreeTo360(degree - resolution); int degEnd = Arena.DegreeTo360(degree + resolution); for (int scanResolution = degStart; scanResolution <= degEnd; ++scanResolution) { if (course == scanResolution) { // Return the range to the discovered target int range = Math.Abs(Arena.Distance((int)bot.Location.X, (int)bot.Location.Y, (int)botAssembly.Location.X, (int)botAssembly.Location.Y)); // Return the range to the discovered robot if distance is MaxScanRange or less return(range);//range >= MaxScanRange ? range : 0; } } } } // No robot found return(0); }
/// <summary> /// Initialize the given robot with the given id, assign a random /// starting location and call the robots InitMethod /// </summary> /// <param name="bot"></param> /// <param name="id"></param> private static void Ininialize(ref BotAssembly bot, int id) { bot.Id = id; bot.Location.X = Arena.Rand(ArenaWidth) - 1; bot.Location.Y = Arena.Rand(ArenaHeight - 1); bot.LastLocation.X = bot.Location.X; bot.LastLocation.Y = bot.Location.Y; // Zero by default : bot.Speed = 0; bot.LastSpeed = 0; bot.Damage = 0; bot.Direction = 0; bot.ScanDirection = 0; bot.MissilesInFlight = 0; bot.Assembly.GetType(Namespace + "." + bot.ClassName).GetProperty("Id").SetValue(bot.AssemblyInstance, id, null); bot.Assembly.GetType(Namespace + "." + bot.ClassName).GetMethod(InitMethod).Invoke(bot.AssemblyInstance, null); }
/// <summary> /// Load given robots, compile, instantiate and initialize /// Sets loaded robots Id's and calls each robots Initialize method /// </summary> /// <param name="botsSource"></param> /// <returns></returns> public bool Load(string[] botsSource) { string currentSourceFile = String.Empty; Bots.Clear(); if (null != Errors) { Errors.Clear(); } try { int botId = 1; foreach (var sourceFile in botsSource) { // Create a unique assembly name so we can pit the same bot class against itself string assemblyName = Path.GetFileNameWithoutExtension(sourceFile) + botId; currentSourceFile = sourceFile; BotAssembly bot = Compile(sourceFile, assemblyName); if (null == bot || null == bot.AssemblyInstance) { return(false); } Ininialize(ref bot, ++botId); Bots.Add(bot); } } catch (Exception ex) { if (null != Errors) { Errors.Add(new CompilerError(currentSourceFile, 0, 0, "0", ex.ToString())); } return(false); } return(true); }
/// <summary> /// The Execute method is called repeatedly and runs the robots /// on the battle field calling each robots Execute method, updating /// in flight missiles, checking for collisions and updating damage. /// </summary> public bool Execute() { int totalDamage = 0; // Work out how long since we were last here in seconds double gameTime = _timer.ElapsedMilliseconds / 1000.0; double elapsedTime = gameTime - _lastTime; _lastTime = gameTime; // Remove any missiles that died last game frame if (_deadMissiles) { RemoveDeadMissles(); } // Update any missiles foreach (var missile in Missiles) { missile.LastLocation = missile.Location; // Update robot position based on the velocity missile.Location.X += (float)Math.Sin(missile.Direction * Math.PI / 180) * missile.Speed * (float)elapsedTime; missile.Location.Y += (float)Math.Cos(missile.Direction * Math.PI / 180) * missile.Speed * (float)elapsedTime; missile.Range -= Arena.Distance((int)missile.LastLocation.X, (int)missile.LastLocation.Y, (int)missile.Location.X, (int)missile.Location.Y); // If a missile is leaving the arena, i.e. hitting a wall, explode it by setting it's range to 0 if (missile.Location.X < 0 || missile.Location.Y < 0 || missile.Location.X > ArenaWidth - 1 || missile.Location.Y > ArenaHeight - 1) { missile.Range = 0; } // Missile has reached it's defined range. if (missile.Range <= 0) { // Explode the missile // TODO Determine any damage to bots in the area // Iterate each robot. Get range to this missile. If in damage range, apply the damage. // Update the bot that fired the missile Missile missile1 = missile; BotAssembly bot = Bots.Find(botAssembly => botAssembly.Id == missile1.Id); bot.MissilesInFlight--; // Mark missile as dead so we can clean it up missile.Dead = true; _deadMissiles = true; } } // Update bots foreach (var bot in Bots) { totalDamage += bot.Damage; // 100% damaged bots do nothing if (bot.Damage != 100) { // Check if robot is changing there speed // TODO Need to ramp up/down to the robots set speed //if (bot.Speed != bot.LastSpeed) //{ // if (bot.Direction >= 0 && bot.Direction <= 180) // { // bot.Velocity.X += 40; // bot.Velocity.Y += 40; // } // else // { // bot.Velocity.X -= 40; // bot.Velocity.Y -= 40; // } // bot.LastSpeed = bot.Speed; //} bot.LastLocation = bot.Location; // Update robot position based on the velocity bot.Location.X += (float)Math.Sin(bot.Direction * Math.PI / 180) * bot.Speed * (float)elapsedTime; bot.Location.Y += (float)Math.Cos(bot.Direction * Math.PI / 180) * bot.Speed * (float)elapsedTime; // Fix the robots position to not leave the Arena if (bot.Location.X < 0) { bot.Location.X = 0; } if (bot.Location.X > ArenaWidth - 1) { bot.Location.X = ArenaWidth - 1; } if (bot.Location.Y < 0) { bot.Location.Y = 0; } if (bot.Location.Y > ArenaHeight - 1) { bot.Location.Y = ArenaHeight - 1; } // TODO Add collision detection and damage // Have robots perform an execution step bot.Assembly.GetType(Namespace + "." + bot.ClassName).GetMethod(ExecuteMethod).Invoke(bot.AssemblyInstance, null); } } return(totalDamage == 300 ? false : true); }
/// <summary> /// Initialize the given robot with the given id, assign a random /// starting location and call the robots InitMethod /// </summary> /// <param name="bot"></param> /// <param name="id"></param> private static void Ininialize(ref BotAssembly bot, int id) { bot.Id = id; bot.Location.X = Arena.Rand(ArenaWidth)-1; bot.Location.Y = Arena.Rand(ArenaHeight-1); bot.LastLocation.X = bot.Location.X; bot.LastLocation.Y = bot.Location.Y; // Zero by default : bot.Speed = 0; bot.LastSpeed = 0; bot.Damage = 0; bot.Direction = 0; bot.ScanDirection = 0; bot.MissilesInFlight = 0; bot.Assembly.GetType(Namespace + "." + bot.ClassName).GetProperty("Id").SetValue(bot.AssemblyInstance, id, null); bot.Assembly.GetType(Namespace + "." + bot.ClassName).GetMethod(InitMethod).Invoke(bot.AssemblyInstance, null); }