From Chromesville to the mythical land of XBox 360

                    

By Dominique Louis

Introduction

It all began back in January 2007 when I decided that there needed to be some example code showing how to use an Object Pascal compiler with XNA. I had done some Delphi for .NET and Managed Direct X ports in the past, so was vaguely familiar with how managed code worked, but XNA was a totally new managed API, which is said to replace Microsoft's current managed API. When I looked at Delphi for .NET it did not support the compact framework ( which is needed for XNA ) or MSBuild, and at the time I knew very little about what Chrome was capable of, only that it supported .NET and more importantly the v2.0 compact framework.

Pre-requisite Downloads

To create games that target the XNA API you will need to have the following installed on your PC, before you start( all free downloads ):

Article Downloads

Once you have installed the above, you will can either download the related Chrome files below as one big package or individually.

Manual Installation of Chrome related files

  1. Unzip XNA-Projects.zip to *\RemObjects Software\Chrome\Bin\Templates\ChromeProjects.2005\
  2. Unzip XNA-ProjectItems.zip to *\RemObjects Software\Chrome\Bin\Templates\ChromeProjectItems.2005
  3. Unzip XNA-Templates.zip to *\RemObjects Software\Chrome\Bin\Templates\
  4. Unzip XNA-Samples.zip to *\RemObjects Software\Chrome\Samples\

XNA

So what is XNA, I hear you mumble into your magma heated cup of coffee? Well it is "a set of tools based on Microsoft Visual C# 2005 Express Edition that allow students and hobbyists to build games for both Microsoft Windows and Xbox 360. XNA Game Studio Express also includes the XNA Framework, which is a set of managed libraries based on the Microsoft .NET Compact Framework 2.0 that are designed for game development. This documentation collection contains technology overviews, tutorials, and reference material related to XNA Game Studio Express.". Essentially it is a comman graphics and sound API which allows you to deploy games to both PC and XBox 360, but may include WinCE devices in future. As Shawn Hargreaves ( XNA Framework developer ) says : “What we do aim for, and something we think is very important, is 'write once, compile anywhere' ”.

At the moment, C# is the default language that you can use to target both PC and XBox 360 via the Game Studio Express IDE ( henceforth refered to as GSE ), which itself is an add-on to Microsoft's Visual Studio Express IDE. So far Microsoft has only allowed C# code to be compiled within the Visual Studio Express and GSE IDEs, but since XNA is built upon the .NET 2.0 Compact Framework, essentially any managed language that can target the Compact Framework should be able to handle XNA. Due to the aforementioned restriction, using Chrome with XNA is not as easy as it could be, but neither is it overly difficult. It just requires little bit of manual intervention here and there. Hopefully that will change in future and Microsoft will allow non-C# language to work within GSE, thereby avoiding the work-arounds I mention below.

Getting Your Hands Dirty

I will be talking about using Chrome's Visual Studio 2005 add-in, but you should still be able to follow this steps if you are using the Command Line compiler because most of the tweaking takes place in the *.chrome project file. So you should be able to use the Visual Studio 2005 add-in to edit, compile and run your XNA code on your PC once the *.chrome file is correctly set up, but adding images or sound files to the project will need some manual intervention for it to work correctly. This is caused by XNA's content pipeline.

The XNA content pipeline

Taken from the GSE help :
“The XNA Game Studio Express Content Pipeline lets you build assets/resources into your game automatically from whatever file formats they are being maintained in.

Most games use art in the form of models, meshes, sprites, textures, effects, terrains, animations, [sounds] and so on. Such art assets can be created in many different ways and stored in many different file formats. They tend to change frequently in the course of game development.

The Content Pipeline is designed to help you include such art assets in your game easily and automatically. An artist working on a a car model can add the resulting file to the XNA Game Studio Express game project, assign the model a name, and choose an importer and content processor for it.”

