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
    A Look At Truecrypt The Open Source Security Tool
    Price Of Piracy
    Acer Aspire 5600U 23" Touchscreen All-in-One PC
    Zalman FX100-Cube Fanless Cooler
    Devolo dLAN LiveCam Starter Kit
    Has Apple Lost It? (Part 2)
    Has Apple Lost It? (Part 1)
    Sony Computer Entertainment (Part 3)
    Sony Computer Entertainment (Part 2)
    Sony Computer Entertainment (Part 1)
    Most View
    Brother MFC- J5910DW - For All Your Printing Needs
    Ultrasone 650 Pro headphone review
    Top Tablet Apps – December 2012 (Part 1)
    DirectX 10 Game Programming : 3D Introduction - Creating a 3D Grid
    Intel In Flux: Are We Heading To A Socket-Less Future? (Part 2)
    Windows System Programming : Registry Management
    Improve Your Mac (Part 1) - Import Pictures into iPhoto
    Some Of The Biggest Brands In The World Had Their Products (Part 10)
    Samsung launched projector, smartphone, and 10.1'' note device
    Smartphones and Accessories - January 2013 (Part 2)
    Iphone SDK : Working with the Address Book Database - Accessing Multi-Value Properties
    Best Video Editing Software – November 2012 (Part 2)
    Best Photo Printers Revealed – Jan 2013 (Part 2) : Canon PIXMA MG6250
    Parallel Programming with Microsoft .Net : Futures - Variations
    ASP.NET AJAX : Partial Refreshes (part 3) - Triggers
    Windows Server 2008 : Create Virtual Hard Drives and Machines
    Introducing SharePoint 2010 (part 2)
    Mobile Application Security : SMS Security - Protocol Attacks (part 1)
    Linux Mint 10 : Tantalizing terminals
    Sageone Payroll : The rock of wages