MOBILE

XNA Game Studio 3.0 : Adding Tomato Targets

9/19/2012 12:46:49 AM
Your younger brother has become adept at balancing the cheese on the bat, but he wants something to aim at, so now’s the time to provide some targets. You decide to use tomatoes for this, so you need to add them to your program. You want to have lots of tomatoes, so you need to create an array of GameSpriteStruct instances to hold all of them:
Texture2D tomatoTexture;
GameSpriteStruct[] tomatoes;
int numberOfTomatoes = 20;

These are the fields that you have to create to hold tomato information. Note that although I’ve created an array reference called tomatoes, I haven’t yet created the array itself. You’ll load the tomato texture from your image into a single Texture2D object which will be loaded with the rest of the content for the game:

protected override void LoadContent()
{
    // Create a new SpriteBatch, which can be used to draw textures.
    spriteBatch = new SpriteBatch(GraphicsDevice);

    cheese.SpriteTexture = Content.Load<Texture2D>("Images/Cheese");
    bread.SpriteTexture = Content.Load<Texture2D>("Images/Bread");
    tomatoTexture = Content.Load<Texture2D>("Images/Tomato");
    setupSprites();
}

Textures are classes, and are managed by reference, not value, so each of your tomatoes contains a reference to the same tomato texture:

void setupSprites()
{
    setupSprite(ref cheese, 0.05f, 200.0f, minDisplayX, minDisplayY);
    setupSprite(ref bread, 0.15f, 120.0f, displayWidth / 2, displayHeight / 2);
    tomatoes = new GameSpriteStruct[numberOfTomatoes];

    float tomatoSpacing = (maxDisplayX - minDisplayX) / numberOfTomatoes;

    for (int i = 0; i < numberOfTomatoes; i++)
    {
        tomatoes[i].SpriteTexture = tomatoTexture;
        setupSprite(
            ref tomatoes[i],
            0.05f,  // 20 tomatoes across the screen
            1000,   // 1000 ticks to move across the screen
            minDisplayX + (i * tomatoSpacing), minDisplayY);
    }
}

					  

The setupSprites method creates the tomatoes array and contains a for loop that works through each tomato sprite and sets its size and position. Your first version of the game has the tomatoes evenly spaced in a line along the top of the screen. To make this work, the method uses a local variable called tomatoSpacing that’s set to the width of the display divided by the number of tomatoes that you’re using in the game. Note that you’re following the advice of the Great Programmer in that it is very easy to change the number of tomatoes in the game; you need only change the value of one variable.

At the moment, you won’t be making the tomatoes move, so the Update method only needs to copy the X and Y positions of the tomato into the rectangle for that sprite:

for (int i = 0; i < numberOfTomatoes; i++)
{
    tomatoes[i].SpriteRectangle.X = (int)tomatoes[i].X;
    tomatoes[i].SpriteRectangle.Y = (int)tomatoes[i].Y;
}

The last thing you need to do is add the code to draw all the tomatoes. This is placed in the Draw method as follows:

protected override void Draw(GameTime gameTime)
{
    graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

    spriteBatch.Begin();
    spriteBatch.Draw(cheese.SpriteTexture, cheese.SpriteRectangle, Color.White);
    spriteBatch.Draw(bread.SpriteTexture, bread.SpriteRectangle, Color.White);
    for (int i = 0; i < numberOfTomatoes; i++)
    {
        spriteBatch.Draw(tomatoes[i].SpriteTexture,
                         tomatoes[i].SpriteRectangle, Color.White);
    }

    spriteBatch.End();

    base.Draw(gameTime);
}

					  

The Draw method contains another for loop that draws each of the tomatoes in turn. Figure 1 shows the display produced with your 20 tomatoes along the top.

Figure 1. Bread, cheese, and 20 tomatoes


1. Zune Image Sizes

The Zune will run XNA games quite happily, but it does not have as much available memory as the Xbox 360 or Windows PC. Up until now I have been using quite high resolution images of the bread, tomatoes, and cheese. However, these images have been so large that if we add too many the Zune is unable to hold them. (And the Zune screen is so small that images made up of fewer pixels are quite acceptable anyway.) For this version of the game I have re-sized the textures so that they look acceptable on the Xbox and Windows PC, but will also fit into the Zune memory. When you create game resources you must be careful to make sure that the images you produce are of the appropriate size and resolution.

2. Tomato Collisions

The idea of the game is that when the cheese hits a tomato, the tomato vanishes. This means that you need a way of making the tomatoes disappear. You can’t make them vanish as such, but you can decide not to draw them.

2.1. Controlling Sprite Visibility

The game must have some way of deciding when a particular sprite shouldn’t be drawn. This turns out to be easy; you need only add an extra field to the GameSpriteStruct structure:

struct GameSpriteStruct
{
    public Texture2D SpriteTexture;
    public Rectangle SpriteRectangle;
    public float X;
    public float Y;
    public float XSpeed;
    public float YSpeed;
    public float WidthFactor;
    public float TicksToCrossScreen;
    public bool Visible;
}

The Visible field is set to true if the sprite is to be drawn on the screen.

2.2. Setting the Initial Visibility State

The initial value of Visible can be set by the setupSprite method, which is now given an additional parameter that is used to set the initial visibility of the sprite:

void setupSprite(
    ref GameSpriteStruct sprite,
    float widthFactor,
    float ticksToCrossScreen,
    float initialX,
    float initialY,
    bool initialVisibility)
{
    //  original setup code here
    sprite.Visible = initialVisibility;
}