In a nut shell the XNA content pipeline takes your assets/resources and converts them into a common format the XNA understands and uses that internally. This is required because on the XBox 360 you cannot just point the game to a particular directory to load an image or sound file ( though this is possible on Windows it is not recommended if you want your game to be cross-platform ). Instead loading of assets/resources is handled via the content pipeline and a virtual directory system as such. Being forced to use the content pipeline is the main reason why you cannot easily use the Visual Studio 2005 add-in to add files to your project. The reason for that is the XNA content pipeline assemblies only work within Visual Studio Express and therefore GSE. Microsoft do plan to release a version, in future, which will work from within Visual Studio Profressional ( maybe Orcas?? ), which theoretically will mean that Chrome will then be able to make use of that functionality, but I do not know when that will be available. This is the main difference between using C# and Chrome. When using C#, adding content to your project automagically creates the link to the correct content pipeline processor, while with Chrome you need to associate the content pipeline links manually. At least for now.

Differences between GSE *.csproj and Chrome *.chrome

When you add a source file to a Chrome project, via the Visual Studio 2005 IDE, the entry for it will look something like this in the .chrome file :

.chrome code :
<Compile Include="mySourceFile.pas"/>


While within GSE it will look like this...

.csproj code :
<Compile Include="mySourceFile.cs">
  <XNAUseContentPipeline>false</XNAUseContentPipeline>
  <Name>mySourceFile</Name>
</Compile>


Source files are not processed by the content pipeline, hence why the tag is set to false.
If you add a content file via Chrome it will more than likely not look very different to the previous example :

.chrome code :
<Compile Include="myTexture.bmp"/>


However in GSE that same texture file added to the project would produce something like this...

.csproj code :
<Content Include="myTexture.bmp">
  <XNAUseContentPipeline>true</XNAUseContentPipeline>
  <Importer>TextureImporter</Importer>
  <Processor>SpriteTextureProcessor</Processor>
  <Name>myTexture</Name>
</Content>



Notice that now the <XNAUseContentPipeline> tag, is now set to true.
This will tell MSBuild that it should use the content importer, specified by the tag, and the content processor, specified by the tag, to compile this resource into an XNA compatible format.


The tag value is what is used in your code to refer to that particular resource at runtime. As mentioned earlier, notice that you only need to know the name of the resource to be able to use it at run-time. You specify a virtual file path at runtime and not an absolute file paths. XNA takes care of where it may be located on your PC or XBox, based on how that resource was compiled into the project.
Therefore when adding content to your Chrome project you will need to specify the content Importer and Processor for things to work correctly.

Here is a table of file types and the associated importers and processors that come with XNA by default :

File Types File Extensions Importer Processor
Images/Textures *.bmp; *.tga; *.png; *.jpg; *.dds TextureImporter SpriteTextureProcessor
Fonts *.spritefont FontDescriptionImporter FontDescriptionProcessor
FontTextureImporter FontTextureProcessor
Models *.fbx FbxImporter ModelProcessor
*.x XImporter ModelProcessor
Music *.xap XactImporter XactProcessor
Shader Effects *.fx EffectImporter EffectProcessor

NOTE : If you have a proprietry file format that you wish you use in XNA, you can create you own custom content importer and processor, but that is beyond the scope of this introduction. Refer to the GSE help or the MSDN help if you would like to do that.

Hello Chromesville

