Posts
  • File → New Project

    Spawning More Enemies (TriangleShooter)

    • 0 Comments

    Time for my favorite part of Monday – Another article improving my TriangleShooter game! Last week, I promised you that I would spawn some more enemies, and that I would add in some other enemy types to make it more visually appealing. The great news is, both of those things are pretty easy. We’ll get started with the code base from last week, so you can grab that from my SkyDrive share.

    We can start by adding in some additional enemy types. To begin with, we’ll drag and drop the rest of the Enemies from the Enemies file from SkyDrive into the Content project with the first enemy. We’ll then create some variables to hold the textures.

    Textures for Enemy
    1. Texture2D txEnemy3;
    2. Texture2D txEnemy4;
    3. Texture2D txEnemy5;
    4. Texture2D txEnemy6;

    We’ll then load them from the content project in the LoadContent method.

    Loading the Enemy Textures
    1. txEnemy3 = Content.Load<Texture2D>("Enemy-3");
    2. txEnemy4 = Content.Load<Texture2D>("Enemy-4");
    3. txEnemy5 = Content.Load<Texture2D>("Enemy-5");
    4. txEnemy6 = Content.Load<Texture2D>("Enemy-6");

    We can try this out by changing the lines further down in LoadContent to make use of the new textures.

    Creating Diverse Enemies
    1. enemies.Add(new Enemy() { Avatar = txEnemy3, Position = new Vector2(600f, 200f), Rotation = 0f, Speed = 3f });
    2. enemies.Add(new Enemy() { Avatar = txEnemy4, Position = new Vector2(600f, 300f), Rotation = 0f, Speed = 3.5f });
    3. enemies.Add(new Enemy() { Avatar = txEnemy5, Position = new Vector2(600f, 400f), Rotation = 0f, Speed = 4f });

    image

    Next up, we need to start spawning some more enemies. What we’re looking to do here is to bring in new enemies every so often. The faster you spawn the enemies, the more difficult the game would be, so you can play with the amount of time between spawns. In order to track them, though, we’ll need a variable to track how long we have left until the next spawn. Since we’ve got some different enemy types, we may as well add in some randomization, so we’ll create a variable to handle randomness as well. As always, we’ll drop the variable up at the top of the game file.

    Spawn Timer and Randomization
    1. TimeSpan timeToSpawn;
    2.  
    3. Random random;

    And then we initialize them down in Initalize()

    Initializing Spawn and Random
    1. timeToSpawn = new TimeSpan(0, 0, 0, 0, 1000);
    2.  
    3. random = new Random();

    This sets up timeToSpawn as one second. We’ll count down until this reaches zero, then spawn another enemy. Luckily, there’s a easy way to get elapsed game time in the Update Method with the gameTime argument. We’ll subtract the elapsed game time from the timeToSpawn variable, then check to see if it is less than or equal to zero. If it is, we create a new enemy and add it to the enemies list. To add variety, we can pick a random edge, and spawn the enemy somewhere along it so that it doesn’t just always come from the same spot. Finally, we’ll reset the timeToSpawn so that we can spawn another. All of this will go in the Update method after we check the enemy collision.

    Spawning More Enemies
    1. timeToSpawn -= gameTime.ElapsedGameTime;
    2.  
    3. if (timeToSpawn < TimeSpan.Zero)
    4. {
    5.     Vector2 spawnPosition;
    6.     switch (random.Next(4))
    7.     {
    8.         case 0:
    9.             spawnPosition = new Vector2(0, random.Next(480));
    10.             break;
    11.         case 1:
    12.             spawnPosition = new Vector2(800, random.Next(480));
    13.             break;
    14.         case 2:
    15.             spawnPosition = new Vector2(random.Next(800), 0);
    16.             break;
    17.         case 3:
    18.             spawnPosition = new Vector2(random.Next(800), 480);
    19.             break;
    20.         default:
    21.             spawnPosition = Vector2.Zero;
    22.             break;
    23.     }
    24.  
    25.     switch (random.Next(4))
    26.     {
    27.         case 0:
    28.             enemies.Add(new Enemy() { Position = spawnPosition, Rotation = 0f, Avatar = txEnemy3, Speed = 3f });
    29.             break;
    30.         case 1:
    31.             enemies.Add(new Enemy() { Position = spawnPosition, Rotation = 0f, Avatar = txEnemy4, Speed = 3.5f });
    32.             break;
    33.         case 2:
    34.             enemies.Add(new Enemy() { Position = spawnPosition, Rotation = 0f, Avatar = txEnemy5, Speed = 4f });
    35.             break;
    36.         case 3:
    37.             enemies.Add(new Enemy() { Position = spawnPosition, Rotation = 0f, Avatar = txEnemy6, Speed = 4.5f });
    38.             break;
    39.         default:
    40.             break;
    41.     }
    42.  
    43.     timeToSpawn = new TimeSpan(0, 0, 0, 0, random.Next(500) + 250);
    44. }

    image

    There’s just so many of them!

    Next week, we’ll add in shooting! Until this point, we were just a triangle moving around, but now we’ll finally be a triangle that shoots!

    Download the latest version of the source code.

  • File → New Project

    Breaking the Player and Enemy out into Classes (TriangleShooter)

    • 0 Comments

    This week, I’m going to go over how to break out Player and Enemy into classes, which will make it easier to handle multiple enemies, collision, AI, that sort of thing. We’ll be starting things off with the project from last week, so you can go grab that now.

    If you take a look at how we’ve been doing things, you’ll notice that I have been using only the file game1.cs, which was automatically generated for me. When I added an enemy, in order to track its position, I created a variable called enemyPosition, because I was already using position for my player. If I wanted to add another enemy, I would have to do something like enemyTwoPosition or enemy2Position, and the next enemy after that would have to be enemy3Position, and it would just be a pain to have to keep track of all of those and copy all of the attributes for each new instance. It would also be a pain to have to check every instance for their collision, and to have to draw each one. If I changed something in one, I’d have to change it in all of them, and missing one of them could result in a bug that might not be noticed right away, when it would be easiest to fix. That’s why I’m going to break out the player and enemy into their own classes. I’m not going to go into subclassing, although there are a good number of shared attributes that would make it make sense to do so.

    Let’s take a look at what we have, first.

    Current Player and Enemy
    1. Texture2D triangle;
    2. Vector2 position;
    3. float rotation;
    4. Color triangleColor;
    5.  
    6. Texture2D enemy;
    7. Vector2 enemyPosition;

    We only have a texture and a position for the enemy, because it was static in the last article. It would make sense to add rotation to it, as well as a speed variable that will allow us to have different classes of enemies with different speeds. To begin, we’ll need to create a new class. Right click on the TriangleShooter project in the Solution Explorer, and choose Add –> Class. When it asks for a filename, type in Player.cs. Add another class, and name this one Enemy.cs. The contents of the two files is below:

    Player.cs
    1. using Microsoft.Xna.Framework;
    2. using Microsoft.Xna.Framework.Graphics;
    3.  
    4. namespace TriangleShooter
    5. {
    6.     class Player
    7.     {
    8.         public Texture2D Avatar { get; set; }
    9.         public Vector2 Position { get; set; }
    10.         public float Rotation { get; set; }
    11.         public float Speed { get; set; }
    12.     }
    13. }

    Enemy.cs
    1. using Microsoft.Xna.Framework;
    2. using Microsoft.Xna.Framework.Graphics;
    3.  
    4. namespace TriangleShooter
    5. {
    6.     class Enemy
    7.     {
    8.         public Texture2D Avatar { get; set; }
    9.         public Vector2 Position { get; set; }
    10.         public float Rotation { get; set; }
    11.         public float Speed { get; set; }
    12.     }
    13. }

    Essentially, they are the same thing. That’s why I said that you could do well with subclassing, but we’ll keep it like this. I also added Speed onto Player, which will be useful a bit later in the series when I get into fine-tuning your game to make it more fun to play. To take advantage of the new classes, we’ll make a few changes to the game1.cs file. Namely, we’ll modify the variable declaration, the Initalize method, LoadContent, Update, and Draw. We’re just refactoring here. No changes to how the game plays are made in this modification.

    Variable Declaration
    1. GraphicsDeviceManager graphics;
    2. SpriteBatch spriteBatch;
    3.  
    4. Player player;
    5. Texture2D txPlayer;
    6.  
    7. Enemy enemy;
    8. Texture2D txEnemy6;
    9.  
    10. Color triangleColor;
    11.  
    12. int movementId = 0;

    We move most of the initialization until after LoadContent, since we need to load the textures.

    Initialize
    1. protected override void Initialize()
    2. {
    3.     triangleColor = Color.White;
    4.  
    5.     base.Initialize();
    6. }

    Here is where we set up the Player and Enemy instances.

    LoadContent
    1. protected override void LoadContent()
    2. {
    3.     // Create a new SpriteBatch, which can be used to draw textures.
    4.     spriteBatch = new SpriteBatch(GraphicsDevice);
    5.  
    6.     txPlayer = Content.Load<Texture2D>("Triangle");
    7.     txEnemy6 = Content.Load<Texture2D>("Enemy-6");
    8.  
    9.     player = new Player();
    10.     player.Avatar = txPlayer;
    11.     player.Position = Vector2.Zero;
    12.     player.Rotation = 0f;
    13.  
    14.     enemy = new Enemy();
    15.     enemy.Avatar = txEnemy6;
    16.     enemy.Position = new Vector2(600f, 200f);
    17.     enemy.Rotation = 0f;
    18. }

    In the Update method, we switch everything over to use the classes.

    Update
    1. protected override void Update(GameTime gameTime)
    2. {
    3.     // Allows the game to exit
    4.     if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
    5.         this.Exit();
    6.  
    7.     foreach (TouchLocation tl in TouchPanel.GetState())
    8.     {
    9.         if (tl.State == TouchLocationState.Pressed)
    10.         {
    11.             if (movementId == 0)
    12.             {
    13.                 movementId = tl.Id;
    14.             }
    15.         }
    16.  
    17.         if (tl.Id == movementId)
    18.         {
    19.             Vector2 direction = tl.Position - player.Position;
    20.  
    21.             if (direction.LengthSquared() > 100)
    22.             {
    23.                 direction.Normalize();
    24.  
    25.                 player.Rotation = (float)(Math.Atan2(direction.Y, direction.X));
    26.  
    27.                 player.Position += direction * 10;
    28.             }
    29.         }
    30.  
    31.         if (tl.State == TouchLocationState.Released)
    32.         {
    33.             if (tl.Id == movementId)
    34.             {
    35.                 movementId = 0;
    36.             }
    37.         }
    38.     }
    39.  
    40.     if (new Rectangle((int)enemy.Position.X, (int)enemy.Position.Y, txEnemy6.Width, txEnemy6.Height).Contains((int)player.Position.X, (int)player.Position.Y))
    41.     {
    42.         triangleColor = Color.Red;
    43.     }
    44.  
    45.     base.Update(gameTime);
    46. }

    And the same with Draw

    Draw
    1. protected override void Draw(GameTime gameTime)
    2. {
    3.     GraphicsDevice.Clear(Color.Black);
    4.  
    5.     spriteBatch.Begin();
    6.     spriteBatch.Draw(player.Avatar, player.Position, null, triangleColor, player.Rotation, new Vector2(0, txPlayer.Height / 2), 1f, SpriteEffects.None, 0f);
    7.     spriteBatch.Draw(enemy.Avatar, enemy.Position, Color.White);
    8.     spriteBatch.End();
    9.  
    10.     base.Draw(gameTime);
    11. }

    This sets us up perfectly to begin adding additional enemies into the game. Next week, I’ll go ahead and do that, and add some basic AI to the enemies.

    Download the latest version of the source code.

  • File → New Project

    Silicon Valley Code Camp XNA Session

    • 1 Comments

    I am giving a session on XNA for the Windows Phone 7 today at 9:15 AM. For the presentation, I will be walking through the development of a game I am calling Triangle Shooter, because you are a triangle that shoots. I’ve posted the graphics I created to SkyDrive, and after the presentation, I will be posting a series where I walk through the source code and explain how I built the game.

    image

  • File → New Project

    Tweaking and Refactoring (TriangleShooter)

    • 0 Comments

    This week, we’ve got a good base for the TriangleShooter game. It shoots, scores, persists high score, has audio, it really gives you something to work off of. To make it easier to work from, this time around, we’re going to tweak a few things and refactor the source to be more readable and modifiable, which will result in a code base you can extend on your own to improve or re-imagine the game. There are still a few things I want to do to the game, as well, and this will get us in a good place to begin doing so. So let’s get started. You can prepare by grabbing the source code from last week over at the SkyDrive share.

    Now before we get to the refactoring, there is one thing that I need to change. The player had been starting at (0,0), the top left of the play space, which was okay most of the time, but could get you killed if an enemy decided to spawn there. Since the enemies spawn around the edges, I want to start by moving the starting location to somewhere away from the edge, to give you a fighting chance at doing better in the game. To do this, we’ll update the initialization of the player in the NewGame function to the following:

    Player NewGame Initialization
    1. player = new Player() { Avatar = txPlayer, Position = new Vector2(100f, 240f), Rotation = 0f };

    Now we’re ready to start refactoring. The big thing we’re going to do here is move related blocks of code out into methods that we’ll call. If you look through the Update method, there are some blocks of code that can easily be pulled out to distinct methods. We’ll end up getting the following methods:

    Update Methods
    1. UpdatePlayer();
    2.  
    3. UpdateEnemies();
    4.  
    5. SpawnEnemies(gameTime);
    6.  
    7. ShootBullets(gameTime);
    8.  
    9. UpdateBullets();

    The source is a simple copy/paste out of Update, giving us the following method bodies:

    UpdatePlayer
    1. private void UpdatePlayer()
    2. {
    3.     foreach (TouchLocation tl in TouchPanel.GetState())
    4.     {
    5.         if (tl.State == TouchLocationState.Pressed)
    6.         {
    7.             if (movementId == 0)
    8.             {
    9.                 movementId = tl.Id;
    10.             }
    11.         }
    12.  
    13.         if (tl.Id == movementId)
    14.         {
    15.             Vector2 direction = tl.Position - player.Position;
    16.  
    17.             if (direction.LengthSquared() > 100)
    18.             {
    19.                 direction.Normalize();
    20.  
    21.                 player.Rotation = (float)(Math.Atan2(direction.Y, direction.X));
    22.  
    23.                 player.Position += direction * 10;
    24.             }
    25.         }
    26.  
    27.         if (tl.State == TouchLocationState.Released)
    28.         {
    29.             if (tl.Id == movementId)
    30.             {
    31.                 movementId = 0;
    32.             }
    33.         }
    34.     }
    35. }
    UpdateEnemies
    1. private void UpdateEnemies()
    2. {
    3.     foreach (Enemy enemy in enemies)
    4.     {
    5.         enemy.Rotation += ((float)Math.PI / 30f) % ((float)Math.PI * 2);
    6.  
    7.         Vector2 enemyDirection = player.Position - enemy.Position;
    8.  
    9.         if (enemyDirection.LengthSquared() > enemy.Speed * enemy.Speed)
    10.         {
    11.             enemyDirection.Normalize();
    12.  
    13.             enemy.Position += enemyDirection * enemy.Speed;
    14.         }
    15.  
    16.         if (new Rectangle((int)enemy.Position.X - enemy.Avatar.Width / 2, (int)enemy.Position.Y - enemy.Avatar.Height / 2, enemy.Avatar.Width, enemy.Avatar.Height).Contains((int)player.Position.X, (int)player.Position.Y))
    17.         {
    18.             triangleColor = Color.Red;
    19.             isPlayerDead = true;
    20.             SaveToFile();
    21.         }
    22.     }
    23. }
    SpawnEnemies
    1. private void SpawnEnemies(GameTime gameTime)
    2. {
    3.     timeToSpawn -= gameTime.ElapsedGameTime;
    4.  
    5.     if (timeToSpawn < TimeSpan.Zero)
    6.     {
    7.         Vector2 spawnPosition;
    8.         switch (random.Next(4))
    9.         {
    10.             case 0:
    11.                 spawnPosition = new Vector2(0, random.Next(480));
    12.                 break;
    13.             case 1:
    14.                 spawnPosition = new Vector2(800, random.Next(480));
    15.                 break;
    16.             case 2:
    17.                 spawnPosition = new Vector2(random.Next(800), 0);
    18.                 break;
    19.             case 3:
    20.                 spawnPosition = new Vector2(random.Next(800), 480);
    21.                 break;
    22.             default:
    23.                 spawnPosition = Vector2.Zero;
    24.                 break;
    25.         }
    26.  
    27.         switch (random.Next(4))
    28.         {
    29.             case 0:
    30.                 enemies.Add(new Enemy() { Position = spawnPosition, Rotation = 0f, Avatar = txEnemy3, Speed = 3f });
    31.                 break;
    32.             case 1:
    33.                 enemies.Add(new Enemy() { Position = spawnPosition, Rotation = 0f, Avatar = txEnemy4, Speed = 3.5f });
    34.                 break;
    35.             case 2:
    36.                 enemies.Add(new Enemy() { Position = spawnPosition, Rotation = 0f, Avatar = txEnemy5, Speed = 4f });
    37.                 break;
    38.             case 3:
    39.                 enemies.Add(new Enemy() { Position = spawnPosition, Rotation = 0f, Avatar = txEnemy6, Speed = 4.5f });
    40.                 break;
    41.             default:
    42.                 break;
    43.         }
    44.  
    45.         timeToSpawn = new TimeSpan(0, 0, 0, 0, random.Next(500) + 250);
    46.     }
    47. }
    ShootBullets
    1. private void ShootBullets(GameTime gameTime)
    2. {
    3.     timeToShoot -= gameTime.ElapsedGameTime;
    4.  
    5.     if (timeToShoot <= TimeSpan.Zero)
    6.     {
    7.         timeToShoot = new TimeSpan(0, 0, 0, 0, ShootDelay);
    8.         bullets.Add(new Bullet() { Avatar = txBullet, Position = new Vector2(player.Position.X + player.Avatar.Width * (float)Math.Cos(player.Rotation), player.Position.Y + player.Avatar.Height * (float)Math.Sin(player.Rotation)), Rotation = player.Rotation, Speed = 15f });
    9.         fire.Play(.5f, 0f, 0f);
    10.     }            
    11. }

    UpdateBullets
    1. private void UpdateBullets()
    2. {
    3.     foreach (Bullet b in bullets.ToList())
    4.     {
    5.         b.Position = new Vector2(b.Position.X + b.Speed * (float)Math.Cos(b.Rotation), b.Position.Y + b.Speed * (float)Math.Sin(b.Rotation));
    6.  
    7.         if (!graphics.GraphicsDevice.Viewport.Bounds.Contains(new Point((int)b.Position.X, (int)b.Position.Y)))
    8.         {
    9.             bullets.Remove(b);
    10.         }
    11.         else
    12.         {
    13.             foreach (Enemy enemy in enemies.ToList())
    14.             {
    15.                 if (new Rectangle((int)enemy.Position.X - enemy.Avatar.Width / 2, (int)enemy.Position.Y - enemy.Avatar.Height / 2, enemy.Avatar.Width, enemy.Avatar.Height).Contains((int)b.Position.X, (int)b.Position.Y))
    16.                 {
    17.                     bullets.Remove(b);
    18.                     enemies.Remove(enemy);
    19.                     enemyHit.Play();
    20.                     score++;
    21.                     if (score > highScore)
    22.                     {
    23.                         highScore = score;
    24.                     }
    25.                     break;
    26.                 }
    27.             }
    28.         }
    29.     }
    30. }

    This makes things easier to update because we won’t be mixing code that doesn’t belong in other blocks. For example, next week, I’ll be adding in code to support the accelerometer, so I can just change up the UpdatePlayer method, and nothing else needs changed!

    Download the latest version of the source code.

  • File → New Project

    Resources and Content from our Phone Camps

    • 0 Comments

    I’ve run a couple of phone camps so far, the largest and most in depth being the 2-day phone camp hosted by Nokia in Sunnyvale. At the camps, and during my work with developers and designers at other events, there are a number of resources that get requested quite often, so I wanted to put together a post that I can link to and point towards in the future. Please let me know if you think that I’m forgetting anything, and I’ll make sure to keep my list up to date.

    Tools

    Windows Phone Getting Started - http://aka.ms/wp7gs

    Visit the Getting Started page to download the Windows Phone SDK, get more information on the Marketplace and how to monetize your apps and games, and explore the documentation and online communities.

    Silverlight Toolkit - http://aka.ms/wp7sl

    The Silverlight Toolkit includes some controls like the DatePicker and WrapPanel that you can drop into your application just like the tools that are included in the SDK. You can download a sample app as a xap that can be deployed to your device or the emulator to try out the included tools and see if they’re right for you.

    Windows Azure Toolkit for Windows Phone - http://aka.ms/wp7wat

    Put the cloud on your phone with the Windows Azure Toolkit. While the power and storage on mobile devices continue to increase, one of the most important things you get is an internet connection. By taking advantage of Windows Azure, your application back end can scale and grow with the needs of your users.

    Geo Augmented Reality Toolkit (GART) - http://aka.ms/gart

    Updates to the Windows Phone in 7.5 have opened up Augmented Reality possibilities through the live camera stream and motion API. The Geo AR Toolkit makes it possible to create location enabled AR applications without having to know Linear Algebra and geospatial math.

    WP7 Tombstone Helper - http://aka.ms/wp7tsh

    If you want to quickly and easily persist your application state to isolated storage, the Tombstone Helper might be just what you need. With a couple of lines of code, you can save and restore state and make it easier to allow users to come back to your application in a state they expect.

    Marketplace

    Join the Marketplace - http://aka.ms/wp7mp

    Joining the Marketplace gives you the ability to submit your apps and games, as well as developer unlock up to three devices so you can test your project. Student developers registered through DreamSpark can join the Marketplace for free, and developer unlock one device. More information on DreamSpark below.

    Community

    App Hub Forums - http://aka.ms/wp7forums

    If you have questions, the forums are a great place to find answers. Between the Microsoft employees and community members who frequent the forums, you’re sure to get pointed in the right direction. Of course, remember that you can learn more by teaching someone than by being taught, so helping out others on the forums is a great way to increase your skills.

    Windows Phone Developer Blog - http://aka.ms/wp7devblog

    The Windows Phone Developer Blog is a great place to find out about developer programs, contests, device news, and to get the latest on what’s happening in the Windows Phone world, from the developer’s perspective.

    Education

    Windows Phone How-To Index - http://aka.ms/wp7howto

    If you want to do something on the Windows Phone and aren’t sure where to start, start here. Through the articles, you can pick up an understanding of any topic on the platform to jump start your own development.

    Programs

    BizSpark for Startups - http://www.bizspark.com

    If you’re a startup and want to get some tools and support, BizSpark is made for you. Through the BizSpark program, you can get access to a suite of tools including an MSDN Premium subscription, access to Azure, production licenses, training, and more.

    DreamSpark for Students - http://www.dreamspark.com

    If you’re a student, you can register for DreamSpark and get a free Marketplace account to begin testing and deploying your phone apps and games. In addition, you can download free tools like Visual Studio Professional and Expression Studio Ultimate, and get access to training from Pluralsight On-Demand.

Page 4 of 8 (37 items) «23456»