Initially, it’s set to true for all the tomatoes, the cheese, and the bread in the setupSprites method:

void setupSprites()
{
    setupSprite(ref cheese, 0.05f, 200.0f, 200, 100, true);
    setupSprite(ref bread, 0.15f, 120.0f, displayWidth / 2, displayHeight / 2, true);

    tomatoes = new GameSpriteStruct[numberOfTomatoes];

    float tomatoSpacing = (maxDisplayX - minDisplayX) / numberOfTomatoes;

    for (int i = 0; i < numberOfTomatoes; i++)
    {
        tomatoes[i].SpriteTexture = tomatoTexture;
        setupSprite(
        ref tomatoes[i],
        0.05f,  // 20 tomatos across the screen
        1000,   // 1000 ticks to move across the screen
        minDisplayX + (i * tomatoSpacing), minDisplayY,
        true  // initially visible
        );
    }
}

					  

This setupSprites method also sets the initial position of the cheese a bit further into the screen so that it does not initially collide with any tomatoes.

2.3. Using the Visible Field When Drawing

You use the value of the Visible field when you draw the sprites in the Draw method:

for (int i = 0; i < numberOfTomatoes; i++)
{
    if (tomatoes[i].Visible)
    {
        spriteBatch.Draw(tomatoes[i].SpriteTexture,
                         tomatoes[i].SpriteRectangle, Color.White);
    }
}

Only tomatoes that have the Visible field set to true are drawn on the screen. To make a tomato vanish, you simply set its Visible property to false. You do this in the Update method:

for (int i = 0; i < numberOfTomatoes; i++)
{
   if (tomatoes[i].Visible)
   {
      if (cheese.SpriteRectangle.Intersects(tomatoes[i].SpriteRectangle))
      {
         tomatoes[i].Visible = false;
         cheese.YSpeed = cheese.YSpeed * -1;
         break;
      }
   }
}

The for loop looks through all the tomatoes and tests to see if any of the tomato rectangles intersect with the cheese. If it finds an intersection, it sets the Visible property of the tomato to false and then reverses the direction of the cheese movement to make it "bounce" off the tomato it has just destroyed. Once it has removed one tomato, it stops looking for any more because the break statement causes the for loop to end at that point. This is important because otherwise, the cheese might collide with and destroy more than one tomato at a time, making the game too easy.

Other  
  •  iPhone Developer : Search Tables and Core Data
  •  iPhone Developer : Using Core Data for a Table Data Source
  •  Anita Mai Tan - The Container Is Worth More Than The Contents
  •  No New Toaster – Refrigerators
  •  The State Of Mobile... Creative Media In 2012 (Part 2)
  •  The State Of Mobile... Creative Media In 2012 (Part 1)
  •  A Not So New Competitor
  •  BlackBerry Java Application : installing the Java Development Kit (JDK), downloading Eclipse with the JDE plugin
  •  BlackBerry Java Application : Installing the Development Environment - downloading the Java Development Kit
  •  iOS 6 Playing It Safe (Part 1)
  •  iOS 6 Playing It Safe (Part 2)
  •  Planet Of The Apps – Travel (Part 1)
  •  Planet Of The Apps – Travel (Part 2)
  •  Planet Of The Apps – Travel (Part 3)
  •  Top 10 Smartphones August – September (Part 1) - Samsung Galaxy S III, HTC One X, Apple iPhone 4S,Nokia Lumia 800,Sony Xperia S
  •  Top 10 Smartphones August – September (Part 2) - Huawei Ascend P1, HTC Radar, Samsung Galaxy Note,BlackBerry Bold 9900
  •  Got Yourself A Fancy New Nexus Flexus
  •  Nokia 808 Pureview - Best For Convergists
  •  Tough Phones : Work or play in harsh environments
  •  Take Your Office On The Go
  •  
    Top 10
    Sigma 120-300mm F/2.8 DG OS HSM S Lens Review
    Motorola RAZR i - How Does The Droid RAZR M Fare With A 2Ghz Intel Processor? (Part 2)
    Motorola RAZR i - How Does The Droid RAZR M Fare With A 2Ghz Intel Processor? (Part 1)
    Nokia Lumia 720 – Attractive Design With Nice Lowlight Images (Part 3)
    Nokia Lumia 720 – Attractive Design With Nice Lowlight Images (Part 2)
    Nokia Lumia 720 – Attractive Design With Nice Lowlight Images (Part 1)
    Nikon D5200 Review - A Mid-Range Digital SLR
    Arctic Cooling Accelero Hybrid GTX 680
    Zalman LQ-320 CPU Cooler
    Google Chromebook Pixel - A Handsome Laptop
    Most View
    8 Essential Free Apps – Q1 2013
    Tips & Tricks Of November 2012 (Part 2)
    HTC Windows Phone 8X - The Best-Looking Windows Phone 8 Handset (Part 2)
    Simple.TV - Transmits TV Programs To Mobile (Part 1)
    Silverstone Heligon HE01 - Asymetrical Cooling
    The Complete Guide To Photography On Your Mac! (Part 3)
    Google’s Data Liberation Front (Part 2)
    Ultrabooks Supertest - The Second Coming (Part 1) : Sony Vaio T SVT1311W1E, HP Envy 6-1006sa Sleekbook, Lenovo IdeaPad U310
    Pentax K-5 II – A Digital SLRS
    Alienware M14X - Super Heavyweight…Literally!