Since I have been through the heart ache of getting this all working, I have created a few project templates that at least simplify the basics of setting up an XNA Chrome project for both Windows and XBox 360. Now let's get some text on the screen. This is not an example of how to code using Chrome, so I will assume that you with programming and as such will be able to follow the code. Most of it is, I think, fairly well commented.

  1. In Visual Studio 2005 goto File->New Project and click on the XNA node on the left. This should list 6 XNA Game project templates on the right. See the screen-shot below.

  2. Select XNA Windows Game from the right and create the project. Now do the same thing again but this time select XNA Xbox 360 Game, but this time once the project is created, find the  XNAXBox360Game1.chrome project file and move it to the same directory as the XNAWinGame1.chrome project file.

  3. For the benefit of command line users the full Chrome project is available for download and the main game code is listed below.We'll come back to the Xbox project later on. For now ensure the Windows project is loaded.

  4. Now press F5 to makes sure that it compiles and runs, thereby confirming that everything is set up correctly. If all goes well you should see the screen shot below.
  5. Take a few moments to looks through the code. You will see that all XNA games inherit from Microsoft.Xna.Framework.Game. You should also notice that within the constructor the width and height of the screen is set ( 853x480) and the GraphicsDeviceManager ( Handles the configuration and management of the graphics devide - used for drawing stuff ) and ContentManager ( the run-time component which loads managed objects from the binary files produced by the design time content pipeline ) are also instantiated for later use here.
     
  6. In order to display text on the screen we need to add a SpriteFont to our project. I suggest keeping Content such as resources under a "Content" folder so that they are not mixed in with source files ( see below ). Once you have created the Content folder, right click on it, got to Add->New Item... and select "SpriteFont" from the item list and add it and then save the project.
  7. As mentioned earlier if you were using GSE it would automagically associate this XNA resource to the correct content pipeline for importing and processing. We will need to delve into the .chrome file ensure that it is processed correctly. Notice that if you look inside the .spritefont file it is an XML file describing various attributes of the font we are about to use. Also note that the FontName tag defaults to Tahoma...

.spritefont Code :
<FontName>Tahoma</FontName>



    But you can change this name to any valid True Type Font name.

  1. Open the project's .chrome file ( probably  XNAWinGame1.chrome ) and search for .spritefont. It will probably look like this

  2. .chrome Code :
    <Content Include="SpriteFont1.spritefont" />

  3. Now change it so that it looks like this...

  4. .chrome Code :
    <Content Include="SpriteFont1.spritefont">
      <XNAUseContentPipeline>true</XNAUseContentPipeline>
      <Importer>FontDescriptionImporter</Importer>
      <Processor>FontDescriptionProcessor</Processor>
      <Name>SpriteFont1</Name>
    </Content>

    then save the changes. This now tells MSBuild to use the respective Importer and Processor to generate an XNA compatible verison of this font.
  5. Now back in IDE make sure you have the latest .chrome project loaded. Open up the game.pas file and add the following code to the private declaration
  6. ...
    Chrome Code:
    // Enables a group of sprites to be drawn using the same settings
    spriteBatch : SpriteBatch;

    // Used to draw the text on the screen
    TahomaFont : SpriteFont;

  7. Now we need to load our font into memory so that we can use it later on to draw onto the screen. Find the LoadGraphicsContent method and add the following code....

  8. Chrome Code:
    if ( loadAllContent ) then
    begin
      // instantiate our sprite batch object
      spriteBatch := new SpriteBatch(graphics.GraphicsDevice);

      // Load the sprite font we added
      TahomaFont := content.Load<SpriteFont>('Content/SpriteFont1');
    end;

    Notice that the content.Load method requires that you specify the generic type you are attempting to load. In this case it is <SpriteFont>. If you were loading a texture it would be <Texture2D> and a model would be <Model> and so on.

  9. Now find the Draw method and ensure it looks like this...

  10. Chrome Code:
    // Clear the back ground to your choice of color
    graphics.GraphicsDevice.Clear( Color.CornflowerBlue );

    // Prepares the graphics device for drawing sprites
    spriteBatch.Begin;

    // Draw some text on the screen at postition 50, 100 in white
    spriteBatch.DrawString( TahomaFont, 'Hello Chromesville', new Vector2( 50, 100 ), Color.White );

    // Flushes the sprite bacth and restores the device state to what it was before Begin was called
    spriteBatch.End;

    // Call the inherited Draw method
    inherited Draw( aGameTime );

  11. Now compile and run the project and you should see "Hello Chromesville" displayed at X pixel position 50 and Y pixel position 100, on the screen

