AI & 2D Development COSC 315 Fall 2014 Bridget M. Blodgett Artificial Intelligence • Why the Turing Test is BS • What is the goal of including AI in games? • Although genuine AI would be nice we need to start small • Making sprites appear randomly is a good first step towards a more natural AI Random • XNA has a built in Random number function – It isn’t great but it works for what we need to do • It is a good idea to create a single random variable and then call it for all your randomization needs • If you make multiple variables and call them too quickly you could end up making numbers off the same seed – This defeats the purpose of randomness Making Random Variables • The first step is to create some placeholder variables to hold your randomly generated number and initialize it in your game1 class constructor public Random rnd{get; private set;} rnd = new Random(); • We also need some class variables to define the frequency of enemy spawns int int int int enemySpawnMinMilliseconds = 1000; enemySpawnMaxmillisends = 2000; enemyMinSpeed = 2; enemyMaxSpeed = 6; Using SpriteManager • Remove the code that makes the stationary sprites from LoadContent • The method should only have the player variable now • Make a class variable called: – int nextSpawnTime = 0; • Make a new method in SpriteManager private void ResetSpawnTime() { nextSpawnTime = ((Game1)Game).rnd.Next( enemySpawnMinMilliseconds, enemySpawnMaxMilliseconds); } ResetSpawnTimer() • Now call your new method in Initialize() • This will set up the spawner but adding code to the Update method will get it running nextSpawnTime -= gameTime.ElapsedGameTime.Milliseconds; if(nextSpawnTime < 0) { SpawnEnemy(); ResetSpawnTime(); } • Right now this makes a call to a function that doesn’t exist but that will be added next Spawn Enemy • There are several things that need to be done: – The enemy needs a starting position, starting speed, added to the spriteList private void SpawnEnemy(){ Vector2 speed = Vector2.Zero; Vector2 position = Vector2.Zero; Point frameSize = new Point(75,75); } • After declaring these variables you need to write code to set them switch (((Game1)Game).rnd.Next(4)){ case 0: position = new Vector2(-frameSize.X, ((Game1)Game).rnd.Next(0,Game.GraphicsDevice.Present ationParameters.BackBufferHeight – frameSize.Y)); speed = new Vector2(((Game1)Game).rnd(Next(enemyMinSpeed, enemyMaxSpeed), 0); break; case 1: position = new Vector2( Game.GraphicsDevice.PresentationParameters.BackBuffe rWidth, ((Game1)Game).rnd.Next(0,Game.GraphicsDevice.Present ationParameters.BackBufferHeight – frameSize.Y)); speed = new Vector2(((Game1)Game).rnd(Next(enemyMinSpeed, enemyMaxSpeed), 0); break; case 2: position = new Vector2(((Game1)Game).rnd.Next(0,Game.GraphicsDevice .PresentationParameters.BackBufferWidth – frameSize.X), Game.GraphicsDevice.PresentationParameters.BackBuffe rHeight); speed = new Vector2(0, ((Game1)Game).rnd(Next(enemyMinSpeed, enemyMaxSpeed)); break; case 3: position = new Vector2(((Game1)Game).rnd.Next(0,Game.GraphicsDevice .PresentationParameters.BackBufferWidth – frameSize.X), -frameSize.Y); speed = new Vector2(0,((Game1)Game).rnd(Next(enemyMinSpeed, enemyMaxSpeed)); break; } spriteList.Add(new AutomatedSprite(Game.Content.Load<Texture2D>(@”images\s kullball”), position, new Point(75,75), 10, new Point(0,0), new Point (6,8), speed, “skullcollision”)); } //this closes the method! Irrelevant Objects • Right now if a sprite passes outside the boundary they just keep going • This means that the game will get slower the longer it’s played – Why? • There are a number of different solutions to this issue Boundary Rectangles • Just like for collisions we can use a rectangle to determine when an object goes outside the window bounds • In the sprite class add the following method public bool IsOutOfBounds(Rectangle clientRect) { if(position.X < -frameSize.X || position.X > clientRect.Width || position.Y < -frameSize.Y || position.Y > clientRect.Height) { return true; } return false; } • Now you need to fix update to check the sprites each call for (int I = 0; I < spriteList.Count; ++i){ Sprite s = spriteList[i]; s.Update(gameTime, Game.Window.ClientBounds); if (s.collisionRect.Intersects(player.collisionRect)) { spriteList.RemoveAt(i); --i; } if (s.IsOutOfBounds(Game.Window.ClientBounds)) { spriteList.RemoveAt(i); --i; } } Player Aware Sprites • So our enemies are still pretty basic and don’t really react to the player • Using a simple algorithm that determines the player’s position and moves the sprites accordingly you can make two new types of enemies: chasers and evaders • Both of these require making a small modification to the Sprite base class to accept the player’s location