So there you have it, 10 relatively easy steps in getting some text on an XNA screen. Once the content pipeline issue is addressed in a future release of Visual Studio, steps 5 and 6 will be taken care of automatically and it will be just a case of fleshing out your game logic and game play just as you would with C#. Now the same basic technique used above to draw the Font could also be used to draw texture ( images to those of you who have not written games before ), but instead of using a SpriteFont Object, you would use a Texture2D

Handling Input and Basic animation

Let's add some quick input handling and basic animation in the form of an in game main menu.

  1. Add the following private variable declarations
  2. Chrome Code:
        // Our List of Menu Items
        menuItems : List<string> := new List<string>();
       
        // What is the currently selected item
        selectedEntry : integer := 0;

        // Previous Input States
        previousKeyboardState : KeyboardState;
        previousGamePadState : GamePadState;
       
        // Variables to keep track of how we are transitioning
        transitionOn : boolean := true;
        transitionPosition : Single := 1;
       
        // Indicates how long the screen takes to transition on when it is activated.
        transitionOnTime : TimeSpan := TimeSpan.FromSeconds(1.5);

    Those of you coming from a standard Object Pascal background may not be familiar with generics, but that is exactly what we are using when we declare the menuItems variable as being of type " List<string> := new List<string>();". It's a strongly typed list of strings.
    The other thing you will notice is that Chrome allows us to instantiate our varitable right where we declare it. You could of course do this in the constructor, but at least Chrome gives you both options.

  3. The following code could be added to the constructor or the overridden Initialize method. Initialize is called after the Game and GraphicsDevice are created, but before LoadGraphicsContent. I personally would probably put it in the Initialize as the List has already been constructed.
  4. Chrome Code:
      menuItems.Add( 'Play' );
      menuItems.Add( 'Options' );
      menuItems.Add( 'Credits' );
      menuItems.Add( 'Exit' );

  5. Now lets Draw the menu items with some animation. ( code taken from Microsoft's GameStateManagement sample and modified ). Change the previous Draw method to look like this.
  6. Chrome Code:
    const
      overlap           : single = 0.3;
    var
      position          : Vector2;
      transitionOffset  : single;
      i                 : integer;
      time              : single;
      colour            : Color;
      scale             : single;
      pulsate           : single;
      numEntries        : integer; 
      origin            : Vector2;
    begin
      position := new Vector2( 100, 150 );

      // Make the menu slide into place during transitions, using a
      // power curve to make things look more interesting (this makes
      // the movement slow down as it nears the end).
      transitionOffset := Math.Pow( transitionPosition, 2 );

      if ( transitionOn ) then
        position.X := position.X - transitionOffset * 256
      else
        position.X := position.X + transitionOffset * 512;

      // Clear the back ground to your colour of choice
      graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
       
      // Draw each menu entry in turn.
      SpriteBatch.Begin;

      for i := 0 to menuItems.Count - 1 do 
      begin
        if ( i = selectedEntry ) then
        begin
          // The selected entry is yellow, and has an animating size.
          time := aGameTime.TotalGameTime.TotalSeconds;

          pulsate := Math.Sin( time * 7 ) + 1;

          colour := Color.Yellow;
          scale := 1 + pulsate * 0.05;
        end
        else
        begin
          // Other entries are white.
          colour := Color.White;
          scale := 1;
        end;

        numEntries := menuItems.Count;

        transitionOffset := MathHelper.Clamp( ( TransitionPosition - ( 1 - overlap ) * i / numEntries ) / overlap, 0, 1 );

        position.X := MathHelper.SmoothStep( 100, -200, transitionOffset );
        scale := scale + MathHelper.SmoothStep( 0, 4, transitionOffset );
       
        // Modify the alpha to fade text.   
        colour := new Color( colour.R, colour.G, colour.B, byte( ( 1 - transitionOffset ) * 255 ) );

        // Draw text, centered on the middle of each line.
        origin := new Vector2( 0.0, single( TahomaFont.LineSpacing / 2 ) );

        SpriteBatch.DrawString( TahomaFont, menuItems[ i ], position, colour, 0, origin, scale, SpriteEffects.None, 0 );

        // LineSpacing
        position.Y := position.Y + TahomaFont.LineSpacing;
      end;

      SpriteBatch.End;
     
      inherited Draw( aGameTime );

  7. Compile and Run the application and you should see a pulsating menu item. Here's a screen shot, though of course you won' notice the pulsating ;-).

    You should hopefully notice that when the demo starts the the text flys in from behind you and then places it self in it's correct position.

  1. Now lets add the Input code. Input is handled by polling for the GamePad, Keyboard or Mouse State objects, which each return a respective structure. NOTE : As it is not currently possible to use the Mouse on an Xbox 360 ( only on Windows ) we will not be testing for it in this example. Change the UpdateInput method
  2. Chrome Code:
    var
      currentGamePadState  : GamePadState;
      currentKeyboardState : KeyboardState;
      menuUpGamePad, menuDownGamePad, menuUpKeyboard, menuDownKeyboard : Boolean;
    begin
      //get the gamepad state
      currentGamePadState := GamePad.GetState( PlayerIndex.One ); 
      if ( currentGamePadState.IsConnected ) then
      begin
        // Allows the default game to exit on Xbox 360 and Windows using a Gamepad
        if ( currentGamePadState.Buttons.Back = ButtonState.Pressed ) then
          Self.Exit;
       
        menuUpGamePad := ((currentGamePadState.DPad.Up = ButtonState.Pressed) and
                            (previousGamePadState.DPad.Up = ButtonState.Released)) or
                           ((currentGamePadState.ThumbSticks.Left.Y > 0) and
                            (previousGamePadState.ThumbSticks.Left.Y <= 0));     
                           
        menuDownGamePad := (( currentGamePadState.DPad.Down = ButtonState.Pressed) and
                            (previousGamePadState.DPad.Down = ButtonState.Released)) or
                           ((currentGamePadState.ThumbSticks.Left.Y <0>= 0));   
      end;
     
      // get the Keyboard state
      currentKeyboardState := Keyboard.GetState();
      if ( currentKeyboardState <> nil ) then
      begin
        // Allows the default game to exit on Xbox 360 and Windows using a Keyboard
        if ( currentKeyboardState.IsKeyDown( Keys.Escape ) then
          Self.Exit; 
         
        menuUpKeyboard := (CurrentKeyboardState.IsKeyDown(Keys.Up) and previousKeyboardState.IsKeyUp(Keys.Up));
        menuDownKeyboard := (CurrentKeyboardState.IsKeyDown(Keys.Down) and previousKeyboardState.IsKeyUp(Keys.Down));   
      end;
     
      if ( menuUpGamePad or menuUpKeyboard ) then
      begin
        selectedEntry := selectedEntry - 1;     
        if selectedEntry < 0 then
          selectedEntry := menuItems.Count - 1;
      end;   
     
      if ( menuDownGamePad or menuDownKeyboard ) then
      begin
        selectedEntry := selectedEntry + 1;     
        if selectedEntry > menuItems.Count - 1 then
          selectedEntry := 0;
      end;   
     
      // keep track of our previous input states
      previousGamePadState := currentGamePadState;
      previousKeyboardState := currentKeyboardState;
    end;

  3. Compile and Run the application and you should now be able to use either the Up or Down arrows to navigate the menu system or the Xbox 360 game pad

Lets see it on an Xbox 360

As mentioned earlier, in order to deploy to an Xbox 360 you need to have a subscribtion to the XNA creators club. You will then need to have both your PC and your Xbox 360 on the same network. The process of getting the 2 machines talking to each other is beyond the scope of this article, but you can watch this article and video which will walk you though the whole process. Once you have done that, continue below.

Assuming we have not introduced any Windows specific code, compiling the code for it to work on an Xbox 360 is fairly straight forward. All you need to do is to ensure that any resources or source code units that you added to the Windows project are also added to the Xbox 360 project. Open the Xbox .chrome project file ( probably ) using notepad and add...

.chrome Code :
<Content Include="SpriteFont1.spritefont">
  <XNAUseContentPipeline>true</XNAUseContentPipeline>
  <Importer>FontDescriptionImporter</Importer>
  <Processor>FontDescriptionProcessor</Processo>
  <Name>SpriteFont1</Name>
</Content>

close to where the other source files ( *.pas ) are declared. Once you have done that, close and save the file and open up the Xbox 360 .chrome project in Visual Studio and compile it. 

Those of you using the command line compiler should find that the zip file already contains batch files that compile

NOTE : If you try and run this project you will get an error.
Now yet again we are faced with the diffence between developing with GSE and Visual Studio. In GSE when you compile and run an Xbox 360 project, assuming everything is set up correctly, it automatically attempts to connect to your Xbox and it will then upload the game and it's content to the Xbox. With Chrome we have to create a .ccgame package and then use GSE to upload the game package to the console. To achieve this with Chrome we will need to use the command line and thankfully Microsoft anticipated this.
  1. Go to Start->Microsoft Game Studio Express->Tools and select XNA Game Studio Express Command Prompt. This will set up the correct path to access the XNA Package tool we will use shortly.
  2. Now via this command line prompt navigate to the directory where your game chrome projects exist.
  3. At the command line type xnapack XNAXboxGame.exe Xbox360 . This will create a .ccgame package, which is essentially a compressed archive of your executable and it's associated content.

  4. The advantage of distrubuting Xbox games via a .ccgame package is that the recipient is not able to look at your code directly. This can also be done for Windows XNA games as well. Though note that using reflection someone could potentially reverse engineer the executable, but that is true of any .NET executable.

  5. Now from Explorer, double click on the newly created .ccgame package. Due to it's file association, this should launch Game Studio Express and it will immediately try and connect to your Xbox 360 and then upload and unpack the game and it's resources onto your Xbox.
  6. Play with the demo on your Xbox

  7. Here is a screen shot of what it looks like on the Xbox 360 Blade before you launch it...

    [ Click to see full version ]

Conclusion

As you can see, getting things working on Windows and then on an Xbox 360 is relatively simple once the content pipeline issues are sorted out. If you can determine what content you need up front, even it it's just place holder textures, sounds and models, then using the Visual Studio add-in is easier. It just requires more forward planning than usual to minimise disruptions later on. This is a very small introduction into the process of creating games using Chrome and the XNA api. I would suggest you look at and play with the sample code that I have put together so far to see how easy it is to create both 2D and 3D games using this new API. Another invaluable resource is the XNA help file and also the XNA Creators forum.

Chrome Project Listing

Game ( Game.pas )

Chrome Code:

namespace XNAWinGame1;

interface

uses
  System,
  Microsoft.Xna.Framework,
  Microsoft.Xna.Framework.Content,
  Microsoft.Xna.Framework.Graphics,
  Microsoft.Xna.Framework.Input;

type
  TXNAWinGame1 = class( Microsoft.Xna.Framework.Game )
  private
    // these are the size of the output window, ignored on Xbox 360
    preferredWindowWidth : integer;
    preferredWindowHeight : integer;

    graphics : GraphicsDeviceManager;

    content : ContentManager;
   
    // Enables a group of sprites to be drawn using the same settings.
    spriteBatch : SpriteBatch;

    // Used to draw the text on the screen.
    TahomaFont : SpriteFont;
   
    // Our List of Menu Items
    menuItems : List<string> := new List<string>();
   
    // What is the currently selected item
    selectedEntry : integer := 0;

    // Previous Input States
    previousKeyboardState : KeyboardState;
    previousGamePadState : GamePadState;
   
    //
    transitionOn : boolean := true;
    transitionPosition : Single := 1;
   
    // Indicates how long the screen takes to transition on when it is activated.
    transitionOnTime : TimeSpan := TimeSpan.FromSeconds(1.5);
  protected
    method Initialize; override;
    method Update( aGameTime : Gametime ); override;
    method Draw( aGameTime : Gametime ); override;
    method LoadGraphicsContent( loadAllContent : boolean ); override;
    method UnloadGraphicsContent( unloadAllContent : boolean ); override;

    method UpdateInput( aGameTime : Gametime );
    method UpdateTransition( aGameTime : GameTime ; aTime : TimeSpan; aDirection : integer ) : boolean;
  public
    constructor;
  end;

implementation

constructor TXNAWinGame1;
begin
  inherited;
  preferredWindowWidth := 853;
  preferredWindowHeight := 480;

  Self.graphics := new Microsoft.Xna.Framework.GraphicsDeviceManager( Self );
                       
  Self.graphics.PreferredBackBufferWidth  := preferredWindowWidth;
  Self.graphics.PreferredBackBufferHeight := preferredWindowHeight;

  content := new ContentManager( Services );
end;

method TXNAWinGame1.Draw( aGameTime : Gametime );
const
  overlap           : single = 0.3;
var
  position          : Vector2;
  transitionOffset  : single;
  i                 : integer;
  time              : single;
  colour            : Color;
  scale             : single;
  pulsate           : single;
  numEntries        : integer; 
  origin            : Vector2;
begin
  position := new Vector2( 100, 150 );

  // Make the menu slide into place during transitions, using a
  // power curve to make things look more interesting (this makes
  // the movement slow down as it nears the end).
  transitionOffset := Math.Pow( transitionPosition, 2 );

  if ( transitionOn ) then
    position.X := position.X - transitionOffset * 256
  else
    position.X := position.X + transitionOffset * 512;

  // Clear the back ground to your colour of choice
  graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
   
  // Draw each menu entry in turn.
  SpriteBatch.Begin;

  for i := 0 to menuItems.Count - 1 do 
  begin
    if ( i = selectedEntry ) then
    begin
      // The selected entry is yellow, and has an animating size.
      time := aGameTime.TotalGameTime.TotalSeconds;

      pulsate := Math.Sin( time * 7 ) + 1;

      colour := Color.Yellow;
      scale := 1 + pulsate * 0.05;
    end
    else
    begin
      // Other entries are white.
      colour := Color.White;
      scale := 1;
    end;

    numEntries := menuItems.Count;

    transitionOffset := MathHelper.Clamp( ( TransitionPosition - ( 1 - overlap ) * i / numEntries ) / overlap, 0, 1 );

    position.X := MathHelper.SmoothStep( 100, -200, transitionOffset );
    scale := scale + MathHelper.SmoothStep( 0, 4, transitionOffset );
   
    // Modify the alpha to fade text.   
    colour := new Color( colour.R, colour.G, colour.B, byte( ( 1 - transitionOffset ) * 255 ) );

    // Draw text, centered on the middle of each line.
    origin := new Vector2( 0.0, single( TahomaFont.LineSpacing / 2 ) );

    SpriteBatch.DrawString( TahomaFont, menuItems[ i ], position, colour, 0, origin, scale, SpriteEffects.None, 0 );

    // LineSpacing
    position.Y := position.Y + TahomaFont.LineSpacing;
  end;

  SpriteBatch.End;
 
  inherited Draw( aGameTime );
end;

method TXNAWinGame1.Initialize;
begin
  // Your Initialize Code here
  menuItems.Add( 'Play' );
  menuItems.Add( 'Options' );
  menuItems.Add( 'Credits' );
  menuItems.Add( 'Exit' );
  inherited;
end;


method TXNAWinGame1.LoadGraphicsContent( loadAllContent : boolean );
begin
  if ( loadAllContent ) then
  begin
    // TODO: Load any ResourceManagementMode.Automatic content
    spriteBatch := new SpriteBatch(graphics.GraphicsDevice);
    TahomaFont := content.Load<SpriteFont>('Content\SpriteFont1');
  end;

  // TODO: Load any ResourceManagementMode.Manual content
end;

method TXNAWinGame1.UnloadGraphicsContent( unloadAllContent : boolean );
begin
  if ( unloadAllContent ) then
  begin
    content.Unload;
  end;
end;

method TXNAWinGame1.Update( aGameTime : Gametime );
begin
  //Get some input
  UpdateInput( aGameTime);

  // Your Update Code here
  transitionOn := UpdateTransition( aGameTime, transitionOnTime, -1 );
 
  inherited Update( aGameTime);
end;

method TXNAWinGame1.UpdateInput( aGameTime : Gametime );
var
  currentGamePadState  : GamePadState;
  currentKeyboardState : KeyboardState;
  menuUpGamePad, menuDownGamePad, menuUpKeyboard, menuDownKeyboard : Boolean;
begin
  //get the gamepad state
  currentGamePadState := GamePad.GetState( PlayerIndex.One ); 
  if ( currentGamePadState.IsConnected ) then
  begin
    // Allows the default game to exit on Xbox 360 and Windows using a Gamepad
    if ( currentGamePadState.Buttons.Back = ButtonState.Pressed ) then
      Self.Exit;
   
    menuUpGamePad := ((currentGamePadState.DPad.Up = ButtonState.Pressed) and
                        (previousGamePadState.DPad.Up = ButtonState.Released)) or
                       ((currentGamePadState.ThumbSticks.Left.Y > 0) and
                        (previousGamePadState.ThumbSticks.Left.Y <= 0));     
                       
    menuDownGamePad := (( currentGamePadState.DPad.Down = ButtonState.Pressed) and
                        (previousGamePadState.DPad.Down = ButtonState.Released)) or
                       ((currentGamePadState.ThumbSticks.Left.Y <0>= 0));   
  end;
 
  // get the Keyboard state
  currentKeyboardState := Keyboard.GetState();
  if ( currentKeyboardState <> nil ) then
  begin
    // Allows the default game to exit on Xbox 360 and Windows using a Keyboard
    if ( ( currentKeyboardState <> nil ) and ( currentKeyboardState.IsKeyDown( Keys.Escape ) ) ) then
      Self.Exit; 
     
    menuUpKeyboard := (CurrentKeyboardState.IsKeyDown(Keys.Up) and previousKeyboardState.IsKeyUp(Keys.Up));
    menuDownKeyboard := (CurrentKeyboardState.IsKeyDown(Keys.Down) and previousKeyboardState.IsKeyUp(Keys.Down));   
  end;
 
  if ( menuUpGamePad or menuUpKeyboard ) then
  begin
    selectedEntry := selectedEntry - 1;     
    if selectedEntry < 0 then
      selectedEntry := menuItems.Count - 1;
  end;   
 
  if ( menuDownGamePad or menuDownKeyboard ) then
  begin
    selectedEntry := selectedEntry + 1;     
    if selectedEntry > menuItems.Count - 1 then
      selectedEntry := 0;
  end;   
 
  // keep track of our previous input states
  previousGamePadState := currentGamePadState;
  previousKeyboardState := currentKeyboardState;
end;

/// <summary>
/// Helper for updating the screen transition position.
/// </summary>
method TXNAWinGame1.UpdateTransition( aGameTime : GameTime ; aTime : TimeSpan; aDirection : integer ) : boolean;
var
  transitionDelta : single; // How much should we move by?
begin
  // Still busy transitioning.
  result := true;

  if (aTime = TimeSpan.Zero) then
    transitionDelta := 1
  else
    transitionDelta := (aGameTime.ElapsedGameTime.TotalMilliseconds / aTime.TotalMilliseconds);

  // Update the transition position.
  transitionPosition := transitionPosition + transitionDelta * aDirection;

  // Did we reach the end of the transition?
  if ((transitionPosition <=0 ) or ( transitionPosition >= 1)) then
  begin
    transitionPosition := MathHelper.Clamp(transitionPosition, 0, 1);
    result := false;
  end;
end;

end.

Essential XNA Links