Browse Source

Samples and Starter Kits, baby[exclamation mark]

Dominique Louis 14 years ago
parent
commit
750acda160
100 changed files with 15993 additions and 0 deletions
  1. BIN
      Samples/Android/ChaseAndEvade/.DS_Store
  2. 21 0
      Samples/Android/ChaseAndEvade/Activity1.cs
  3. 89 0
      Samples/Android/ChaseAndEvade/MonoGame.Samples.ChaseAndEvade.Android.csproj
  4. 0 0
      Samples/Android/ChaseAndEvade/Resources/Resource.Designer.cs
  5. BIN
      Samples/Android/Draw2D/.DS_Store
  6. 19 0
      Samples/Android/Draw2D/Activity1.cs
  7. 103 0
      Samples/Android/Draw2D/MonoGame.Samples.Draw2D.Android.csproj
  8. 6 0
      Samples/Android/Draw2D/Properties/AndroidManifest.xml
  9. 36 0
      Samples/Android/Draw2D/Properties/AssemblyInfo.cs
  10. BIN
      Samples/Android/Draw2D/Resources/Drawable/Icon.png
  11. 7 0
      Samples/Android/Draw2D/Resources/Layout/Main.axml
  12. 62 0
      Samples/Android/Draw2D/Resources/Resource.Designer.cs
  13. 5 0
      Samples/Android/Draw2D/Resources/Values/Strings.xml
  14. BIN
      Samples/Android/Peer2Peer/.DS_Store
  15. 21 0
      Samples/Android/Peer2Peer/Activity1.cs
  16. 97 0
      Samples/Android/Peer2Peer/MonoGame.Samples.Peer2Peer.Android.csproj
  17. 6 0
      Samples/Android/Peer2Peer/Properties/AndroidManifest.xml
  18. 0 0
      Samples/Android/Peer2Peer/Resources/Resource.Designer.cs
  19. 148 0
      Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/AsteroidBeltAssault/MonoGame.Samples.AsteroidBeltAssault.Linux.csproj
  20. 53 0
      Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/AsteroidBeltAssault/Program.cs
  21. 113 0
      Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/FloodControl/MonoGame.Samples.FloodControl.Linux.csproj
  22. 53 0
      Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/FloodControl/Program.cs
  23. 205 0
      Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/GemstoneHunter/GemstoneHunter.csproj
  24. 61 0
      Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/GemstoneHunter/GemstoneHunter.sln
  25. 53 0
      Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/GemstoneHunter/Program.cs
  26. 12 0
      Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/GemstoneHunter/TileEngine/MyClass.cs
  27. 63 0
      Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/GemstoneHunter/TileEngine/Tile Engine.csproj
  28. 129 0
      Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/RobotRampage/MonoGame.Samples.RobotRampage.Linux.csproj
  29. 54 0
      Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/RobotRampage/Program.cs
  30. BIN
      Samples/Linux/ChaseAndEvade/GameThumbnail.png
  31. 16 0
      Samples/Linux/ChaseAndEvade/Info.plist
  32. 76 0
      Samples/Linux/ChaseAndEvade/MonoGame.Samples.ChaseAndEvade.Linux.csproj
  33. 12 0
      Samples/Linux/ChaseAndEvade/Program.cs
  34. 87 0
      Samples/Linux/Draw2D/MonoGame.Samples.Draw2D.Linux.csproj
  35. 21 0
      Samples/Linux/Draw2D/Program.cs
  36. 169 0
      Samples/Linux/NetRumble/AudioManager.cs
  37. 55 0
      Samples/Linux/NetRumble/Effects/BloomCombineEffect.cs
  38. 55 0
      Samples/Linux/NetRumble/Effects/BloomExtractEffect.cs
  39. 56 0
      Samples/Linux/NetRumble/Effects/CloudsEffect.cs
  40. 56 0
      Samples/Linux/NetRumble/Effects/GaussianBlurEffect.cs
  41. 261 0
      Samples/Linux/NetRumble/Gameplay/Asteroid.cs
  42. 568 0
      Samples/Linux/NetRumble/Gameplay/CollisionManager.cs
  43. 224 0
      Samples/Linux/NetRumble/Gameplay/GameplayObject.cs
  44. 149 0
      Samples/Linux/NetRumble/Gameplay/PlayerData.cs
  45. 123 0
      Samples/Linux/NetRumble/Gameplay/PowerUps/DoubleLaserPowerUp.cs
  46. 160 0
      Samples/Linux/NetRumble/Gameplay/PowerUps/PowerUp.cs
  47. 123 0
      Samples/Linux/NetRumble/Gameplay/PowerUps/RocketPowerUp.cs
  48. 123 0
      Samples/Linux/NetRumble/Gameplay/PowerUps/TripleLaserPowerUp.cs
  49. 162 0
      Samples/Linux/NetRumble/Gameplay/Projectiles/LaserProjectile.cs
  50. 196 0
      Samples/Linux/NetRumble/Gameplay/Projectiles/MineProjectile.cs
  51. 197 0
      Samples/Linux/NetRumble/Gameplay/Projectiles/Projectile.cs
  52. 229 0
      Samples/Linux/NetRumble/Gameplay/Projectiles/RocketProjectile.cs
  53. 878 0
      Samples/Linux/NetRumble/Gameplay/Ship.cs
  54. 221 0
      Samples/Linux/NetRumble/Gameplay/ShipInput.cs
  55. 80 0
      Samples/Linux/NetRumble/Gameplay/Weapons/DoubleLaserWeapon.cs
  56. 70 0
      Samples/Linux/NetRumble/Gameplay/Weapons/LaserWeapon.cs
  57. 73 0
      Samples/Linux/NetRumble/Gameplay/Weapons/MineWeapon.cs
  58. 63 0
      Samples/Linux/NetRumble/Gameplay/Weapons/RocketWeapon.cs
  59. 92 0
      Samples/Linux/NetRumble/Gameplay/Weapons/TripleLaserWeapon.cs
  60. 137 0
      Samples/Linux/NetRumble/Gameplay/Weapons/Weapon.cs
  61. 1412 0
      Samples/Linux/NetRumble/Gameplay/World.cs
  62. 602 0
      Samples/Linux/NetRumble/MonoGame.Samples.NetRumble.Linux.csproj
  63. 77 0
      Samples/Linux/NetRumble/Program.cs
  64. 105 0
      Samples/Linux/NetRumble/Rendering/Particles/Particle.cs
  65. 144 0
      Samples/Linux/NetRumble/Rendering/Particles/ParticleCache.cs
  66. 297 0
      Samples/Linux/NetRumble/Rendering/Particles/ParticleEffect.cs
  67. 259 0
      Samples/Linux/NetRumble/Rendering/Particles/ParticleEffectManager.cs
  68. 28 0
      Samples/Linux/NetRumble/Rendering/Particles/ParticleEffectType.cs
  69. 712 0
      Samples/Linux/NetRumble/Rendering/Particles/ParticleSystem.cs
  70. 392 0
      Samples/Linux/NetRumble/Rendering/Starfield.cs
  71. 320 0
      Samples/Linux/NetRumble/ScreenManager/GameScreen.cs
  72. 224 0
      Samples/Linux/NetRumble/ScreenManager/InputState.cs
  73. 150 0
      Samples/Linux/NetRumble/ScreenManager/LoadingScreen.cs
  74. 181 0
      Samples/Linux/NetRumble/ScreenManager/MenuScreen.cs
  75. 174 0
      Samples/Linux/NetRumble/ScreenManager/MessageBoxScreen.cs
  76. 385 0
      Samples/Linux/NetRumble/ScreenManager/ScreenManager.cs
  77. 235 0
      Samples/Linux/NetRumble/Screens/BackgroundScreen.cs
  78. 618 0
      Samples/Linux/NetRumble/Screens/GameplayScreen.cs
  79. 591 0
      Samples/Linux/NetRumble/Screens/LobbyScreen.cs
  80. 675 0
      Samples/Linux/NetRumble/Screens/MainMenuScreen.cs
  81. 204 0
      Samples/Linux/NetRumble/Screens/NetworkBusyScreen.cs
  82. 351 0
      Samples/Linux/NetRumble/Screens/SearchResultsScreen.cs
  83. 188 0
      Samples/Linux/NetworkStateManagement/NetworkStateManagement.csproj
  84. 18 0
      Samples/Linux/NetworkStateManagement/Program.cs
  85. 36 0
      Samples/Linux/NetworkStateManagement/Properties/AssemblyInfo.cs
  86. 433 0
      Samples/Linux/NetworkStateManagement/Resources.Designer.cs
  87. 250 0
      Samples/Linux/NetworkStateManagement/Resources.resx
  88. 77 0
      Samples/Linux/Peer2PeerSample/MonoGame.Samples.Peer2PeerSample.Linux.csproj
  89. 15 0
      Samples/Linux/Peer2PeerSample/Program.cs
  90. 32 0
      Samples/Linux/Peer2PeerSample/Properties/AssemblyInfo.cs
  91. 3 0
      Samples/Linux/Peer2PeerSample/app.config
  92. 134 0
      Samples/Linux/Sound/Game1.cs
  93. 82 0
      Samples/Linux/Sound/MonoGame.Samples.Sound.Linux.csproj
  94. 21 0
      Samples/Linux/Sound/Program.cs
  95. 57 0
      Samples/Linux/SpriteEffects/DesaturateEffect.cs
  96. 102 0
      Samples/Linux/SpriteEffects/DisappearEffect.cs
  97. 119 0
      Samples/Linux/SpriteEffects/MonoGame.Samples.SpriteEffects.Linux.csproj
  98. 63 0
      Samples/Linux/SpriteEffects/NormalmapEffect.cs
  99. 16 0
      Samples/Linux/SpriteEffects/Program.cs
  100. 63 0
      Samples/Linux/SpriteEffects/RefractionEffect.cs

BIN
Samples/Android/ChaseAndEvade/.DS_Store


+ 21 - 0
Samples/Android/ChaseAndEvade/Activity1.cs

@@ -0,0 +1,21 @@
+using Android.App;
+using Android.Content.PM;
+using Android.OS;
+using ChaseAndEvade;
+
+namespace MonoGame.Samples.ChaseAndEvade.Droid
+{
+    [Activity(Label = "ChaseAndEvade", MainLauncher = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden)]
+    public class Activity1 : Activity
+    {
+        protected override void OnCreate(Bundle bundle)
+        {
+            base.OnCreate(bundle);
+
+            ChaseAndEvadeGame g = new ChaseAndEvadeGame(this);
+            SetContentView(g.Window);
+            g.Run();
+        }
+    }
+}
+

+ 89 - 0
Samples/Android/ChaseAndEvade/MonoGame.Samples.ChaseAndEvade.Android.csproj

@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{F05F90DC-DD37-4967-A96A-8D36C1C23E81}</ProjectGuid>
+    <ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>MonoGame.Samples.ChaseAndEvade.Android</RootNamespace>
+    <AssemblyName>MonoGame.Samples.ChaseAndEvade.Android</AssemblyName>
+    <FileAlignment>512</FileAlignment>
+    <AndroidApplication>true</AndroidApplication>
+    <AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
+    <AndroidSupportedAbis>armeabi</AndroidSupportedAbis>
+    <AndroidStoreUncompressedFileExtensions />
+    <TargetFrameworkVersion>v2.2</TargetFrameworkVersion>
+    <MandroidI18n />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>TRACE;DEBUG;ANDROID</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <AndroidLinkMode>None</AndroidLinkMode>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE;ANDROID</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
+    <AndroidLinkMode>SdkOnly</AndroidLinkMode>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Mono.Android" />
+    <Reference Include="mscorlib" />
+    <Reference Include="OpenTK" />
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Activity1.cs" />
+    <Compile Include="..\..\iOS\ChaseAndEvade\ChaseAndEvadeGame.cs">
+      <Link>ChaseAndEvadeGame.cs</Link>
+    </Compile>
+    <Compile Include="Resources\Resource.Designer.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <AndroidAsset Include="..\..\iOS\ChaseAndEvade\Content\Arial.xnb">
+      <Link>Assets\Content\Arial.xnb</Link>
+    </AndroidAsset>
+    <AndroidAsset Include="..\..\iOS\ChaseAndEvade\Content\cat.png">
+      <Link>Assets\Content\Cat.png</Link>
+    </AndroidAsset>
+    <AndroidAsset Include="..\..\iOS\ChaseAndEvade\Content\mouse.png">
+      <Link>Assets\Content\Mouse.png</Link>
+    </AndroidAsset>
+    <AndroidAsset Include="..\..\iOS\ChaseAndEvade\Content\tank.png">
+      <Link>Assets\Content\Tank.png</Link>
+    </AndroidAsset>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\MonoGame.Framework\MonoGame.Framework.Android.csproj">
+      <Project>{BA9476CF-99BA-4D03-92F2-73D2C5E58883}</Project>
+      <Name>MonoGame.Framework.Android</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Properties\" />
+  </ItemGroup>
+  <Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+     Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 0 - 0
Samples/Android/ChaseAndEvade/Resources/Resource.Designer.cs


BIN
Samples/Android/Draw2D/.DS_Store


+ 19 - 0
Samples/Android/Draw2D/Activity1.cs

@@ -0,0 +1,19 @@
+using Android.App;
+using Android.OS;
+
+namespace Microsoft.Xna.Samples.Draw2D
+{
+    [Activity(Label = "Draw2D", MainLauncher = true, Icon = "@drawable/icon")]
+    public class Activity1 : Activity
+    {
+        protected override void OnCreate(Bundle bundle)
+        {
+            base.OnCreate(bundle);
+
+            var g = new Game1(this);
+            SetContentView(g.Window);
+            g.Run();
+        }
+    }
+}
+

+ 103 - 0
Samples/Android/Draw2D/MonoGame.Samples.Draw2D.Android.csproj

@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{616BBFA6-52F2-40A1-AA76-1CF2BD6390D5}</ProjectGuid>
+    <ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>MonoGame.Samples.Draw2D.Android</RootNamespace>
+    <AssemblyName>Draw2D</AssemblyName>
+    <FileAlignment>512</FileAlignment>
+    <AndroidApplication>true</AndroidApplication>
+    <AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
+    <AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
+    <TargetFrameworkVersion>v2.2</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE;ANDROID</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <AndroidLinkMode>None</AndroidLinkMode>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE;ANDROID</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
+    <AndroidLinkMode>SdkOnly</AndroidLinkMode>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Mono.Android" />
+    <Reference Include="OpenTK" />
+    <Reference Include="mscorlib" />
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Activity1.cs" />
+    <Compile Include="..\..\iOS\Draw2D\Game1.cs">
+      <Link>Game1.cs</Link>
+    </Compile>
+    <Compile Include="Resources\Resource.Designer.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="..\..\iOS\Draw2D\FPSCounterComponent.cs">
+      <Link>FPSCounterComponent.cs</Link>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <AndroidResource Include="Resources\Layout\Main.axml" />
+  </ItemGroup>
+  <ItemGroup>
+    <AndroidResource Include="Resources\Values\Strings.xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <AndroidResource Include="Resources\Drawable\Icon.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="Properties\AndroidManifest.xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <AndroidAsset Include="..\..\iOS\Draw2D\Default.png">
+      <Link>Default.png</Link>
+    </AndroidAsset>
+    <AndroidAsset Include="..\..\iOS\Draw2D\Content\monogameicon.png">
+      <Link>Assets\Content\monogameicon.png</Link>
+    </AndroidAsset>
+    <AndroidAsset Include="..\..\iOS\Draw2D\Content\purpleBall.xnb">
+      <Link>Assets\Content\purpleBall.xnb</Link>
+    </AndroidAsset>
+    <AndroidAsset Include="..\..\iOS\Draw2D\Content\spriteFont1.xnb">
+      <Link>Assets\Content\spriteFont1.xnb</Link>
+    </AndroidAsset>
+  </ItemGroup>
+  <Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+     Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\MonoGame.Framework\MonoGame.Framework.Android.csproj">
+      <Project>{BA9476CF-99BA-4D03-92F2-73D2C5E58883}</Project>
+      <Name>MonoGame.Framework.Android</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Assets\Content\" />
+  </ItemGroup>
+</Project>

+ 6 - 0
Samples/Android/Draw2D/Properties/AndroidManifest.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly">
+  <application>
+  </application>
+  <uses-sdk android:minSdkVersion="9" />
+</manifest>

+ 36 - 0
Samples/Android/Draw2D/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("MonoDroidXnaTouchGame")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("MonoDroidXnaTouchGame")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("a557ce8c-9dbe-4b93-8fc4-95ffc126cf14")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

BIN
Samples/Android/Draw2D/Resources/Drawable/Icon.png


+ 7 - 0
Samples/Android/Draw2D/Resources/Layout/Main.axml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    >
+</LinearLayout>

+ 62 - 0
Samples/Android/Draw2D/Resources/Resource.Designer.cs

@@ -0,0 +1,62 @@
+// ------------------------------------------------------------------------------
+//  <autogenerated>
+//      This code was generated by a tool.
+//      Mono Runtime Version: 4.0.30319.1
+// 
+//      Changes to this file may cause incorrect behavior and will be lost if 
+//      the code is regenerated.
+//  </autogenerated>
+// ------------------------------------------------------------------------------
+
+namespace MonoGame.Samples.Draw2D.Android
+{
+	
+	
+	public partial class Resource
+	{
+		
+		public partial class Attribute
+		{
+			
+			private Attribute()
+			{
+			}
+		}
+		
+		public partial class Drawable
+		{
+			
+			// aapt resource value: 0x7f020000
+			public const int Icon = 2130837504;
+			
+			private Drawable()
+			{
+			}
+		}
+		
+		public partial class Layout
+		{
+			
+			// aapt resource value: 0x7f030000
+			public const int Main = 2130903040;
+			
+			private Layout()
+			{
+			}
+		}
+		
+		public partial class String
+		{
+			
+			// aapt resource value: 0x7f040001
+			public const int ApplicationName = 2130968577;
+			
+			// aapt resource value: 0x7f040000
+			public const int Hello = 2130968576;
+			
+			private String()
+			{
+			}
+		}
+	}
+}

+ 5 - 0
Samples/Android/Draw2D/Resources/Values/Strings.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="Hello">Hello World, Click Me!</string>
+    <string name="ApplicationName">MonoDroidXnaTouchGame</string>
+</resources>

BIN
Samples/Android/Peer2Peer/.DS_Store


+ 21 - 0
Samples/Android/Peer2Peer/Activity1.cs

@@ -0,0 +1,21 @@
+using Android.App;
+using Android.Content.PM;
+using Android.OS;
+using PeerToPeer;
+
+namespace MonoGame.Samples.PeerToPeerGame.Droid
+{
+    [Activity(Label = "Peer2Peer", MainLauncher = true, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.KeyboardHidden)]
+    public class Activity1 : Activity
+    {
+        protected override void OnCreate(Bundle bundle)
+        {
+            base.OnCreate(bundle);
+
+            var g = new PeerToPeer.PeerToPeerGame(this);
+            SetContentView(g.Window);
+            g.Run();
+        }
+    }
+}
+

+ 97 - 0
Samples/Android/Peer2Peer/MonoGame.Samples.Peer2Peer.Android.csproj

@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{56F6C06F-6F07-402E-89A5-39EDB037A516}</ProjectGuid>
+    <ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>MonoGame.Samples.Peer2Peer.Android</RootNamespace>
+    <AssemblyName>MonoGame.Samples.Peer2Peer.Android</AssemblyName>
+    <FileAlignment>512</FileAlignment>
+    <AndroidApplication>true</AndroidApplication>
+    <AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
+    <AndroidSupportedAbis>armeabi</AndroidSupportedAbis>
+    <AndroidStoreUncompressedFileExtensions />
+    <TargetFrameworkVersion>v2.2</TargetFrameworkVersion>
+    <MandroidI18n />
+    <AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>TRACE;DEBUG;ANDROID</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <AndroidLinkMode>None</AndroidLinkMode>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE;ANDROID</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
+    <AndroidLinkMode>SdkOnly</AndroidLinkMode>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Mono.Android" />
+    <Reference Include="mscorlib" />
+    <Reference Include="OpenTK" />
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Activity1.cs" />
+    <Compile Include="Resources\Resource.Designer.cs" />
+    <Compile Include="..\..\MacOS\Peer2PeerSample\PeerToPeerGame.cs">
+      <Link>PeerToPeerGame.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\Peer2PeerSample\Tank.cs">
+      <Link>Tank.cs</Link>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\MonoGame.Framework\MonoGame.Framework.Android.csproj">
+      <Project>{BA9476CF-99BA-4D03-92F2-73D2C5E58883}</Project>
+      <Name>MonoGame.Framework.Android</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Properties\" />
+    <Folder Include="Assets\Content\" />
+  </ItemGroup>
+  <Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+     Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <ItemGroup>
+    <AndroidAsset Include="..\..\MacOS\Peer2PeerSample\Content\Font.xnb">
+      <Link>Assets\Content\Font.xnb</Link>
+    </AndroidAsset>
+    <AndroidAsset Include="..\..\iOS\Peer2Peer\Content\gamepad.png">
+      <Link>Assets\Content\gamepad.png</Link>
+    </AndroidAsset>
+    <AndroidAsset Include="..\..\MacOS\Peer2PeerSample\Content\Tank.xnb">
+      <Link>Assets\Content\Tank.xnb</Link>
+    </AndroidAsset>
+    <AndroidAsset Include="..\..\MacOS\Peer2PeerSample\Content\Turret.xnb">
+      <Link>Assets\Content\Turret.xnb</Link>
+    </AndroidAsset>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Properties\AndroidManifest.xml" />
+  </ItemGroup>
+</Project>

+ 6 - 0
Samples/Android/Peer2Peer/Properties/AndroidManifest.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="monogamesamplespeer2peerandroid.monogamesamplespeer2peerandroid">
+	<application android:label="MonoGame.Samples.Peer2Peer.Android"></application>
+	<uses-sdk />
+	<uses-permission android:name="android.permission.INTERNET" />
+</manifest>

+ 0 - 0
Samples/Android/Peer2Peer/Resources/Resource.Designer.cs


+ 148 - 0
Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/AsteroidBeltAssault/MonoGame.Samples.AsteroidBeltAssault.Linux.csproj

@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{86A219E2-C8F0-452B-B762-C69D5BB07C99}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>AsteroidBeltAssault</RootNamespace>
+    <AssemblyName>FloodControl</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG,LINUX</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <ConsolePause>false</ConsolePause>
+    <EnvironmentVariables>
+      <EnvironmentVariables>
+        <Variable name="MONO_IOMAP" value="all" />
+      </EnvironmentVariables>
+    </EnvironmentVariables>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <DebugType>none</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Drawing" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\README.md">
+      <Link>README.md</Link>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\Info.plist">
+      <Link>Info.plist</Link>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\GameThumbnail.png">
+      <Link>GameThumbnail.png</Link>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\Game.ico">
+      <Link>Game.ico</Link>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\Content\Fonts\Pericles14.xnb">
+      <Link>Content\Fonts\Pericles14.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\Content\Sounds\Shot2.xnb">
+      <Link>Content\Sounds\Shot2.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\Content\Sounds\Shot1.xnb">
+      <Link>Content\Sounds\Shot1.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\Content\Sounds\Explosion4.xnb">
+      <Link>Content\Sounds\Explosion4.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\Content\Sounds\Explosion3.xnb">
+      <Link>Content\Sounds\Explosion3.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\Content\Sounds\Explosion2.xnb">
+      <Link>Content\Sounds\Explosion2.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\Content\Sounds\Explosion1.xnb">
+      <Link>Content\Sounds\Explosion1.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\Content\Textures\TitleScreen.xnb">
+      <Link>Content\Textures\TitleScreen.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\Content\Textures\SpriteSheet.xnb">
+      <Link>Content\Textures\SpriteSheet.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Content\" />
+    <Folder Include="Content\Fonts\" />
+    <Folder Include="Content\Sounds\" />
+    <Folder Include="Content\Textures\" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\StarField.cs">
+      <Link>StarField.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\Sprite.cs">
+      <Link>Sprite.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\SoundManager.cs">
+      <Link>SoundManager.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\ShotManager.cs">
+      <Link>ShotManager.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\PlayerManager.cs">
+      <Link>PlayerManager.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\Particle.cs">
+      <Link>Particle.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\Game1.cs">
+      <Link>Game1.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\ExplosionManager.cs">
+      <Link>ExplosionManager.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\EnemyManager.cs">
+      <Link>EnemyManager.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\Enemy.cs">
+      <Link>Enemy.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\CollisionManager.cs">
+      <Link>CollisionManager.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\AsteroidBeltAssault\AsteroidManager.cs">
+      <Link>AsteroidManager.cs</Link>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\..\..\MonoGame.Framework\MonoGame.Framework.Linux.csproj">
+      <Project>{35253CE1-C864-4CD3-8249-4D1319748E8F}</Project>
+      <Name>MonoGame.Framework.Linux</Name>
+    </ProjectReference>
+  </ItemGroup>
+</Project>

+ 53 - 0
Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/AsteroidBeltAssault/Program.cs

@@ -0,0 +1,53 @@
+using System;
+
+namespace Asteroid_Belt_Assault
+{
+#if WINDOWS || XBOX || LINUX
+    static class Program
+    {
+        /// <summary>
+        /// The main entry point for the application.
+        /// </summary>
+        static void Main(string[] args)
+        {
+            using (Game1 game = new Game1())
+            {
+                game.Run();
+            }
+        }
+    }
+#else
+	static class Program
+	{
+		/// <summary>
+		/// The main entry point for the application.
+		/// </summary>
+		static void Main (string[] args)
+		{
+			NSApplication.Init ();
+			
+			using (var p = new NSAutoreleasePool ()) {
+				NSApplication.SharedApplication.Delegate = new AppDelegate();
+				NSApplication.Main(args);
+			}
+		}
+	}
+	
+	class AppDelegate : NSApplicationDelegate
+	{
+		
+		public override void FinishedLaunching (MonoMac.Foundation.NSObject notification)
+		{
+			using (Game1 game = new Game1 ()) {
+				game.Run ();
+			}
+		}
+		
+		public override bool ApplicationShouldTerminateAfterLastWindowClosed (NSApplication sender)
+		{
+			return true;
+		}
+	}		
+#endif
+}
+

+ 113 - 0
Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/FloodControl/MonoGame.Samples.FloodControl.Linux.csproj

@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{86A219E2-C8F1-422B-C762-C69D5BB07C98}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>FloodControl</RootNamespace>
+    <AssemblyName>FloodControl</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG,LINUX</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <DebugType>none</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Drawing" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\README.md">
+      <Link>README.md</Link>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\Info.plist">
+      <Link>Info.plist</Link>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\GameThumbnail.png">
+      <Link>GameThumbnail.png</Link>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\Game.ico">
+      <Link>Game.ico</Link>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\FloodControl.sln">
+      <Link>FloodControl.sln</Link>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\FloodControl.csproj">
+      <Link>FloodControl.csproj</Link>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\Content\Fonts\Pericles36.xnb">
+      <Link>Content\Fonts\Pericles36.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\Content\Textures\TitleScreen.xnb">
+      <Link>Content\Textures\TitleScreen.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\Content\Textures\Tile_Sheet.xnb">
+      <Link>Content\Textures\Tile_Sheet.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\Content\Textures\Background.xnb">
+      <Link>Content\Textures\Background.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Content\" />
+    <Folder Include="Content\Textures\" />
+    <Folder Include="Content\Fonts\" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\ScoreZooms.cs">
+      <Link>ScoreZooms.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\RotatingPiece.cs">
+      <Link>RotatingPiece.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\GamePiece.cs">
+      <Link>GamePiece.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\GameBoard.cs">
+      <Link>GameBoard.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\Game1.cs">
+      <Link>Game1.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\FallingPiece.cs">
+      <Link>FallingPiece.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\FloodControl\FadingPiece.cs">
+      <Link>FadingPiece.cs</Link>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\..\..\MonoGame.Framework\MonoGame.Framework.Linux.csproj">
+      <Project>{35253CE1-C864-4CD3-8249-4D1319748E8F}</Project>
+      <Name>MonoGame.Framework.Linux</Name>
+    </ProjectReference>
+  </ItemGroup>
+</Project>

+ 53 - 0
Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/FloodControl/Program.cs

@@ -0,0 +1,53 @@
+using System;
+
+namespace Flood_Control
+{
+#if WINDOWS || XBOX || LINUX
+	static class Program
+	{
+	/// <summary>
+	/// The main entry point for the application.
+	/// </summary>
+	static void Main(string[] args)
+	{
+		using (Game1 game = new Game1())
+		{
+		game.Run();
+		}
+	}
+	}
+#else
+	static class Program
+	{
+		/// <summary>
+		/// The main entry point for the application.
+		/// </summary>
+		static void Main (string[] args)
+		{
+			NSApplication.Init ();
+			
+			using (var p = new NSAutoreleasePool ()) {
+				NSApplication.SharedApplication.Delegate = new AppDelegate();
+				NSApplication.Main(args);
+			}
+		}
+	}
+	
+	class AppDelegate : NSApplicationDelegate
+	{
+		
+		public override void FinishedLaunching (MonoMac.Foundation.NSObject notification)
+		{
+			using (Game1 game = new Game1 ()) {
+				game.Run ();
+			}
+		}
+		
+		public override bool ApplicationShouldTerminateAfterLastWindowClosed (NSApplication sender)
+		{
+			return true;
+		}
+	}		
+#endif
+}
+

+ 205 - 0
Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/GemstoneHunter/GemstoneHunter.csproj

@@ -0,0 +1,205 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{86A219E2-C8F0-452B-B762-C69D5BB07C98}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>AsteroidBeltAssault</RootNamespace>
+    <AssemblyName>FloodControl</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG,LINUX</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <DebugType>none</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Drawing" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\README.md">
+      <Link>README.md</Link>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Info.plist">
+      <Link>Info.plist</Link>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\GameThumbnail.png">
+      <Link>GameThumbnail.png</Link>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Game.ico">
+      <Link>Game.ico</Link>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Fonts\Pericles10Bold.xnb">
+      <Link>Content\Fonts\Pericles10Bold.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Fonts\Pericles8.xnb">
+      <Link>Content\Fonts\Pericles8.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Maps\MAP001.MAP">
+      <Link>Content\Maps\MAP001.MAP</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Maps\MAP000.MAP">
+      <Link>Content\Maps\MAP000.MAP</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Gem.xnb">
+      <Link>Content\Textures\Gem.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\PlatformTiles.xnb">
+      <Link>Content\Textures\PlatformTiles.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\TitleScreen.xnb">
+      <Link>Content\Textures\TitleScreen.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\Gem.xnb">
+      <Link>Content\Textures\Sprites\Gem.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\MonsterA\Run.xnb">
+      <Link>Content\Textures\Sprites\MonsterA\Run.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\MonsterA\Idle.xnb">
+      <Link>Content\Textures\Sprites\MonsterA\Idle.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\MonsterA\Die.xnb">
+      <Link>Content\Textures\Sprites\MonsterA\Die.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\MonsterB\Run.xnb">
+      <Link>Content\Textures\Sprites\MonsterB\Run.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\MonsterB\Idle.xnb">
+      <Link>Content\Textures\Sprites\MonsterB\Idle.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\MonsterB\Die.xnb">
+      <Link>Content\Textures\Sprites\MonsterB\Die.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\MonsterC\Run.xnb">
+      <Link>Content\Textures\Sprites\MonsterC\Run.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\MonsterC\Idle.xnb">
+      <Link>Content\Textures\Sprites\MonsterC\Idle.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\MonsterC\Die.xnb">
+      <Link>Content\Textures\Sprites\MonsterC\Die.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\MonsterD\Run.xnb">
+      <Link>Content\Textures\Sprites\MonsterD\Run.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\MonsterD\Idle.xnb">
+      <Link>Content\Textures\Sprites\MonsterD\Idle.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\MonsterD\Die.xnb">
+      <Link>Content\Textures\Sprites\MonsterD\Die.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\Player\Run.xnb">
+      <Link>Content\Textures\Sprites\Player\Run.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\Player\Jump.xnb">
+      <Link>Content\Textures\Sprites\Player\Jump.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\Player\Idle.xnb">
+      <Link>Content\Textures\Sprites\Player\Idle.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\Player\Die.xnb">
+      <Link>Content\Textures\Sprites\Player\Die.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Content\Textures\Sprites\Player\Celebrate.xnb">
+      <Link>Content\Textures\Sprites\Player\Celebrate.xnb</Link>
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(MSBuildExtensionsPath)\Mono\MonoMac\v0.0\Mono.MonoMac.targets" />
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\..\..\MonoGame.Framework\MonoGame.Framework.Linux.csproj">
+      <Project>{35253CE1-C864-4CD3-8249-4D1319748E8F}</Project>
+      <Name>MonoGame.Framework.Linux</Name>
+    </ProjectReference>
+    <ProjectReference Include="TileEngine\Tile Engine.csproj">
+      <Project>{521972FD-1A9B-4CFD-A435-EB2224985131}</Project>
+      <Name>Tile Engine</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Content\" />
+    <Folder Include="Content\Fonts\" />
+    <Folder Include="Content\Maps\" />
+    <Folder Include="Content\Textures\Sprites\MonsterA\" />
+    <Folder Include="Content\Textures\Sprites\MonsterB\" />
+    <Folder Include="Content\Textures\Sprites\MonsterC\" />
+    <Folder Include="Content\Textures\Sprites\MonsterD\" />
+    <Folder Include="Content\Textures\Sprites\Player\" />
+    <Folder Include="Content\Textures\" />
+    <Folder Include="Content\Textures\" />
+    <Folder Include="Content\Textures\" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Player.cs">
+      <Link>Player.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\LevelManager.cs">
+      <Link>LevelManager.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Gemstone.cs">
+      <Link>Gemstone.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\GameObject.cs">
+      <Link>GameObject.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Game1.cs">
+      <Link>Game1.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\Enemy.cs">
+      <Link>Enemy.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\AnimationStrip.cs">
+      <Link>AnimationStrip.cs</Link>
+    </Compile>
+  </ItemGroup>
+</Project>

+ 61 - 0
Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/GemstoneHunter/GemstoneHunter.sln

@@ -0,0 +1,61 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tile Engine", "TileEngine\Tile Engine.csproj", "{521972FD-1A9B-4CFD-A435-EB2224985131}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GemstoneHunter", "GemstoneHunter.csproj", "{86A219E2-C8F0-452B-B762-C69D5BB07C98}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonoGame.Framework.Linux", "..\..\..\..\..\MonoGame.Framework\MonoGame.Framework.Linux.csproj", "{35253CE1-C864-4CD3-8249-4D1319748E8F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lidgren.Network.Linux", "..\..\..\..\..\ThirdParty\Lidgren.Network\Lidgren.Network.Linux.csproj", "{AE483C29-042E-4226-BA52-D247CE7676DA}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+		Distribution|Any CPU = Distribution|Any CPU
+		Debug|x86 = Debug|x86
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|Any CPU.ActiveCfg = Debug|x86
+		{35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|Any CPU.Build.0 = Debug|x86
+		{35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|x86.ActiveCfg = Debug|x86
+		{35253CE1-C864-4CD3-8249-4D1319748E8F}.Debug|x86.Build.0 = Debug|x86
+		{35253CE1-C864-4CD3-8249-4D1319748E8F}.Distribution|Any CPU.ActiveCfg = Debug|x86
+		{35253CE1-C864-4CD3-8249-4D1319748E8F}.Distribution|Any CPU.Build.0 = Debug|x86
+		{35253CE1-C864-4CD3-8249-4D1319748E8F}.Release|Any CPU.ActiveCfg = Release|x86
+		{35253CE1-C864-4CD3-8249-4D1319748E8F}.Release|Any CPU.Build.0 = Release|x86
+		{35253CE1-C864-4CD3-8249-4D1319748E8F}.Release|x86.ActiveCfg = Release|x86
+		{35253CE1-C864-4CD3-8249-4D1319748E8F}.Release|x86.Build.0 = Release|x86
+		{521972FD-1A9B-4CFD-A435-EB2224985131}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{521972FD-1A9B-4CFD-A435-EB2224985131}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{521972FD-1A9B-4CFD-A435-EB2224985131}.Distribution|Any CPU.ActiveCfg = Debug|Any CPU
+		{521972FD-1A9B-4CFD-A435-EB2224985131}.Distribution|Any CPU.Build.0 = Debug|Any CPU
+		{521972FD-1A9B-4CFD-A435-EB2224985131}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{521972FD-1A9B-4CFD-A435-EB2224985131}.Release|Any CPU.Build.0 = Release|Any CPU
+		{86A219E2-C8F0-452B-B762-C69D5BB07C98}.Debug|Any CPU.ActiveCfg = Debug|x86
+		{86A219E2-C8F0-452B-B762-C69D5BB07C98}.Debug|Any CPU.Build.0 = Debug|x86
+		{86A219E2-C8F0-452B-B762-C69D5BB07C98}.Debug|x86.ActiveCfg = Debug|x86
+		{86A219E2-C8F0-452B-B762-C69D5BB07C98}.Debug|x86.Build.0 = Debug|x86
+		{86A219E2-C8F0-452B-B762-C69D5BB07C98}.Distribution|Any CPU.ActiveCfg = Debug|x86
+		{86A219E2-C8F0-452B-B762-C69D5BB07C98}.Distribution|Any CPU.Build.0 = Debug|x86
+		{86A219E2-C8F0-452B-B762-C69D5BB07C98}.Release|Any CPU.ActiveCfg = Release|x86
+		{86A219E2-C8F0-452B-B762-C69D5BB07C98}.Release|Any CPU.Build.0 = Release|x86
+		{86A219E2-C8F0-452B-B762-C69D5BB07C98}.Release|x86.ActiveCfg = Release|x86
+		{86A219E2-C8F0-452B-B762-C69D5BB07C98}.Release|x86.Build.0 = Release|x86
+		{AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{AE483C29-042E-4226-BA52-D247CE7676DA}.Debug|x86.Build.0 = Debug|Any CPU
+		{AE483C29-042E-4226-BA52-D247CE7676DA}.Distribution|Any CPU.ActiveCfg = Debug|Any CPU
+		{AE483C29-042E-4226-BA52-D247CE7676DA}.Distribution|Any CPU.Build.0 = Debug|Any CPU
+		{AE483C29-042E-4226-BA52-D247CE7676DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AE483C29-042E-4226-BA52-D247CE7676DA}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AE483C29-042E-4226-BA52-D247CE7676DA}.Release|x86.ActiveCfg = Release|Any CPU
+		{AE483C29-042E-4226-BA52-D247CE7676DA}.Release|x86.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(MonoDevelopProperties) = preSolution
+		StartupItem = GemstoneHunter.csproj
+	EndGlobalSection
+EndGlobal

+ 53 - 0
Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/GemstoneHunter/Program.cs

@@ -0,0 +1,53 @@
+using System;
+
+namespace Gemstone_Hunter
+{
+#if WINDOWS || XBOX || LINUX
+    static class Program
+    {
+        /// <summary>
+        /// The main entry point for the application.
+        /// </summary>
+        static void Main(string[] args)
+        {
+            using (Game1 game = new Game1())
+            {
+                game.Run();
+            }
+        }
+    }
+#else
+	static class Program
+	{
+		/// <summary>
+		/// The main entry point for the application.
+		/// </summary>
+		static void Main (string[] args)
+		{
+			NSApplication.Init ();
+			
+			using (var p = new NSAutoreleasePool ()) {
+				NSApplication.SharedApplication.Delegate = new AppDelegate();
+				NSApplication.Main(args);
+			}
+		}
+	}
+	
+	class AppDelegate : NSApplicationDelegate
+	{
+		
+		public override void FinishedLaunching (MonoMac.Foundation.NSObject notification)
+		{
+			using (Game1 game = new Game1 ()) {
+				game.Run ();
+			}
+		}
+		
+		public override bool ApplicationShouldTerminateAfterLastWindowClosed (NSApplication sender)
+		{
+			return true;
+		}
+	}			
+#endif
+}
+

+ 12 - 0
Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/GemstoneHunter/TileEngine/MyClass.cs

@@ -0,0 +1,12 @@
+using System;
+
+namespace TileEngine
+{
+	public class MyClass
+	{
+		public MyClass ()
+		{
+		}
+	}
+}
+

+ 63 - 0
Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/GemstoneHunter/TileEngine/Tile Engine.csproj

@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>10.0.0</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{521972FD-1A9B-4CFD-A435-EB2224985131}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <RootNamespace>Tile_Engine</RootNamespace>
+    <AssemblyName>Tile Engine</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>none</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Xml.Linq" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\TileEngine\TileMap.cs">
+      <Link>TileMap.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\TileEngine\MyClass.cs">
+      <Link>MyClass.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\TileEngine\MapSquare.cs">
+      <Link>MapSquare.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\TileEngine\Camera.cs">
+      <Link>Camera.cs</Link>
+    </Compile>
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\..\..\..\MonoGame.Framework\MonoGame.Framework.Linux.csproj">
+      <Project>{35253CE1-C864-4CD3-8249-4D1319748E8F}</Project>
+      <Name>MonoGame.Framework.Linux</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\..\..\..\..\..\..\projects\monogame\Samples\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\GemstoneHunter\TileEngine\AssemblyInfo.cs">
+      <Link>AssemblyInfo.cs</Link>
+    </None>
+  </ItemGroup>
+</Project>

+ 129 - 0
Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/RobotRampage/MonoGame.Samples.RobotRampage.Linux.csproj

@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{86A219E2-C8F0-452B-B762-C69D5BB07C98}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>AsteroidBeltAssault</RootNamespace>
+    <AssemblyName>FloodControl</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG,LINUX</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <DebugType>none</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Drawing" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\README.md">
+      <Link>README.md</Link>
+    </None>
+    <None Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\Info.plist">
+      <Link>Info.plist</Link>
+    </None>
+    <None Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\GameThumbnail.png">
+      <Link>GameThumbnail.png</Link>
+    </None>
+    <None Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\Game.ico">
+      <Link>Game.ico</Link>
+    </None>
+    <None Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\Content\Fonts\Pericles14.xnb">
+      <Link>Content\Fonts\Pericles14.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\Content\Textures\TitleScreen.xnb">
+      <Link>Content\Textures\TitleScreen.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\Content\Textures\SpriteSheet.xnb">
+      <Link>Content\Textures\SpriteSheet.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(MSBuildExtensionsPath)\Mono\MonoMac\v0.0\Mono.MonoMac.targets" />
+  <ItemGroup>
+    <Folder Include="Content\" />
+    <Folder Include="Content\Fonts\" />
+    <Folder Include="Content\Textures\" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\WeaponManager.cs">
+      <Link>WeaponManager.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\TileMap.cs">
+      <Link>TileMap.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\Sprite.cs">
+      <Link>Sprite.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\Player.cs">
+      <Link>Player.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\PathNode.cs">
+      <Link>PathNode.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\PathFinder.cs">
+      <Link>PathFinder.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\Particle.cs">
+      <Link>Particle.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\GoalManager.cs">
+      <Link>GoalManager.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\GameManager.cs">
+      <Link>GameManager.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\Game1.cs">
+      <Link>Game1.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\EnemyManager.cs">
+      <Link>EnemyManager.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\Enemy.cs">
+      <Link>Enemy.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\EffectsManager.cs">
+      <Link>EffectsManager.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\ComputerTerminal.cs">
+      <Link>ComputerTerminal.cs</Link>
+    </Compile>
+    <Compile Include="..\..\..\..\MacOS\BookSourceCode\XNAGameDevelopmentbyExampleCode\RobotRampage\Camera.cs">
+      <Link>Camera.cs</Link>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\..\..\MonoGame.Framework\MonoGame.Framework.Linux.csproj">
+      <Project>{35253CE1-C864-4CD3-8249-4D1319748E8F}</Project>
+      <Name>MonoGame.Framework.Linux</Name>
+    </ProjectReference>
+  </ItemGroup>
+</Project>

+ 54 - 0
Samples/Linux/BookSourceCode/XNAGameDevelopmentbyExampleCode/RobotRampage/Program.cs

@@ -0,0 +1,54 @@
+using System;
+
+
+namespace Robot_Rampage
+{
+#if WINDOWS || XBOX || LINUX
+    static class Program
+    {
+        /// <summary>
+        /// The main entry point for the application.
+        /// </summary>
+        static void Main(string[] args)
+        {
+            using (Game1 game = new Game1())
+            {
+                game.Run();
+            }
+        }
+    }
+#else
+	static class Program
+	{
+		/// <summary>
+		/// The main entry point for the application.
+		/// </summary>
+		static void Main (string[] args)
+		{
+			NSApplication.Init ();
+			
+			using (var p = new NSAutoreleasePool ()) {
+				NSApplication.SharedApplication.Delegate = new AppDelegate();
+				NSApplication.Main(args);
+			}
+		}
+	}
+	
+	class AppDelegate : NSApplicationDelegate
+	{
+		
+		public override void FinishedLaunching (MonoMac.Foundation.NSObject notification)
+		{
+			using (Game1 game = new Game1 ()) {
+				game.Run ();
+			}
+		}
+		
+		public override bool ApplicationShouldTerminateAfterLastWindowClosed (NSApplication sender)
+		{
+			return true;
+		}
+	}		
+#endif
+}
+

BIN
Samples/Linux/ChaseAndEvade/GameThumbnail.png


+ 16 - 0
Samples/Linux/ChaseAndEvade/Info.plist

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleIdentifier</key>
+	<string>com.yourcompany.ChaseAndEvade</string>
+	<key>CFBundleName</key>
+	<string>ChaseAndEvade</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>LSMinimumSystemVersion</key>
+	<string>10.6</string>
+	<key>NSPrincipalClass</key>
+	<string>NSApplication</string>
+</dict>
+</plist>

+ 76 - 0
Samples/Linux/ChaseAndEvade/MonoGame.Samples.ChaseAndEvade.Linux.csproj

@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{86A619E2-C8F0-452B-B764-C69D5BB07C98}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>ChaseAndEvade</RootNamespace>
+    <AssemblyName>ChaseAndEvade</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <DebugType>none</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Drawing" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Info.plist" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\..\iOS\ChaseAndEvade\ChaseAndEvadeGame.cs">
+      <Link>ChaseAndEvadeGame.cs</Link>
+    </Compile>
+    <Compile Include="Program.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="..\..\iOS\ChaseAndEvade\Content\Arial.xnb">
+      <Link>Content\Arial.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\iOS\ChaseAndEvade\Content\cat.png">
+      <Link>Content\cat.png</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\iOS\ChaseAndEvade\Content\mouse.png">
+      <Link>Content\mouse.png</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\iOS\ChaseAndEvade\Content\tank.png">
+      <Link>Content\tank.png</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="GameThumbnail.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\MonoGame.Framework\MonoGame.Framework.Linux.csproj">
+      <Project>{35253CE1-C864-4CD3-8249-4D1319748E8F}</Project>
+      <Name>MonoGame.Framework.Linux</Name>
+    </ProjectReference>
+  </ItemGroup>
+</Project>

+ 12 - 0
Samples/Linux/ChaseAndEvade/Program.cs

@@ -0,0 +1,12 @@
+namespace ChaseAndEvade
+{
+	class Program
+	{
+		static void Main (string[] args)
+		{
+			using (ChaseAndEvadeGame game = new ChaseAndEvadeGame ()) {
+				game.Run ();
+			}
+		}
+	}
+}

+ 87 - 0
Samples/Linux/Draw2D/MonoGame.Samples.Draw2D.Linux.csproj

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{8CFEF1FE-9E32-43EB-A730-EB3AACDC77B1}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Draw2D</RootNamespace>
+    <AssemblyName>Draw2D</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE;WINDOWS</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE;WINDOWS</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="..\..\iOS\Draw2D\FPSCounterComponent.cs">
+      <Link>FPSCounterComponent.cs</Link>
+    </Compile>
+    <Compile Include="..\..\iOS\Draw2D\Game1.cs">
+      <Link>Game1.cs</Link>
+    </Compile>
+    <Compile Include="Program.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="..\..\iOS\Draw2D\Content\monogameicon.png">
+      <Link>Content\monogameicon.png</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\iOS\Draw2D\Content\purpleBall.xnb">
+      <Link>Content\purpleBall.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\iOS\Draw2D\Content\spriteFont1.xnb">
+      <Link>Content\spriteFont1.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\iOS\Draw2D\Default.png">
+      <Link>Default.png</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="..\..\iOS\Draw2D\Default.png">
+      <Link>Default.png</Link>
+    </Content>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\MonoGame.Framework\MonoGame.Framework.Linux.csproj">
+      <Project>{35253CE1-C864-4CD3-8249-4D1319748E8F}</Project>
+      <Name>MonoGame.Framework.Linux</Name>
+    </ProjectReference>
+  </ItemGroup>
+</Project>

+ 21 - 0
Samples/Linux/Draw2D/Program.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Microsoft.Xna.Samples.Draw2D
+{
+    static class Program
+    {
+        private static Game1 game;
+
+        /// <summary>
+        /// The main entry point for the application.
+        /// </summary>
+        [STAThread]
+        static void Main()
+        {
+            game = new Game1();
+            game.Run();
+        }
+    }
+}

+ 169 - 0
Samples/Linux/NetRumble/AudioManager.cs

@@ -0,0 +1,169 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// AudioManager.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.IO;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Audio;
+using Microsoft.Xna.Framework.Media;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// Component that manages audio playback for all sound effects.
+    /// </summary>
+    public class AudioManager : GameComponent
+    {
+        #region Singleton
+
+
+        /// <summary>
+        /// The singleton for this type
+        /// </summary>
+        private static AudioManager audioManager = null;
+
+
+        #endregion
+
+
+        #region Audio Data
+
+        /// <summary>
+        /// File list of all wav audio files
+        /// </summary>
+        private FileInfo[] audioFileList;
+
+        /// <summary>
+        /// Content folder containing audio files
+        /// </summary>
+        private DirectoryInfo audioFolder;
+        
+        /// <summary>
+        /// Collection of all loaded sound effects
+        /// </summary>
+        private static Dictionary<string, SoundEffect> soundList;
+
+        /// <summary>
+        /// Looping song used as the in-game soundtrack
+        /// </summary>
+        private static Song soundtrack;
+
+        #endregion
+
+
+        #region Initialization Methods
+
+        /// <summary>
+        /// Constructs the manager for audio playback of all sound effects.
+        /// </summary>
+        /// <param name="game">The game that this component will be attached to.</param>
+        /// <param name="audioFolder">The directory containing audio files.</param>
+        private AudioManager(Game game, DirectoryInfo audioDirectory )
+            : base(game)
+        {
+            try
+            {
+                audioFolder = audioDirectory;
+                audioFileList = audioFolder.GetFiles("*.xnb");
+                soundList = new Dictionary<string, SoundEffect>();
+
+                for (int i = 0; i < audioFileList.Length; i++)
+                {
+                    string soundName = Path.GetFileNameWithoutExtension(audioFileList[i].Name);
+                    soundList[soundName] = game.Content.Load<SoundEffect>("audio\\wav\\"+ soundName);
+                    soundList[soundName].Name = soundName;
+                }
+
+                //soundtrack = game.Content.Load<Song>("One Step Beyond");
+            }
+#if !LINUX			
+			catch (NoAudioHardwareException)
+#else
+			catch (Exception)
+#endif			
+            
+            {
+                // silently fall back to silence
+            }
+        }
+
+        public static void Initialize(Game game, DirectoryInfo audioDirectory)
+        {
+            if (game == null)
+                return;
+
+            audioManager = new AudioManager(game, audioDirectory);
+            game.Components.Add(audioManager);
+        }
+
+        public static void PlaySoundTrack()
+        {
+            if (soundtrack == null)
+                return;
+
+            MediaPlayer.Play(soundtrack);
+        }
+
+        #endregion
+
+
+        #region Sound Play Methods
+
+        /// <summary>
+        /// Plays a fire-and-forget sound effect by name.
+        /// </summary>
+        /// <param name="soundName">The name of the sound to play.</param>
+        public static void PlaySoundEffect(string soundName)
+        {
+            if (audioManager == null || soundList == null)
+                return;
+
+            if (soundList.ContainsKey(soundName))
+            {
+                soundList[soundName].Play();
+            }
+        }
+
+        /// <summary>
+        /// Plays a sound effect by name and returns an instance of that sound.
+        /// </summary>
+        /// <param name="soundName">The name of the sound to play.</param>
+        /// <param name="looped">True if sound effect should loop.</param>
+        /// <param name="instance">The SoundEffectInstance created for this sound effect.</param>
+        public static void PlaySoundEffect(string soundName, bool looped, out SoundEffectInstance instance)
+        {
+            instance = null;
+            if (audioManager == null || soundList == null)
+                return;
+
+            if (soundList.ContainsKey(soundName))
+            {
+                try
+                {
+                    instance = soundList[soundName].CreateInstance();
+                    if (instance != null)
+                    {
+                        instance.IsLooped = looped;
+                        instance.Play();
+                    }
+                }
+                catch (InstancePlayLimitException)
+                {
+                    // silently fail (returns null instance) if instance limit reached
+                }
+            }
+        }
+
+        #endregion
+
+    }
+}

+ 55 - 0
Samples/Linux/NetRumble/Effects/BloomCombineEffect.cs

@@ -0,0 +1,55 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework;
+
+#if !LINUX
+
+using MonoMac.Foundation;
+using MonoMac.AppKit;
+
+#endif
+namespace NetRumble
+{
+	public class BloomCombineEffect : Effect
+	{
+		public BloomCombineEffect (GraphicsDevice graphicsDevice) : base (graphicsDevice)
+		{
+			// We do not need this but here for test
+			LoadShaderFromFile ("BloomPostprocess/Effects/BloomCombine.fsh");
+			
+			DefineTechnique ("BloomCombine", "Pass1", 0, 0);
+			CurrentTechnique = Techniques ["BloomCombine"];
+		}
+
+		protected void LoadShaderFromFile (string sourceFile)
+		{
+			string path;
+#if !LINUX
+			path = Path.Combine (NSBundle.MainBundle.ResourcePath, "Content");
+#else
+			path = "Content";
+#endif
+			// Load the source into a string
+			string shaderSource = LoadShaderSource (sourceFile);
+
+			CreateFragmentShaderFromSource (shaderSource);				
+
+		}
+
+		// Load the source code of a GLSL program from the content
+		private string LoadShaderSource (string name)
+		{
+
+			StreamReader streamReader = new StreamReader (name);
+			string text = streamReader.ReadToEnd ();
+			streamReader.Close ();
+
+			return text;
+
+		}
+	}
+}
+

+ 55 - 0
Samples/Linux/NetRumble/Effects/BloomExtractEffect.cs

@@ -0,0 +1,55 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework;
+
+#if !LINUX
+
+using MonoMac.Foundation;
+using MonoMac.AppKit;
+
+#endif
+namespace NetRumble
+{
+	public class BloomExtractEffect : Effect
+	{
+		public BloomExtractEffect (GraphicsDevice graphicsDevice) : base (graphicsDevice)
+		{
+			// We do not need this but here for test
+			LoadShaderFromFile ("BloomPostprocess/Effects/BloomExtract.fsh");
+			
+			DefineTechnique ("Technique1", "Pass1", 0, 0);
+			CurrentTechnique = Techniques ["Technique1"];
+		}
+
+		protected void LoadShaderFromFile (string sourceFile)
+		{
+			string path;
+#if !LINUX
+			path = Path.Combine (NSBundle.MainBundle.ResourcePath, "Content");
+#else
+			path = "Content";
+#endif
+			// Load the source into a string
+			string shaderSource = LoadShaderSource (sourceFile);
+
+			CreateFragmentShaderFromSource (shaderSource);				
+
+		}
+
+		// Load the source code of a GLSL program from the content
+		private string LoadShaderSource (string name)
+		{
+
+			StreamReader streamReader = new StreamReader (name);
+			string text = streamReader.ReadToEnd ();
+			streamReader.Close ();
+
+			return text;
+
+		}
+	}
+}
+

+ 56 - 0
Samples/Linux/NetRumble/Effects/CloudsEffect.cs

@@ -0,0 +1,56 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework;
+
+#if !LINUX
+
+using MonoMac.Foundation;
+using MonoMac.AppKit;
+
+#endif
+namespace NetRumble
+{
+	public class CloudsEffect : Effect
+	{
+		public CloudsEffect (GraphicsDevice graphicsDevice) : base (graphicsDevice)
+		{
+			// We do not need this but here for test
+			LoadShaderFromFile ("Effects/Clouds.fsh");
+			
+			DefineTechnique ("Technique1", "Pass1", 0, 0);
+			CurrentTechnique = Techniques ["Technique1"];
+		}
+
+		protected void LoadShaderFromFile (string sourceFile)
+		{
+			string path;
+#if !LINUX
+			path = Path.Combine (NSBundle.MainBundle.ResourcePath, "Content");
+#else
+			path = "Content";
+#endif			
+			
+			// Load the source into a string
+			string shaderSource = LoadShaderSource (sourceFile);
+
+			CreateFragmentShaderFromSource (shaderSource);				
+
+		}
+
+		// Load the source code of a GLSL program from the content
+		private string LoadShaderSource (string name)
+		{
+
+			StreamReader streamReader = new StreamReader (name);
+			string text = streamReader.ReadToEnd ();
+			streamReader.Close ();
+
+			return text;
+
+		}
+	}
+}
+

+ 56 - 0
Samples/Linux/NetRumble/Effects/GaussianBlurEffect.cs

@@ -0,0 +1,56 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework;
+
+#if !LINUX
+
+using MonoMac.Foundation;
+using MonoMac.AppKit;
+
+#endif
+
+namespace NetRumble
+{
+	public class GaussianBlurEffect : Effect
+	{
+		public GaussianBlurEffect (GraphicsDevice graphicsDevice) : base (graphicsDevice)
+		{
+			// We do not need this but here for test
+			LoadShaderFromFile ("BloomPostprocess/Effects/GaussianBlur.fsh");
+			
+			DefineTechnique ("Technique1", "Pass1", 0, 0);
+			CurrentTechnique = Techniques ["Technique1"];
+		}
+
+		protected void LoadShaderFromFile (string sourceFile)
+		{
+			string path;
+#if !LINUX
+			path = Path.Combine (NSBundle.MainBundle.ResourcePath, "Content");
+#else
+			path = "Content";
+#endif
+			// Load the source into a string
+			string shaderSource = LoadShaderSource (sourceFile);
+
+			CreateFragmentShaderFromSource (shaderSource);				
+
+		}
+
+		// Load the source code of a GLSL program from the content
+		private string LoadShaderSource (string name)
+		{
+
+			StreamReader streamReader = new StreamReader (name);
+			string text = streamReader.ReadToEnd ();
+			streamReader.Close ();
+
+			return text;
+
+		}
+	}
+}
+

+ 261 - 0
Samples/Linux/NetRumble/Gameplay/Asteroid.cs

@@ -0,0 +1,261 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// Asteroid.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Content;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// Asteroids that fill the game world, blocking the player's shots and movements.
+    /// </summary>
+    public class Asteroid : GameplayObject
+    {
+        #region Constants
+
+
+        /// <summary>
+        /// The ratio of the mass of an asteroid to its radius.
+        /// </summary>
+        const float massRadiusRatio = 0.5f;
+
+        /// <summary>
+        /// The amount of drag applied to velocity per second, 
+        /// as a percentage of velocity.
+        /// </summary>
+        const float dragPerSecond = 0.15f;
+
+        /// <summary>
+        /// Scalar to convert the velocity / mass ratio into a "nice" rotational value.
+        /// </summary>
+        const float velocityMassRatioToRotationScalar = 0.0017f;
+
+        /// <summary>
+        /// Scalar for calculated damage values that asteroids apply to players.
+        /// </summary>
+        const float momentumToDamageScalar = 0.007f;
+
+        /// <summary>
+        /// The number of variations in textures for asteroids.
+        /// </summary>
+        const int variations = 3;
+
+        /// <summary>
+        /// The minimum possible initial speed for asteroids.
+        /// </summary>
+        const float initialSpeedMinimum = 32f;
+
+        /// <summary>
+        /// The minimum possible initial speed for asteroids.
+        /// </summary>
+        const float initialSpeedMaximum = 96f;
+
+
+        #endregion
+
+
+        #region Static Graphics Data
+
+
+        /// <summary>
+        /// The asteroid textures.
+        /// </summary>
+        private static Texture2D[] textures = new Texture2D[variations];
+
+
+        #endregion
+
+
+        #region Graphics Data
+
+
+        /// <summary>
+        /// The variation of this particular asteroid.
+        /// </summary>
+        private int variation = 0;
+        public int Variation
+        {
+            get { return variation; }
+            set
+            {
+                if ((value < 0) || (value >= variations))
+                {
+                    throw new ArgumentOutOfRangeException("value");
+                }
+                variation = value;
+            }
+        }
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Construct a new asteroid.
+        /// </summary>
+        /// <param name="world">The world that this asteroid belongs to.</param>
+        /// <param name="radius">The size of the asteroid.</param>
+        public Asteroid(float radius)
+            : base()
+        {
+            // safety-check the parameters
+            if (radius <= 0f)
+            {
+                throw new ArgumentOutOfRangeException("radius");
+            }
+
+            // set the collision data
+            this.radius = radius;
+            this.mass = this.radius * massRadiusRatio;
+
+            this.Velocity = RandomMath.RandomDirection() * 
+                RandomMath.RandomBetween(initialSpeedMinimum, initialSpeedMaximum);
+        }
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+
+        /// <summary>
+        /// Update the asteroid.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        public override void Update(float elapsedTime)
+        {
+            // spin the asteroid based on the radius and velocity
+            float velocityMassRatio = (Velocity.LengthSquared() / Mass);
+            rotation += velocityMassRatio * velocityMassRatioToRotationScalar * 
+                elapsedTime;
+
+            // apply some drag so the asteroids settle down
+            Velocity -= Velocity * (elapsedTime * dragPerSecond);
+
+            base.Update(elapsedTime);
+        }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draw the asteroid.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
+        public void Draw(float elapsedTime, SpriteBatch spriteBatch)
+        {
+            base.Draw(elapsedTime, spriteBatch, textures[variation], null,
+                Color.White);
+        }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Defines the interaction between the asteroid and a target GameplayObject
+        /// when they touch.
+        /// </summary>
+        /// <param name="target">The GameplayObject that is touching this one.</param>
+        /// <returns>True if the objects meaningfully interacted.</returns>
+        public override bool Touch(GameplayObject target)
+        {
+            // if the asteroid has touched a player, then damage it
+            Ship player = target as Ship;
+            if (player != null)
+            {
+                // calculate damage as a function of how much the two GameplayObject's
+                // velocities were going towards one another
+                Vector2 playerAsteroidVector = Position - player.Position;
+                if (playerAsteroidVector.LengthSquared() > 0)
+                {
+                    playerAsteroidVector.Normalize();
+
+                    float rammingSpeed =
+                        Vector2.Dot(playerAsteroidVector, player.Velocity) -
+                        Vector2.Dot(playerAsteroidVector, Velocity);
+                    float momentum = Mass * rammingSpeed;
+                    player.Damage(this, momentum * momentumToDamageScalar);
+                }
+            }
+            // if the asteroid didn't hit a projectile, play the asteroid-touch sound effect
+            if ((target is Projectile) == false)
+            {
+                AudioManager.PlaySoundEffect("asteroid_touch");
+            }
+            return true;
+        }
+
+
+        #endregion
+
+
+        #region Static Graphics Methods
+
+
+        /// <summary>
+        /// The number of variations in asteroids.
+        /// </summary>
+        public static int Variations
+        {
+            get { return variations; }
+        }
+        
+        
+        /// <summary>
+        /// Load all of the static graphics content for this class.
+        /// </summary>
+        /// <param name="contentManager">The content manager to load with.</param>
+        public static void LoadContent(ContentManager contentManager)
+        {
+            // safety-check the parameters
+            if (contentManager == null)
+            {
+                throw new ArgumentNullException("contentManager");
+            }
+
+            // load each asteroid's texture
+            for (int i = 0; i < variations; i++)
+            {
+                textures[i] = contentManager.Load<Texture2D>(
+                    "Textures/asteroid" + i.ToString());
+            }
+        }
+
+        /// <summary>
+        /// Unload all of the static graphics content for this class.
+        /// </summary>
+        public static void UnloadContent()
+        {
+            for (int i = 0; i < variations; i++)
+            {
+                textures[i] = null;
+            }
+        }
+
+
+        #endregion
+    }
+}

+ 568 - 0
Samples/Linux/NetRumble/Gameplay/CollisionManager.cs

@@ -0,0 +1,568 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// CollisionManager.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// Manages collisions and collision events between all gameplay objects.
+    /// </summary>
+    public class CollisionManager : BatchRemovalCollection<GameplayObject>
+    {
+        #region Constants
+
+
+        /// <summary>
+        /// The ratio of speed to damage applied, for explosions.
+        /// </summary>
+        private const float speedDamageRatio = 0.5f;
+
+        /// <summary>
+        /// The number of times that the FindSpawnPoint method will try to find a point.
+        /// </summary>
+        private const int findSpawnPointAttempts = 25;
+
+
+        #endregion
+
+
+        #region Helper Types
+
+
+        /// <summary>
+        /// The result of a collision query.
+        /// </summary>
+        struct CollisionResult
+        {
+            /// <summary>
+            /// How far away did the collision occur down the ray
+            /// </summary>
+            public float Distance;
+
+            /// <summary>
+            /// The collision "direction"
+            /// </summary>
+            public Vector2 Normal;
+
+            /// <summary>
+            /// What caused the collison (what the source ran into)
+            /// </summary>
+            public GameplayObject GameplayObject;
+
+
+            public static int Compare(CollisionResult a, CollisionResult b)
+            {
+                return a.Distance.CompareTo(b.Distance);
+            }
+        }
+
+
+        #endregion
+
+
+        #region Singleton
+
+
+        /// <summary>
+        /// Singleton for collision management.
+        /// </summary>
+        private static CollisionManager collisionManager = new CollisionManager();
+        public static BatchRemovalCollection<GameplayObject> Collection
+        {
+            get { return collisionManager as BatchRemovalCollection<GameplayObject>; }
+        }
+
+
+        #endregion
+
+
+        #region Collision Data
+
+
+        /// <summary>
+        /// The dimensions of the space in which collision occurs.
+        /// </summary>
+        private Rectangle dimensions = new Rectangle(0, 0, 2048, 2048);
+        public static Rectangle Dimensions
+        {
+            get { return (collisionManager == null ? Rectangle.Empty : 
+                collisionManager.dimensions); }
+            set
+            {
+                // safety-check the singleton
+                if (collisionManager == null)
+                {
+                    throw new InvalidOperationException(
+                        "The collision manager has not yet been initialized.");
+                }
+                collisionManager.dimensions = value;
+            }
+        }
+
+        /// <summary>
+        /// The list of barriers in the game world.
+        /// </summary>
+        /// <remarks>This list is not owned by this object.</remarks>
+        private List<Rectangle> barriers = new List<Rectangle>();
+        public static List<Rectangle> Barriers
+        {
+            get { return (collisionManager == null ? null : 
+                collisionManager.barriers); }
+        }
+
+
+        /// <summary>
+        /// Cached list of collision results, for more optimal collision detection.
+        /// </summary>
+        List<CollisionResult> collisionResults = new List<CollisionResult>();
+
+        
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Constructs a new collision manager.
+        /// </summary>
+        private CollisionManager() { }
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+
+        /// <summary>
+        /// Update the collision system.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        public static void Update(float elapsedTime)
+        {
+            // safety-check the singleton
+            if (collisionManager == null)
+            {
+                throw new InvalidOperationException(
+                    "The collision manager has not yet been initialized.");
+            }
+
+
+            // move each object
+            for (int i = 0; i < collisionManager.Count; ++i)
+            {
+                if (collisionManager[i].Active)
+                {
+                    // determine how far they are going to move
+                    Vector2 movement = collisionManager[i].Velocity * elapsedTime;
+                    // only allow collisionManager that have not collided yet 
+                    // collisionManager frame to collide
+                    // -- otherwise, objects can "double-hit" and trade their momentum
+                    if (collisionManager[i].CollidedThisFrame == false)
+                    {
+                        movement = MoveAndCollide(collisionManager[i], movement);
+                    }
+                    // determine the new position
+                    collisionManager[i].Position += movement;
+
+                    // collide with the barriers
+                    for (int b = 0; b < collisionManager.barriers.Count; ++b)
+                    {
+                        CollisionMath.CircleLineCollisionResult result = 
+                            new CollisionMath.CircleLineCollisionResult();
+                        if (collisionManager[i] is Projectile)
+                        {
+                            CollisionMath.CircleRectangleCollide(
+                                collisionManager[i].Position - movement, 
+                                collisionManager[i].Radius, 
+                                collisionManager.barriers[b], ref result);
+                            if (result.Collision)
+                            {
+                                collisionManager[i].Position -= movement;
+                                collisionManager[i].Die(null, false);
+                            }
+                        }
+                        else
+                        {
+                            CollisionMath.CircleRectangleCollide(
+                                collisionManager[i].Position, 
+                                collisionManager[i].Radius, 
+                                collisionManager.barriers[b], ref result);
+                            if (result.Collision)
+                            {
+                                // if a non-projectile hits a barrier, bounce slightly
+                                float vn = Vector2.Dot(collisionManager[i].Velocity, 
+                                    result.Normal);
+                                collisionManager[i].Velocity -= (2.0f * vn) * 
+                                    result.Normal;
+                                collisionManager[i].Position += result.Normal * 
+                                    result.Distance;
+                            }
+                        }
+                    }
+                }
+            }
+
+            CollisionManager.Collection.ApplyPendingRemovals();
+        }
+
+
+        /// <summary>
+        /// Move the given gameplayObject by the given movement, colliding and adjusting
+        /// as necessary.
+        /// </summary>
+        /// <param name="gameplayObject">The gameplayObject who is moving.</param>
+        /// <param name="movement">The desired movement vector for this update.</param>
+        /// <returns>The movement vector after considering all collisions.</returns>
+        private static Vector2 MoveAndCollide(GameplayObject gameplayObject, 
+            Vector2 movement)
+        {
+            // safety-check the singleton
+            if (collisionManager == null)
+            {
+                throw new InvalidOperationException(
+                    "The collision manager has not yet been initialized.");
+            }
+
+            if (gameplayObject == null)
+            {
+                throw new ArgumentNullException("gameplayObject");
+            }
+            // make sure we care about where this gameplayObject goes
+            if (!gameplayObject.Active)
+            {
+                return movement;
+            }
+            // make sure the movement is significant
+            if (movement.LengthSquared() <= 0f)
+            {
+                return movement;
+            }
+
+            // generate the list of collisions
+            Collide(gameplayObject, movement);
+
+            // determine if we had any collisions
+            if (collisionManager.collisionResults.Count > 0)
+            {
+                collisionManager.collisionResults.Sort(CollisionResult.Compare);
+                foreach (CollisionResult collision in collisionManager.collisionResults)
+                {
+                    // let the two objects touch each other, and see what happens
+                    if (gameplayObject.Touch(collision.GameplayObject) && 
+                        collision.GameplayObject.Touch(gameplayObject))
+                    {
+                        gameplayObject.CollidedThisFrame =
+                            collision.GameplayObject.CollidedThisFrame = true;
+                        // they should react to the other, even if they just died
+                        AdjustVelocities(gameplayObject, collision.GameplayObject);
+                        return Vector2.Zero;
+                    }
+                }
+            }
+
+            return movement;
+        }
+
+
+        /// <summary>
+        /// Determine all collisions that will happen as the given gameplayObject moves.
+        /// </summary>
+        /// <param name="gameplayObject">The gameplayObject that is moving.</param>
+        /// <param name="movement">The gameplayObject's movement vector.</param>
+        /// <remarks>The results are stored in the cached list.</remarks>
+        public static void Collide(GameplayObject gameplayObject, Vector2 movement)
+        {
+            // safety-check the singleton
+            if (collisionManager == null)
+            {
+                throw new InvalidOperationException(
+                    "The collision manager has not yet been initialized.");
+            }
+
+            collisionManager.collisionResults.Clear();
+
+            if (gameplayObject == null)
+            {
+                throw new ArgumentNullException("gameplayObject");
+            }
+            if (!gameplayObject.Active)
+            {
+                return;
+            }
+
+            // determine the movement direction and scalar
+            float movementLength = movement.Length();
+            if (movementLength <= 0f)
+            {
+                return;
+            }
+
+            // check each gameplayObject
+            foreach (GameplayObject checkActor in collisionManager)
+            {
+                if ((gameplayObject == checkActor) || !checkActor.Active)
+                {
+                    continue;
+                }
+
+                // calculate the target vector
+                float combinedRadius = checkActor.Radius + gameplayObject.Radius;
+                Vector2 checkVector = checkActor.Position - gameplayObject.Position;
+                float checkVectorLength = checkVector.Length();
+                if (checkVectorLength <= 0f)
+                {
+                    continue;
+                }
+
+                float distanceBetween = MathHelper.Max(checkVectorLength - 
+                    (checkActor.Radius + gameplayObject.Radius), 0);
+
+                // check if they could possibly touch no matter the direction
+                if (movementLength < distanceBetween)
+                {
+                    continue;
+                }
+
+                // determine how much of the movement is bringing the two together
+                float movementTowards = Vector2.Dot(movement, checkVector);
+
+                // check to see if the movement is away from each other
+                if (movementTowards < 0f)
+                {
+                    continue;
+                }
+
+                if (movementTowards < distanceBetween)
+                {
+                    continue;
+                }
+
+                CollisionResult result = new CollisionResult();
+                result.Distance = distanceBetween;
+                result.Normal = Vector2.Normalize(checkVector);
+                result.GameplayObject = checkActor;
+
+                collisionManager.collisionResults.Add(result);
+            }
+        }
+
+
+        /// <summary>
+        /// Adjust the velocities of the two collisionManager as if they have collided,
+        /// distributing their velocities according to their masses.
+        /// </summary>
+        /// <param name="actor1">The first gameplayObject.</param>
+        /// <param name="actor2">The second gameplayObject.</param>
+        private static void AdjustVelocities(GameplayObject actor1, 
+            GameplayObject actor2)
+        {
+            // don't adjust velocities if at least one has negative mass
+            if ((actor1.Mass <= 0f) || (actor2.Mass <= 0f))
+            {
+                return;
+            }
+
+            // determine the vectors normal and tangent to the collision
+            Vector2 collisionNormal = actor2.Position - actor1.Position;
+            if (collisionNormal.LengthSquared() > 0f)
+            {
+                collisionNormal.Normalize();
+            }
+            else
+            {
+                return;
+            }
+
+            Vector2 collisionTangent = new Vector2(
+                -collisionNormal.Y, collisionNormal.X);
+
+            // determine the velocity components along the normal and tangent vectors
+            float velocityNormal1 = Vector2.Dot(actor1.Velocity, collisionNormal);
+            float velocityTangent1 = Vector2.Dot(actor1.Velocity, collisionTangent);
+            float velocityNormal2 = Vector2.Dot(actor2.Velocity, collisionNormal);
+            float velocityTangent2 = Vector2.Dot(actor2.Velocity, collisionTangent);
+
+            // determine the new velocities along the normal
+            float velocityNormal1New = ((velocityNormal1 * (actor1.Mass - actor2.Mass))
+                + (2f * actor2.Mass * velocityNormal2)) / (actor1.Mass + actor2.Mass);
+            float velocityNormal2New = ((velocityNormal2 * (actor2.Mass - actor1.Mass))
+                + (2f * actor1.Mass * velocityNormal1)) / (actor1.Mass + actor2.Mass);
+
+            // determine the new total velocities
+            actor1.Velocity = (velocityNormal1New * collisionNormal) +
+                (velocityTangent1 * collisionTangent);
+            actor2.Velocity = (velocityNormal2New * collisionNormal) +
+                (velocityTangent2 * collisionTangent);
+        }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Find a valid spawn point in the world.
+        /// </summary>
+        /// <param name="radius">The radius of the object to be spawned.</param>
+        /// <param name="random">A persistent Random object.</param>
+        /// <returns>The spawn point.</returns>
+        public static Vector2 FindSpawnPoint(GameplayObject spawnedObject, float radius)
+        {
+            // safety-check the singleton
+            if (collisionManager == null)
+            {
+                throw new InvalidOperationException(
+                    "The collision manager has not yet been initialized.");
+            }
+
+            // safety-check the parameters
+            if ((radius < 0f) || (radius > Dimensions.Width / 2))
+            {
+                throw new ArgumentOutOfRangeException("radius");
+            }
+
+            // keep trying to find a valid point
+            Vector2 spawnPoint = new Vector2(
+                radius + Dimensions.X + 
+                   RandomMath.Random.Next((int)Math.Floor(Dimensions.Width - radius)),
+                radius + Dimensions.Y + 
+                   RandomMath.Random.Next((int)Math.Floor(Dimensions.Height - radius)));
+            for (int i = 0; i < findSpawnPointAttempts; i++)
+            {
+                bool valid = true;
+
+                // check the barriers
+                if (Barriers != null)
+                {
+                    CollisionMath.CircleLineCollisionResult result = 
+                        new CollisionMath.CircleLineCollisionResult();
+                    foreach (Rectangle rectangle in Barriers)
+                    {
+                        if (CollisionMath.CircleRectangleCollide(spawnPoint, radius, 
+                            rectangle, ref result))
+                        {
+                            valid = false;
+                            break;
+                        }
+                    }
+                }
+
+                // check the other objects
+                if (valid)
+                {
+                    foreach (GameplayObject gameplayObject in collisionManager)
+                    {
+                        if (!gameplayObject.Active || (gameplayObject == spawnedObject))
+                        {
+                            continue;
+                        }
+                        if (CollisionMath.CircleCircleIntersect(spawnPoint, radius, 
+                            gameplayObject.Position, gameplayObject.Radius))
+                        {
+                            valid = false;
+                            break;
+                        }
+                    }
+                }
+                if (valid)
+                {
+                    break;
+                }
+                spawnPoint = new Vector2(
+                    radius + Dimensions.X + RandomMath.Random.Next(
+                       (int)Math.Floor(Dimensions.Width - radius)),
+                    radius + Dimensions.Y + RandomMath.Random.Next(
+                       (int)Math.Floor(Dimensions.Height - radius)));
+            }
+
+            return spawnPoint;
+        }
+
+
+        /// <summary>
+        /// Process an explosion in the world against the objects in it.
+        /// </summary>
+        /// <param name="source">The source of the explosion.</param>
+        /// <param name="target">The target of the attack.</param>
+        /// <param name="damageAmount">The amount of explosive damage.</param>
+        /// <param name="position">The position of the explosion.</param>
+        /// <param name="damageRadius">The radius of the explosion.</param>
+        /// <param name="damageOwner">If true, it will hit the source.</param>
+        public static void Explode(GameplayObject source, GameplayObject target, 
+            float damageAmount, Vector2 position, float damageRadius, bool damageOwner)
+        {
+            // safety-check the singleton
+            if (collisionManager == null)
+                {
+                    throw new InvalidOperationException(
+                        "The collision manager has not yet been initialized.");
+            }
+
+            if (damageRadius <= 0f)
+            {
+                return;
+            }
+            float damageRadiusSquared = damageRadius * damageRadius;
+
+            foreach (GameplayObject gameplayObject in collisionManager)
+            {
+                // don't bother if it's already dead
+                if (!gameplayObject.Active)
+                {
+                    continue;
+                }
+                // don't hurt the GameplayObject that the projectile hit, it's hurt
+                if (gameplayObject == target)
+                {
+                    continue;
+                }
+                // don't hit the owner if the damageOwner flag is off
+                if ((gameplayObject == source) && !damageOwner)
+                {
+                    continue;
+                }
+                // measure the distance to the GameplayObject and see if it's in range
+                Vector2 direction = gameplayObject.Position - position;
+                float distanceSquared = direction.LengthSquared();
+                if ((distanceSquared > 0f) && (distanceSquared <= damageRadiusSquared))
+                {
+                    float distance = (float)Math.Sqrt((float)distanceSquared);
+                    // adjust the amount of damage based on the distance
+                    // -- note that damageRadius <= 0 is accounted for earlier
+                    float adjustedDamage = damageAmount *
+                        (damageRadius - distance) / damageRadius;
+                    // if we're still damaging the GameplayObject, then apply it
+                    if (adjustedDamage > 0f)
+                    {
+                        gameplayObject.Damage(source, adjustedDamage);
+                    }
+                    // move those affected by the blast
+                    if (gameplayObject != source)
+                    {
+                        direction.Normalize();
+                        gameplayObject.Velocity += direction * adjustedDamage * 
+                            speedDamageRatio;
+                    }
+                }
+            }
+        }
+
+
+        #endregion
+    }
+}

+ 224 - 0
Samples/Linux/NetRumble/Gameplay/GameplayObject.cs

@@ -0,0 +1,224 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// GameplayObject.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A base public class for all gameplay objects.
+    /// </summary>
+    abstract public class GameplayObject
+    {
+        #region Status Data
+
+        
+        /// <summary>
+        /// If true, the object is active in the world.
+        /// </summary>
+        protected bool active = false;
+        public bool Active
+        {
+            get { return active; }
+        }
+
+
+        #endregion
+
+
+        #region Graphics Data
+
+
+        protected Vector2 position = Vector2.Zero;
+        public Vector2 Position
+        {
+            get { return position; }
+            set
+            {
+                position = value;
+            }
+        }
+
+        protected Vector2 velocity = Vector2.Zero;
+        public Vector2 Velocity
+        {
+            get { return velocity; }
+            set 
+            {
+                if ((value.X == Single.NaN) || (value.Y == Single.NaN))
+                {
+                    throw new ArgumentException("Velocity was NaN");
+                }
+                velocity = value;
+            }
+        }
+
+        protected float rotation = 0f;
+        public float Rotation
+        {
+            get { return rotation; }
+            set { rotation = value; }
+        }
+
+
+        #endregion
+
+
+        #region Collision Data
+
+        
+        protected float radius = 1f;
+        public float Radius
+        {
+            get { return radius; }
+            set { radius = value; }
+        }
+
+        protected float mass = 1f;
+        public float Mass
+        {
+            get { return mass; }
+        }
+
+        protected bool collidedThisFrame = false;
+        public bool CollidedThisFrame
+        {
+            get { return collidedThisFrame; }
+            set { collidedThisFrame = value; }
+        }
+
+    
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Constructs a new gameplay object.
+        /// </summary>
+        protected GameplayObject() { }
+
+
+        /// <summary>
+        /// Initialize the object to it's default gameplay states.
+        /// </summary>
+        public virtual void Initialize() 
+        {
+            if (!active)
+            {
+                active = true;
+                CollisionManager.Collection.Add(this);
+            }
+        }
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+
+        /// <summary>
+        /// Update the gameplay object.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        public virtual void Update(float elapsedTime) 
+        {
+            collidedThisFrame = false;
+        }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draw the gameplay object.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
+        /// <param name="sprite">The texture used to draw this object.</param>
+        /// <param name="sourceRectangle">The source rectangle.</param>
+        /// <param name="color">The color of the sprite.</param>
+        public virtual void Draw(float elapsedTime, SpriteBatch spriteBatch, 
+            Texture2D sprite, Rectangle? sourceRectangle, Color color)
+        {
+            if ((spriteBatch != null) && (sprite != null))
+            {
+                spriteBatch.Draw(sprite, position, sourceRectangle, color, rotation, 
+                    new Vector2(sprite.Width / 2f, sprite.Height / 2f), 
+                    2f * radius / MathHelper.Min(sprite.Width, sprite.Height), 
+                    SpriteEffects.None, 0f);
+            }
+        }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Defines the interaction between this GameplayObject and 
+        /// a target GameplayObject when they touch.
+        /// </summary>
+        /// <param name="target">The GameplayObject that is touching this one.</param>
+        /// <returns>True if the objects meaningfully interacted.</returns>
+        public virtual bool Touch(GameplayObject target)
+        {
+            return true;
+        }
+
+
+        /// <summary>
+        /// Damage this object by the amount provided.
+        /// </summary>
+        /// <remarks>
+        /// This function is provided in lieu of a Life mutation property to allow 
+        /// classes of objects to restrict which kinds of objects may damage them,
+        /// and under what circumstances they may be damaged.
+        /// </remarks>
+        /// <param name="source">The GameplayObject responsible for the damage.</param>
+        /// <param name="damageAmount">The amount of damage.</param>
+        /// <returns>If true, this object was damaged.</returns>
+        public virtual bool Damage(GameplayObject source, float damageAmount)
+        {
+            return false;
+        }
+
+
+        /// <summary>
+        /// Kills this object, in response to the given GameplayObject.
+        /// </summary>
+        /// <param name="source">The GameplayObject responsible for the kill.</param>
+        /// <param name="cleanupOnly">
+        /// If true, the object dies without any further effects.
+        /// </param>
+        public virtual void Die(GameplayObject source, bool cleanupOnly) 
+        {
+            // deactivate the object
+            if (active)
+            {
+                active = false;
+                CollisionManager.Collection.QueuePendingRemoval(this);
+            }
+        }
+
+
+        #endregion
+    }
+}

+ 149 - 0
Samples/Linux/NetRumble/Gameplay/PlayerData.cs

@@ -0,0 +1,149 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// PlayerData.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Net;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// Data for each player in a network session.
+    /// </summary>
+    public class PlayerData
+    {
+        #region Gameplay Data
+
+
+        /// <summary>
+        /// The color of the overlay portion of the ship.
+        /// </summary>
+        private byte shipColor = 0;
+        public byte ShipColor
+        {
+            get { return shipColor; }
+            set
+            {
+                if ((value < 0) || (value >= Ship.ShipColors.Length))
+                {
+                    throw new ArgumentOutOfRangeException("value");
+                }
+                shipColor = value;
+                // apply the change to the ship immediately 
+                if (ship != null)
+                {
+                    ship.Color = Ship.ShipColors[shipColor];
+                }
+            }
+        }
+
+        /// <summary>
+        /// The ship model to use.
+        /// </summary>
+        private byte shipVariation = 0;
+        public byte ShipVariation
+        {
+            get { return shipVariation; }
+            set 
+            {
+                if ((value < 0) || (value >= Ship.Variations))
+                {
+                    throw new ArgumentOutOfRangeException("value");
+                }
+                shipVariation = value;
+                // apply the change to the ship immediately 
+                if (ship != null)
+                {
+                    ship.Variation = shipVariation;
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// The ship used by this player.
+        /// </summary>
+        private Ship ship = null;
+        public Ship Ship
+        {
+            get { return ship; }
+            set 
+            { 
+                ship = value;
+                // apply the other values to the ship immediately 
+                if (ship != null)
+                {
+                    ship.Variation = shipVariation;
+                    ship.Color = Ship.ShipColors[shipColor];
+                }
+            }
+        }
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Constructs a PlayerData object.
+        /// </summary>
+        public PlayerData() 
+        {
+            Ship = new Ship();
+        }
+
+
+        #endregion
+
+
+        #region Networking Methods
+
+
+        /// <summary>
+        /// Deserialize from the packet into the current object.
+        /// </summary>
+        /// <param name="packetReader">The packet reader that has the data.</param>
+        public void Deserialize(PacketReader packetReader)
+        {
+            // safety-check the parameter, as it must be valid.
+            if (packetReader == null)
+            {
+                throw new ArgumentNullException("packetReader");
+            }
+
+            ShipColor = packetReader.ReadByte();
+            ShipVariation = packetReader.ReadByte();
+        }
+
+
+        /// <summary>
+        /// Serialize the current object to a packet.
+        /// </summary>
+        /// <param name="packetWriter">The packet writer that receives the data.</param>
+        public void Serialize(PacketWriter packetWriter)
+        {
+            // safety-check the parameter, as it must be valid.
+            if (packetWriter == null)
+            {
+                throw new ArgumentNullException("packetWriter");
+            }
+
+            packetWriter.Write(ShipColor);
+            packetWriter.Write(ShipVariation);
+        }
+
+
+        #endregion
+    }
+}

+ 123 - 0
Samples/Linux/NetRumble/Gameplay/PowerUps/DoubleLaserPowerUp.cs

@@ -0,0 +1,123 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// DoubleLaserPowerUp.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Content;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A power-up that gives a player a double-laser-shooting weapon.
+    /// </summary>
+    public class DoubleLaserPowerUp : PowerUp
+    {
+        #region Static Graphics Data
+
+
+        /// <summary>
+        /// Texture for the double-laser power-up.
+        /// </summary>
+        private static Texture2D texture;
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Constructs a new DoubleLaserPowerUp.
+        /// </summary>
+        public DoubleLaserPowerUp() 
+            : base() { }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draw the double-laser power-up.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
+        public override void Draw(float elapsedTime, SpriteBatch spriteBatch)
+        {
+            // ignore the parameter color if we have an owner
+            base.Draw(elapsedTime, spriteBatch, texture, null, Color.White);
+        }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Defines the interaction between this power-up and a target GameplayObject
+        /// when they touch.
+        /// </summary>
+        /// <param name="target">The GameplayObject that is touching this one.</param>
+        /// <returns>True if the objects meaningfully interacted.</returns>
+        public override bool Touch(GameplayObject target)
+        {
+            // if we hit a ship, give it the weapon
+            Ship ship = target as Ship;
+            if (ship != null)
+            {
+                ship.Weapon = new DoubleLaserWeapon(ship);
+            }
+
+            return base.Touch(target);
+        }
+
+
+        #endregion
+
+
+        #region Static Graphics Methods
+
+
+        /// <summary>
+        /// Load all of the static graphics content for this class.
+        /// </summary>
+        /// <param name="contentManager">The content manager to load with.</param>
+        public static void LoadContent(ContentManager contentManager)
+        {
+            // safety-check the parameters
+            if (contentManager == null)
+            {
+                throw new ArgumentNullException("contentManager");
+            }
+
+            // load the texture
+            texture = contentManager.Load<Texture2D>("Textures/powerupDoubleLaser");
+        }
+
+
+        /// <summary>
+        /// Unload all of the static graphics content for this class.
+        /// </summary>
+        public static void UnloadContent()
+        {
+            texture = null;
+        }
+
+
+        #endregion
+    }
+}

+ 160 - 0
Samples/Linux/NetRumble/Gameplay/PowerUps/PowerUp.cs

@@ -0,0 +1,160 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// PowerUp.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// Base public class for all power-ups that exist in the game.
+    /// </summary>
+    abstract public class PowerUp : GameplayObject
+    {
+        #region Constant Data
+
+
+        /// <summary>
+        /// The speed of the rotation of the power-up, in radians/sec.
+        /// </summary>
+        const float rotationSpeed = 2f;
+
+        /// <summary>
+        /// The amplitude of the pulse
+        /// </summary>
+        const float pulseAmplitude = 0.1f;
+
+        /// <summary>
+        /// The rate of the pulse.
+        /// </summary>
+        const float pulseRate = 0.1f;
+
+
+        public const float PowerUpRadius = 20f;
+
+        #endregion
+
+
+        #region Graphics Data
+
+
+        /// <summary>
+        /// The time accumulator for the power-up pulse.
+        /// </summary>
+        private float pulseTime = 0f;
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Constructs a new power-up.
+        /// </summary>
+        protected PowerUp() 
+            : base() 
+        {
+            // set the collision data
+            this.radius = PowerUpRadius;
+            this.mass = Int32.MaxValue;
+        }
+
+
+        /// <summary>
+        /// Initialize the power-up to it's default gameplay states.
+        /// </summary>
+        public override void Initialize()
+        {
+            if (!active)
+            {
+                // play the spawn sound effect
+                AudioManager.PlaySoundEffect("powerup_spawn");
+            }
+
+            base.Initialize();
+        }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draw the triple-laser power-up.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
+        public abstract void Draw(float elapsedTime, SpriteBatch spriteBatch);
+        
+        
+        /// <summary>
+        /// Draw the power-up.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
+        /// <param name="sprite">The texture used to draw this object.</param>
+        /// <param name="sourceRectangle">The source rectangle in the texture.</param>
+        /// <param name="color">The color of the sprite, ignored here.</param>
+        public override void Draw(float elapsedTime, SpriteBatch spriteBatch, 
+            Texture2D sprite, Rectangle? sourceRectangle, Color color)
+        {
+            // update the rotation
+            rotation += rotationSpeed * elapsedTime;
+
+            // adjust the radius to affect the scale
+            float oldRadius = radius;
+            pulseTime += elapsedTime;
+            radius *= 1f + pulseAmplitude * (float)Math.Sin(pulseTime / pulseRate);
+            base.Draw(elapsedTime, spriteBatch, sprite, sourceRectangle, color);
+            radius = oldRadius;
+        }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Defines the interaction between this power-up and a target GameplayObject
+        /// when they touch.
+        /// </summary>
+        /// <param name="target">The GameplayObject that is touching this one.</param>
+        /// <returns>True if the objects meaningfully interacted.</returns>
+        public override bool Touch(GameplayObject target)
+        {
+            // if it touched a ship, then create a particle system and play a sound
+            Ship ship = target as Ship;
+            if (ship != null)
+            {
+                // play the "power-up picked up" sound effect
+                AudioManager.PlaySoundEffect("powerup_touch");
+
+                // kill the power-up
+                Die(target, false);
+
+                // the ship keeps going as if it didn't hit anything
+                return false;
+            }
+
+            return base.Touch(target);
+        }
+
+
+        #endregion
+    }
+}

+ 123 - 0
Samples/Linux/NetRumble/Gameplay/PowerUps/RocketPowerUp.cs

@@ -0,0 +1,123 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// RocketPowerUp.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Content;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A power-up that gives a player a rocket-launching weapon.
+    /// </summary>
+    public class RocketPowerUp : PowerUp
+    {
+        #region Static Graphics Data
+
+
+        /// <summary>
+        /// Texture for the rocket power-up.
+        /// </summary>
+        private static Texture2D texture;
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Constructs a new rocket-launcher power-up.
+        /// </summary>
+        public RocketPowerUp()
+            : base() { }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draw the rocket power-up.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
+        public override void Draw(float elapsedTime, SpriteBatch spriteBatch)
+        {
+            // ignore the parameter color if we have an owner
+            base.Draw(elapsedTime, spriteBatch, texture, null, Color.White);
+        }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Defines the interaction between this power-up and a target GameplayObject
+        /// when they touch.
+        /// </summary>
+        /// <param name="target">The GameplayObject that is touching this one.</param>
+        /// <returns>True if the objects meaningfully interacted.</returns>
+        public override bool Touch(GameplayObject target)
+        {
+            // if we hit a ship, give it the weapon
+            Ship ship = target as Ship;
+            if (ship != null)
+            {
+                ship.Weapon = new RocketWeapon(ship);
+            }
+
+            return base.Touch(target);
+        }
+
+
+        #endregion
+
+
+        #region Static Graphics Methods
+
+
+        /// <summary>
+        /// Load all of the static graphics content for this class.
+        /// </summary>
+        /// <param name="contentManager">The content manager to load with.</param>
+        public static void LoadContent(ContentManager contentManager)
+        {
+            // safety-check the parameters
+            if (contentManager == null)
+            {
+                throw new ArgumentNullException("contentManager");
+            }
+
+            // load the texture
+            texture = contentManager.Load<Texture2D>("Textures/powerupRocket");
+        }
+
+
+        /// <summary>
+        /// Unload all of the static graphics content for this class.
+        /// </summary>
+        public static void UnloadContent()
+        {
+            texture = null;
+        }
+
+
+        #endregion
+    }
+}

+ 123 - 0
Samples/Linux/NetRumble/Gameplay/PowerUps/TripleLaserPowerUp.cs

@@ -0,0 +1,123 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// TripleLaserPowerUp.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Content;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A power-up that gives a player a triple-laser-shooting weapon.
+    /// </summary>
+    public class TripleLaserPowerUp : PowerUp
+    {
+        #region Static Graphics Data
+
+
+        /// <summary>
+        /// Texture for the triple-laser power-up.
+        /// </summary>
+        private static Texture2D texture;
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Constructs a new triple-laser power-up.
+        /// </summary>
+        public TripleLaserPowerUp()
+            : base() { }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draw the triple-laser power-up.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
+        public override void Draw(float elapsedTime, SpriteBatch spriteBatch)
+        {
+            // ignore the parameter color if we have an owner
+            base.Draw(elapsedTime, spriteBatch, texture, null, Color.White);
+        }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Defines the interaction between this power-up and a target GameplayObject
+        /// when they touch.
+        /// </summary>
+        /// <param name="target">The GameplayObject that is touching this one.</param>
+        /// <returns>True if the objects meaningfully interacted.</returns>
+        public override bool Touch(GameplayObject target)
+        {
+            // if we hit a ship, give it the weapon
+            Ship ship = target as Ship;
+            if (ship != null)
+            {
+                ship.Weapon = new TripleLaserWeapon(ship);
+            }
+
+            return base.Touch(target);
+        }
+
+
+        #endregion
+
+
+        #region Static Graphics Methods
+
+
+        /// <summary>
+        /// Load all of the static graphics content for this class.
+        /// </summary>
+        /// <param name="contentManager">The content manager to load with.</param>
+        public static void LoadContent(ContentManager contentManager)
+        {
+            // safety-check the parameters
+            if (contentManager == null)
+            {
+                throw new ArgumentNullException("contentManager");
+            }
+
+            // load the texture
+            texture = contentManager.Load<Texture2D>("Textures/powerupTripleLaser");
+        }
+
+
+        /// <summary>
+        /// Unload all of the static graphics content for this class.
+        /// </summary>
+        public static void UnloadContent()
+        {
+            texture = null;
+        }
+
+
+        #endregion
+    }
+}

+ 162 - 0
Samples/Linux/NetRumble/Gameplay/Projectiles/LaserProjectile.cs

@@ -0,0 +1,162 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// LaserProjectile.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Content;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A laser bolt projectile.
+    /// </summary>
+    public class LaserProjectile : Projectile
+    {
+        #region Constants
+
+
+        /// <summary>
+        /// The length of the laser-bolt line, expressed as a percentage of velocity.
+        /// </summary>
+        const float initialSpeed = 640f;
+
+
+        #endregion
+
+
+        #region Static Graphics Data
+
+
+        /// <summary>
+        /// Texture for all laser projectiles.
+        /// </summary>
+        private static Texture2D texture;
+
+
+        /// <summary>
+        /// The particle-effect manager which receives the effects from lasers.
+        /// </summary>
+        public static ParticleEffectManager ParticleEffectManager;
+
+
+        #endregion
+
+
+        #region Initialization
+
+
+        /// <summary>
+        /// Constructs a new laser projectile.
+        /// </summary>
+        /// <param name="owner">The ship that fired this projectile, if any.</param>
+        /// <param name="direction">The initial direction for this projectile.</param>
+        public LaserProjectile(Ship owner, Vector2 direction)
+            : base(owner, direction)
+        {
+            // set the gameplay data
+            this.velocity = initialSpeed * direction;
+
+            // set the collision data
+            this.radius = 4f;
+            this.mass = 0.5f;
+
+            // set the projectile data
+            this.duration = 5f;
+            this.damageAmount = 20f;
+            this.damageRadius = 0f;
+            this.damageOwner = false;
+        }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draw the laser projectile.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
+        public override void Draw(float elapsedTime, SpriteBatch spriteBatch)
+        {
+            // ignore the parameter color if we have an owner
+            base.Draw(elapsedTime, spriteBatch, texture, null,
+                owner != null ? owner.Color : Color.White);
+        }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Kills this object, in response to the given GameplayObject.
+        /// </summary>
+        /// <param name="source">The GameplayObject responsible for the kill.</param>
+        /// <param name="cleanupOnly">
+        /// If true, the object dies without any further effects.
+        /// </param>
+        public override void Die(GameplayObject source, bool cleanupOnly)
+        {
+            if (active)
+            {
+                // display the laser explosion
+                if (!cleanupOnly && (ParticleEffectManager != null))
+                {
+                    ParticleEffectManager.SpawnEffect(ParticleEffectType.LaserExplosion,
+                        Position);
+                }
+            }
+
+            base.Die(source, cleanupOnly);
+        }
+
+
+        #endregion
+
+
+        #region Static Graphics Methods
+
+
+        /// <summary>
+        /// Load all of the static graphics content for this class.
+        /// </summary>
+        /// <param name="contentManager">The content manager to load with.</param>
+        public static void LoadContent(ContentManager contentManager)
+        {
+            // safety-check the parameters
+            if (contentManager == null)
+            {
+                throw new ArgumentNullException("contentManager");
+            }
+
+            // load the texture
+            texture = contentManager.Load<Texture2D>("Textures/laser");
+        }
+
+
+        /// <summary>
+        /// Unload all of the static graphics content for this class.
+        /// </summary>
+        public static void UnloadContent()
+        {
+            texture = null;
+        }
+
+
+        #endregion
+    }
+}

+ 196 - 0
Samples/Linux/NetRumble/Gameplay/Projectiles/MineProjectile.cs

@@ -0,0 +1,196 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// MineProjectile.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Content;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A mine projectile.
+    /// </summary>
+    public class MineProjectile : Projectile
+    {
+        #region Constants
+
+
+        /// <summary>
+        /// The initial speed of this projectile.
+        /// </summary>
+        const float initialSpeed = 64f;
+
+        /// <summary>
+        /// The amount of drag applied to velocity per second, 
+        /// as a percentage of velocity.
+        /// </summary>
+        const float dragPerSecond = 0.9f;
+
+        /// <summary>
+        /// The radians-per-second that this object rotates at.
+        /// </summary>
+        const float rotationRadiansPerSecond = 1f;
+
+
+        #endregion
+
+
+        #region Static Graphics Data
+
+
+        /// <summary>
+        /// Texture for all mine projectiles.
+        /// </summary>
+        private static Texture2D texture;
+
+
+        /// <summary>
+        /// The particle-effect manager which recieves the effects from mines.
+        /// </summary>
+        public static ParticleEffectManager ParticleEffectManager;
+
+
+        #endregion
+
+
+        #region Initialization
+
+
+        /// <summary>
+        /// Constructs a new mine projectile.
+        /// </summary>
+        /// <param name="owner">The ship that fired this projectile, if any.</param>
+        /// <param name="direction">The initial direction for this projectile.</param>
+        public MineProjectile(Ship owner, Vector2 direction)
+            : base(owner, direction)
+        {
+            // set the gameplay data
+            this.velocity = initialSpeed * direction;
+
+            // set the collision data
+            this.radius = 10f;
+            this.mass = 5f;
+
+            // set projectile data
+            this.duration = 15f;
+            this.damageAmount = 200f;
+            this.damageOwner = false;
+            this.damageRadius = 80f;
+        }
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+
+        /// <summary>
+        /// Update the mine.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        public override void Update(float elapsedTime)
+        {
+            base.Update(elapsedTime);
+
+            this.velocity -= velocity * (elapsedTime * dragPerSecond);
+            this.rotation += elapsedTime * rotationRadiansPerSecond;
+        }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draw the mine.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
+        public override void Draw(float elapsedTime, SpriteBatch spriteBatch)
+        {
+            // ignore the parameter color if we have an owner
+            base.Draw(elapsedTime, spriteBatch, texture, null, Color.White);
+        }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Kills this object, in response to the given GameplayObject.
+        /// </summary>
+        /// <param name="source">The GameplayObject responsible for the kill.</param>
+        /// <param name="cleanupOnly">
+        /// If true, the object dies without any further effects.
+        /// </param>
+        public override void Die(GameplayObject source, bool cleanupOnly)
+        {
+            if (active)
+            {
+                if (!cleanupOnly)
+                {
+                    // play the explosion sound effect
+                    AudioManager.PlaySoundEffect("explosion_large");
+
+                    // play the mine particle-effect
+                    if (ParticleEffectManager != null)
+                    {
+                        ParticleEffectManager.SpawnEffect(
+                            ParticleEffectType.MineExplosion, Position);
+                    }
+                }
+            }
+
+            base.Die(source, cleanupOnly);
+        }
+
+
+        #endregion
+
+
+        #region Static Graphics Methods
+
+
+        /// <summary>
+        /// Load all of the static graphics content for this class.
+        /// </summary>
+        /// <param name="contentManager">The content manager to load with.</param>
+        public static void LoadContent(ContentManager contentManager)
+        {
+            // safety-check the parameters
+            if (contentManager == null)
+            {
+                throw new ArgumentNullException("contentManager");
+            }
+
+            // load the texture
+            texture = contentManager.Load<Texture2D>("Textures/mine");
+        }
+
+        /// <summary>
+        /// Unload all of the static graphics content for this class.
+        /// </summary>
+        public static void UnloadContent()
+        {
+            texture = null;
+        }
+
+
+        #endregion
+    }
+}

+ 197 - 0
Samples/Linux/NetRumble/Gameplay/Projectiles/Projectile.cs

@@ -0,0 +1,197 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// Projectile.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// Base public class for all projectiles that exist in the game.
+    /// </summary>
+    abstract public class Projectile : GameplayObject
+    {
+        #region Gameplay Data
+
+
+        /// <summary>
+        /// The player who fired this projectile.
+        /// </summary>
+        protected Ship owner;
+        public Ship Owner
+        {
+            get { return owner; }
+        }
+
+        /// <summary>
+        /// The amount that this projectile hurts it's target and those around it.
+        /// </summary>
+        protected float damageAmount = 0f;
+
+        /// <summary>
+        /// The radius at which this projectile hurts others when it explodes.
+        /// </summary>
+        protected float damageRadius = 0f;
+
+        /// <summary>
+        /// If true, this object will damage it's owner if it hits it
+        /// </summary>
+        protected bool damageOwner = true;
+
+        /// <summary>
+        /// The amount of time before this projectile dies on it's own.
+        /// </summary>
+        protected float duration = 0f;
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Constructs a new projectile.
+        /// </summary>
+        /// <param name="owner">The ship that fired this projectile.</param>
+        /// <param name="direction">The initial direction for this projectile.</param>
+        protected Projectile(Ship owner, Vector2 direction)
+            : base() 
+        {
+            // safety-check the parameter
+            if (owner == null)
+            {
+                throw new ArgumentNullException("owner");
+            }
+
+            // apply the parameters
+            this.owner = owner;
+            this.velocity = direction; // speed will be applied in the subclass
+
+            // initialize the graphics data
+            this.position = owner.Position;
+            this.rotation = (float)Math.Acos(Vector2.Dot(Vector2.UnitY, direction));
+            if (direction.X > 0f)
+            {
+                this.rotation *= -1f;
+            }
+        }
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+
+        /// <summary>
+        /// Update the projectile.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        public override void Update(float elapsedTime)
+        {
+            // projectiles can "time out"
+            if (duration > 0f)
+            {
+                duration -= elapsedTime;
+                if (duration < 0f)
+                {
+                    Die(null, false);
+                }
+            }
+
+            base.Update(elapsedTime);
+        }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draw the projectile.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
+        public abstract void Draw(float elapsedTime, SpriteBatch spriteBatch);
+
+
+        #endregion
+
+
+        #region Interaction
+
+
+        /// <summary>
+        /// Defines the interaction between this projectile and a target GameplayObject
+        /// when they touch.
+        /// </summary>
+        /// <param name="target">The GameplayObject that is touching this one.</param>
+        /// <returns>True if the objects meaningfully interacted.</returns>
+        public override bool Touch(GameplayObject target)
+        {
+            // check the target, if we have one
+            if (target != null)
+            {
+                // don't bother hitting any power-ups
+                if (target is PowerUp)
+                {
+                    return false;
+                }
+                // don't hit the owner if the damageOwner flag isn't set
+                if ((this.damageOwner == false) && (target == owner))
+                {
+                    return false;
+                }
+                // don't hit other projectiles from the same ship
+                Projectile projectile = target as Projectile;
+                if ((projectile != null) && (projectile.Owner == this.Owner))
+                {
+                    return false;
+                }
+                // damage the target
+                target.Damage(this, this.damageAmount);
+            }
+
+            // either we hit something or the target is null - in either case, die
+            Die(target, false);
+            
+            return base.Touch(target);
+        }
+        
+        /// <summary>
+        /// Kills this projectile, in response to the given GameplayObject.
+        /// </summary>
+        /// <param name="source">The GameplayObject responsible for the kill.</param>
+        /// <param name="cleanupOnly">
+        /// If true, the object dies without any further effects.
+        /// </param>
+        public override void Die(GameplayObject source, bool cleanupOnly)
+        {
+            if (active)
+            {
+                if (!cleanupOnly)
+                {
+                    CollisionManager.Explode(this, source, damageAmount, Position,
+                        damageRadius, damageOwner);
+                }
+            }
+
+            base.Die(source, cleanupOnly);
+        }
+
+
+        #endregion
+    }
+}

+ 229 - 0
Samples/Linux/NetRumble/Gameplay/Projectiles/RocketProjectile.cs

@@ -0,0 +1,229 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// RocketProjectile.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Audio;
+using Microsoft.Xna.Framework.Content;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A rocket projectile.
+    /// </summary>
+    public class RocketProjectile : Projectile
+    {
+        #region Constants
+
+
+        /// <summary>
+        /// The initial speed of the rocket.
+        /// </summary>
+        const float initialSpeed = 650f;
+
+
+        #endregion
+
+
+        #region Static Graphics Data
+
+
+        /// <summary>
+        /// Texture for all rocket projectiles.
+        /// </summary>
+        private static Texture2D texture;
+
+
+        /// <summary>
+        /// The particle-effect manager which recieves the effects from rockets.
+        /// </summary>
+        public static ParticleEffectManager ParticleEffectManager;
+
+
+        #endregion
+
+
+        #region Graphics Data
+
+
+        /// <summary>
+        /// The trailing effect behind a rocket.
+        /// </summary>
+        protected ParticleEffect rocketTrailEffect = null;
+
+
+        #endregion
+
+
+        #region Audio Data
+
+
+        /// <summary>
+        /// The sound effect of the rocket as it flies.
+        /// </summary>
+        protected SoundEffectInstance rocketSound = null;
+
+
+        #endregion
+
+
+        #region Initialization
+
+
+        /// <summary>
+        /// Constructs a new rocket projectile.
+        /// </summary>
+        /// <param name="owner">The ship that fired this projectile, if any.</param>
+        /// <param name="direction">The initial direction for this projectile.</param>
+        public RocketProjectile(Ship owner, Vector2 direction)
+            : base(owner, direction)
+        {
+            // set the gameplay data
+            this.velocity = initialSpeed * direction;
+
+            // set the collision data
+            this.radius = 14f;
+            this.mass = 10f;
+
+            // set the projectile data
+            this.duration = 4f;
+            this.damageAmount = 150f;
+            this.damageOwner = false;
+            this.damageRadius = 128f;
+            this.rotation += MathHelper.Pi;
+        }
+
+
+        /// <summary>
+        /// Initialize the rocket projectile to it's default gameplay states.
+        /// </summary>
+        public override void Initialize()
+        {
+            if (!active)
+            {
+                // get and play the rocket-flying sound effect
+
+                AudioManager.PlaySoundEffect("rocket", true, out rocketSound);
+
+                // start the rocket-trail effect
+                if (ParticleEffectManager != null)
+                {
+                    rocketTrailEffect = ParticleEffectManager.SpawnEffect(
+                        ParticleEffectType.RocketTrail, this);
+                }
+            }
+            
+            base.Initialize();
+        }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draw the rocket.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
+        public override void Draw(float elapsedTime, SpriteBatch spriteBatch)
+        {
+            // ignore the parameter color if we have an owner
+            base.Draw(elapsedTime, spriteBatch, texture, null, Color.White);
+        }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Kills this object, in response to the given GameplayObject.
+        /// </summary>
+        /// <param name="source">The GameplayObject responsible for the kill.</param>
+        /// <param name="cleanupOnly">
+        /// If true, the object dies without any further effects.
+        /// </param>
+        public override void Die(GameplayObject source, bool cleanupOnly)
+        {
+            if (active)
+            {
+                if (!cleanupOnly)
+                {
+                    // play the explosion sound
+                    AudioManager.PlaySoundEffect("explosion_medium");
+
+                    // display the rocket explosion
+                    if (ParticleEffectManager != null)
+                    {
+                        ParticleEffectManager.SpawnEffect(
+                            ParticleEffectType.RocketExplosion, Position);
+                    }
+                }
+
+                // stop the rocket-flying sound effect
+                if (rocketSound != null)
+                {
+                    rocketSound.Stop(true);
+                    rocketSound.Dispose();
+                    rocketSound = null;
+                }
+
+                // stop the rocket-trail effect
+                if (rocketTrailEffect != null)
+                {
+                    rocketTrailEffect.Stop(false);
+                }
+            }
+
+            base.Die(source, cleanupOnly);
+        }
+
+
+        #endregion
+
+
+        #region Static Graphics Methods
+
+
+        /// <summary>
+        /// Load all of the static graphics content for this class.
+        /// </summary>
+        /// <param name="contentManager">The content manager to load with.</param>
+        public static void LoadContent(ContentManager contentManager)
+        {
+            // safety-check the parameters
+            if (contentManager == null)
+            {
+                throw new ArgumentNullException("contentManager");
+            }
+
+            // load the texture
+            texture = contentManager.Load<Texture2D>("Textures/rocket");
+        }
+
+        /// <summary>
+        /// Unload all of the static graphics content for this class.
+        /// </summary>
+        public static void UnloadContent()
+        {
+            texture = null;
+        }
+
+
+        #endregion
+    }
+}

+ 878 - 0
Samples/Linux/NetRumble/Gameplay/Ship.cs

@@ -0,0 +1,878 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// Ship.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using Microsoft.Xna.Framework.Net;
+using Microsoft.Xna.Framework.Content;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// The ship, which is the primary playing-piece in the game.
+    /// </summary>
+    public class Ship : GameplayObject
+    {
+        #region Constants
+
+
+        /// <summary>
+        /// The full speed possible for the ship.
+        /// </summary>
+        const float fullSpeed = 320f;
+
+        /// <summary>
+        /// The amount of drag applied to velocity per second, 
+        /// as a percentage of velocity.
+        /// </summary>
+        const float dragPerSecond = 0.9f;
+
+        /// <summary>
+        /// The amount that the right-stick must be pressed to fire, squared so that
+        /// we can use LengthSquared instead of Length, which has a square-root in it.
+        /// </summary>
+        const float fireThresholdSquared = 0.25f;
+
+        /// <summary>
+        /// The number of radians that the ship can turn in a second at full left-stick.
+        /// </summary>
+        const float rotationRadiansPerSecond = 6f;
+
+        /// <summary>
+        /// The maximum length of the velocity vector on a ship.
+        /// </summary>
+        const float velocityMaximum = 320f;
+
+        /// <summary>
+        /// The maximum strength of the shield.
+        /// </summary>
+        const float shieldMaximum = 100f;
+
+        /// <summary>
+        /// The maximum opacity for the shield, when it's fully recharged.
+        /// </summary>
+        const float shieldAlphaMaximum = 150f;
+
+        /// <summary>
+        /// How much the shield recharges per second.
+        /// </summary>
+        const float shieldRechargePerSecond = 50f;
+
+        /// <summary>
+        /// The duration of the shield-recharge timer when the ship is hit.
+        /// </summary>
+        const float shieldRechargeTimerMaximum = 2.5f;
+
+        /// <summary>
+        /// The base scale for the shield, compared to the size of the ship.
+        /// </summary>
+        const float shieldScaleBase = 1.2f;
+
+        /// <summary>
+        /// The amplitude of the shield pulse
+        /// </summary>
+        const float shieldPulseAmplitude = 0.15f;
+
+        /// <summary>
+        /// The rate of the shield pulse.
+        /// </summary>
+        const float shieldPulseRate = 0.2f;
+
+        /// <summary>
+        /// The maximum value of the "safe" timer.
+        /// </summary>
+        const float safeTimerMaximum = 4f;
+
+        /// <summary>
+        /// The maximum amount of life that a ship can have.
+        /// </summary>
+        const float lifeMaximum = 25f;
+
+        /// <summary>
+        /// The value of the spawn timer set when the ship dies.
+        /// </summary>
+        const float respawnTimerOnDeath = 5f;
+
+        /// <summary>
+        /// The number of variations in textures for ships.
+        /// </summary>
+        const int variations = 4;
+
+
+        #endregion
+
+
+        #region Static Graphics Data
+
+
+        /// <summary>
+        /// The primary ship textures.
+        /// </summary>
+        private static Texture2D[] primaryTextures = new Texture2D[variations];
+
+        /// <summary>
+        /// The overlay ship textures, which get tinted.
+        /// </summary>
+        private static Texture2D[] overlayTextures = new Texture2D[variations];
+
+        /// <summary>
+        /// The ship shield texture.
+        /// </summary>
+        private static Texture2D shieldTexture;
+
+        /// <summary>
+        /// The colors used for each ship.
+        /// </summary>
+        public static readonly Color[] ShipColors = 
+            {
+                Color.Lime,      Color.CornflowerBlue, Color.Fuchsia,
+                Color.Red,       Color.LightSeaGreen,  Color.LightGray,
+                Color.Gold,      Color.ForestGreen,    Color.Beige, 
+                Color.LightPink, Color.Lavender,       Color.OrangeRed, 
+                Color.Plum,      Color.Tan,            Color.YellowGreen,
+                Color.Azure,     Color.Aqua,           Color.Salmon
+            };
+
+        /// <summary>
+        /// The particle-effect manager which recieves the effects from ships.
+        /// </summary>
+        public static ParticleEffectManager ParticleEffectManager;
+
+
+        #endregion
+
+
+        #region Gameplay Data
+
+
+        /// <summary>
+        /// The score for this ship.
+        /// </summary>
+        private int score = 0;
+        public int Score
+        {
+            get { return score; }
+            set { score = value; }
+        }
+
+        /// <summary>
+        /// The amount of damage that the ship can take before exploding.
+        /// </summary>
+        private float life;
+        public float Life
+        {
+            get { return life; }
+            set { life = value; }
+        }
+
+        /// <summary>
+        /// The ship's primary weapon.
+        /// </summary>
+        private Weapon weapon;
+        public Weapon Weapon
+        {
+            get { return weapon; }
+            set
+            {
+                if (value == null)
+                {
+                    throw new ArgumentNullException("value");
+                }
+                weapon = value;
+            }
+        }
+
+        /// <summary>
+        /// The ship's mine-laying weapon.
+        /// </summary>
+        private MineWeapon mineWeapon;
+
+        /// <summary>
+        /// All of the projectiles fired by this ship.
+        /// </summary>
+        private BatchRemovalCollection<Projectile> projectiles = 
+            new BatchRemovalCollection<Projectile>();
+        public BatchRemovalCollection<Projectile> Projectiles
+        {
+            get { return projectiles; }
+        }
+
+        /// <summary>
+        /// The strength of the shield.
+        /// </summary>
+        private float shield;
+        public float Shield
+        {
+            get { return shield; }
+            set { shield = value; }
+        }
+
+        /// <summary>
+        /// Timer for how long until the shield starts to recharge.
+        /// </summary>
+        private float shieldRechargeTimer;
+
+        /// <summary>
+        /// Timer for how long the player is safe after spawning.
+        /// </summary>
+        private float safeTimer;
+        public bool Safe
+        {
+            get { return (safeTimer > 0f); }
+            set
+            {
+                if (value)
+                {
+                    safeTimer = safeTimerMaximum;
+                }
+                else
+                {
+                    safeTimer = 0f;
+                }
+            }
+        }
+
+        /// <summary>
+        /// The tint of the ship.
+        /// </summary>
+        private Color color = Color.White;
+        public Color Color
+        {
+            get { return color; }
+            set { color = value; }
+        }
+        
+        /// <summary>
+        /// The amount of time left before respawning the ship.
+        /// </summary>
+        private float respawnTimer;
+        public float RespawnTimer
+        {
+            get { return respawnTimer; }
+            set { respawnTimer = value; }
+        }
+
+        /// <summary>
+        /// The last object to damage the ship.
+        /// </summary>
+        private GameplayObject lastDamagedBy = null;
+        public GameplayObject LastDamagedBy
+        {
+            get { return lastDamagedBy; }
+        }
+
+
+        #endregion
+
+
+        #region Input Data
+
+
+        /// <summary>
+        /// The current player input for the ship.
+        /// </summary>
+        private ShipInput shipInput;
+        public ShipInput ShipInput
+        {
+            get { return shipInput; }
+            set { shipInput = value; }
+        }
+
+
+        #endregion
+
+
+        #region Graphics Data
+
+
+        /// <summary>
+        /// The variation of this ship.
+        /// </summary>
+        private int variation = 0;
+        public int Variation
+        {
+            get { return variation; }
+            set 
+            {
+                if ((value < 0) || (value >= variations))
+                {
+                    throw new ArgumentOutOfRangeException("value");
+                }
+                variation = value;
+            }
+        }
+
+
+        /// <summary>
+        /// The time accumulator for the shield pulse.
+        /// </summary>
+        private float shieldPulseTime = 0f;
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Construct a new ship.
+        /// </summary>
+        public Ship() 
+            : base() 
+        {
+            // set the collision data
+            this.radius = 24f;
+            this.mass = 32f;
+        }
+
+
+        /// <summary>
+        /// Initialize a ship to its default gameplay states.
+        /// </summary>
+        public override void Initialize()
+        {
+            if (!active)
+            {
+                // set the initial gameplay data values
+                shipInput = ShipInput.Empty;
+                rotation = 0f;
+                velocity = Vector2.Zero;
+                life = lifeMaximum;
+                shield = shieldMaximum;
+                shieldRechargeTimer = 0f;
+                safeTimer = safeTimerMaximum;
+                weapon = new LaserWeapon(this);
+                mineWeapon = new MineWeapon(this);
+
+                // play the player-spawn sound
+                AudioManager.PlaySoundEffect("player_spawn");
+
+                // add the ship-spawn particle effect
+                if (ParticleEffectManager != null)
+                {
+                    ParticleEffectManager.SpawnEffect(ParticleEffectType.ShipSpawn,
+                        this);
+                }
+
+                // clear out the projectiles list
+                projectiles.Clear();
+            }
+
+            base.Initialize();
+        }
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+
+        /// <summary>
+        /// Update the ship.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        public override void Update(float elapsedTime)
+        {
+            // calculate the current forward vector
+            Vector2 forward = new Vector2((float)Math.Sin(Rotation),
+                -(float)Math.Cos(Rotation));
+            Vector2 right = new Vector2(-forward.Y, forward.X);
+
+            // calculate the new forward vector with the left stick
+            shipInput.LeftStick.Y *= -1f;
+            if (shipInput.LeftStick.LengthSquared() > 0f)
+            {
+                // change the direction
+                Vector2 wantedForward = Vector2.Normalize(shipInput.LeftStick);
+                float angleDiff = (float)Math.Acos(
+                    Vector2.Dot(wantedForward, forward));
+                float facing = (Vector2.Dot(wantedForward, right) > 0f) ?
+                    1f : -1f;
+                if (angleDiff > 0.001f)
+                {
+                    Rotation += Math.Min(angleDiff, facing * elapsedTime *
+                        rotationRadiansPerSecond);
+                }
+
+                // add velocity
+                Velocity += shipInput.LeftStick * (elapsedTime * fullSpeed);
+                if (Velocity.Length() > velocityMaximum)
+                {
+                    Velocity = Vector2.Normalize(Velocity) *
+                        velocityMaximum;
+                }
+            }
+            shipInput.LeftStick = Vector2.Zero;
+
+            // apply drag to the velocity
+            Velocity -= Velocity * (elapsedTime * dragPerSecond);
+            if (Velocity.LengthSquared() <= 0f)
+            {
+                Velocity = Vector2.Zero;
+            }
+
+            // check for firing with the right stick
+            shipInput.RightStick.Y *= -1f;
+            if (shipInput.RightStick.LengthSquared() > fireThresholdSquared)
+            {
+                weapon.Fire(Vector2.Normalize(shipInput.RightStick));
+            }
+            shipInput.RightStick = Vector2.Zero;
+
+            // check for laying mines
+            if (shipInput.MineFired)
+            {
+                // fire behind the ship
+                mineWeapon.Fire(-forward);
+            }
+            shipInput.MineFired = false;
+            
+            // recharge the shields
+            if (shieldRechargeTimer > 0f)
+            {
+                shieldRechargeTimer = Math.Max(shieldRechargeTimer - elapsedTime, 
+                    0f);
+            }
+            if (shieldRechargeTimer <= 0f)
+            {
+                if (shield < shieldMaximum)
+                {
+                    shield = Math.Min(shieldMaximum,
+                        shield + shieldRechargePerSecond * elapsedTime);
+                }
+            }
+
+            // update the radius based on the shield
+            radius = (shield > 0f) ? 24f : 20f;
+
+            // update the weapons
+            if (weapon != null)
+            {
+                weapon.Update(elapsedTime);
+            }
+            if (mineWeapon != null)
+            {
+                mineWeapon.Update(elapsedTime);
+            }
+
+            // decrement the safe timer
+            if (safeTimer > 0f)
+            {
+                safeTimer = Math.Max(safeTimer - elapsedTime, 0f);
+            }
+
+            // update the projectiles
+            foreach (Projectile projectile in projectiles)
+            {
+                if (projectile.Active)
+                {
+                    projectile.Update(elapsedTime);
+                }
+                else
+                {
+                    projectiles.QueuePendingRemoval(projectile);
+                }
+            }
+            projectiles.ApplyPendingRemovals();
+
+            base.Update(elapsedTime);
+        }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draw the ship.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
+        public void Draw(float elapsedTime, SpriteBatch spriteBatch)
+        {
+            // draw the uniform section of the ship
+            base.Draw(elapsedTime, spriteBatch, primaryTextures[variation], 
+                null, Color.White);
+
+            // draw the tinted section of the ship
+            base.Draw(elapsedTime, spriteBatch, overlayTextures[variation],
+                null, color);
+
+            if (shield > 0)
+            {
+                // calculate the current shield radius
+                float oldRadius = radius;
+                shieldPulseTime += elapsedTime;
+                radius *= shieldScaleBase + shieldPulseAmplitude * 
+                    (float)Math.Sin(shieldPulseTime / shieldPulseRate);
+                // draw the shield
+                base.Draw(elapsedTime, spriteBatch, shieldTexture, null, 
+                    new Color(color.R, color.G, color.B,
+                       (byte)Math.Floor(shieldAlphaMaximum * shield / shieldMaximum)));
+                // return to the old radius
+                radius = oldRadius;
+            }
+
+            // draw the projectiles
+            foreach (Projectile projectile in projectiles)
+            {
+                projectile.Draw(elapsedTime, spriteBatch);
+            }
+        }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Damage this ship by the amount provided.
+        /// </summary>
+        /// <remarks>
+        /// This function is provided in lieu of a Life mutation property to allow 
+        /// classes of objects to restrict which kinds of objects may damage them,
+        /// and under what circumstances they may be damaged.
+        /// </remarks>
+        /// <param name="source">The GameplayObject responsible for the damage.</param>
+        /// <param name="damageAmount">The amount of damage.</param>
+        /// <returns>If true, this object was damaged.</returns>
+        public override bool Damage(GameplayObject source, float damageAmount)
+        {
+            // if the safe timer hasn't yet gone off, then the ship can't be hurt
+            if ((safeTimer > 0f) || (damageAmount <= 0f))
+            {
+                return false;
+            }
+
+            // once you're hit, the shield-recharge timer starts over
+            shieldRechargeTimer = 2.5f;
+
+            // damage the shield first, then life
+            if (shield <= 0f)
+            {
+                life -= damageAmount;
+            }
+            else
+            {
+                shield -= damageAmount;
+                if (shield < 0f)
+                {
+                    // shield has the overflow value as a negative value, just add it
+                    life += shield;
+                    shield = 0f;
+                }
+            }
+
+            Projectile sourceAsProjectile = source as Projectile;
+            if (sourceAsProjectile != null)
+            {
+                lastDamagedBy = sourceAsProjectile.Owner;
+            }
+            else
+            {
+                lastDamagedBy = source;
+            }
+
+            return true;
+        }
+
+
+        /// <summary>
+        /// Kills this ship, in response to the given GameplayObject.
+        /// </summary>
+        /// <param name="source">The GameplayObject responsible for the kill.</param>
+        /// <param name="cleanupOnly">
+        /// If true, the object dies without any further effects.
+        /// </param>
+        public override void Die(GameplayObject source, bool cleanupOnly)
+        {
+            if (active)
+            {
+                if (!cleanupOnly)
+                {
+                    // update the score
+                    Ship ship = source as Ship;
+                    if (ship == null)
+                    {
+                        Projectile projectile = source as Projectile;
+                        if (projectile != null)
+                        {
+                            ship = projectile.Owner;
+                        }
+                    }
+                    if (ship != null)
+                    {
+                        if (ship == this)
+                        {
+                            // reduce the score, since i blew myself up
+                            ship.Score--;
+                        }
+                        else
+                        {
+                            // add score to the ship who shot this object
+                            ship.Score++;
+                        }
+                    }
+                    else
+                    {
+                        // if it wasn't a ship, then this object loses score
+                        this.Score--;
+                    }
+
+                    // play the player-death sound
+                    AudioManager.PlaySoundEffect("explosion_shockwave");
+                    AudioManager.PlaySoundEffect("explosion_large");
+
+                    // display the ship explosion
+                    if (ParticleEffectManager != null)
+                    {
+                        ParticleEffectManager.SpawnEffect(
+                            ParticleEffectType.ShipExplosion, Position);
+                    }
+                }
+
+                // clear out the projectiles list
+                foreach (Projectile projectile in projectiles)
+                {
+                    projectile.Die(null, true);
+                }
+                projectiles.Clear();
+
+                // set the respawn timer
+                respawnTimer = respawnTimerOnDeath;
+            }
+
+            base.Die(source, cleanupOnly);
+        }
+
+
+        #endregion
+
+
+        #region Static Graphics Methods
+
+
+        /// <summary>
+        /// Load all of the static graphics content for this class.
+        /// </summary>
+        /// <param name="contentManager">The content manager to load with.</param>
+        public static void LoadContent(ContentManager contentManager)
+        {
+            // safety-check the parameters
+            if (contentManager == null)
+            {
+                throw new ArgumentNullException("contentManager");
+            }
+
+            // load each ship's texture
+            for (int i = 0; i < variations; i++)
+            {
+                primaryTextures[i] = contentManager.Load<Texture2D>(
+                    "Textures/ship" + i.ToString());
+                overlayTextures[i] = contentManager.Load<Texture2D>(
+                    "Textures/ship" + i.ToString() + "Overlay");
+            }
+
+            // load the shield texture
+            shieldTexture = contentManager.Load<Texture2D>("Textures/shipShields");
+        }
+
+
+        /// <summary>
+        /// Unload all of the static graphics content for this class.
+        /// </summary>
+        public static void UnloadContent()
+        {
+            for (int i = 0; i < variations; i++)
+            {
+                primaryTextures[i] = overlayTextures[i] = null;
+            }
+            shieldTexture = null;
+        }
+
+
+        /// <summary>
+        /// Determines if a color index is unique.
+        /// </summary>
+        /// <param name="networkGamer">The gamer with the color index.</param>
+        /// <param name="networkSession">The session the player belongs to.</param>
+        /// <returns>If true, the gamer has a unique color ID.</returns>
+        public static bool HasUniqueColorIndex(NetworkGamer networkGamer, 
+            NetworkSession networkSession)
+        {
+            // safety-check the parameters
+            if (networkGamer == null)
+            {
+                throw new ArgumentNullException("networkGamer");
+            }
+            if (networkSession == null)
+            {
+                throw new ArgumentNullException("networkSession");
+            }
+            PlayerData playerData = networkGamer.Tag as PlayerData;
+            if (playerData == null)
+            {
+                throw new ArgumentNullException("networkGamer.Tag as PlayerData");
+            }
+
+            // search for a match
+            foreach (NetworkGamer gamer in networkSession.AllGamers)
+            {
+                if (gamer == networkGamer)
+                {
+                    continue;
+                }
+                PlayerData gamerData = gamer.Tag as PlayerData;
+                if ((gamerData != null) && 
+                    (gamerData.ShipColor == playerData.ShipColor))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+
+        /// <summary>
+        /// Find the next unique color index among the players.
+        /// </summary>
+        /// <param name="currentColorIndex">The current color index.</param>
+        /// <param name="networkSession">The network session.</param>
+        /// <returns>The next unique color index.</returns>
+        public static byte GetNextUniqueColorIndex(byte currentColorIndex, 
+            NetworkSession networkSession)
+        {
+            // safety-check the parameters
+            if ((currentColorIndex < 0) || (currentColorIndex >= ShipColors.Length))
+            {
+                throw new ArgumentOutOfRangeException("currentColorIndex");
+            }
+            if (networkSession == null)
+            {
+                throw new ArgumentNullException("networkSession");
+            }
+            if (networkSession.AllGamers.Count > ShipColors.Length)
+            {
+                throw new InvalidOperationException(
+                    "There are more gamers than there are colors.");
+            }
+
+            // if there are as many gamers as there are colors, then we can't change
+            if (networkSession.AllGamers.Count == ShipColors.Length)
+            {
+                return currentColorIndex;
+            }
+
+            bool colorFound;
+            byte newColorIndex = currentColorIndex;
+            do
+            {
+                newColorIndex++;
+                if (newColorIndex >= ShipColors.Length)
+                {
+                    newColorIndex = 0;
+                }
+                colorFound = false;
+                foreach (NetworkGamer networkGamer in networkSession.AllGamers)
+                {
+                    PlayerData playerData = networkGamer.Tag as PlayerData;
+                    if ((playerData != null) && (playerData.ShipColor == newColorIndex))
+                    {
+                        colorFound = true;
+                        break;
+                    }
+                }
+            }
+            while (colorFound && (newColorIndex != currentColorIndex));
+
+            return newColorIndex;
+        }
+
+
+        /// <summary>
+        /// Find the previous unique color index among the players.
+        /// </summary>
+        /// <param name="currentColorIndex">The current color index.</param>
+        /// <param name="networkSession">The network session..</param>
+        /// <returns>The previous unique color index.</returns>
+        public static byte GetPreviousUniqueColorIndex(byte currentColorIndex, 
+            NetworkSession networkSession)
+        {
+            // safety-check the parameters
+            if ((currentColorIndex < 0) || (currentColorIndex >= ShipColors.Length))
+            {
+                throw new ArgumentOutOfRangeException("currentColorIndex");
+            }
+            if (networkSession == null)
+            {
+                throw new ArgumentNullException("networkSession");
+            }
+            if (networkSession.AllGamers.Count > ShipColors.Length)
+            {
+                throw new InvalidOperationException(
+                    "There are more gamers than there are colors.");
+            }
+
+            // if there are as many gamers as there are colors, then we can't change
+            if (networkSession.AllGamers.Count == ShipColors.Length)
+            {
+                return currentColorIndex;
+            }
+
+            bool colorFound;
+            byte newColorIndex = currentColorIndex;
+            do
+            {
+                if (newColorIndex == 0)
+                {
+                    newColorIndex = (byte)(ShipColors.Length - 1);
+                }
+                else
+                {
+                    newColorIndex--;
+                }
+                colorFound = false;
+                foreach (NetworkGamer networkGamer in networkSession.AllGamers)
+                {
+                    PlayerData playerData = networkGamer.Tag as PlayerData;
+                    if ((playerData != null) && (playerData.ShipColor == newColorIndex))
+                    {
+                        colorFound = true;
+                        break;
+                    }
+                }
+            }
+            while (colorFound && (newColorIndex != currentColorIndex));
+
+            return newColorIndex;
+        }
+
+        /// <summary>
+        /// The number of variations in ships.
+        /// </summary>
+        public static int Variations
+        {
+            get { return variations; }
+        }
+
+
+        #endregion
+    }
+}

+ 221 - 0
Samples/Linux/NetRumble/Gameplay/ShipInput.cs

@@ -0,0 +1,221 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// ShipInput.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Input;
+using Microsoft.Xna.Framework.Net;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// Player input abstraction for ships.
+    /// </summary>
+    public struct ShipInput
+    {
+        #region Static Constants
+
+
+        /// <summary>
+        /// The empty version of this structure.
+        /// </summary>
+        private static ShipInput empty = 
+            new ShipInput(Vector2.Zero, Vector2.Zero, false);
+        public static ShipInput Empty
+        {
+            get { return empty; }
+        }
+
+
+        #endregion
+
+
+        #region Input Data
+
+
+        /// <summary>
+        /// The left-stick value of the ship input, used for movement.
+        /// </summary>
+        public Vector2 LeftStick;
+
+        /// <summary>
+        /// The right-stick value of the ship input, used for firing.
+        /// </summary>
+        public Vector2 RightStick;
+
+        /// <summary>
+        /// If true, the player is trying to fire a mine.
+        /// </summary>
+        public bool MineFired;
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Constructs a new ShipInput object.
+        /// </summary>
+        /// <param name="leftStick">The left-stick value of the ship input.</param>
+        /// <param name="rightStick">The right-stick value of the ship input.</param>
+        /// <param name="mineFired">If true, the player is firing a mine.</param>
+        public ShipInput(Vector2 leftStick, Vector2 rightStick, bool mineFired)
+        {
+            this.LeftStick = leftStick;
+            this.RightStick = rightStick;
+            this.MineFired = mineFired;
+        }
+
+
+        /// <summary>
+        /// Create a new ShipInput object based on the data in the packet.
+        /// </summary>
+        /// <param name="packetReader">The packet with the data.</param>
+        public ShipInput(PacketReader packetReader)
+        {
+            // safety-check the parameters, as they must be valid
+            if (packetReader == null)
+            {
+                throw new ArgumentNullException("packetReader");
+            }
+
+            // read the data
+            LeftStick = packetReader.ReadVector2();
+            RightStick = packetReader.ReadVector2();
+            MineFired = packetReader.ReadBoolean();
+        }
+
+
+        /// <summary>
+        /// Create a new ShipInput object based on local input state.
+        /// </summary>
+        /// <param name="gamePadState">The local gamepad state.</param>
+        /// <param name="keyboardState">The local keyboard state</param>
+        public ShipInput(GamePadState gamePadState, KeyboardState keyboardState)
+        {
+            // check for movement action
+            bool keyHit = false;
+            LeftStick = Vector2.Zero;
+            if (keyboardState.IsKeyDown(Keys.W))
+            {
+                LeftStick += Vector2.UnitY;
+                keyHit = true;
+            }
+            if (keyboardState.IsKeyDown(Keys.A))
+            {
+                LeftStick += Vector2.Multiply(Vector2.UnitX, -1f);
+                keyHit = true;
+            }
+            if (keyboardState.IsKeyDown(Keys.S))
+            {
+                LeftStick += Vector2.Multiply(Vector2.UnitY, -1f);
+                keyHit = true;
+            }
+            if (keyboardState.IsKeyDown(Keys.D))
+            {
+                LeftStick += Vector2.UnitX;
+                keyHit = true;
+            } 
+
+            if (keyHit)
+            {
+                if (LeftStick.LengthSquared() > 0)
+                {
+                    LeftStick.Normalize();
+                }
+            }
+            else
+            {
+                LeftStick = gamePadState.ThumbSticks.Left;
+            }
+
+            // check for firing action
+            keyHit = false;
+            RightStick = Vector2.Zero;
+            if (keyboardState.IsKeyDown(Keys.Up))
+            {
+                RightStick += Vector2.UnitY;
+                keyHit = true;
+            }
+            if (keyboardState.IsKeyDown(Keys.Left))
+            {
+                RightStick += Vector2.Multiply(Vector2.UnitX, -1f);
+                keyHit = true;
+            }
+            if (keyboardState.IsKeyDown(Keys.Down))
+            {
+                RightStick += Vector2.Multiply(Vector2.UnitY, -1f);
+                keyHit = true;
+            }
+            if (keyboardState.IsKeyDown(Keys.Right))
+            {
+                RightStick += Vector2.UnitX;
+                keyHit = true;
+            }
+
+            if (keyHit)
+            {
+                if (RightStick.LengthSquared() > 0)
+                {
+                    RightStick.Normalize();
+                }
+            }
+            else
+            {
+                RightStick = gamePadState.ThumbSticks.Right;
+            }
+
+            // check for firing a mine
+            keyHit = false;
+            MineFired = false;
+            if (keyboardState.IsKeyDown(Keys.Space))
+            {
+                MineFired = true;
+                keyHit = true;
+            }
+
+            if (!keyHit)
+            {
+                MineFired = gamePadState.Triggers.Right >= 0.9f;
+            }
+        }
+
+
+        #endregion
+
+
+        #region Networking Methods
+
+
+        /// <summary>
+        /// Serialize the object out to a packet.
+        /// </summary>
+        /// <param name="packetWriter">The packet to write to.</param>
+        public void Serialize(PacketWriter packetWriter)
+        {
+            // safety-check the parameters, as they must be valid
+            if (packetWriter == null)
+            {
+                throw new ArgumentNullException("packetWriter");
+            }
+
+            packetWriter.Write((int)World.PacketTypes.ShipInput); 
+            packetWriter.Write(LeftStick);
+            packetWriter.Write(RightStick);
+            packetWriter.Write(MineFired);
+        }
+
+
+        #endregion
+    }
+}

+ 80 - 0
Samples/Linux/NetRumble/Gameplay/Weapons/DoubleLaserWeapon.cs

@@ -0,0 +1,80 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// DoubleLaserWeapon.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A weapon that shoots a double stream of laser projectiles.
+    /// </summary>
+    public class DoubleLaserWeapon : LaserWeapon
+    {
+        #region Constants
+
+
+        /// <summary>
+        /// The distance that the laser bolts are moved off of the owner's position.
+        /// </summary>
+        const float laserSpread = 8f;
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Constructs a new double-laser weapon.
+        /// </summary>
+        /// <param name="owner">The ship that owns this weapon.</param>
+        public DoubleLaserWeapon(Ship owner)
+            : base(owner) { }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Create and spawn the projectile(s) from a firing from this weapon.
+        /// </summary>
+        /// <param name="direction">The direction that the projectile will move.</param>
+        protected override void CreateProjectiles(Vector2 direction)
+        {
+            // calculate the spread of the laser bolts
+            Vector2 cross = Vector2.Multiply(new Vector2(-direction.Y, direction.X),
+                laserSpread);
+
+            // create the new projectile
+            LaserProjectile projectile = new LaserProjectile(owner,
+                direction);
+            projectile.Initialize();
+            owner.Projectiles.Add(projectile);
+            // adjust the position for the laser spread
+            projectile.Position += cross;
+
+            // create the second projectile
+            projectile = new LaserProjectile(owner, direction);
+            projectile.Initialize();
+            owner.Projectiles.Add(projectile);
+            // adjust the position for the laser spread
+            projectile.Position -= cross;
+        }
+
+
+        #endregion
+    }
+}

+ 70 - 0
Samples/Linux/NetRumble/Gameplay/Weapons/LaserWeapon.cs

@@ -0,0 +1,70 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// LaserWeapon.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A weapon that shoots a single stream of laser projectiles.
+    /// </summary>
+    public class LaserWeapon : Weapon
+    {
+        #region Initialization Methods
+
+        /// <summary>
+        /// Constructs a new laser weapon.
+        /// </summary>
+        /// <param name="owner">The ship that owns this weapon.</param>
+        public LaserWeapon(Ship owner)
+            : base(owner)
+        {
+            fireDelay = 0.15f;
+
+            // Pick one of the laser sound variations for this instance.
+            switch (RandomMath.Random.Next(3))
+            {
+                case 0:
+                    fireSoundEffect = "fire_laser1";
+                    break;
+                case 1:
+                    fireSoundEffect = "fire_laser2";
+                    break;
+                case 2:
+                    fireSoundEffect = "fire_laser3";
+                    break;
+            }
+        }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Create and spawn the projectile(s) from a firing from this weapon.
+        /// </summary>
+        /// <param name="direction">The direction that the projectile will move.</param>
+        protected override void CreateProjectiles(Vector2 direction)
+        {
+            // create the new projectile
+            LaserProjectile projectile = new LaserProjectile(owner, direction);
+            projectile.Initialize();
+            owner.Projectiles.Add(projectile);
+        }
+
+
+        #endregion
+    }
+}

+ 73 - 0
Samples/Linux/NetRumble/Gameplay/Weapons/MineWeapon.cs

@@ -0,0 +1,73 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// MineWeapon.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A weapon that fires a single mine on a long timer.
+    /// </summary>
+    public class MineWeapon : Weapon
+    {
+        #region Constants
+
+
+        /// <summary>
+        /// The distance that the mine spawns behind the ship.
+        /// </summary>
+        const float mineSpawnDistance = 8f;
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Constructs a new mine-laying weapon.
+        /// </summary>
+        /// <param name="owner">The ship that owns this weapon.</param>
+        public MineWeapon(Ship owner)
+            : base(owner)
+        {
+            fireDelay = 2f;         
+        }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Create and spawn the projectile(s) from a firing from this weapon.
+        /// </summary>
+        /// <param name="direction">The direction that the projectile will move.</param>
+        protected override void CreateProjectiles(Vector2 direction)
+        {
+            // create the new projectile
+            MineProjectile projectile = new MineProjectile(owner, direction);
+            projectile.Initialize();
+            owner.Projectiles.Add(projectile);
+
+            // move the mine out from the ship
+            projectile.Position = owner.Position +
+                direction * (owner.Radius + projectile.Radius + mineSpawnDistance);
+        }
+
+
+        #endregion
+    }
+}

+ 63 - 0
Samples/Linux/NetRumble/Gameplay/Weapons/RocketWeapon.cs

@@ -0,0 +1,63 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// RocketWeapon.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A weapon that shoots a rockets.
+    /// </summary>
+    public class RocketWeapon : Weapon
+    {
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Constructs a new rocket-launching weapon.
+        /// </summary>
+        /// <param name="owner">The ship that owns this weapon.</param>
+        public RocketWeapon(Ship owner)
+            : base(owner)
+        {
+            fireDelay = 0.5f;
+
+            // Pick one of the rocket sound variations for this instance.
+            if (RandomMath.Random.Next(2) == 0)
+                fireSoundEffect = "fire_rocket1";
+            else
+                fireSoundEffect = "fire_rocket2";
+        }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Create and spawn the projectile(s) from a firing from this weapon.
+        /// </summary>
+        /// <param name="direction">The direction that the projectile will move.</param>
+        protected override void CreateProjectiles(Vector2 direction)
+        {
+            // create the new projectile
+            RocketProjectile projectile = new RocketProjectile(owner, direction);
+            projectile.Initialize();
+            owner.Projectiles.Add(projectile);
+        }
+
+
+        #endregion
+    }
+}

+ 92 - 0
Samples/Linux/NetRumble/Gameplay/Weapons/TripleLaserWeapon.cs

@@ -0,0 +1,92 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// TripleLaserWeapon.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A weapon that shoots a triple stream of laser projectiles.
+    /// </summary>
+    public class TripleLaserWeapon : LaserWeapon
+    {
+        #region Constants
+
+
+        /// <summary>
+        /// The spread of the second and third laser projectiles' directions, in radians
+        /// </summary>
+        static readonly float laserSpreadRadians = MathHelper.ToRadians(2.5f);
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Constructs a new triple-laser weapon.
+        /// </summary>
+        /// <param name="owner">The ship that owns this weapon.</param>
+        public TripleLaserWeapon(Ship owner)
+            : base(owner) 
+        {
+            fireDelay = 0.3f;
+        }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Create and spawn the projectile(s) from a firing from this weapon.
+        /// </summary>
+        /// <param name="direction">The direction that the projectile will move.</param>
+        protected override void CreateProjectiles(Vector2 direction)
+        {
+            // calculate the direction vectors for the second and third projectiles
+            float rotation = (float)Math.Acos(Vector2.Dot(new Vector2(0f, -1f), 
+                direction));
+            rotation *= (Vector2.Dot(new Vector2(0f, -1f), 
+                new Vector2(direction.Y, -direction.X)) > 0f) ? 1f : -1f;
+            Vector2 direction2 = new Vector2(
+                 (float)Math.Sin(rotation - laserSpreadRadians), 
+                -(float)Math.Cos(rotation - laserSpreadRadians));
+            Vector2 direction3 = new Vector2(
+                 (float)Math.Sin(rotation + laserSpreadRadians), 
+                -(float)Math.Cos(rotation + laserSpreadRadians));
+
+            // create the first projectile
+            LaserProjectile projectile = new LaserProjectile(owner,
+                direction);
+            projectile.Initialize();
+            owner.Projectiles.Add(projectile);
+
+            // create the second projectile
+            projectile = new LaserProjectile(owner, direction2);
+            projectile.Initialize();
+            owner.Projectiles.Add(projectile);
+
+            // create the third projectile
+            projectile = new LaserProjectile(owner, direction3);
+            projectile.Initialize();
+            owner.Projectiles.Add(projectile);
+        }
+
+
+        #endregion
+    }
+}

+ 137 - 0
Samples/Linux/NetRumble/Gameplay/Weapons/Weapon.cs

@@ -0,0 +1,137 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// Weapon.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// Base public class for all weapons that exist in the game.
+    /// </summary>
+    abstract public class Weapon
+    {
+        #region Gameplay Data
+
+
+        /// <summary>
+        /// The ship that owns this weapon.
+        /// </summary>
+        protected Ship owner = null;
+
+        /// <summary>
+        /// The amount of time remaining before this weapon can fire again.
+        /// </summary>
+        protected float timeToNextFire = 0f;
+
+        /// <summary>
+        /// The minimum amount of time between each firing of this weapon.
+        /// </summary>
+        protected float fireDelay = 0f;
+
+
+        #endregion
+
+
+        #region Audio Data
+
+
+        /// <summary>
+        /// The name of the sound effect played when this weapon fires.
+        /// </summary>
+        protected string fireSoundEffect = String.Empty;
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Constructs a new weapon.
+        /// </summary>
+        /// <param name="owner">The ship that owns this weapon.</param>
+        protected Weapon(Ship owner)
+        {
+            if (owner == null)
+            {
+                throw new ArgumentNullException("owner");
+            }
+            this.owner = owner;
+        }
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+
+        /// <summary>
+        /// Update the weapon.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        public virtual void Update(float elapsedTime)
+        {
+            // count down to when the weapon can fire again
+            if (timeToNextFire > 0f)
+            {
+                timeToNextFire = MathHelper.Max(timeToNextFire - elapsedTime, 0f);
+            }
+        }
+
+
+        #endregion
+
+
+        #region Interaction Methods
+
+
+        /// <summary>
+        /// Fire the weapon in the direction given.
+        /// </summary>
+        /// <param name="direction">The direction that the weapon is firing in.</param>
+        public virtual void Fire(Vector2 direction)
+        {
+            // if we can't fire yet, then we're done
+            if (timeToNextFire > 0f)
+            {
+                return;
+            }
+
+            // the owner is no longer safe from damage
+            owner.Safe = false;
+
+            // set the timer
+            timeToNextFire = fireDelay;
+
+            // create and spawn the projectile
+            CreateProjectiles(direction);
+
+            // play the sound effect for firing
+            if (String.IsNullOrEmpty(fireSoundEffect) == false)
+            {
+                AudioManager.PlaySoundEffect(fireSoundEffect);
+            }
+        }
+
+
+        /// <summary>
+        /// Create and spawn the projectile(s) from a firing from this weapon.
+        /// </summary>
+        /// <param name="direction">The direction that the projectile will move.</param>
+        protected abstract void CreateProjectiles(Vector2 direction);
+
+
+        #endregion
+    }
+}

+ 1412 - 0
Samples/Linux/NetRumble/Gameplay/World.cs

@@ -0,0 +1,1412 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// World.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.GamerServices;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using Microsoft.Xna.Framework.Net;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A container for the game-specific logic and code.
+    /// </summary>
+    public class World : IDisposable
+    {
+        #region Public Constants
+
+        /// <summary>
+        /// The maximum number of players in the game.
+        /// </summary>
+        public const int MaximumPlayers = 16;
+
+        /// <summary>
+        /// The different types of packets sent in the game.
+        /// </summary>
+        /// <remarks>Frequently used in packets to identify their type.</remarks>
+        public enum PacketTypes
+        {
+            PlayerData,
+            ShipData,
+            WorldSetup,
+            WorldData,
+            ShipInput,
+            PowerUpSpawn,
+            ShipDeath,
+            ShipSpawn,
+            GameWon,
+        };
+
+
+        #endregion
+
+
+        #region Constants
+
+
+        /// <summary>
+        /// The score required to win the game.
+        /// </summary>
+        const int winningScore = 5;
+
+        /// <summary>
+        /// The number of asteroids in the game.
+        /// </summary>
+        const int numberOfAsteroids = 15;
+
+        /// <summary>
+        /// The length of time it takes for another power-up to spawn.
+        /// </summary>
+        const float maximumPowerUpTimer = 10f;
+
+        /// <summary>
+        /// The size of all of the barriers in the game.
+        /// </summary>
+        const int barrierSize = 48;
+
+        /// <summary>
+        /// The number of updates between WorldData packets.
+        /// </summary>
+        const int updatesBetweenWorldDataSend = 30;
+
+        /// <summary>
+        /// The number of updates between ship status packets from this machine.
+        /// </summary>
+        const int updatesBetweenStatusPackets = MaximumPlayers;
+
+        /// <summary>
+        /// The number of barriers in each dimension.
+        /// </summary>
+        static readonly Point barrierCounts = new Point(50, 50);
+
+        /// <summary>
+        /// The dimensions of the game world.
+        /// </summary>
+        static readonly Rectangle dimensions = new Rectangle(0, 0, 
+            barrierCounts.X * barrierSize, barrierCounts.Y * barrierSize);
+
+
+        #endregion
+
+
+        #region State Data
+
+
+        /// <summary>
+        /// If true, the game has been initialized by receiving a WorldSetup packet.
+        /// </summary>
+        bool initialized = false;
+        public bool Initialized
+        {
+            get { return initialized; }
+        }
+        
+        /// <summary>
+        /// If true, the game is over, and somebody has won.
+        /// </summary>
+        private bool gameWon = false;
+        public bool GameWon
+        {
+            get { return gameWon; }
+            set { gameWon = value; }
+        }
+
+        /// <summary>
+        /// The index of the player who won the game.
+        /// </summary>
+        private int winnerIndex = -1;
+        public int WinnerIndex
+        {
+            get { return winnerIndex; }
+        }
+
+
+        /// <summary>
+        /// If true, the game is over, because the game ended before somebody won.
+        /// </summary>
+        /// <remarks></remarks>
+        private bool gameExited = false;
+        public bool GameExited
+        {
+            get { return gameExited; }
+            set { gameExited = value; }
+        }
+
+
+        // presence support
+        private List<int> highScorers = new List<int>();
+        public List<int> HighScorers
+        {
+            get { return highScorers; }
+        }
+
+        #endregion
+
+
+        #region Gameplay Data
+
+
+        /// <summary>
+        /// The number of asteroids in the game.
+        /// </summary>
+        Asteroid[] asteroids = new Asteroid[numberOfAsteroids];
+
+        /// <summary>
+        /// The current power-up in the game.
+        /// </summary>
+        PowerUp powerUp = null;
+
+        /// <summary>
+        /// The amount of time left until the next power-up spawns.
+        /// </summary>
+        float powerUpTimer = maximumPowerUpTimer / 2f;
+
+
+        #endregion
+
+
+        #region Graphics Data
+
+
+        /// <summary>
+        /// The sprite batch used to draw the objects in the world.
+        /// </summary>
+        private SpriteBatch spriteBatch;
+
+        /// <summary>
+        /// The corner-barrier texture.
+        /// </summary>
+        private Texture2D cornerBarrierTexture;
+
+        /// <summary>
+        /// The vertical-barrier texture.
+        /// </summary>
+        private Texture2D verticalBarrierTexture;
+
+        /// <summary>
+        /// The horizontal-barrier texture.
+        /// </summary>
+        private Texture2D horizontalBarrierTexture;
+
+        /// <summary>
+        /// The texture signifying that the player can chat.
+        /// </summary>
+        private Texture2D chatAbleTexture;
+
+        /// <summary>
+        /// The texture signifying that the player has been muted.
+        /// </summary>
+        private Texture2D chatMuteTexture;
+
+        /// <summary>
+        /// The texture signifying that the player is talking right now.
+        /// </summary>
+        private Texture2D chatTalkingTexture;
+
+        /// <summary>
+        /// The texture signifying that the player is ready
+        /// </summary>
+        private Texture2D readyTexture;
+
+        /// <summary>
+        /// The sprite used to draw the player names.
+        /// </summary>
+        private SpriteFont playerFont;
+        public SpriteFont PlayerFont
+        {
+            get { return playerFont; }
+        }
+        
+        /// <summary>
+        /// The list of corner barriers in the game world.
+        /// </summary>
+        /// <remarks>This list is not owned by this object.</remarks>
+        private List<Rectangle> cornerBarriers = new List<Rectangle>();
+
+        /// <summary>
+        /// The list of vertical barriers in the game world.
+        /// </summary>
+        /// <remarks>This list is not owned by this object.</remarks>
+        private List<Rectangle> verticalBarriers = new List<Rectangle>();
+
+        /// <summary>
+        /// The list of horizontal barriers in the game world.
+        /// </summary>
+        /// <remarks>This list is not owned by this object.</remarks>
+        private List<Rectangle> horizontalBarriers = new List<Rectangle>();
+
+        /// <summary>
+        /// The particle-effect manager for the game.
+        /// </summary>
+        ParticleEffectManager particleEffectManager;
+
+
+        #endregion
+
+
+        #region Networking Data
+
+
+        /// <summary>
+        /// The network session for the game.
+        /// </summary>
+        private NetworkSession networkSession;
+
+        /// <summary>
+        /// The packet writer for all of the data for the world.
+        /// </summary>
+        private PacketWriter packetWriter = new PacketWriter();
+
+        /// <summary>
+        /// The packet reader for all of the data for the world.
+        /// </summary>
+        private PacketReader packetReader = new PacketReader();
+
+        /// <summary>
+        /// The number of updates that have passed since the world data was sent.
+        /// </summary>
+        private int updatesSinceWorldDataSend = 0;
+
+        /// <summary>
+        /// The number of updates that have passed since a status packet was sent.
+        /// </summary>
+        private int updatesSinceStatusPacket = 0;
+
+
+        #endregion
+
+
+        #region Initialization
+
+
+        /// <summary>
+        /// Construct a new World object.
+        /// </summary>
+        /// <param name="graphicsDevice">The graphics device used for this game.</param>
+        /// <param name="networkSession">The network session for this game.</param>
+        public World(GraphicsDevice graphicsDevice, ContentManager contentManager, 
+            NetworkSession networkSession)
+        {
+            // safety-check the parameters, as they must be valid
+            if (graphicsDevice == null)
+            {
+                throw new ArgumentNullException("graphicsDevice");
+            }
+            if (contentManager == null)
+            {
+                throw new ArgumentNullException("contentManager");
+            }
+            if (networkSession == null)
+            {
+                throw new ArgumentNullException("networkSession");
+            }
+
+            // apply the parameter values
+            this.networkSession = networkSession;
+
+            // set up the staggered status packet system
+            // -- your first update happens based on where you are in the collection
+            for (int i = 0; i < networkSession.AllGamers.Count; i++)
+            {
+                if (networkSession.AllGamers[i].IsLocal)
+                {
+                    updatesSinceStatusPacket = i;
+                    break;
+                }
+            }
+
+            // create the spritebatch
+            spriteBatch = new SpriteBatch(graphicsDevice);
+
+            // create and initialize the particle-effect manager
+            particleEffectManager = new ParticleEffectManager(contentManager);
+            particleEffectManager.RegisterParticleEffect(
+                ParticleEffectType.LaserExplosion,
+                "Particles/laserExplosion.xml", 40);
+            particleEffectManager.RegisterParticleEffect(
+                ParticleEffectType.MineExplosion, 
+                "Particles/mineExplosion.xml", 8);
+            particleEffectManager.RegisterParticleEffect(
+                ParticleEffectType.RocketExplosion, 
+                "Particles/rocketExplosion.xml", 24);
+            particleEffectManager.RegisterParticleEffect(
+                ParticleEffectType.RocketTrail, 
+                "Particles/rocketTrail.xml", 16);
+            particleEffectManager.RegisterParticleEffect(
+                ParticleEffectType.ShipExplosion, 
+                "Particles/shipExplosion.xml", 4);
+            particleEffectManager.RegisterParticleEffect(
+                ParticleEffectType.ShipSpawn, 
+                "Particles/shipSpawn.xml", 4);
+            Ship.ParticleEffectManager = particleEffectManager;
+            RocketProjectile.ParticleEffectManager = particleEffectManager;
+            MineProjectile.ParticleEffectManager = particleEffectManager;
+            LaserProjectile.ParticleEffectManager = particleEffectManager;
+
+            // load the font
+            playerFont = contentManager.Load<SpriteFont>("Fonts/NetRumbleFont");
+
+            // load the gameplay-object textures
+            Ship.LoadContent(contentManager);
+            Asteroid.LoadContent(contentManager);
+            LaserProjectile.LoadContent(contentManager);
+            MineProjectile.LoadContent(contentManager);
+            RocketProjectile.LoadContent(contentManager);
+            DoubleLaserPowerUp.LoadContent(contentManager);
+            TripleLaserPowerUp.LoadContent(contentManager);
+            RocketPowerUp.LoadContent(contentManager);
+            
+            // load the non-gameplay-object textures
+            chatAbleTexture = contentManager.Load<Texture2D>("Textures/chatAble");
+            chatMuteTexture = contentManager.Load<Texture2D>("Textures/chatMute");
+            chatTalkingTexture = contentManager.Load<Texture2D>("Textures/chatTalking");
+            readyTexture = contentManager.Load<Texture2D>("Textures/ready");
+            cornerBarrierTexture = 
+                contentManager.Load<Texture2D>("Textures/barrierEnd");
+            verticalBarrierTexture = 
+                contentManager.Load<Texture2D>("Textures/barrierPurple");
+            horizontalBarrierTexture = 
+                contentManager.Load<Texture2D>("Textures/barrierRed");
+
+            // clear the collision manager
+            CollisionManager.Collection.Clear();
+
+            // add the collision version of the edge barriers
+            CollisionManager.Barriers.Clear();
+            CollisionManager.Barriers.Add(new Rectangle(dimensions.X, dimensions.Y, 
+                dimensions.Width, barrierSize));  // top edge
+            CollisionManager.Barriers.Add(new Rectangle(
+                dimensions.X, dimensions.Y + dimensions.Height, 
+                dimensions.Width, barrierSize));  // bottom edge
+            CollisionManager.Barriers.Add(new Rectangle(dimensions.X, dimensions.Y, 
+                barrierSize, dimensions.Height)); // left edge
+            CollisionManager.Barriers.Add(new Rectangle(
+                dimensions.X + dimensions.Width, dimensions.Y, 
+                barrierSize, dimensions.Height)); // right edge
+
+            // add the rendering version of the edge barriers
+            cornerBarriers.Clear();
+            cornerBarriers.Add(new Rectangle(dimensions.X, dimensions.Y, 
+                barrierSize, barrierSize)); // top-left corner
+            cornerBarriers.Add(new Rectangle(
+                dimensions.X + dimensions.Width, dimensions.Y, 
+                barrierSize, barrierSize)); // top-right corner
+            cornerBarriers.Add(new Rectangle(
+                dimensions.X, dimensions.Y + dimensions.Height, 
+                barrierSize, barrierSize)); // bottom-left corner
+            cornerBarriers.Add(new Rectangle(
+                dimensions.X + dimensions.Width, dimensions.Y + dimensions.Height, 
+                barrierSize, barrierSize)); // bottom-right corner
+            verticalBarriers.Clear();
+            for (int i = 1; i < barrierCounts.Y; i++)
+            {
+                verticalBarriers.Add(new Rectangle(
+                    dimensions.X, dimensions.Y + barrierSize * i, 
+                    barrierSize, barrierSize)); // top edge
+                verticalBarriers.Add(new Rectangle(
+                    dimensions.X + dimensions.Width, dimensions.Y + barrierSize * i,
+                    barrierSize, barrierSize)); // bottom edge
+            }
+            horizontalBarriers.Clear();
+            for (int i = 1; i < barrierCounts.X; i++)
+            {
+                horizontalBarriers.Add(new Rectangle(
+                    dimensions.X + barrierSize * i, dimensions.Y,
+                    barrierSize, barrierSize)); // left edge
+                horizontalBarriers.Add(new Rectangle(
+                    dimensions.X + barrierSize * i, dimensions.Y + dimensions.Width,
+                    barrierSize, barrierSize)); // right edge
+            }
+        }
+
+
+        /// <summary>
+        /// Generate the initial state of the game, and send it to everyone.
+        /// </summary>
+        public void GenerateWorld()
+        {
+            if ((networkSession != null) && (networkSession.LocalGamers.Count > 0))
+            {
+                // write the identification value
+                packetWriter.Write((int)PacketTypes.WorldSetup);
+
+                // place the ships
+                // -- we always write the maximum number of players, making the packet
+                //    predictable, in case the player count changes on the client before 
+                //    this packet is received
+                for (int i = 0; i < MaximumPlayers; i++)
+                {
+                    Vector2 position = Vector2.Zero;
+                    if (i < networkSession.AllGamers.Count)
+                    {
+                        PlayerData playerData = networkSession.AllGamers[i].Tag
+                            as PlayerData;
+                        if ((playerData != null) && (playerData.Ship != null))
+                        {
+                            playerData.Ship.Initialize();
+                            position = playerData.Ship.Position =
+                                CollisionManager.FindSpawnPoint(playerData.Ship,
+                                playerData.Ship.Radius * 5f);
+                            playerData.Ship.Score = 0;
+                        }
+                    }
+                    // write the ship position
+                    packetWriter.Write(position);
+                }
+
+                // place the asteroids
+                // -- for simplicity, the same number of asteroids is always the same
+                for (int i = 0; i < asteroids.Length; i++)
+                {
+                    // choose one of three radii
+                    float radius = 32f;
+                    switch (RandomMath.Random.Next(3))
+                    {
+                        case 0:
+                            radius = 32f;
+                            break;
+                        case 1:
+                            radius = 60f;
+                            break;
+                        case 2:
+                            radius = 96f;
+                            break;
+                    }
+                    // create the asteroid
+                    asteroids[i] = new Asteroid(radius);
+                    // write the radius
+                    packetWriter.Write(asteroids[i].Radius);
+                    // choose a variation
+                    asteroids[i].Variation = i % Asteroid.Variations;
+                    // write the variation
+                    packetWriter.Write(asteroids[i].Variation);
+                    // initialize the asteroid and it's starting position
+                    asteroids[i].Initialize();
+                    asteroids[i].Position =
+                        CollisionManager.FindSpawnPoint(asteroids[i], 
+                        asteroids[i].Radius);
+                    // write the starting position and velocity
+                    packetWriter.Write(asteroids[i].Position);
+                    packetWriter.Write(asteroids[i].Velocity);
+                }
+
+                // send the packet to everyone
+                networkSession.LocalGamers[0].SendData(packetWriter,
+                    SendDataOptions.ReliableInOrder);
+            }
+        }
+
+
+        /// <summary>
+        /// Initialize the world with the data from the WorldSetup packet.
+        /// </summary>
+        /// <param name="packetReader">The packet reader with the world data.</param>
+        public void Initialize()
+        {
+            // reset the game status
+            gameWon = false;
+            winnerIndex = -1;
+            gameExited = false;
+
+            // initialize the ships with the data from the packet
+            for (int i = 0; i < MaximumPlayers; i++)
+            {
+                // read each of the positions
+                Vector2 position = packetReader.ReadVector2();
+                // use the position value if we know of that many players
+                if (i < networkSession.AllGamers.Count)
+                {
+                    PlayerData playerData = networkSession.AllGamers[i].Tag 
+                        as PlayerData;
+                    if ((playerData != null) && (playerData.Ship != null))
+                    {
+                        // initialize the ship with the provided position
+                        playerData.Ship.Position = position;
+                        playerData.Ship.Score = 0;
+                        playerData.Ship.Initialize();
+                    }
+                }
+            }
+
+            // initialize the ships with the data from the packet
+            for (int i = 0; i < asteroids.Length; i++)
+            {
+                float radius = packetReader.ReadSingle();
+                if (asteroids[i] == null)
+                {
+                    asteroids[i] = new Asteroid(radius);
+                }
+                asteroids[i].Variation = packetReader.ReadInt32();
+                asteroids[i].Position = packetReader.ReadVector2();
+                asteroids[i].Initialize();
+                asteroids[i].Velocity = packetReader.ReadVector2();
+            }
+
+            // set the initialized state
+            initialized = true;
+        }
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+
+        /// <summary>
+        /// Update the world.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        /// <param name="paused">If true, the game is paused.</param>
+        public void Update(float elapsedTime, bool paused)
+        {
+            if (gameWon)
+            {
+                // update the particle-effect manager
+                particleEffectManager.Update(elapsedTime);
+
+                // make sure the collision manager is empty
+                CollisionManager.Collection.ApplyPendingRemovals();
+                if (CollisionManager.Collection.Count > 0)
+                {
+                    CollisionManager.Collection.Clear();
+                }
+            }
+            else
+            {
+                // process all incoming packets
+                ProcessPackets();
+
+                // if the game is in progress, update the state of it
+                if (initialized && (networkSession != null) &&
+                    (networkSession.SessionState == NetworkSessionState.Playing))
+                {
+                    // presence support
+                    int highScore = int.MinValue;
+                    int highScoreIndex = -1;
+                    for (int i = 0; i < networkSession.AllGamers.Count; i++)
+                    {
+                        NetworkGamer networkGamer = networkSession.AllGamers[i];
+                        PlayerData playerData = networkGamer.Tag as PlayerData;
+                        if ((playerData != null) && (playerData.Ship != null))
+                        {
+                            int playerScore = playerData.Ship.Score;
+                            if (playerScore == highScore)
+                            {
+                                highScorers.Add(i);
+                            }
+                            else if (playerScore > highScore)
+                            {
+                                highScorers.Clear();
+                                highScorers.Add(i);
+                                highScore = playerScore;
+                                highScoreIndex = i;
+                            }
+                        }
+                    }
+
+                    // the host has singular responsibilities to the game world, 
+                    // that need to be done once, by one authority
+                    if (networkSession.IsHost)
+                    {
+                        // get the local player, for frequent re-use
+                        LocalNetworkGamer localGamer = networkSession.Host
+                            as LocalNetworkGamer;
+
+                        // check for victory
+                        // if victory has been achieved, send a packet to everyone
+                        if (highScore >= winningScore)
+                        {
+                            packetWriter.Write((int)PacketTypes.GameWon);
+                            packetWriter.Write(highScoreIndex);
+                            localGamer.SendData(packetWriter, 
+                                SendDataOptions.ReliableInOrder);
+                        }
+
+                        // respawn each player, if it is time to do so
+                        for (int i = 0; i < networkSession.AllGamers.Count; i++)
+                        {
+                            NetworkGamer networkGamer = networkSession.AllGamers[i];
+                            PlayerData playerData = networkGamer.Tag as PlayerData;
+                            if ((playerData != null) && (playerData.Ship != null) &&
+                                !playerData.Ship.Active &&
+                                (playerData.Ship.RespawnTimer <= 0f))
+                            {
+                                // write the ship-spawn packet
+                                packetWriter.Write((int)PacketTypes.ShipSpawn);
+                                packetWriter.Write(i);
+                                packetWriter.Write(CollisionManager.FindSpawnPoint(
+                                    playerData.Ship, playerData.Ship.Radius));
+                                localGamer.SendData(packetWriter,
+                                    SendDataOptions.ReliableInOrder);
+                            }
+
+                        }
+
+                        // respawn the power-up if it is time to do so
+                        if (powerUp == null)
+                        {
+                            powerUpTimer -= elapsedTime;
+                            if (powerUpTimer < 0)
+                            {
+                                // write the power-up-spawn packet
+                                packetWriter.Write((int)PacketTypes.PowerUpSpawn);
+                                packetWriter.Write(RandomMath.Random.Next(3));
+                                packetWriter.Write(CollisionManager.FindSpawnPoint(null,
+                                    PowerUp.PowerUpRadius * 3f));
+                                localGamer.SendData(packetWriter, 
+                                    SendDataOptions.ReliableInOrder);
+                            }
+                        }
+                        else
+                        {
+                            powerUpTimer = maximumPowerUpTimer;
+                        }
+
+                        // send everyone an update on the state of the world
+                        if (updatesSinceWorldDataSend >= updatesBetweenWorldDataSend)
+                        {
+                            packetWriter.Write((int)PacketTypes.WorldData);
+                            // write each of the asteroids
+                            for (int i = 0; i < asteroids.Length; i++)
+                            {
+                                packetWriter.Write(asteroids[i].Position);
+                                packetWriter.Write(asteroids[i].Velocity);
+                            }
+                            localGamer.SendData(packetWriter,
+                                SendDataOptions.InOrder);
+                            updatesSinceWorldDataSend = 0;
+                        }
+                        else
+                        {
+                            updatesSinceWorldDataSend++;
+                        }
+                    }
+
+                    // update each asteroid
+                    foreach (Asteroid asteroid in asteroids)
+                    {
+                        if (asteroid.Active)
+                        {
+                            asteroid.Update(elapsedTime);
+                        }
+                    }
+
+                    // update the power-up
+                    if (powerUp != null)
+                    {
+                        if (powerUp.Active)
+                        {
+                            powerUp.Update(elapsedTime);
+                        }
+                        else
+                        {
+                            powerUp = null;
+                        }
+                    }
+
+                    // process the local player's input
+                    if (!paused)
+                    {
+                        ProcessLocalPlayerInput();
+                    }
+
+                    // update each ship
+                    foreach (NetworkGamer networkGamer in networkSession.AllGamers)
+                    {
+                        PlayerData playerData = networkGamer.Tag as PlayerData;
+                        if ((playerData != null) && (playerData.Ship != null))
+                        {
+                            if (playerData.Ship.Active)
+                            {
+                                playerData.Ship.Update(elapsedTime);
+                                // check for death 
+                                // -- only check on local machines - the local player is
+                                //    the authority on the death of their own ship
+                                if (networkGamer.IsLocal && (playerData.Ship.Life < 0))
+                                {
+                                    SendLocalShipDeath();
+                                }
+                            }
+                            else if (playerData.Ship.RespawnTimer > 0f)
+                            {
+                                playerData.Ship.RespawnTimer -= elapsedTime;
+                                if (playerData.Ship.RespawnTimer < 0f)
+                                {
+                                    playerData.Ship.RespawnTimer = 0f;
+                                }
+                            }
+                        }
+                    }
+
+                    // update the other players with the current state of the local ship
+                    if (updatesSinceStatusPacket >= updatesBetweenStatusPackets)
+                    {
+                        updatesSinceStatusPacket = 0;
+                        SendLocalShipData();
+                    }
+                    else
+                    {
+                        updatesSinceStatusPacket++;
+                    }
+
+                    // update the collision manager
+                    CollisionManager.Update(elapsedTime);
+
+                    // update the particle-effect manager
+                    particleEffectManager.Update(elapsedTime);
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Process the local player's input.
+        /// </summary>
+        private void ProcessLocalPlayerInput()
+        {
+            if ((networkSession != null) && (networkSession.LocalGamers.Count > 0))
+            {
+                // create the new input structure
+                ShipInput shipInput = new ShipInput(
+                    GamePad.GetState(
+                       networkSession.LocalGamers[0].SignedInGamer.PlayerIndex),
+                    Keyboard.GetState(
+                       networkSession.LocalGamers[0].SignedInGamer.PlayerIndex));
+
+                // send it out
+                // -- the local machine will receive and apply it from the network just
+                //    like the other clients
+                shipInput.Serialize(packetWriter);
+                networkSession.LocalGamers[0].SendData(packetWriter,
+                    SendDataOptions.InOrder);
+            }
+        }
+
+
+        /// <summary>
+        /// Send the current state of the ship to the other players.
+        /// </summary>
+        private void SendLocalShipData()
+        {
+            if ((networkSession != null) && (networkSession.LocalGamers.Count > 0))
+            {
+                PlayerData playerData = networkSession.LocalGamers[0].Tag as PlayerData;
+                if ((playerData != null) && (playerData.Ship != null))
+                {
+                    packetWriter.Write((int)World.PacketTypes.ShipData);
+                    packetWriter.Write(playerData.Ship.Position);
+                    packetWriter.Write(playerData.Ship.Velocity);
+                    packetWriter.Write(playerData.Ship.Rotation);
+                    packetWriter.Write(playerData.Ship.Life);
+                    packetWriter.Write(playerData.Ship.Shield);
+                    packetWriter.Write(playerData.Ship.Score);
+                    networkSession.LocalGamers[0].SendData(packetWriter,
+                        SendDataOptions.InOrder);
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Send a notification of the death of the local ship to the other players.
+        /// </summary>
+        private void SendLocalShipDeath()
+        {
+            if ((networkSession != null) && (networkSession.LocalGamers.Count > 0))
+            {
+                LocalNetworkGamer localNetworkGamer = networkSession.LocalGamers[0]
+                    as LocalNetworkGamer;
+                PlayerData playerData = localNetworkGamer.Tag as PlayerData;
+                if ((playerData != null) && (playerData.Ship != null))
+                {
+                    // send a ship-death notification
+                    packetWriter.Write((int)PacketTypes.ShipDeath);
+                    // determine the player behind the last damage taken
+                    int lastDamagedByPlayer = -1;
+                    Ship lastDamagedByShip = playerData.Ship.LastDamagedBy as Ship;
+                    if ((lastDamagedByShip != null) &&
+                        (lastDamagedByShip != playerData.Ship))
+                    {
+                        for (int i = 0; i < networkSession.AllGamers.Count; i++)
+                        {
+                            PlayerData sourcePlayerData =
+                                networkSession.AllGamers[i].Tag as PlayerData;
+                            if ((sourcePlayerData != null) &&
+                                (sourcePlayerData.Ship != null) &&
+                                (sourcePlayerData.Ship == lastDamagedByShip))
+                            {
+                                lastDamagedByPlayer = i;
+                                break;
+                            }
+                        }
+                    }
+                    packetWriter.Write(lastDamagedByPlayer);
+                    localNetworkGamer.SendData(packetWriter,
+                        SendDataOptions.ReliableInOrder);
+                }
+            }
+        }
+
+
+        #endregion
+
+
+        #region Packet Handling Methods
+
+
+        /// <summary>
+        /// Process incoming packets on the local gamer.
+        /// </summary>
+        private void ProcessPackets()
+        {
+            if ((networkSession != null) && (networkSession.LocalGamers.Count > 0))
+            {
+                // process all packets found, every frame
+                while (networkSession.LocalGamers[0].IsDataAvailable)
+                {
+                    NetworkGamer sender;
+                    networkSession.LocalGamers[0].ReceiveData(packetReader, out sender);
+                    // read the type of packet...
+                    PacketTypes packetType = (PacketTypes)packetReader.ReadInt32();
+                    // ... and dispatch appropriately
+                    switch (packetType)
+                    {
+                        case PacketTypes.PlayerData:
+                            UpdatePlayerData(sender);
+                            break;
+
+                        case PacketTypes.WorldSetup:
+                            // apply the world setup data, but only once
+                            if (!Initialized)
+                            {
+                                Initialize();
+                            }
+                            break;
+                            
+                        case PacketTypes.ShipData:
+                            if ((sender != null) && !sender.IsLocal)
+                            {
+                                UpdateShipData(sender);
+                            }
+                            break;
+
+                        case PacketTypes.WorldData:
+                            if (!networkSession.IsHost && Initialized)
+                            {
+                                UpdateWorldData();
+                            }
+                            break;
+
+                        case PacketTypes.ShipInput:
+                            if (sender != null)
+                            {
+                                PlayerData playerData = sender.Tag as PlayerData;
+                                if ((playerData != null) && (playerData.Ship != null))
+                                {
+                                    playerData.Ship.ShipInput = 
+                                        new ShipInput(packetReader);
+                                }
+                            }
+                            break;
+
+                        case PacketTypes.ShipSpawn:
+                            SpawnShip();
+                            break;
+
+                        case PacketTypes.PowerUpSpawn:
+                            SpawnPowerup();
+                            break;
+
+                        case PacketTypes.ShipDeath:
+                            KillShip(sender);
+                            break;
+
+                        case PacketTypes.GameWon:
+                            gameWon = true;
+                            winnerIndex = packetReader.ReadInt32();
+                            if (networkSession.IsHost && (networkSession.SessionState ==
+                                NetworkSessionState.Playing))
+                            {
+                                networkSession.EndGame();
+                            }
+                            break;
+                    }
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Spawn a ship based on the data in the packet.
+        /// </summary>
+        private void SpawnShip()
+        {
+            int whichGamer = packetReader.ReadInt32();
+            if (whichGamer < networkSession.AllGamers.Count)
+            {
+                NetworkGamer networkGamer = networkSession.AllGamers[whichGamer];
+                PlayerData playerData = networkGamer.Tag as PlayerData;
+                if ((playerData != null) && (playerData.Ship != null))
+                {
+                    playerData.Ship.Position = packetReader.ReadVector2();
+                    playerData.Ship.Initialize();
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Spawn a power-up based on the data in the packet.
+        /// </summary>
+        private void SpawnPowerup()
+        {
+            int whichPowerUp = packetReader.ReadInt32();
+            if (powerUp == null)
+            {
+                switch (whichPowerUp)
+                {
+                    case 0:
+                        powerUp = new DoubleLaserPowerUp();
+                        break;
+                    case 1:
+                        powerUp = new TripleLaserPowerUp();
+                        break;
+                    case 2:
+                        powerUp = new RocketPowerUp();
+                        break;
+                }
+            }
+            if (powerUp != null)
+            {
+                powerUp.Position = packetReader.ReadVector2();
+                powerUp.Initialize();
+            }
+        }
+
+
+        /// <summary>
+        /// Kill the sender's ship based on data in the packet.
+        /// </summary>
+        /// <param name="sender">The sender of the packet.</param>
+        private void KillShip(NetworkGamer sender)
+        {
+            if (sender != null)
+            {
+                PlayerData playerData = sender.Tag as PlayerData;
+                if ((playerData != null) && (playerData.Ship != null) &&
+                    playerData.Ship.Active)
+                {
+                    GameplayObject source = null;
+                    // read the index of the source of the last damage taken
+                    int sourcePlayerIndex = packetReader.ReadInt32();
+                    if ((sourcePlayerIndex >= 0) &&
+                        (sourcePlayerIndex < networkSession.AllGamers.Count))
+                    {
+                        PlayerData sourcePlayerData =
+                            networkSession.AllGamers[sourcePlayerIndex].Tag 
+                            as PlayerData;
+                        source = sourcePlayerData != null ? sourcePlayerData.Ship : 
+                            null;
+                    }
+                    // kill the ship
+                    playerData.Ship.Die(source, false);
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Update the player data for the sender based on the data in the packet.
+        /// </summary>
+        /// <param name="sender">The sender of the packet.</param>
+        private void UpdatePlayerData(NetworkGamer sender)
+        {
+            if ((networkSession != null) && (networkSession.LocalGamers.Count > 0) && 
+                (sender != null))
+            {
+                PlayerData playerData = sender.Tag as PlayerData;
+                if (playerData != null)
+                {
+                    playerData.Deserialize(packetReader);
+                    // see if we're still unique
+                    // -- this can happen legitimately as we receive introductory data
+                    foreach (LocalNetworkGamer localNetworkGamer in
+                        networkSession.LocalGamers)
+                    {
+                        PlayerData localPlayerData =
+                            localNetworkGamer.Tag as PlayerData;
+                        if ((localPlayerData != null) && 
+                            !Ship.HasUniqueColorIndex(localNetworkGamer,
+                               networkSession))
+                        {
+                            localPlayerData.ShipColor = Ship.GetNextUniqueColorIndex(
+                                localPlayerData.ShipColor, networkSession);
+                            packetWriter.Write((int)World.PacketTypes.PlayerData);
+                            localPlayerData.Serialize(packetWriter);
+                            networkSession.LocalGamers[0].SendData(packetWriter, 
+                                SendDataOptions.ReliableInOrder);
+                        }
+                    }
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Update ship state based on the data in the packet.
+        /// </summary>
+        /// <param name="sender">The sender of the packet.</param>
+        private void UpdateShipData(NetworkGamer sender)
+        {
+            if (sender != null)
+            {
+                PlayerData playerData = sender.Tag as PlayerData;
+                if ((playerData != null) && (playerData.Ship != null))
+                {
+                    playerData.Ship.Position = packetReader.ReadVector2();
+                    playerData.Ship.Velocity = packetReader.ReadVector2();
+                    playerData.Ship.Rotation = packetReader.ReadSingle();
+                    playerData.Ship.Life = packetReader.ReadSingle();
+                    playerData.Ship.Shield = packetReader.ReadSingle();
+                    playerData.Ship.Score = packetReader.ReadInt32();
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Update the world data based on the data in the packet.
+        /// </summary>
+        private void UpdateWorldData()
+        {
+            // safety-check the parameters, as they must be valid
+            if (packetReader == null)
+            {
+                throw new ArgumentNullException("packetReader");
+            }
+
+            for (int i = 0; i < asteroids.Length; i++)
+            {
+                asteroids[i].Position = packetReader.ReadVector2();
+                asteroids[i].Velocity = packetReader.ReadVector2();
+            }
+        }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draws the objects in the world.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        /// <param name="center">The center of the current view.</param>
+        public void Draw(float elapsedTime, Vector2 center)
+        {
+            Matrix transform = Matrix.CreateTranslation(
+                new Vector3(-center.X, -center.Y, 0f));
+
+            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, 
+                null, null, null, null, transform);
+
+            // draw the barriers
+            foreach (Rectangle rectangle in cornerBarriers)
+            {
+                spriteBatch.Draw(cornerBarrierTexture, rectangle, Color.White);
+            }
+            foreach (Rectangle rectangle in verticalBarriers)
+            {
+                spriteBatch.Draw(verticalBarrierTexture, rectangle, Color.White);
+            }
+            foreach (Rectangle rectangle in horizontalBarriers)
+            {
+                spriteBatch.Draw(horizontalBarrierTexture, rectangle, Color.White);
+            }
+            
+            // draw the asteroids
+            foreach (Asteroid asteroid in asteroids)
+            {
+                if (asteroid.Active)
+                {
+                    asteroid.Draw(elapsedTime, spriteBatch);
+                }
+            }
+
+            // draw the powerup
+            if ((powerUp != null) && powerUp.Active)
+            {
+                powerUp.Draw(elapsedTime, spriteBatch);
+            }
+
+            // draw the ships
+            foreach (NetworkGamer networkGamer in networkSession.AllGamers)
+            {
+                PlayerData playerData = networkGamer.Tag as PlayerData;
+                if ((playerData != null) && (playerData.Ship != null) && 
+                    playerData.Ship.Active)
+                {
+                    playerData.Ship.Draw(elapsedTime, spriteBatch);
+                }
+            }
+
+            // draw the alpha-blended particles
+            particleEffectManager.Draw(spriteBatch, SpriteBlendMode.AlphaBlend);
+
+            spriteBatch.End();
+
+            // draw the additive particles
+            spriteBatch.Begin(SpriteSortMode.Texture, BlendState.Additive, 
+                null, null, null, null, transform);
+
+            particleEffectManager.Draw(spriteBatch, SpriteBlendMode.Additive);
+
+            spriteBatch.End();
+        }
+
+
+        /// <summary>
+        /// Draw the specified player's data in the screen - gamertag, etc.
+        /// </summary>
+        /// <param name="totalTime">The total time spent in the game.</param>
+        /// <param name="networkGamer">The player to be drawn.</param>
+        /// <param name="position">The center of the desired location.</param>
+        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
+        /// <param name="lobby">If true, drawn "lobby style"</param>
+        public void DrawPlayerData(float totalTime, NetworkGamer networkGamer, 
+            Vector2 position, SpriteBatch spriteBatch, bool lobby)
+        {
+            // safety-check the parameters, as they must be valid
+            if (networkGamer == null)
+            {
+                throw new ArgumentNullException("networkGamer");
+            }
+            if (spriteBatch == null)
+            {
+                throw new ArgumentNullException("spriteBatch");
+            }
+
+            // get the player data
+            PlayerData playerData = networkGamer.Tag as PlayerData;
+            if (playerData == null)
+            {
+                return;
+            }
+
+            // draw the gamertag
+            float playerStringScale = 1.0f;
+            if (networkGamer.IsLocal)
+            {
+                // pulse the scale of local gamers
+                playerStringScale = 1f + 0.08f * (1f + (float)Math.Sin(totalTime * 4f));
+            }
+            string playerString = networkGamer.Gamertag;
+            Color playerColor = playerData.Ship == null ? 
+                Ship.ShipColors[playerData.ShipColor] : playerData.Ship.Color;
+            Vector2 playerStringSize = playerFont.MeasureString(playerString);
+            Vector2 playerStringPosition = position;
+            spriteBatch.DrawString(playerFont, playerString, playerStringPosition,
+                playerColor, 0f, 
+                new Vector2(playerStringSize.X / 2f, playerStringSize.Y / 2f), 
+                playerStringScale, SpriteEffects.None, 0f);
+
+            // draw the chat texture
+            Texture2D chatTexture = null;
+            if (networkGamer.IsMutedByLocalUser)
+            {
+                chatTexture = chatMuteTexture;
+            }
+            else if (networkGamer.IsTalking)
+            {
+                chatTexture = chatTalkingTexture;
+            }
+            else if (networkGamer.HasVoice)
+            {
+                chatTexture = chatAbleTexture;
+            }
+            if (chatTexture != null)
+            {
+                float chatTextureScale = 0.9f * playerStringSize.Y / 
+                    (float)chatTexture.Height;
+                Vector2 chatTexturePosition = new Vector2(playerStringPosition.X - 
+                    1.2f * playerStringSize.X / 2f -
+                    1.1f * chatTextureScale * (float)chatTexture.Width / 2f,
+                    playerStringPosition.Y);
+                spriteBatch.Draw(chatTexture, chatTexturePosition, null,
+                    Color.White, 0f, new Vector2((float)chatTexture.Width / 2f, 
+                    (float)chatTexture.Height / 2f), chatTextureScale, 
+                    SpriteEffects.None, 0f);
+            }
+
+            // if we're in "lobby mode", draw a sample version of the ship,
+            // and the ready texture
+            if (lobby)
+            {
+                // draw the ship
+                if (playerData.Ship != null)
+                {
+                    float oldShipShield = playerData.Ship.Shield;
+                    float oldShipRadius = playerData.Ship.Radius;
+                    Vector2 oldShipPosition = playerData.Ship.Position;
+                    float oldShipRotation = playerData.Ship.Rotation;
+                    playerData.Ship.Shield = 0f;
+                    playerData.Ship.Radius = 0.6f * (float)playerStringSize.Y;
+                    playerData.Ship.Position = new Vector2(playerStringPosition.X +
+                        1.2f * playerStringSize.X / 2f + 1.1f * playerData.Ship.Radius,
+                        playerStringPosition.Y);
+                    playerData.Ship.Rotation = 0f;
+                    playerData.Ship.Draw(0f, spriteBatch);
+                    playerData.Ship.Rotation = oldShipRotation;
+                    playerData.Ship.Position = oldShipPosition;
+                    playerData.Ship.Shield = oldShipShield;
+                    playerData.Ship.Radius = oldShipRadius;
+                }
+                
+                // draw the ready texture
+                if ((readyTexture != null) && networkGamer.IsReady)
+                {
+                    float readyTextureScale = 0.9f * playerStringSize.Y / 
+                        (float)readyTexture.Height;
+                    Vector2 readyTexturePosition = new Vector2(playerStringPosition.X +
+                        1.2f * playerStringSize.X / 2f + 
+                        2.2f * playerData.Ship.Radius + 
+                        1.1f * readyTextureScale * (float)readyTexture.Width / 2f,
+                        playerStringPosition.Y);
+                    spriteBatch.Draw(readyTexture, readyTexturePosition, null,
+                        Color.White, 0f, new Vector2((float)readyTexture.Width / 2f, 
+                        (float)readyTexture.Height / 2f), readyTextureScale,
+                        SpriteEffects.None, 0f);
+                }
+
+            }
+            else
+            {
+                // if we're not in "lobby mode", draw the score
+                if (playerData.Ship != null)
+                {
+                    string scoreString = String.Empty;
+                    if (playerData.Ship.Active)
+                    {
+                        scoreString = playerData.Ship.Score.ToString();
+                    }
+                    else
+                    {
+                        int respawnTimer = 
+                            (int)Math.Ceiling(playerData.Ship.RespawnTimer);
+                        scoreString = "Respawning in: " + respawnTimer.ToString();
+                    }
+                    Vector2 scoreStringSize = playerFont.MeasureString(scoreString);
+                    Vector2 scoreStringPosition = new Vector2(position.X,
+                        position.Y + 0.9f * playerStringSize.Y);
+                    spriteBatch.DrawString(playerFont, scoreString, scoreStringPosition,
+                        playerColor, 0f, new Vector2(scoreStringSize.X / 2f, 
+                        scoreStringSize.Y / 2f), 1f, SpriteEffects.None, 0f);
+                }
+            }
+        }
+
+
+        #endregion
+
+
+        #region IDisposable Implementation
+
+
+        /// <summary>
+        /// Finalizes the World object, calls Dispose(false)
+        /// </summary>
+        ~World()
+        {
+            Dispose(false);
+        }
+
+
+        /// <summary>
+        /// Disposes the World object.
+        /// </summary>
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        
+        /// <summary>
+        /// Disposes this object.
+        /// </summary>
+        /// <param name="disposing">
+        /// True if this method was called as part of the Dispose method.
+        /// </param>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                lock (this)
+                {
+                    if (packetReader != null)
+                    {
+                        packetReader.Close();
+                        packetReader = null;
+                    }
+
+                    if (packetWriter != null)
+                    {
+                        packetWriter.Close();
+                        packetWriter = null;
+                    }
+
+                    if (spriteBatch != null)
+                    {
+                        spriteBatch.Dispose();
+                        spriteBatch = null;
+                    }
+
+                    cornerBarrierTexture = null;
+                    verticalBarrierTexture = null;
+                    horizontalBarrierTexture = null;
+
+                    Ship.UnloadContent();
+                    Asteroid.UnloadContent();
+                    LaserProjectile.UnloadContent();
+                    MineProjectile.UnloadContent();
+                    RocketProjectile.UnloadContent();
+                    DoubleLaserPowerUp.UnloadContent();
+                    TripleLaserPowerUp.UnloadContent();
+
+                    Ship.ParticleEffectManager = null;
+                    RocketProjectile.ParticleEffectManager = null;
+                    MineProjectile.ParticleEffectManager = null;
+                    LaserProjectile.ParticleEffectManager = null;
+                    particleEffectManager.UnregisterParticleEffect(
+                        ParticleEffectType.MineExplosion);
+                    particleEffectManager.UnregisterParticleEffect(
+                        ParticleEffectType.RocketExplosion);
+                    particleEffectManager.UnregisterParticleEffect(
+                        ParticleEffectType.RocketTrail);
+                    particleEffectManager.UnregisterParticleEffect(
+                        ParticleEffectType.ShipExplosion);
+                    particleEffectManager.UnregisterParticleEffect(
+                        ParticleEffectType.ShipSpawn);
+                }
+            }
+        }
+
+
+        #endregion
+    }
+}

+ 602 - 0
Samples/Linux/NetRumble/MonoGame.Samples.NetRumble.Linux.csproj

@@ -0,0 +1,602 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{52735207-2136-433B-A3E4-4C082728EED8}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>NetRumble</RootNamespace>
+    <AssemblyName>NetRumble</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG LINUX</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <DebugType>none</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Drawing" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\MacOS\NetRumble\Info.plist">
+      <Link>Info.plist</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\GameThumbnail.png">
+      <Link>GameThumbnail.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Game.ico">
+      <Link>Game.ico</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\One Step Beyond.xnb">
+      <Link>Content\One Step Beyond.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\One Step Beyond.wma">
+      <Link>Content\One Step Beyond.wma</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\title.xnb">
+      <Link>Content\Textures\title.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\title.png">
+      <Link>Content\Textures\title.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\shipShields.xnb">
+      <Link>Content\Textures\shipShields.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\shipShields.png">
+      <Link>Content\Textures\shipShields.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ship3Overlay.xnb">
+      <Link>Content\Textures\ship3Overlay.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ship3Overlay.png">
+      <Link>Content\Textures\ship3Overlay.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ship3.xnb">
+      <Link>Content\Textures\ship3.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ship3.png">
+      <Link>Content\Textures\ship3.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ship2Overlay.xnb">
+      <Link>Content\Textures\ship2Overlay.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ship2Overlay.png">
+      <Link>Content\Textures\ship2Overlay.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ship2.xnb">
+      <Link>Content\Textures\ship2.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ship2.png">
+      <Link>Content\Textures\ship2.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ship1Overlay.xnb">
+      <Link>Content\Textures\ship1Overlay.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ship1Overlay.png">
+      <Link>Content\Textures\ship1Overlay.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ship1.xnb">
+      <Link>Content\Textures\ship1.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ship1.png">
+      <Link>Content\Textures\ship1.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ship0Overlay.xnb">
+      <Link>Content\Textures\ship0Overlay.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ship0Overlay.png">
+      <Link>Content\Textures\ship0Overlay.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ship0.xnb">
+      <Link>Content\Textures\ship0.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ship0.png">
+      <Link>Content\Textures\ship0.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\rocket.xnb">
+      <Link>Content\Textures\rocket.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\rocket.png">
+      <Link>Content\Textures\rocket.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ready.xnb">
+      <Link>Content\Textures\ready.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\ready.png">
+      <Link>Content\Textures\ready.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\powerupTripleLaser.xnb">
+      <Link>Content\Textures\powerupTripleLaser.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\powerupTripleLaser.png">
+      <Link>Content\Textures\powerupTripleLaser.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\powerupRocket.xnb">
+      <Link>Content\Textures\powerupRocket.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\powerupRocket.png">
+      <Link>Content\Textures\powerupRocket.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\powerupDoubleLaser.xnb">
+      <Link>Content\Textures\powerupDoubleLaser.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\powerupDoubleLaser.png">
+      <Link>Content\Textures\powerupDoubleLaser.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\mine.xnb">
+      <Link>Content\Textures\mine.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\mine.png">
+      <Link>Content\Textures\mine.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\laser.xnb">
+      <Link>Content\Textures\laser.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\laser.png">
+      <Link>Content\Textures\laser.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\explosion.xnb">
+      <Link>Content\Textures\explosion.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\explosion.png">
+      <Link>Content\Textures\explosion.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\clouds.xnb">
+      <Link>Content\Textures\clouds.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\clouds.png">
+      <Link>Content\Textures\clouds.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\chatTalking.xnb">
+      <Link>Content\Textures\chatTalking.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\chatTalking.png">
+      <Link>Content\Textures\chatTalking.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\chatMute.xnb">
+      <Link>Content\Textures\chatMute.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\chatMute.png">
+      <Link>Content\Textures\chatMute.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\chatAble.xnb">
+      <Link>Content\Textures\chatAble.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\chatAble.png">
+      <Link>Content\Textures\chatAble.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\blank.xnb">
+      <Link>Content\Textures\blank.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\blank.png">
+      <Link>Content\Textures\blank.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\barrierRed.xnb">
+      <Link>Content\Textures\barrierRed.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\barrierRed.png">
+      <Link>Content\Textures\barrierRed.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\barrierPurple.xnb">
+      <Link>Content\Textures\barrierPurple.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\barrierPurple.png">
+      <Link>Content\Textures\barrierPurple.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\barrierEnd.xnb">
+      <Link>Content\Textures\barrierEnd.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\barrierEnd.png">
+      <Link>Content\Textures\barrierEnd.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\asteroid2.xnb">
+      <Link>Content\Textures\asteroid2.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\asteroid2.png">
+      <Link>Content\Textures\asteroid2.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\asteroid1.xnb">
+      <Link>Content\Textures\asteroid1.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\asteroid1.png">
+      <Link>Content\Textures\asteroid1.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\asteroid0.xnb">
+      <Link>Content\Textures\asteroid0.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\asteroid0.png">
+      <Link>Content\Textures\asteroid0.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\Particles\defaultParticle.PNG">
+      <Link>Content\Textures\Particles\defaultParticle.PNG</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\Particles\defaultParticle.xnb">
+      <Link>Content\Textures\Particles\defaultParticle.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\Particles\particle.png">
+      <Link>Content\Textures\Particles\particle.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\Particles\particle.xnb">
+      <Link>Content\Textures\Particles\particle.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\Particles\smoke.png">
+      <Link>Content\Textures\Particles\smoke.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\Particles\smoke.xnb">
+      <Link>Content\Textures\Particles\smoke.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\Particles\spark.png">
+      <Link>Content\Textures\Particles\spark.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Textures\Particles\spark.xnb">
+      <Link>Content\Textures\Particles\spark.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Particles\laserExplosion.xml">
+      <Link>Content\Particles\laserExplosion.xml</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Particles\mineExplosion.xml">
+      <Link>Content\Particles\mineExplosion.xml</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Particles\rocketExplosion.xml">
+      <Link>Content\Particles\rocketExplosion.xml</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Particles\rocketTrail.xml">
+      <Link>Content\Particles\rocketTrail.xml</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Particles\shipExplosion.xml">
+      <Link>Content\Particles\shipExplosion.xml</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Particles\shipSpawn.xml">
+      <Link>Content\Particles\shipSpawn.xml</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Fonts\NetRumbleFont.xnb">
+      <Link>Content\Fonts\NetRumbleFont.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Fonts\NetRumbleFont.png">
+      <Link>Content\Fonts\NetRumbleFont.png</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Fonts\MessageBox.xnb">
+      <Link>Content\Fonts\MessageBox.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Fonts\MessageBox.spritefont">
+      <Link>Content\Fonts\MessageBox.spritefont</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Fonts\MenuFont.xnb">
+      <Link>Content\Fonts\MenuFont.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Fonts\MenuFont.spritefont">
+      <Link>Content\Fonts\MenuFont.spritefont</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\BloomPostprocess\Effects\BloomCombine.fsh">
+      <Link>Content\BloomPostprocess\Effects\BloomCombine.fsh</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\BloomPostprocess\Effects\BloomCombine.fx">
+      <Link>Content\BloomPostprocess\Effects\BloomCombine.fx</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\BloomPostprocess\Effects\BloomCombine.xnb">
+      <Link>Content\BloomPostprocess\Effects\BloomCombine.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\BloomPostprocess\Effects\BloomExtract.fsh">
+      <Link>Content\BloomPostprocess\Effects\BloomExtract.fsh</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\BloomPostprocess\Effects\BloomExtract.fx">
+      <Link>Content\BloomPostprocess\Effects\BloomExtract.fx</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\BloomPostprocess\Effects\BloomExtract.xnb">
+      <Link>Content\BloomPostprocess\Effects\BloomExtract.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\BloomPostprocess\Effects\GaussianBlur.fsh">
+      <Link>Content\BloomPostprocess\Effects\GaussianBlur.fsh</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\BloomPostprocess\Effects\GaussianBlur.fx">
+      <Link>Content\BloomPostprocess\Effects\GaussianBlur.fx</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\BloomPostprocess\Effects\GaussianBlur.xnb">
+      <Link>Content\BloomPostprocess\Effects\GaussianBlur.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\rocket.xnb">
+      <Link>Content\Audio\wav\rocket.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\rocket.wav">
+      <Link>Content\Audio\wav\rocket.wav</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\powerup_touch.xnb">
+      <Link>Content\Audio\wav\powerup_touch.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\powerup_touch.wav">
+      <Link>Content\Audio\wav\powerup_touch.wav</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\powerup_spawn.xnb">
+      <Link>Content\Audio\wav\powerup_spawn.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\powerup_spawn.wav">
+      <Link>Content\Audio\wav\powerup_spawn.wav</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\player_spawn.xnb">
+      <Link>Content\Audio\wav\player_spawn.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\player_spawn.wav">
+      <Link>Content\Audio\wav\player_spawn.wav</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\menu_select.xnb">
+      <Link>Content\Audio\wav\menu_select.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\menu_select.wav">
+      <Link>Content\Audio\wav\menu_select.wav</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\menu_scroll.xnb">
+      <Link>Content\Audio\wav\menu_scroll.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\menu_scroll.wav">
+      <Link>Content\Audio\wav\menu_scroll.wav</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\fire_rocket2.xnb">
+      <Link>Content\Audio\wav\fire_rocket2.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\fire_rocket2.wav">
+      <Link>Content\Audio\wav\fire_rocket2.wav</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\fire_rocket1.xnb">
+      <Link>Content\Audio\wav\fire_rocket1.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\fire_rocket1.wav">
+      <Link>Content\Audio\wav\fire_rocket1.wav</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\fire_laser3.xnb">
+      <Link>Content\Audio\wav\fire_laser3.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\fire_laser3.wav">
+      <Link>Content\Audio\wav\fire_laser3.wav</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\fire_laser2.xnb">
+      <Link>Content\Audio\wav\fire_laser2.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\fire_laser2.wav">
+      <Link>Content\Audio\wav\fire_laser2.wav</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\fire_laser1.xnb">
+      <Link>Content\Audio\wav\fire_laser1.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\fire_laser1.wav">
+      <Link>Content\Audio\wav\fire_laser1.wav</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\explosion_shockwave.xnb">
+      <Link>Content\Audio\wav\explosion_shockwave.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\explosion_shockwave.wav">
+      <Link>Content\Audio\wav\explosion_shockwave.wav</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\explosion_medium.xnb">
+      <Link>Content\Audio\wav\explosion_medium.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\explosion_medium.wav">
+      <Link>Content\Audio\wav\explosion_medium.wav</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\explosion_large.xnb">
+      <Link>Content\Audio\wav\explosion_large.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\explosion_large.wav">
+      <Link>Content\Audio\wav\explosion_large.wav</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\asteroid_touch.xnb">
+      <Link>Content\Audio\wav\asteroid_touch.xnb</Link>
+    </None>
+    <None Include="..\..\MacOS\NetRumble\Content\Audio\wav\asteroid_touch.wav">
+      <Link>Content\Audio\wav\asteroid_touch.wav</Link>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="..\..\MacOS\NetRumble\RandomMath.cs">
+      <Link>RandomMath.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\OperationCompletedEventArgs.cs">
+      <Link>OperationCompletedEventArgs.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\NetRumbleGame.cs">
+      <Link>NetRumbleGame.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\CollisionMath.cs">
+      <Link>CollisionMath.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\BatchRemovalCollection.cs">
+      <Link>BatchRemovalCollection.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Screens\SearchResultsScreen.cs">
+      <Link>Screens\SearchResultsScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Screens\NetworkBusyScreen.cs">
+      <Link>Screens\NetworkBusyScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Screens\MainMenuScreen.cs">
+      <Link>Screens\MainMenuScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Screens\LobbyScreen.cs">
+      <Link>Screens\LobbyScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Screens\GameplayScreen.cs">
+      <Link>Screens\GameplayScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Screens\BackgroundScreen.cs">
+      <Link>Screens\BackgroundScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\ScreenManager\ScreenManager.cs">
+      <Link>ScreenManager\ScreenManager.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\ScreenManager\MessageBoxScreen.cs">
+      <Link>ScreenManager\MessageBoxScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\ScreenManager\MenuScreen.cs">
+      <Link>ScreenManager\MenuScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\ScreenManager\LoadingScreen.cs">
+      <Link>ScreenManager\LoadingScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\ScreenManager\InputState.cs">
+      <Link>ScreenManager\InputState.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\ScreenManager\GameScreen.cs">
+      <Link>ScreenManager\GameScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Rendering\Particles\ParticleSystem.cs">
+      <Link>Rendering\Particles\ParticleSystem.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Rendering\Particles\ParticleEffectType.cs">
+      <Link>Rendering\Particles\ParticleEffectType.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Rendering\Particles\ParticleEffectManager.cs">
+      <Link>Rendering\Particles\ParticleEffectManager.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Rendering\Particles\ParticleEffect.cs">
+      <Link>Rendering\Particles\ParticleEffect.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Rendering\Particles\ParticleCache.cs">
+      <Link>Rendering\Particles\ParticleCache.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Rendering\Particles\Particle.cs">
+      <Link>Rendering\Particles\Particle.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\World.cs">
+      <Link>Gameplay\World.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\ShipInput.cs">
+      <Link>Gameplay\ShipInput.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\Ship.cs">
+      <Link>Gameplay\Ship.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\PlayerData.cs">
+      <Link>Gameplay\PlayerData.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\GameplayObject.cs">
+      <Link>Gameplay\GameplayObject.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\CollisionManager.cs">
+      <Link>Gameplay\CollisionManager.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\Asteroid.cs">
+      <Link>Gameplay\Asteroid.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\PowerUps\TripleLaserPowerUp.cs">
+      <Link>Gameplay\PowerUps\TripleLaserPowerUp.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\PowerUps\RocketPowerUp.cs">
+      <Link>Gameplay\PowerUps\RocketPowerUp.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\PowerUps\PowerUp.cs">
+      <Link>Gameplay\PowerUps\PowerUp.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\PowerUps\DoubleLaserPowerUp.cs">
+      <Link>Gameplay\PowerUps\DoubleLaserPowerUp.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\Projectiles\RocketProjectile.cs">
+      <Link>Gameplay\Projectiles\RocketProjectile.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\Projectiles\Projectile.cs">
+      <Link>Gameplay\Projectiles\Projectile.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\Projectiles\MineProjectile.cs">
+      <Link>Gameplay\Projectiles\MineProjectile.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\Projectiles\LaserProjectile.cs">
+      <Link>Gameplay\Projectiles\LaserProjectile.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\Weapons\Weapon.cs">
+      <Link>Gameplay\Weapons\Weapon.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\Weapons\TripleLaserWeapon.cs">
+      <Link>Gameplay\Weapons\TripleLaserWeapon.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\Weapons\RocketWeapon.cs">
+      <Link>Gameplay\Weapons\RocketWeapon.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\Weapons\MineWeapon.cs">
+      <Link>Gameplay\Weapons\MineWeapon.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\Weapons\LaserWeapon.cs">
+      <Link>Gameplay\Weapons\LaserWeapon.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\Gameplay\Weapons\DoubleLaserWeapon.cs">
+      <Link>Gameplay\Weapons\DoubleLaserWeapon.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\BloomPostprocess\BloomSettings.cs">
+      <Link>BloomPostprocess\BloomSettings.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetRumble\BloomPostprocess\BloomComponent.cs">
+      <Link>BloomPostprocess\BloomComponent.cs</Link>
+    </Compile>
+    <Compile Include="AudioManager.cs" />
+    <Compile Include="Effects\GaussianBlurEffect.cs" />
+    <Compile Include="Effects\CloudsEffect.cs" />
+    <Compile Include="Effects\BloomExtractEffect.cs" />
+    <Compile Include="Effects\BloomCombineEffect.cs" />
+    <Compile Include="Rendering\Starfield.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Effects\" />
+    <Folder Include="BloomPostprocess\" />
+    <Folder Include="Content\Audio\wav\" />
+    <Folder Include="Content\BloomPostprocess\Effects\" />
+    <Folder Include="Content\Effects\" />
+    <Folder Include="Content\Fonts\" />
+    <Folder Include="Content\Particles\" />
+    <Folder Include="Content\Textures\Particles\" />
+    <Folder Include="Gameplay\Weapons\" />
+    <Folder Include="Gameplay\Projectiles\" />
+    <Folder Include="Gameplay\PowerUps\" />
+    <Folder Include="Rendering\Particles\" />
+    <Folder Include="ScreenManager\" />
+    <Folder Include="Screens\" />
+    <Folder Include="Content\Particles\" />
+    <Folder Include="Content\Particles\" />
+    <Folder Include="Content\Particles\" />
+    <Folder Include="Content\Particles\" />
+    <Folder Include="Content\Particles\" />
+    <Folder Include="Content\Particles\" />
+    <Folder Include="Content\Particles\" />
+    <Folder Include="Content\Particles\" />
+    <Folder Include="Content\Textures\Particles\" />
+    <Folder Include="Content\Textures\Particles\" />
+    <Folder Include="Content\Textures\Particles\" />
+    <Folder Include="Content\Textures\Particles\" />
+    <Folder Include="Content\Textures\Particles\" />
+    <Folder Include="Content\Textures\Particles\" />
+    <Folder Include="Content\BloomPostprocess\" />
+    <Folder Include="Content\BloomPostprocess\" />
+    <Folder Include="Content\BloomPostprocess\" />
+    <Folder Include="Content\BloomPostprocess\" />
+    <Folder Include="Content\BloomPostprocess\" />
+    <Folder Include="Content\BloomPostprocess\" />
+    <Folder Include="Content\BloomPostprocess\" />
+    <Folder Include="Content\BloomPostprocess\" />
+    <Folder Include="Content\BloomPostprocess\" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\MonoGame.Framework\MonoGame.Framework.Linux.csproj">
+      <Project>{35253CE1-C864-4CD3-8249-4D1319748E8F}</Project>
+      <Name>MonoGame.Framework.Linux</Name>
+    </ProjectReference>
+  </ItemGroup>
+</Project>

+ 77 - 0
Samples/Linux/NetRumble/Program.cs

@@ -0,0 +1,77 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// Program.cs
+//
+//-----------------------------------------------------------------------------
+#endregion
+
+#region License
+/*
+Microsoft Public License (Ms-PL)
+MonoGame - Copyright © 2009 The MonoGame Team
+
+All rights reserved.
+
+This license governs use of the accompanying software. If you use the software, you accept this license. If you do not
+accept the license, do not use the software.
+
+1. Definitions
+The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under 
+U.S. copyright law.
+
+A "contribution" is the original software, or any additions or changes to the software.
+A "contributor" is any person that distributes its contribution under this license.
+"Licensed patents" are a contributor's patent claims that read directly on its contribution.
+
+2. Grant of Rights
+(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, 
+each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
+(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, 
+each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
+
+3. Conditions and Limitations
+(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
+(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, 
+your patent license from such contributor to the software ends automatically.
+(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution 
+notices that are present in the software.
+(D) If you distribute any portion of the software in source code form, you may do so only under this license by including 
+a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object 
+code form, you may only do so under a license that complies with this license.
+(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees
+or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent
+permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular
+purpose and non-infringement.
+*/
+#endregion License
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.GamerServices;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using Microsoft.Xna.Framework.Net;
+
+#endregion
+
+
+namespace NetRumble
+{
+	
+	#region Entry Point
+	static class Program
+	{
+		/// <summary>
+		/// The main entry point for the application.
+		/// </summary>
+		static void Main (string[] args)
+		{
+			using (NetRumbleGame game = new NetRumbleGame ()) {
+				game.Run ();
+			}
+		}
+	}
+	
+	#endregion
+}

+ 105 - 0
Samples/Linux/NetRumble/Rendering/Particles/Particle.cs

@@ -0,0 +1,105 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// Particle.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A single particle in a particle-based effect.
+    /// </summary>
+    public class Particle
+    {
+        #region Status Data
+        
+
+        /// <summary>
+        /// The time remaining for this particle.
+        /// </summary>
+        public float TimeRemaining;
+
+
+        #endregion
+
+
+        #region Graphics Data
+
+
+        /// <summary>
+        /// The position of this particle.
+        /// </summary>
+        public Vector2 Position;
+
+        /// <summary>
+        /// The velocity of this particle.
+        /// </summary>
+        public Vector2 Velocity;
+
+        /// <summary>
+        /// The acceleration of this particle.
+        /// </summary>
+        public Vector2 Acceleration;
+
+        /// <summary>
+        /// The scale applied to this particle.
+        /// </summary>
+        public float Scale = 1f;
+
+        /// <summary>
+        /// The rotation applied to this particle.
+        /// </summary>
+        public float Rotation;
+
+        /// <summary>
+        /// The opacity of the particle.
+        /// </summary>
+        public float Opacity = 1f;
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+
+        /// <summary>
+        /// Update the particle.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        /// <param name="angularVelocity">The angular velocity of the particle.</param>
+        /// <param name="scaleDeltaPerSecond">The change in the scale</param>
+        /// <param name="opacityDeltaPerSecond">The change in the opacity.</param>
+        public void Update(float elapsedTime, float angularVelocity, 
+            float scaleDeltaPerSecond, float opacityDeltaPerSecond)
+        {
+            Velocity.X += Acceleration.X * elapsedTime;
+            Velocity.Y += Acceleration.Y * elapsedTime;
+
+            Position.X += Velocity.X * elapsedTime;
+            Position.Y += Velocity.Y * elapsedTime;
+
+            Rotation += angularVelocity * elapsedTime;
+            Scale += scaleDeltaPerSecond * elapsedTime;
+            if (Scale < 0f)
+            {
+                Scale = 0f;
+            }
+
+            Opacity = MathHelper.Clamp(Opacity + opacityDeltaPerSecond * elapsedTime,
+                0f, 1f);
+        }
+
+
+        #endregion
+    }
+}

+ 144 - 0
Samples/Linux/NetRumble/Rendering/Particles/ParticleCache.cs

@@ -0,0 +1,144 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// ParticleCache.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// Cache of Particle objects.
+    /// </summary>
+    public class ParticleCache
+    {
+        #region Fields
+
+
+        /// <summary>
+        /// Container of the particles in the cache.
+        /// </summary>
+        public Particle[] Particles;
+
+        /// <summary>
+        /// The particles available to be spawned.
+        /// </summary>
+        private Queue<Particle> freeParticles;
+
+
+        #endregion
+
+
+        #region Statistics Properties
+
+
+        /// <summary>
+        /// The total of all particles in the cache.
+        /// </summary>
+        public int TotalCount
+        {
+            get { return Particles.Length; }
+        }
+
+        /// <summary>
+        /// The number of particles remaining in the cache.
+        /// </summary>
+        public int FreeCount
+        {
+            get { return freeParticles.Count; }
+        }
+
+        /// <summary>
+        /// The number of particles in use.
+        /// </summary>
+        public int UsedCount
+        {
+            get { return TotalCount - FreeCount; }
+        }
+
+
+        #endregion
+        
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Construct a new particle cache.
+        /// </summary>
+        /// <param name="count">The number of particles to be allocated.</param>
+        public ParticleCache(int count)
+        {
+            // safety-check the parameter
+            if (count <= 0)
+            {
+                throw new ArgumentOutOfRangeException("count");
+            }
+
+            // create the particles
+            Particles = new Particle[count];
+            for (int i = 0; i < count; i++)
+            {
+                Particles[i] = new Particle();
+            }
+
+            // create the freed list, which initially contains all particles
+            freeParticles = new Queue<Particle>(Particles);
+        }
+
+
+        /// <summary>
+        /// Reset the particle cache to a freed state.
+        /// </summary>
+        public void Reset()
+        {
+            // reset the time on particles
+            for (int i = 0; i < Particles.Length; ++i)
+            {
+                Particles[i].TimeRemaining = 0.0f;
+            }
+
+            // recreate the freed list, containing all particles
+            freeParticles = new Queue<Particle>(Particles);
+        }
+
+
+        #endregion
+
+
+        #region Membership Methods
+
+
+        /// <summary>
+        /// Gets the new particle to be used out of the cache.
+        /// </summary>
+        /// <returns>The new particle.</returns>
+        public Particle GetNextParticle()
+        {
+            return (freeParticles.Count > 0) ? freeParticles.Dequeue() : null;
+        }
+
+
+        /// <summary>
+        /// Releases a particle back to the cache.
+        /// </summary>
+        /// <param name="particle">The particle to be released.</param>
+        public void ReleaseParticle(Particle particle)
+        {
+            if (particle != null)
+            {
+                freeParticles.Enqueue(particle);
+            }
+        }
+
+
+        #endregion
+    }
+}

+ 297 - 0
Samples/Linux/NetRumble/Rendering/Particles/ParticleEffect.cs

@@ -0,0 +1,297 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// ParticleEffect.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Xml.Serialization;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Content;
+#endregion
+
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A multi-emitter particle effect, comprised of multiple particle systems.
+    /// </summary>
+    public class ParticleEffect
+    {
+        #region Description Data
+
+
+        /// <summary>
+        /// The name of the particle effect.
+        /// </summary>
+        private string name;
+
+        /// <summary>
+        /// The particle systems in this effect.
+        /// </summary>
+        private Collection<ParticleSystem> particleSystems =
+            new Collection<ParticleSystem>();
+
+
+        #endregion
+
+
+        #region Graphics Data
+
+
+        /// <summary>
+        /// The position of the particle effect in the world.
+        /// </summary>
+        private Vector2 position;
+
+
+        /// <summary>
+        /// The gameplay object that the system is following, if any.
+        /// </summary>
+        private GameplayObject followObject;
+        [XmlIgnore()]
+        public GameplayObject GameplayObject
+        {
+            get { return followObject; }
+            set { followObject = value; }
+        }
+
+
+        #endregion
+
+
+        #region Status Data
+
+
+        /// <summary>
+        /// If true, the particle effect is currently active.
+        /// </summary>
+        private bool active = false;
+        [XmlIgnore()]
+        public bool Active
+        {
+            get { return active; }
+        }
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Create a new particle effect.
+        /// </summary>
+        public ParticleEffect() { }
+
+
+        /// <summary>
+        /// Create a new particle effect that is a clone of another one.
+        /// </summary>
+        /// <returns></returns>
+        public ParticleEffect Clone()
+        {
+            ParticleEffect clone = new ParticleEffect();
+
+            // copy the data
+            clone.name = this.name;
+            clone.position = this.position;
+
+            // copy each system
+            for (int i = 0; i < this.particleSystems.Count; ++i)
+            {
+                clone.ParticleSystems.Add(this.particleSystems[i].Clone());
+            }
+
+            return clone;
+        }
+
+        
+        /// <summary>
+        /// Initialize the particle effect.
+        /// </summary>
+        /// <param name="content">The contenet manager that owns the texture.</param>
+        public virtual void Initialize(ContentManager content)
+        {
+            // initialize each system
+            for (int i = 0; i < particleSystems.Count; ++i)
+            {
+                particleSystems[i].Initialize(content);
+            }
+
+            // allow us to start updating and drawing
+            active = true;
+        }
+
+
+        /// <summary>
+        /// Reset the particle effect.
+        /// </summary>
+        public virtual void Reset()
+        {
+            // reset each system
+            for (int i = 0; i < particleSystems.Count; ++i)
+            {
+                particleSystems[i].Reset();
+            }
+
+            // allow us to start updating and drawing
+            active = true;
+        }
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+
+        /// <summary>
+        /// Update the particle effect.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        public virtual void Update(float elapsedTime)
+        {
+            // update the position based on the follow-object, if any
+            if (followObject != null)
+            {
+                if (followObject.Active)
+                {
+                    Position = followObject.Position;
+                }
+                else
+                {
+                    followObject = null;
+                    Stop(false);
+                }
+            }
+
+            // update each system
+            active = false;
+            for (int i = 0; i < particleSystems.Count; ++i)
+            {
+                if (particleSystems[i].Active)
+                {
+                    particleSystems[i].Update(elapsedTime);
+                    active = true;
+                }
+            }
+        }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draw the particle effect.
+        /// </summary>
+        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
+        /// <param name="blendMode">Filters the systems drawn in this pass.</param>
+        public virtual void Draw(SpriteBatch spriteBatch, SpriteBlendMode blendMode)
+        {
+            if (!active)
+                return;
+
+            // draw each system
+            for (int i = 0; i < particleSystems.Count; ++i)
+            {
+                if (particleSystems[i].BlendMode == blendMode)
+                {
+                    particleSystems[i].Draw(spriteBatch);
+                }
+            }
+        }
+
+
+        #endregion
+
+
+        #region Control Methods
+
+
+        /// <summary>
+        /// Stop the particle effect.
+        /// </summary>
+        /// <param name="immediately">
+        /// If true, particles are no longer drawn or updated.
+        /// Otherwise, only generation is halted.
+        /// </param>
+        public void Stop(bool immediately)
+        {
+            // stop all of the systems
+            for (int i = 0; i < particleSystems.Count; ++i)
+            {
+                particleSystems[i].Stop(immediately);
+            }
+
+            // halt updating/drawing of the particles if requested
+            if (immediately)
+            {
+                active = false;
+            }
+        }
+
+
+        #endregion
+
+
+        #region Serialization Interface
+
+
+        public string Name
+        {
+            get { return name; }
+            set { name = value; }
+        }
+
+        public Vector2 Position
+        {
+            get { return position; }
+            set
+            {
+                position = value;
+                for (int i = 0; i < particleSystems.Count; ++i)
+                {
+                    particleSystems[i].Position = position;
+                }
+            }
+        }
+
+        public Collection<ParticleSystem> ParticleSystems
+        {
+            get { return particleSystems as Collection<ParticleSystem>; }
+        }
+
+
+        #endregion
+
+
+        #region Static Initialization Methods
+
+
+        /// <summary>
+        /// Create a new ParticleEffect object from the data in an XML file.
+        /// </summary>
+        /// <param name="filepath">The filename of the XML file.</param>
+        /// <returns>A new ParticleEffect object.</returns>
+        public static ParticleEffect Load(string filepath)
+        {
+            XmlSerializer serializer = new XmlSerializer(typeof(ParticleEffect));
+            return (ParticleEffect)serializer.Deserialize(File.OpenRead(filepath));
+        }
+
+
+        #endregion
+    }
+}

+ 259 - 0
Samples/Linux/NetRumble/Rendering/Particles/ParticleEffectManager.cs

@@ -0,0 +1,259 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// ParticleEffectManager.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.IO;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Content;
+#endregion
+
+namespace NetRumble
+{
+    public class ParticleEffectManager
+    {
+        #region Effect Collection Data
+
+        /// <summary>
+        /// Cache of registered particle effects.
+        /// </summary>
+        private Dictionary<ParticleEffectType, List<ParticleEffect>> particleEffectCache
+            = new Dictionary<ParticleEffectType,List<ParticleEffect>>();
+
+        /// <summary>
+        /// Active particle effects.
+        /// </summary>
+        private BatchRemovalCollection<ParticleEffect> activeParticleEffects = 
+            new BatchRemovalCollection<ParticleEffect>();
+
+
+        #endregion
+
+
+        #region Graphics Data
+
+
+        /// <summary>
+        /// The content manager used to load textures in the particle systems.
+        /// </summary>
+        private ContentManager contentManager;
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Construct a new particle-effect manager.
+        /// </summary>
+        public ParticleEffectManager(ContentManager contentManager) 
+        {
+            // safety-check the parameters
+            if (contentManager == null)
+            {
+                throw new ArgumentNullException("contentManager");
+            }
+
+            this.contentManager = contentManager;
+        }
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+        
+        /// <summary>
+        /// Update the particle-effect manager.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        public void Update(float elapsedTime)
+        {
+            for (int i = 0; i < activeParticleEffects.Count; ++i)
+            {
+                if (activeParticleEffects[i].Active)
+                {
+                    activeParticleEffects[i].Update(elapsedTime);
+                    if (!activeParticleEffects[i].Active)
+                    {
+                        activeParticleEffects.QueuePendingRemoval(
+                            activeParticleEffects[i]);
+                    }
+                }
+            }
+            activeParticleEffects.ApplyPendingRemovals();
+        }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draw all of the particle effects in the manager.
+        /// </summary>
+        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
+        /// <param name="blendMode">Filters the systems drawn in this pass.</param>
+        public virtual void Draw(SpriteBatch spriteBatch, SpriteBlendMode blendMode)
+        {
+            for (int i = 0; i < activeParticleEffects.Count; ++i)
+            {
+                if (activeParticleEffects[i].Active)
+                {
+                    activeParticleEffects[i].Draw(spriteBatch, blendMode);
+                }
+            }
+        }
+
+
+        #endregion
+
+
+        #region Particle-Effect Creation Methods
+
+
+        /// <summary>
+        /// Spawn a new particle effect at a given location
+        /// </summary>
+        /// <param name="effectType">The effect in question.</param>
+        /// <param name="position">The position of the effect.</param>
+        /// <returns>The new particle effect.</returns>
+        public ParticleEffect SpawnEffect(ParticleEffectType effectType, 
+            Vector2 position)
+        {
+            return SpawnEffect(effectType, position, null);
+        }
+
+
+        /// <summary>
+        /// Spawn a new particle effect at a the position of a given gameplay object
+        /// </summary>
+        /// <param name="effectType">The effect in question.</param>
+        /// <param name="actor">The gameplay object.</param>
+        /// <returns>The new particle effect.</returns>
+        public ParticleEffect SpawnEffect(ParticleEffectType effectType,
+            GameplayObject gameplayObject)
+        {
+            // safety-check the parameter
+            if (gameplayObject == null)
+            {
+                throw new ArgumentNullException("gameplayObject");
+            }
+
+            return SpawnEffect(effectType, gameplayObject.Position, gameplayObject);
+        }
+
+
+        /// <summary>
+        /// Spawn a new particle effect at a given location and gameplay object
+        /// </summary>
+        /// <param name="effectType">The effect in question.</param>
+        /// <param name="position">The position of the effect.</param>
+        /// <param name="actor">The gameplay object.</param>
+        /// <returns>The new particle effect.</returns>
+        public ParticleEffect SpawnEffect(ParticleEffectType effectType, 
+            Vector2 position, GameplayObject gameplayObject)
+        {
+            ParticleEffect particleEffect = null;
+
+            if (particleEffectCache.ContainsKey(effectType) == true)
+            {
+                List<ParticleEffect> availableSystems = particleEffectCache[effectType];
+
+                for (int i = 0; i < availableSystems.Count; ++i)
+                {
+                    if (availableSystems[i].Active == false)
+                    {
+                        particleEffect = availableSystems[i];
+                        break;
+                    }
+                }
+
+                if (particleEffect == null)
+                {
+                    particleEffect = availableSystems[0].Clone();
+                    particleEffect.Initialize(contentManager);
+                    availableSystems.Add(particleEffect);
+                }
+            }
+
+            if (particleEffect != null)
+            {
+                particleEffect.Reset();
+                particleEffect.GameplayObject = gameplayObject;
+                particleEffect.Position = position;
+                activeParticleEffects.Add(particleEffect);
+            }
+
+            return particleEffect;
+        }
+
+
+        #endregion
+
+
+        #region Registration Methods
+
+
+        /// <summary>
+        /// Register a new type of particle effect with the manager.
+        /// </summary>
+        /// <param name="effectType">The enumeration associated with this type.</param>
+        /// <param name="filename">The path to the XML file to be deserialized.</param>
+        /// <param name="initialCount">How many of these to pre-create.</param>
+        public void RegisterParticleEffect(ParticleEffectType effectType, 
+            string filename, int initialCount)
+        {
+            if (!particleEffectCache.ContainsKey(effectType))
+            {
+                string filepath = Path.Combine(contentManager.RootDirectory, filename);
+                ParticleEffect particleEffect = ParticleEffect.Load(filepath);
+                particleEffect.Initialize(contentManager);
+                particleEffect.Stop(true);
+                particleEffectCache.Add(effectType, new List<ParticleEffect>());
+                particleEffectCache[effectType].Add(particleEffect);
+                for (int i = 1; i < initialCount; i++)
+                {
+                    ParticleEffect cloneEffect = particleEffect.Clone();
+                    cloneEffect.Initialize(contentManager);
+                    cloneEffect.Stop(true);
+                    particleEffectCache[effectType].Add(cloneEffect);
+                }
+            }
+        }
+
+
+
+        /// <summary>
+        /// Remove the given particle-effect type from the maanger.
+        /// </summary>
+        /// <param name="effectType">The enumeration to be cleared against.</param>
+        public void UnregisterParticleEffect(ParticleEffectType effectType)
+        {
+            if (particleEffectCache.ContainsKey(effectType) == true)
+            {
+                for (int i = 0; i < particleEffectCache[effectType].Count; ++i)
+                {
+                    activeParticleEffects.Remove(particleEffectCache[effectType][i]);
+                }
+                particleEffectCache.Remove(effectType);
+            }
+        }
+
+
+        #endregion
+    }
+}

+ 28 - 0
Samples/Linux/NetRumble/Rendering/Particles/ParticleEffectType.cs

@@ -0,0 +1,28 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// ParticleEffectType.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// All of the particle effects that the game currently supports.
+    /// </summary>
+    public enum ParticleEffectType
+    {
+        ShipSpawn,
+        ShipExplosion,
+        RocketTrail,
+        RocketExplosion,
+        MineExplosion,
+        LaserExplosion,
+    }
+}

+ 712 - 0
Samples/Linux/NetRumble/Rendering/Particles/ParticleSystem.cs

@@ -0,0 +1,712 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// ParticleSystem.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.Xml.Serialization;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Content;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A single-emitter particle system within a larger effect.
+    /// </summary>
+    public class ParticleSystem
+    {
+        #region Description Data
+
+
+        /// <summary>
+        /// The name of the particle system.
+        /// </summary>
+        private string name = "DefaultParticleSystem";
+
+        /// <summary>
+        /// The number of particles in this system.
+        /// </summary>
+        private int particleCount = 256;
+
+
+        #endregion
+
+
+        #region Graphics Data
+
+
+        /// <summary>
+        /// The current position of the system, relative to the effect.
+        /// </summary>
+        private Vector2 position = Vector2.Zero;
+
+        /// <summary>
+        /// The tint of the particles in the system.
+        /// </summary>
+        private Vector4 color = 
+            Microsoft.Xna.Framework.Color.White.ToVector4();
+
+        /// <summary>
+        /// The content name of the texture used with this system.
+        /// </summary>
+        private string textureName = "default_particle";
+
+        /// <summary>
+        /// The texture used with this system.
+        /// </summary>
+        private Texture2D texture = null;
+
+        /// <summary>
+        /// The center of the texture used with this system.
+        /// </summary>
+        /// <remarks>This is derived from the texture, calculated and stored.</remarks>
+        private Vector2 textureOrigin;
+
+        /// <summary>
+        /// The blending mode for this system.
+        /// </summary>
+        private SpriteBlendMode blendMode = SpriteBlendMode.AlphaBlend;
+
+
+        #endregion
+
+
+        #region Status Data
+
+
+        /// <summary>
+        /// If true, the particle system is currently active.
+        /// </summary>
+        private bool active = false;
+        [XmlIgnore()]
+        public bool Active
+        {
+            get { return (active || (timeRemaining > 0.0f)); }
+        }
+
+        /// <summary>
+        /// The amount of time that the particle system generates particles.
+        /// </summary>
+        private float duration = float.MaxValue;
+
+        /// <summary>
+        /// The time remaining for the particle system's generation.
+        /// </summary>
+        private float timeRemaining = float.MaxValue;
+
+        /// <summary>
+        /// The initial delay before the particle system starts generating particles.
+        /// </summary>
+        /// <remarks>Used for offsetting the start of particle systems.</remarks>
+        private float initialDelay = 0f;
+
+        /// <summary>
+        /// The amount of time left on the initial delay.
+        /// </summary>
+        private float initialDelayRemaining = 0f;
+
+
+        #endregion
+
+
+        #region Particle Creation Data
+
+
+        /// <summary>
+        /// The number of particles that this system releases per second.
+        /// </summary>
+        private int particlesPerSecond = 128;
+
+        /// <summary>
+        /// The number of seconds between particle releases.
+        /// </summary>
+        /// <remarks>This is derived from particlesPerSecond.</remarks>
+        private float releaseRate = 0.25f;
+
+        /// <summary>
+        /// The amount of time since the last particle was emitted.
+        /// </summary>
+        private float releaseTimer = 0f;
+        
+        /// <summary>
+        /// The minimum lifetime possible for new particles.
+        /// </summary>
+        private float durationMinimum = 1f;
+
+        /// <summary>
+        /// The maximum lifetime possible for new particles.
+        /// </summary>
+        private float durationMaximum = 1f;
+        
+        /// <summary>
+        /// The minimum initial velocity of new particles.
+        /// </summary>
+        private float velocityMinimum = 16f;
+
+        /// <summary>
+        /// The maximum initial velocity of new particles.
+        /// </summary>
+        private float velocityMaximum = 32f;
+
+        /// <summary>
+        /// The minimum acceleration of new particles.
+        /// </summary>
+        private float accelerationMinimum = 0f;
+
+        /// <summary>
+        /// The maximum acceleration of new particles.
+        /// </summary>
+        private float accelerationMaximum = 0f;
+
+        /// <summary>
+        /// The minimum initial scale of new particles.
+        /// </summary>
+        private float scaleMinimum = 1f;
+
+        /// <summary>
+        /// The maximum initial scale of new particles.
+        /// </summary>
+        private float scaleMaximum = 1f;
+
+        /// <summary>
+        /// The minimum initial opacity of new particles.
+        /// </summary>
+        private float opacityMinimum = 1f;
+
+        /// <summary>
+        /// The maximum initial opacity of new particles.
+        /// </summary>
+        private float opacityMaximum = 1f;
+
+        /// <summary>
+        /// The minimum release angle of new particles from the center.
+        /// </summary>
+        private float releaseAngleMinimum = 0f;
+
+        /// <summary>
+        /// The maximum release angle of new particles from the center.
+        /// </summary>
+        private float releaseAngleMaximum = 360f;
+
+        /// <summary>
+        /// The minimum release distance of new particles from the center.
+        /// </summary>
+        private float releaseDistanceMinimum = 0f;
+
+        /// <summary>
+        /// The maximum release distance of new particles from the center.
+        /// </summary>
+        private float releaseDistanceMaximum = 0f;
+
+
+        #endregion
+
+
+        #region Particle Updating Data
+
+
+        /// <summary>
+        /// The angular velocity of particles in this system.
+        /// </summary>
+        private float angularVelocity = 0f;
+
+        /// <summary>
+        /// The change in the scale per second for particles in this system.
+        /// </summary>
+        private float scaleDeltaPerSecond = 0f;
+
+        /// <summary>
+        /// The change in the opacity per second for particles in this system.
+        /// </summary>
+        private float opacityDeltaPerSecond = 0f;
+
+
+        #endregion
+
+
+        #region Particle Cache
+
+
+        /// <summary>
+        /// The cache of all particle objects in this system.
+        /// </summary>
+        private ParticleCache particles;
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Construct a new particle system.
+        /// </summary>
+        public ParticleSystem() { }
+
+
+        /// <summary>
+        /// Clone a particle system.
+        /// </summary>
+        /// <returns>A clone of this particle system.</returns>
+        public ParticleSystem Clone()
+        {
+            ParticleSystem clone = new ParticleSystem();
+
+            clone.name = this.name;
+            clone.particleCount = this.particleCount;
+
+            clone.position = this.position;
+            clone.color = this.color;
+            clone.textureName = this.textureName;
+            clone.blendMode = this.blendMode;
+
+            clone.duration = this.duration;
+            clone.initialDelay = this.initialDelay;
+
+            clone.particlesPerSecond = this.particlesPerSecond;
+            clone.releaseRate = this.releaseRate;
+            clone.durationMinimum = this.durationMinimum;
+            clone.durationMaximum = this.durationMaximum;
+            clone.velocityMinimum = this.velocityMinimum;
+            clone.velocityMaximum = this.velocityMaximum;
+            clone.accelerationMinimum = this.accelerationMinimum;
+            clone.accelerationMaximum = this.accelerationMaximum;
+            clone.scaleMinimum = this.scaleMinimum;
+            clone.scaleMaximum = this.scaleMaximum;
+            clone.opacityMinimum = this.opacityMinimum;
+            clone.opacityMaximum = this.opacityMaximum;
+            clone.releaseAngleMinimum = this.releaseAngleMinimum;
+            clone.releaseAngleMaximum = this.releaseAngleMaximum;
+            clone.releaseDistanceMinimum = this.releaseDistanceMinimum;
+            clone.releaseDistanceMaximum = this.releaseDistanceMaximum;
+
+            clone.angularVelocity = this.angularVelocity;
+            clone.scaleDeltaPerSecond = this.scaleDeltaPerSecond;
+            clone.opacityDeltaPerSecond = this.opacityDeltaPerSecond;
+
+            return clone;
+        }
+
+
+        /// <summary>
+        /// Initialize the particle system.
+        /// </summary>
+        /// <param name="content">The content manager that owns the texture.</param>
+        public virtual void Initialize(ContentManager content)
+        {
+            // calculate the release rate
+            releaseRate = 1.0f / (float)particlesPerSecond;
+
+            // create the cache
+            particles = new ParticleCache(particleCount);
+
+            // load the texture
+            try
+            {
+                texture = content.Load<Texture2D>(textureName);
+            }
+            catch (ContentLoadException)
+            {
+                texture = content.Load<Texture2D>("Textures/Particles/defaultParticle");
+            }
+
+            // calculate the origin on the texture
+            textureOrigin = new Vector2(texture.Width / 2f, texture.Height / 2f);
+            
+            // allow us to start updating and drawing
+            active = true;
+        }
+
+
+        /// <summary>
+        /// Resets the particle system.
+        /// </summary>
+        public virtual void Reset()
+        {
+            // reset the cache
+            particles.Reset();
+
+            // reset the timers
+            timeRemaining = duration;
+            initialDelayRemaining = initialDelay;
+
+            // allow us to start updating and drawing
+            active = true;
+        }
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+
+        /// <summary>
+        /// Update the particle system.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        public virtual void Update(float elapsedTime)
+        {
+            // if the system isn't active, dont' update at all
+            if (!Active)
+                return;
+
+            // update the initial delay
+            if (initialDelayRemaining > 0.0f)
+            {
+                initialDelayRemaining -= elapsedTime;
+                return;
+            }
+            
+            // generate new particles
+            GenerateParticles(elapsedTime);
+
+            // update the existing particles
+            UpdateParticles(elapsedTime);
+
+            // update the active flag, based on if there are any used particles
+            active = particles.UsedCount > 0;
+        }
+
+
+        /// <summary>
+        /// Generate new particles into the system.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        private void GenerateParticles(float elapsedTime)
+        {
+            if (timeRemaining <= 0.0f)
+            {
+                return;
+            }
+
+            // update the timer
+            timeRemaining -= elapsedTime;
+
+            // release some particles if it's time
+            releaseTimer += elapsedTime;
+            while (releaseTimer >= releaseRate)
+            {
+                // only get new particles if you can
+                Particle particle = particles.GetNextParticle();
+                if (particle == null)
+                {
+                    break;
+                }
+                else
+                {
+                    // initialize the new particle 
+                    InitializeParticle(particle);
+                    // reduce the release timer for the release rate of a particle
+                    releaseTimer -= releaseRate;
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Update all of the individual particles in this system.
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        private void UpdateParticles(float elapsedTime)
+        {
+            for (int i = 0; i < particles.Particles.Length; ++i)
+            {
+                if (particles.Particles[i].TimeRemaining > 0.0f)
+                {
+                    // update the timer on the particle
+                    particles.Particles[i].TimeRemaining -= elapsedTime;
+
+                    // if the particle just timed out on this update, 
+                    // add it to the freed-list.
+                    if (particles.Particles[i].TimeRemaining <= 0.0f)
+                    {
+                        particles.ReleaseParticle(particles.Particles[i]);
+                        continue;
+                    }
+
+                    // update the particle
+                    particles.Particles[i].Update(elapsedTime, angularVelocity, 
+                        scaleDeltaPerSecond, opacityDeltaPerSecond);
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Initialize a new particle using the values in this system.
+        /// </summary>
+        /// <param name="particle">The particle to be initialized.</param>
+        private void InitializeParticle(Particle particle)
+        {
+            // safety-check the parameter
+            if (particle == null)
+            {
+                throw new ArgumentNullException("particle");
+            }
+
+            // set the time remaining on the new particle
+            particle.TimeRemaining = RandomMath.RandomBetween(durationMinimum, 
+                durationMaximum);
+
+            // generate a random direction
+            Vector2 direction = RandomMath.RandomDirection(releaseAngleMinimum, 
+                releaseAngleMaximum);
+
+            // set the graphics data on the new particle
+            particle.Position = position + direction * 
+                RandomMath.RandomBetween(releaseDistanceMinimum, 
+                releaseDistanceMaximum);
+            particle.Velocity = direction * RandomMath.RandomBetween(velocityMinimum, 
+                velocityMaximum);
+            if (particle.Velocity.LengthSquared() > 0f)
+            {
+                particle.Acceleration = direction * 
+                    RandomMath.RandomBetween(accelerationMinimum, accelerationMaximum);
+            }
+            else
+            {
+                particle.Acceleration = Vector2.Zero;
+            }
+            particle.Rotation = RandomMath.RandomBetween(0f, MathHelper.TwoPi);
+            particle.Scale = RandomMath.RandomBetween(scaleMinimum, scaleMaximum);
+            particle.Opacity = RandomMath.RandomBetween(opacityMinimum, opacityMaximum);
+        }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draw the particle system.
+        /// </summary>
+        /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
+        public void Draw(SpriteBatch spriteBatch)
+        {
+            // only draw if we're active
+            if (!Active)
+                return;
+
+            // draw each particle
+            for (int p = 0; p < particles.Particles.Length; ++p)
+            {
+                Particle particle = particles.Particles[p];
+
+                if (particle.TimeRemaining > 0.0f)
+                {
+                    color.W = particle.Opacity;
+                    spriteBatch.Draw(texture, particle.Position, null, new Color(color),
+                        particle.Rotation, textureOrigin, particle.Scale, 
+                        SpriteEffects.None, 1f);
+                }
+            }
+        }
+
+
+        #endregion
+
+
+        #region Control Methods
+
+
+        /// <summary>
+        /// Stop the particle system.
+        /// </summary>
+        /// <param name="immediately">
+        /// If true, particles are no longer drawn or updated. 
+        /// Otherwise, only generation is halted.
+        /// </param>
+        public void Stop(bool immediately)
+        {
+            // halt generation
+            timeRemaining = 0.0f;
+
+            // halt updating/drawing of the particles if requested
+            if (immediately)
+            {
+                active = false;
+            }
+        }
+
+
+        #endregion
+
+
+        #region Serialization Interface
+
+
+        public string Name
+        {
+            get { return name; }
+            set { name = value; }
+        }
+
+        public int ParticleCount
+        {
+            get { return particleCount; }
+            set { particleCount = value; }
+        }
+
+
+        public Vector2 Position
+        {
+            get { return position; }
+            set { position = value; }
+        }
+
+        public Vector4 Color
+        {
+            get { return color; }
+            set { color = value; }
+        }
+
+        public string TextureName
+        {
+            get { return textureName; }
+            set { textureName = value; }
+        }
+
+        public SpriteBlendMode BlendMode
+        {
+            get { return blendMode; }
+            set { blendMode = value; }
+        }
+
+        
+        public float Duration
+        {
+            get { return duration; }
+            set { duration = value; }
+        }
+
+        public float InitialDelay
+        {
+            get { return initialDelay; }
+            set { initialDelay = value; }
+        }
+
+
+        public int ParticlesPerSecond
+        {
+            get { return particlesPerSecond; }
+            set { particlesPerSecond = value; }
+        }
+
+        public float DurationMinimum
+        {
+            get { return durationMinimum; }
+            set { durationMinimum = value; }
+        }
+
+        public float DurationMaximum
+        {
+            get { return durationMaximum; }
+            set { durationMaximum = value; }
+        }
+
+        public float VelocityMinimum
+        {
+            get { return velocityMinimum; }
+            set { velocityMinimum = value; }
+        }
+
+        public float VelocityMaximum
+        {
+            get { return velocityMaximum; }
+            set { velocityMaximum = value; }
+        }
+
+        public float AccelerationMinimum
+        {
+            get { return accelerationMinimum; }
+            set { accelerationMinimum = value; }
+        }
+
+        public float AccelerationMaximum
+        {
+            get { return accelerationMaximum; }
+            set { accelerationMaximum = value; }
+        }
+
+        public float ScaleMinimum
+        {
+            get { return scaleMinimum; }
+            set { scaleMinimum = value; }
+        }
+
+        public float ScaleMaximum
+        {
+            get { return scaleMaximum; }
+            set { scaleMaximum = value; }
+        }
+
+        public float OpacityMinimum
+        {
+            get { return opacityMinimum; }
+            set { opacityMinimum = value; }
+        }
+
+        public float OpacityMaximum
+        {
+            get { return opacityMaximum; }
+            set { opacityMaximum = value; }
+        }
+
+        public float ReleaseAngleMinimum
+        {
+            get { return releaseAngleMinimum; }
+            set { releaseAngleMinimum = value; }
+        }
+
+        public float ReleaseAngleMaximum
+        {
+            get { return releaseAngleMaximum; }
+            set { releaseAngleMaximum = value; }
+        }
+
+        public float ReleaseDistanceMinimum
+        {
+            get { return releaseDistanceMinimum; }
+            set { releaseDistanceMinimum = value; }
+        }
+
+        public float ReleaseDistanceMaximum
+        {
+            get { return releaseDistanceMaximum; }
+            set { releaseDistanceMaximum = value; }
+        }
+
+
+        public float AngularVelocity
+        {
+            get { return angularVelocity; }
+            set { angularVelocity = value; }
+        }
+        
+        public float ScaleDeltaPerSecond
+        {
+            get { return scaleDeltaPerSecond; }
+            set { scaleDeltaPerSecond = value; }
+        }
+
+        public float OpacityDeltaPerSecond
+        {
+            get { return opacityDeltaPerSecond; }
+            set { opacityDeltaPerSecond = value; }
+        }
+
+
+        #endregion
+    }
+}

+ 392 - 0
Samples/Linux/NetRumble/Rendering/Starfield.cs

@@ -0,0 +1,392 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// Starfield.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Content;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// The starfield that renders behind the game, including a parallax effect.
+    /// </summary>
+    public class Starfield : IDisposable
+    {
+        #region Constants
+
+
+        /// <summary>
+        /// The number of stars in the starfield.
+        /// </summary>
+        const int numberOfStars = 256;
+
+        /// <summary>
+        /// The number of layers in the starfield.
+        /// </summary>
+        const int numberOfLayers = 8;
+
+        /// <summary>
+        /// The colors for each layer of stars.
+        /// </summary>
+        static readonly Color[] layerColors = new Color[numberOfLayers] 
+            { 
+                new Color(255, 255, 255, 255), 
+                new Color(255, 255, 255, 216), 
+                new Color(255, 255, 255, 192), 
+                new Color(255, 255, 255, 160), 
+                new Color(255, 255, 255, 128), 
+                new Color(255, 255, 255, 96), 
+                new Color(255, 255, 255, 64), 
+                new Color(255, 255, 255, 32) 
+            };
+
+        /// <summary>
+        /// The movement factor for each layer of stars, used in the parallax effect.
+        /// </summary>
+        static readonly float[] movementFactors = new float[numberOfLayers]
+            {
+                0.9f, 0.8f, 0.7f, 0.6f, 0.5f, 0.4f, 0.3f, 0.2f
+            };
+
+        /// <summary>
+        /// The maximum amount of movement allowed per update.
+        /// </summary>
+        /// <remarks>
+        /// Any per-update movement values that exceed this will trigger a 
+        /// starfield reset.
+        /// </remarks>
+        const float maximumMovementPerUpdate = 128f;
+
+        /// <summary>
+        /// The background color of the starfield.
+        /// </summary>
+        static readonly Color backgroundColor = new Color(0, 0, 32);
+
+        /// <summary>
+        /// The size of each star, in pixels.
+        /// </summary>
+        const int starSize = 2;
+
+
+        #endregion
+
+
+        #region Gameplay Data
+
+
+        /// <summary>
+        /// The last position, used for the parallax effect.
+        /// </summary>
+        private Vector2 lastPosition;
+
+        /// <summary>
+        /// The current position, used for the parallax effect.
+        /// </summary>
+        private Vector2 position;
+
+        /// <summary>
+        /// The stars in the starfield.
+        /// </summary>
+        private Vector2[] stars;
+
+
+        #endregion
+
+
+        #region Graphics Data
+
+
+        /// <summary>
+        /// The graphics device used to render the starfield.
+        /// </summary>
+        private GraphicsDevice graphicsDevice;
+
+        /// <summary>
+        /// The content manager used to manage the textures in the starfield.
+        /// </summary>
+        private ContentManager contentManager;
+
+        /// <summary>
+        /// The SpriteBatch used to render the starfield.
+        /// </summary>
+        private SpriteBatch spriteBatch;
+
+        /// <summary>
+        /// The texture used for each star, typically one white pixel.
+        /// </summary>
+        private Texture2D starTexture;
+
+        /// <summary>
+        /// The cloud texture that appears behind the stars.
+        /// </summary>
+        private Texture2D cloudTexture;
+
+        /// <summary>
+        /// The effect used to draw the clouds.
+        /// </summary>
+        private Effect cloudEffect;
+
+        /// <summary>
+        /// The parameter on the cloud effect that receives the current position
+        /// </summary>
+        private EffectParameter cloudEffectPosition;
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Create a new Starfield object.
+        /// </summary>
+        /// <param name="position"></param>
+        /// <param name="graphicsDevice">The graphics device used to render.</param>
+        /// <param name="contentManager">The content manager for this object.</param>
+        public Starfield(Vector2 position, GraphicsDevice graphicsDevice, 
+            ContentManager contentManager)
+        {
+            // safety-check the parameters, as they must be valid
+            if (graphicsDevice == null)
+            {
+                throw new ArgumentNullException("graphicsDevice");
+            }
+            if (contentManager == null)
+            {
+                throw new ArgumentNullException("contentManager");
+            }
+
+            // assign the parameters
+            this.graphicsDevice = graphicsDevice;
+            this.contentManager = contentManager;
+
+            // initialize the stars
+            stars = new Vector2[numberOfStars];
+            Reset(position);
+        }
+
+
+        /// <summary>
+        /// Load graphics data from the system.
+        /// </summary>
+        public void LoadContent()
+        {
+            // load the cloud texture
+            cloudTexture = contentManager.Load<Texture2D>("Textures/clouds");
+
+            // load the cloud effect
+            cloudEffect = contentManager.Load<Effect>("Effects/Clouds");
+			//cloudEffect = new CloudsEffect(graphicsDevice); 
+            cloudEffectPosition = cloudEffect.Parameters["Position"];
+      
+            // create the star texture
+            starTexture = new Texture2D(graphicsDevice, 1, 1, false, SurfaceFormat.Color);
+            starTexture.SetData<Color>(new Color[] { Color.White });
+
+            // create the SpriteBatch object
+            spriteBatch = new SpriteBatch(graphicsDevice);
+        }
+
+
+        /// <summary>
+        /// Release graphics data.
+        /// </summary>
+        public void UnloadContent()
+        {
+            cloudTexture = null;
+            cloudEffect = null;
+            cloudEffectPosition = null;
+
+            if (starTexture != null)
+            {
+                starTexture.Dispose();
+                starTexture = null;
+            }
+
+            if (spriteBatch != null)
+            {
+                spriteBatch.Dispose();
+                spriteBatch = null;
+            }
+        }
+
+
+        /// <summary>
+        /// Reset the stars and the parallax effect.
+        /// </summary>
+        /// <param name="position">The new origin point for the parallax effect.</param>
+        public void Reset(Vector2 position)
+        {
+            // recreate the stars
+            int viewportWidth = graphicsDevice.Viewport.Width;
+            int viewportHeight = graphicsDevice.Viewport.Height;
+            for (int i = 0; i < stars.Length; ++i)
+            {
+                stars[i] = new Vector2(RandomMath.Random.Next(0, viewportWidth), 
+                    RandomMath.Random.Next(0, viewportHeight));
+            }
+
+            // reset the position
+            this.lastPosition = this.position = position;
+        }
+
+
+        #endregion
+
+
+        #region Draw Methods
+
+
+        /// <summary>
+        /// Update and draw the starfield.
+        /// </summary>
+        /// <remarks>
+        /// This function updates and draws the starfield, 
+        /// so that the per-star loop is only run once per frame.
+        /// </remarks>
+        /// <param name="position">The new position for the parallax effect.</param>
+        public void Draw(Vector2 position)
+        {
+            // update the current position
+            this.lastPosition = this.position;
+            this.position = position;
+
+            // determine the movement vector of the stars
+            // -- for the purposes of the parallax effect, 
+            //    this is the opposite direction as the position movement.
+            Vector2 movement = -1.0f * (position - lastPosition);
+
+            // create a rectangle representing the screen dimensions of the starfield
+            Rectangle starfieldRectangle = new Rectangle(0, 0, 
+                graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height);
+
+            // draw a background color for the starfield
+            spriteBatch.Begin();
+            spriteBatch.Draw(starTexture, starfieldRectangle, backgroundColor);
+            spriteBatch.End();
+
+            // draw the cloud texture
+            cloudEffectPosition.SetValue(this.position);
+            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, 
+                null, null, null, cloudEffect);
+            spriteBatch.Draw(cloudTexture, starfieldRectangle, null, Color.White, 0.0f,
+                Vector2.Zero, SpriteEffects.None, 1.0f);
+            spriteBatch.End();
+
+            // if we've moved too far, then reset, as the stars will be moving too fast
+            if (movement.Length() > maximumMovementPerUpdate)
+            {
+                Reset(position);
+                return;
+            }
+
+            // draw all of the stars
+            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied);
+            for (int i = 0; i < stars.Length; i++)
+            {
+                // move the star based on the depth
+                int depth = i % movementFactors.Length;
+                stars[i] += movement * movementFactors[depth];
+
+                // wrap the stars around
+                if (stars[i].X < starfieldRectangle.X)
+                {
+                    stars[i].X = starfieldRectangle.X + starfieldRectangle.Width;
+                    stars[i].Y = starfieldRectangle.Y + 
+                        RandomMath.Random.Next(starfieldRectangle.Height);
+                }
+                if (stars[i].X > (starfieldRectangle.X + starfieldRectangle.Width))
+                {
+                    stars[i].X = starfieldRectangle.X;
+                    stars[i].Y = starfieldRectangle.Y + 
+                        RandomMath.Random.Next(starfieldRectangle.Height);
+                }
+                if (stars[i].Y < starfieldRectangle.Y)
+                {
+                    stars[i].X = starfieldRectangle.X + 
+                        RandomMath.Random.Next(starfieldRectangle.Width);
+                    stars[i].Y = starfieldRectangle.Y + starfieldRectangle.Height;
+                }
+                if (stars[i].Y > 
+                    (starfieldRectangle.Y + graphicsDevice.Viewport.Height))
+                {
+                    stars[i].X = starfieldRectangle.X + 
+                        RandomMath.Random.Next(starfieldRectangle.Width);
+                    stars[i].Y = starfieldRectangle.Y;
+                }
+
+                // draw the star
+                spriteBatch.Draw(starTexture, 
+                    new Rectangle((int)stars[i].X, (int)stars[i].Y, starSize, starSize),
+                    null, layerColors[depth]);
+            }
+            spriteBatch.End();
+        }
+
+
+        #endregion
+
+    
+        #region IDisposable Implementation
+
+
+        /// <summary>
+        /// Finalizes the Starfield object, calls Dispose(false)
+        /// </summary>
+        ~Starfield()
+        {
+            Dispose(false);
+        }
+
+
+        /// <summary>
+        /// Disposes the Starfield object.
+        /// </summary>
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        
+        /// <summary>
+        /// Disposes this object.
+        /// </summary>
+        /// <param name="disposing">
+        /// True if this method was called as part of the Dispose method.
+        /// </param>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                lock (this)
+                {
+                    if (starTexture != null)
+                    {
+                        starTexture.Dispose();
+                        starTexture = null;
+                    }
+                    if (spriteBatch != null)
+                    {
+                        spriteBatch.Dispose();
+                        spriteBatch = null;
+                    }
+                }
+            }
+        }
+
+
+        #endregion
+    }
+}
+

+ 320 - 0
Samples/Linux/NetRumble/ScreenManager/GameScreen.cs

@@ -0,0 +1,320 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// GameScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// Enum describes the screen transition state.
+    /// </summary>
+    public enum ScreenState
+    {
+        TransitionOn,
+        Active,
+        TransitionOff,
+        Hidden,
+    }
+
+
+    /// <summary>
+    /// A screen is a single layer that has update and draw logic, and which
+    /// can be combined with other layers to build up a complex menu system.
+    /// For instance the main menu, the options menu, the "are you sure you
+    /// want to quit" message box, and the main game itself are all implemented
+    /// as screens.
+    /// </summary>
+    /// <remarks>
+    /// This public class is similar to one in the GameStateManagement sample.
+    /// </remarks>
+    public abstract class GameScreen
+    {
+        #region Properties
+
+
+        /// <summary>
+        /// Normally when one screen is brought up over the top of another,
+        /// the first screen will transition off to make room for the new
+        /// one. This property indicates whether the screen is only a small
+        /// popup, in which case screens underneath it do not need to bother
+        /// transitioning off.
+        /// </summary>
+        public bool IsPopup
+        {
+            get { return isPopup; }
+            protected set { isPopup = value; }
+        }
+
+        bool isPopup = false;
+
+
+        /// <summary>
+        /// Indicates how long the screen takes to
+        /// transition on when it is activated.
+        /// </summary>
+        public TimeSpan TransitionOnTime
+        {
+            get { return transitionOnTime; }
+            protected set { transitionOnTime = value; }
+        }
+
+        TimeSpan transitionOnTime = TimeSpan.Zero;
+
+
+        /// <summary>
+        /// Indicates how long the screen takes to
+        /// transition off when it is deactivated.
+        /// </summary>
+        public TimeSpan TransitionOffTime
+        {
+            get { return transitionOffTime; }
+            protected set { transitionOffTime = value; }
+        }
+
+        TimeSpan transitionOffTime = TimeSpan.Zero;
+
+
+        /// <summary>
+        /// Gets the current position of the screen transition, ranging
+        /// from zero (fully active, no transition) to one (transitioned
+        /// fully off to nothing).
+        /// </summary>
+        public float TransitionPosition
+        {
+            get { return transitionPosition; }
+            protected set { transitionPosition = value; }
+        }
+
+        float transitionPosition = 1;
+
+
+        /// <summary>
+        /// Gets the current alpha of the screen transition, ranging
+        /// from 255 (fully active, no transition) to 0 (transitioned
+        /// fully off to nothing).
+        /// </summary>
+        public byte TransitionAlpha
+        {
+            get { return (byte)(255 - TransitionPosition * 255); }
+        }
+
+
+        /// <summary>
+        /// Gets the current screen transition state.
+        /// </summary>
+        public ScreenState ScreenState
+        {
+            get { return screenState; }
+            protected set { screenState = value; }
+        }
+
+        ScreenState screenState = ScreenState.TransitionOn;
+
+
+        /// <summary>
+        /// There are two possible reasons why a screen might be transitioning
+        /// off. It could be temporarily going away to make room for another
+        /// screen that is on top of it, or it could be going away for good.
+        /// This property indicates whether the screen is exiting for real:
+        /// if set, the screen will automatically remove itself as soon as the
+        /// transition finishes.
+        /// </summary>
+        public bool IsExiting
+        {
+            get { return isExiting; }
+            protected set { isExiting = value; }
+        }
+
+        bool isExiting = false;
+
+
+        /// <summary>
+        /// Checks whether this screen is active and can respond to user input.
+        /// </summary>
+        public bool IsActive
+        {
+            get
+            {
+                return !otherScreenHasFocus &&
+                       (screenState == ScreenState.TransitionOn ||
+                        screenState == ScreenState.Active);
+            }
+        }
+
+        bool otherScreenHasFocus;
+
+
+        /// <summary>
+        /// Gets the manager that this screen belongs to.
+        /// </summary>
+        public ScreenManager ScreenManager
+        {
+            get { return screenManager; }
+            internal set { screenManager = value; }
+        }
+
+        ScreenManager screenManager;
+
+
+        #endregion
+
+        #region Initialization
+
+
+        /// <summary>
+        /// Load graphics content for the screen.
+        /// </summary>
+        public virtual void LoadContent() { }
+
+
+        /// <summary>
+        /// Unload content for the screen.
+        /// </summary>
+        public virtual void UnloadContent() { }
+
+
+        #endregion
+
+        #region Update and Draw
+
+
+        /// <summary>
+        /// Allows the screen to run logic, such as updating the transition position.
+        /// Unlike HandleInput, this method is called regardless of whether the screen
+        /// is active, hidden, or in the middle of a transition.
+        /// </summary>
+        public virtual void Update(GameTime gameTime, bool otherScreenHasFocus,
+                                                      bool coveredByOtherScreen)
+        {
+            this.otherScreenHasFocus = otherScreenHasFocus;
+
+            if (isExiting)
+            {
+                // If the screen is going away to die, it should transition off.
+                screenState = ScreenState.TransitionOff;
+
+                if (!UpdateTransition(gameTime, transitionOffTime, 1))
+                {
+                    // When the transition finishes, remove the screen.
+                    ScreenManager.RemoveScreen(this);
+
+                    isExiting = false;
+                }
+            }
+            else if (coveredByOtherScreen)
+            {
+                // If the screen is covered by another, it should transition off.
+                if (UpdateTransition(gameTime, transitionOffTime, 1))
+                {
+                    // Still busy transitioning.
+                    screenState = ScreenState.TransitionOff;
+                }
+                else
+                {
+                    // Transition finished!
+                    screenState = ScreenState.Hidden;
+                }
+            }
+            else
+            {
+                // Otherwise the screen should transition on and become active.
+                if (UpdateTransition(gameTime, transitionOnTime, -1))
+                {
+                    // Still busy transitioning.
+                    screenState = ScreenState.TransitionOn;
+                }
+                else
+                {
+                    // Transition finished!
+                    screenState = ScreenState.Active;
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Helper for updating the screen transition position.
+        /// </summary>
+        bool UpdateTransition(GameTime gameTime, TimeSpan time, int direction)
+        {
+            // How much should we move by?
+            float transitionDelta;
+
+            if (time == TimeSpan.Zero)
+                transitionDelta = 1;
+            else
+                transitionDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds /
+                                          time.TotalMilliseconds);
+
+            // Update the transition position.
+            transitionPosition += transitionDelta * direction;
+
+            // Did we reach the end of the transition?
+            if ((transitionPosition <= 0) || (transitionPosition >= 1))
+            {
+                transitionPosition = MathHelper.Clamp(transitionPosition, 0, 1);
+                return false;
+            }
+            
+            // Otherwise we are still busy transitioning.
+            return true;
+        }
+
+
+        /// <summary>
+        /// Allows the screen to handle user input. Unlike Update, this method
+        /// is only called when the screen is active, and not when some other
+        /// screen has taken the focus.
+        /// </summary>
+        public virtual void HandleInput(InputState input) { }
+
+
+        /// <summary>
+        /// Screen-specific update to gamer rich presence.
+        /// </summary>
+        public virtual void UpdatePresence() { }
+
+
+        /// <summary>
+        /// This is called when the screen should draw itself.
+        /// </summary>
+        public abstract void Draw(GameTime gameTime);
+
+
+        #endregion
+
+        #region Public Methods
+
+
+        /// <summary>
+        /// Tells the screen to go away. Unlike ScreenManager.RemoveScreen, which
+        /// instantly kills the screen, this method respects the transition timings
+        /// and will give the screen a chance to gradually transition off.
+        /// </summary>
+        public virtual void ExitScreen()
+        {
+            if (TransitionOffTime == TimeSpan.Zero)
+            {
+                // If the screen has a zero transition time, remove it immediately.
+                ScreenManager.RemoveScreen(this);
+            }
+            else
+            {
+                // Otherwise flag that it should transition off and then exit.
+                isExiting = true;
+            }
+        }
+
+
+        #endregion
+    }
+}

+ 224 - 0
Samples/Linux/NetRumble/ScreenManager/InputState.cs

@@ -0,0 +1,224 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// InputState.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Input;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// Helper for reading input from keyboard and gamepad. This public class tracks
+    /// the current and previous state of both input devices, and implements query
+    /// properties for high level input actions such as "move up through the menu"
+    /// or "pause the game".
+    /// </summary>
+    /// <remarks>
+    /// This public class is similar to one in the GameStateManagement sample.
+    /// </remarks>
+    public class InputState
+    {
+        #region Fields
+
+        public KeyboardState CurrentKeyboardState;
+        public GamePadState CurrentGamePadState;
+
+        public KeyboardState LastKeyboardState;
+        public GamePadState LastGamePadState;
+
+        #endregion
+
+        #region Properties
+
+
+        /// <summary>
+        /// Checks for a "menu up" input action (on either keyboard or gamepad).
+        /// </summary>
+        public bool MenuUp
+        {
+            get
+            {
+                return IsNewKeyPress(Keys.Up) ||
+                       (CurrentGamePadState.DPad.Up == ButtonState.Pressed &&
+                        LastGamePadState.DPad.Up == ButtonState.Released) ||
+                       (CurrentGamePadState.ThumbSticks.Left.Y > 0 &&
+                        LastGamePadState.ThumbSticks.Left.Y <= 0);
+            }
+        }
+
+
+        /// <summary>
+        /// Checks for a "menu down" input action (on either keyboard or gamepad).
+        /// </summary>
+        public bool MenuDown
+        {
+            get
+            {
+                return IsNewKeyPress(Keys.Down) ||
+                       (CurrentGamePadState.DPad.Down == ButtonState.Pressed &&
+                        LastGamePadState.DPad.Down == ButtonState.Released) ||
+                       (CurrentGamePadState.ThumbSticks.Left.Y < 0 &&
+                        LastGamePadState.ThumbSticks.Left.Y >= 0);
+            }
+        }
+
+
+        /// <summary>
+        /// Checks for a "menu select" input action (on either keyboard or gamepad).
+        /// </summary>
+        public bool MenuSelect
+        {
+            get
+            {
+                return IsNewKeyPress(Keys.Space) ||
+                       IsNewKeyPress(Keys.Enter) ||
+                       (CurrentGamePadState.Buttons.A == ButtonState.Pressed &&
+                        LastGamePadState.Buttons.A == ButtonState.Released) ||
+                       (CurrentGamePadState.Buttons.Start == ButtonState.Pressed &&
+                        LastGamePadState.Buttons.Start == ButtonState.Released);
+            }
+        }
+
+
+        /// <summary>
+        /// Checks for a "menu cancel" input action (on either keyboard or gamepad).
+        /// </summary>
+        public bool MenuCancel
+        {
+            get
+            {
+                return IsNewKeyPress(Keys.Escape) ||
+                       (CurrentGamePadState.Buttons.B == ButtonState.Pressed &&
+                        LastGamePadState.Buttons.B == ButtonState.Released) ||
+                       (CurrentGamePadState.Buttons.Back == ButtonState.Pressed &&
+                        LastGamePadState.Buttons.Back == ButtonState.Released);
+            }
+        }
+
+
+        /// <summary>
+        /// Checks for a "pause the game" input action (on either keyboard or gamepad).
+        /// </summary>
+        public bool PauseGame
+        {
+            get
+            {
+                return IsNewKeyPress(Keys.Escape) ||
+                       (CurrentGamePadState.Buttons.Back == ButtonState.Pressed &&
+                        LastGamePadState.Buttons.Back == ButtonState.Released) ||
+                       (CurrentGamePadState.Buttons.Start == ButtonState.Pressed &&
+                        LastGamePadState.Buttons.Start == ButtonState.Released);
+            }
+        }
+
+
+        /// <summary>
+        /// Checks for a positive "ship color change" input action
+        /// </summary>
+        public bool ShipColorChangeUp
+        {
+            get
+            {
+                return IsNewKeyPress(Keys.Up) ||
+                   (CurrentGamePadState.Buttons.RightShoulder == ButtonState.Pressed &&
+                    LastGamePadState.Buttons.RightShoulder == ButtonState.Released);
+            }
+        }
+
+
+        /// <summary>
+        /// Checks for a negative "ship color change" input action.
+        /// </summary>
+        public bool ShipColorChangeDown
+        {
+            get
+            {
+                return IsNewKeyPress(Keys.Down) ||
+                    (CurrentGamePadState.Buttons.LeftShoulder == ButtonState.Pressed &&
+                     LastGamePadState.Buttons.LeftShoulder == ButtonState.Released);
+            }
+        }
+
+
+
+        /// <summary>
+        /// Checks for a positive "ship model change" input action.
+        /// </summary>
+        public bool ShipModelChangeUp
+        {
+            get
+            {
+                return IsNewKeyPress(Keys.Right) ||
+                    (CurrentGamePadState.Triggers.Right >= 1f &&
+                     LastGamePadState.Triggers.Right < 1f);
+            }
+        }
+
+
+        /// <summary>
+        /// Checks for a negative "ship model change" input action.
+        /// </summary>
+        public bool ShipModelChangeDown
+        {
+            get
+            {
+                return IsNewKeyPress(Keys.Left) ||
+                    (CurrentGamePadState.Triggers.Left >= 1f &&
+                     LastGamePadState.Triggers.Left < 1f);
+            }
+        }
+
+
+        /// <summary>
+        /// Checks for a "mark ready" input action (on either keyboard or gamepad).
+        /// </summary>
+        public bool MarkReady
+        {
+            get
+            {
+                return IsNewKeyPress(Keys.X) ||
+                       (CurrentGamePadState.Buttons.X == ButtonState.Pressed &&
+                        LastGamePadState.Buttons.X == ButtonState.Released);
+            }
+        }
+
+
+        #endregion
+
+        #region Methods
+
+
+        /// <summary>
+        /// Reads the latest state of the keyboard and gamepad.
+        /// </summary>
+        public void Update()
+        {
+            LastKeyboardState = CurrentKeyboardState;
+            LastGamePadState = CurrentGamePadState;
+
+            CurrentKeyboardState = Keyboard.GetState();
+            CurrentGamePadState = GamePad.GetState(PlayerIndex.One);
+        }
+
+
+        /// <summary>
+        /// Helper for checking if a key was newly pressed during this update.
+        /// </summary>
+        public bool IsNewKeyPress(Keys key)
+        {
+            return (CurrentKeyboardState.IsKeyDown(key) &&
+                    LastKeyboardState.IsKeyUp(key));
+        }
+
+
+        #endregion
+    }
+}

+ 150 - 0
Samples/Linux/NetRumble/ScreenManager/LoadingScreen.cs

@@ -0,0 +1,150 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// LoadingScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// The loading screen coordinates transitions between the menu system and the
+    /// game itself. Normally one screen will transition off at the same time as
+    /// the next screen is transitioning on, but for larger transitions that can
+    /// take a longer time to load their data, we want the menu system to be entirely
+    /// gone before we start loading the game. This is done as follows:
+    /// 
+    /// - Tell all the existing screens to transition off.
+    /// - Activate a loading screen, which will transition on at the same time.
+    /// - The loading screen watches the state of the previous screens.
+    /// - When it sees they have finished transitioning off, it activates the real
+    ///   next screen, which may take a long time to load its data. The loading
+    ///   screen will be the only thing displayed while this load is taking place.
+    /// </summary>
+    /// <remarks>
+    /// This public class is similar to one in the GameStateManagement sample.
+    /// </remarks>
+    public class LoadingScreen : GameScreen
+    {
+        #region Fields
+
+        bool loadingIsSlow;
+        bool otherScreensAreGone;
+        EventHandler<EventArgs> loadNextScreen;
+
+        #endregion
+
+        #region Initialization
+
+
+        /// <summary>
+        /// The constructor is private: loading screens should
+        /// be activated via the static Load method instead.
+        /// </summary>
+        private LoadingScreen()
+        {
+            TransitionOnTime = TimeSpan.FromSeconds(0.5);
+        }
+
+
+        /// <summary>
+        /// Activates the loading screen.
+        /// </summary>
+        public static void Load(ScreenManager screenManager,
+                                EventHandler<EventArgs> loadNextScreen,
+                                bool loadingIsSlow)
+        {
+            // Tell all the current screens to transition off.
+            foreach (GameScreen screen in screenManager.GetScreens())
+                screen.ExitScreen();
+
+            // Create and activate the loading screen.
+            LoadingScreen loadingScreen = new LoadingScreen();
+
+            loadingScreen.loadingIsSlow = loadingIsSlow;
+            loadingScreen.loadNextScreen = loadNextScreen;
+
+            screenManager.AddScreen(loadingScreen);
+        }
+
+
+        #endregion
+
+        #region Update and Draw
+
+
+        /// <summary>
+        /// Updates the loading screen.
+        /// </summary>
+        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+                                                       bool coveredByOtherScreen)
+        {
+            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+
+            // If all the previous screens have finished transitioning
+            // off, it is time to actually perform the load.
+            if (otherScreensAreGone)
+            {
+                ScreenManager.RemoveScreen(this);
+
+                loadNextScreen(this, EventArgs.Empty);
+            }
+        }
+
+
+        /// <summary>
+        /// Draws the loading screen.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            // If we are the only active screen, that means all the previous screens
+            // must have finished transitioning off. We check for this in the Draw
+            // method, rather than in Update, because it isn't enough just for the
+            // screens to be gone: in order for the transition to look good we must
+            // have actually drawn a frame without them before we perform the load.
+            if ((ScreenState == ScreenState.Active) &&
+                (ScreenManager.GetScreens().Length == 1))
+            {
+                otherScreensAreGone = true;
+            }
+
+            // The gameplay screen takes a while to load, so we display a loading
+            // message while that is going on, but the menus load very quickly, and
+            // it would look silly if we flashed this up for just a fraction of a
+            // second while returning from the game to the menus. This parameter
+            // tells us how long the loading is going to take, so we know whether
+            // to bother drawing the message.
+            if (loadingIsSlow)
+            {
+                const string message = "Loading...";
+
+                // Center the text in the viewport.
+                Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
+                Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
+                Vector2 textSize = ScreenManager.Font.MeasureString(message);
+                Vector2 textPosition = (viewportSize - textSize) / 2;
+
+                Color color = new Color(255, 255, 255, TransitionAlpha);
+
+                // Draw the text.
+                ScreenManager.SpriteBatch.Begin();
+                
+                ScreenManager.SpriteBatch.DrawString(ScreenManager.Font, message,
+                                                     textPosition, color);
+                
+                ScreenManager.SpriteBatch.End();
+            }
+        }
+
+
+        #endregion
+    }
+}

+ 181 - 0
Samples/Linux/NetRumble/ScreenManager/MenuScreen.cs

@@ -0,0 +1,181 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// MenuScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// Base public class for screens that contain a menu of options. The user can
+    /// move up and down to select an entry, or cancel to back out of the screen.
+    /// </summary>
+    /// <remarks>
+    /// This public class is similar to one in the GameStateManagement sample.
+    /// </remarks>
+    abstract public class MenuScreen : GameScreen
+    {
+        #region Fields
+        List<string> menuEntries = new List<string>();
+        int selectedEntry = 0;
+        #endregion
+
+        #region Properties
+
+
+        /// <summary>
+        /// Gets the list of menu entry strings, so derived classes can add
+        /// or change the menu contents.
+        /// </summary>
+        protected IList<string> MenuEntries
+        {
+            get { return menuEntries; }
+        }
+
+
+        #endregion
+
+        #region Initialization
+
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        protected MenuScreen()
+        {
+            TransitionOnTime = TimeSpan.FromSeconds(1.0);
+            TransitionOffTime = TimeSpan.FromSeconds(1.0);
+        }
+
+        #endregion
+
+        #region Handle Input
+
+
+        /// <summary>
+        /// Responds to user input, changing the selected entry and accepting
+        /// or cancelling the menu.
+        /// </summary>
+        public override void HandleInput(InputState input)
+        {
+            // Move to the previous menu entry?
+            if (input.MenuUp)
+            {
+                selectedEntry--;
+
+                if (selectedEntry < 0)
+                    selectedEntry = menuEntries.Count - 1;
+
+                AudioManager.PlaySoundEffect("menu_scroll");
+            }
+
+            // Move to the next menu entry?
+            if (input.MenuDown)
+            {
+                selectedEntry++;
+
+                if (selectedEntry >= menuEntries.Count)
+                    selectedEntry = 0;
+
+                AudioManager.PlaySoundEffect("menu_scroll");
+            }
+
+            // Accept or cancel the menu?
+            if (input.MenuSelect)
+            {
+                AudioManager.PlaySoundEffect("menu_select");
+                OnSelectEntry(selectedEntry);
+            }
+            else if (input.MenuCancel)
+            {
+                OnCancel();
+            }
+        }
+
+
+        /// <summary>
+        /// Notifies derived classes that a menu entry has been chosen.
+        /// </summary>
+        protected abstract void OnSelectEntry(int entryIndex);
+
+
+        /// <summary>
+        /// Notifies derived classes that the menu has been cancelled.
+        /// </summary>
+        protected abstract void OnCancel();
+
+
+        #endregion
+
+        #region Draw
+
+
+        /// <summary>
+        /// Draws the menu.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
+            Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
+
+            Vector2 position = new Vector2(0f, viewportSize.Y * 0.65f);
+
+            // 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).
+            float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
+
+            if (ScreenState == ScreenState.TransitionOn)
+                position.Y += transitionOffset * 256;
+            else
+                position.Y += transitionOffset * 512;
+
+            // Draw each menu entry in turn.
+            ScreenManager.SpriteBatch.Begin();
+
+            for (int i = 0; i < menuEntries.Count; i++)
+            {
+                Color color = Color.White;
+                float scale = 1.0f;
+
+                if (IsActive && (i == selectedEntry))
+                {
+                    // The selected entry is yellow, and has an animating size.
+                    double time = gameTime.TotalGameTime.TotalSeconds;
+                    float pulsate = (float)Math.Sin(time * 6f) + 1f;
+                    
+                    color = Color.Orange;
+                    scale += pulsate * 0.05f;
+                }
+
+                // Modify the alpha to fade text out during transitions.
+                color = new Color(color.R, color.G, color.B, TransitionAlpha);
+
+                // Draw text, centered on the middle of each line.
+                Vector2 origin = new Vector2(0, ScreenManager.Font.LineSpacing / 2);
+                Vector2 size = ScreenManager.Font.MeasureString(menuEntries[i]);
+                position.X = viewportSize.X / 2f - size.X / 2f * scale;
+                ScreenManager.SpriteBatch.DrawString(ScreenManager.Font, menuEntries[i],
+                                                     position, color, 0, origin, scale,
+                                                     SpriteEffects.None, 0);
+
+                position.Y += ScreenManager.Font.LineSpacing;
+            }
+
+            ScreenManager.SpriteBatch.End();
+        }
+
+
+        #endregion
+    }
+}

+ 174 - 0
Samples/Linux/NetRumble/ScreenManager/MessageBoxScreen.cs

@@ -0,0 +1,174 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// MessageBoxScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// A popup message box screen, used to display "are you sure?"
+    /// confirmation messages.
+    /// </summary>
+    /// <remarks>
+    /// This public class is somewhat similar to one of the same name in the 
+    /// GameStateManagement sample.
+    /// </remarks>
+    public class MessageBoxScreen : GameScreen
+    {
+        #region Constants
+        const string usageText = "A button = Okay\n" +
+                                 "B button = Cancel";
+        #endregion
+
+        #region Fields
+
+        bool pauseMenu = false;
+        string message;
+        SpriteFont smallFont;
+
+        #endregion
+
+        #region Events
+
+        public event EventHandler<EventArgs> Accepted;
+        public event EventHandler<EventArgs> Cancelled;
+
+        #endregion
+
+        #region Initialization
+
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        public MessageBoxScreen(string message)
+        {
+            this.message = message;
+
+            IsPopup = true;
+
+            TransitionOnTime = TimeSpan.FromSeconds(0.25);
+            TransitionOffTime = TimeSpan.FromSeconds(0.25);
+        }
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        public MessageBoxScreen(string message, bool pauseMenu) : this(message)
+        {
+            this.pauseMenu = pauseMenu;
+        }
+
+
+        /// <summary>
+        /// Loads graphics content for this screen. This uses the shared ContentManager
+        /// provided by the ScreenManager, so the content will remain loaded forever.
+        /// Whenever a subsequent MessageBoxScreen tries to load this same content,
+        /// it will just get back another reference to the already loaded instance.
+        /// </summary>
+        public override void LoadContent()
+        {
+            smallFont = ScreenManager.Content.Load<SpriteFont>("Fonts/MessageBox");
+        }
+
+
+        #endregion
+
+        #region Handle Input
+
+
+        /// <summary>
+        /// Responds to user input, accepting or cancelling the message box.
+        /// </summary>
+        public override void HandleInput(InputState input)
+        {
+            if (input.MenuSelect && (!pauseMenu || 
+                (input.CurrentGamePadState.Buttons.A == ButtonState.Pressed)))
+            {
+                // Raise the accepted event, then exit the message box.
+                if (Accepted != null)
+                    Accepted(this, EventArgs.Empty);
+            
+                ExitScreen();
+            }
+            else if (input.MenuCancel || (input.MenuSelect && pauseMenu && 
+                (input.CurrentGamePadState.Buttons.A == ButtonState.Released)))
+            {
+                // Raise the cancelled event, then exit the message box.
+                if (Cancelled != null)
+                    Cancelled(this, EventArgs.Empty);
+
+                ExitScreen();
+            }
+        }
+
+
+        #endregion
+
+        #region Draw
+
+
+        /// <summary>
+        /// Draws the message box.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            // Darken down any other screens that were drawn beneath the popup.
+            ScreenManager.FadeBackBufferToBlack(TransitionAlpha * 2 / 3);
+
+            // Center the message text in the viewport.
+            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
+            Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
+            Vector2 textSize = ScreenManager.Font.MeasureString(message);
+            Vector2 textPosition = (viewportSize - textSize) / 2;
+            Vector2 usageTextSize = smallFont.MeasureString(usageText);
+            Vector2 usageTextPosition = (viewportSize - usageTextSize) / 2;
+            usageTextPosition.Y = textPosition.Y + 
+                ScreenManager.Font.LineSpacing * 1.1f;
+
+            // Fade the popup alpha during transitions.
+            Color color = new Color(255, 255, 255, TransitionAlpha);
+
+            // Draw the background rectangles
+            Rectangle rect = new Rectangle(
+                (int)(Math.Min(usageTextPosition.X, textPosition.X)),
+                (int)(textPosition.Y),
+                (int)(Math.Max(usageTextSize.X, textSize.X)),
+                (int)(ScreenManager.Font.LineSpacing * 1.1f+ usageTextSize.Y)
+                );
+            rect.X -= (int)(0.1f * rect.Width);
+            rect.Y -= (int)(0.1f * rect.Height);
+            rect.Width += (int)(0.2f * rect.Width);
+            rect.Height += (int)(0.2f * rect.Height);
+
+            Rectangle rect2 = new Rectangle(rect.X - 1, rect.Y - 1, 
+                rect.Width + 2, rect.Height + 2);
+            ScreenManager.DrawRectangle(rect2, new Color(128, 128, 128, 
+                (byte)(192.0f * (float)TransitionAlpha / 255.0f)));
+            ScreenManager.DrawRectangle(rect, new Color(0, 0, 0, 
+                (byte)(232.0f * (float)TransitionAlpha / 255.0f)));
+
+            // Draw the message box text.
+            ScreenManager.SpriteBatch.Begin();
+            ScreenManager.SpriteBatch.DrawString(ScreenManager.Font, message,
+                                                 textPosition, color);
+            ScreenManager.SpriteBatch.DrawString(smallFont, usageText,
+                                                 usageTextPosition, color);
+            ScreenManager.SpriteBatch.End();
+        }
+
+
+        #endregion
+    }
+}

+ 385 - 0
Samples/Linux/NetRumble/ScreenManager/ScreenManager.cs

@@ -0,0 +1,385 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// ScreenManager.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.Diagnostics;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.GamerServices;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// The screen manager is a component which manages one or more GameScreen
+    /// instances. It maintains a stack of screens, calls their Update and Draw
+    /// methods at the appropriate times, and automatically routes input to the
+    /// topmost active screen.
+    /// </summary>
+    /// <remarks>
+    /// This public class is similar to one in the GameStateManagement sample.
+    /// </remarks>
+    public class ScreenManager : DrawableGameComponent
+    {
+        #region Fields
+
+        List<GameScreen> screens = new List<GameScreen>();
+        List<GameScreen> screensToUpdate = new List<GameScreen>();
+        List<GameScreen> screensToDraw = new List<GameScreen>();
+
+        InputState input = new InputState();
+
+        IGraphicsDeviceService graphicsDeviceService;
+        public SignedInGamer invited;
+
+        ContentManager content;
+        SpriteBatch spriteBatch;
+        SpriteFont font;
+        Texture2D blankTexture;
+        Rectangle titleSafeArea;
+
+        bool traceEnabled;
+
+        #endregion
+
+
+        #region Properties
+
+        /// <summary>
+        /// Expose access to our Game instance (this is protected in the
+        /// default GameComponent, but we want to make it public).
+        /// </summary>
+        new public Game Game
+        {
+            get { return base.Game; }
+        }
+
+
+        /// <summary>
+        /// Expose access to our graphics device (this is protected in the
+        /// default DrawableGameComponent, but we want to make it public).
+        /// </summary>
+        new public GraphicsDevice GraphicsDevice
+        {
+            get { return base.GraphicsDevice; }
+        }
+
+        
+        /// <summary>
+        /// A content manager used to load data that is shared between multiple
+        /// screens. This is never unloaded, so if a screen requires a large amount
+        /// of temporary data, it should create a local content manager instead.
+        /// </summary>
+        public ContentManager Content
+        {
+            get { return content; }
+        }
+
+
+        /// <summary>
+        /// A default SpriteBatch shared by all the screens. This saves
+        /// each screen having to bother creating their own local instance.
+        /// </summary>
+        public SpriteBatch SpriteBatch
+        {
+            get { return spriteBatch; }
+        }
+
+
+        /// <summary>
+        /// A default font shared by all the screens. This saves
+        /// each screen having to bother loading their own local copy.
+        /// </summary>
+        public SpriteFont Font
+        {
+            get { return font; }
+        }
+
+
+        /// <summary>
+        /// If true, the manager prints out a list of all the screens
+        /// each time it is updated. This can be useful for making sure
+        /// everything is being added and removed at the right times.
+        /// </summary>
+        public bool TraceEnabled
+        {
+            get { return traceEnabled; }
+            set { traceEnabled = value; }
+        }
+
+
+        /// <summary>
+        /// The title-safe area for the menus.
+        /// </summary>
+        public Rectangle TitleSafeArea
+        {
+            get { return titleSafeArea; }
+        }
+
+
+        #endregion
+
+
+        #region Initialization
+
+
+        /// <summary>
+        /// Constructs a new screen manager component.
+        /// </summary>
+        public ScreenManager(Game game)
+            : base(game)
+        {
+            content = new ContentManager(game.Services, "Content");
+
+            graphicsDeviceService = (IGraphicsDeviceService)game.Services.GetService(
+                                                        typeof(IGraphicsDeviceService));
+
+            if (graphicsDeviceService == null)
+                throw new InvalidOperationException("No graphics device service.");
+
+            invited = null;
+        }
+
+
+        /// <summary>
+        /// Load your graphics content.
+        /// </summary>
+        protected override void LoadContent()
+        {
+            // Load content belonging to the screen manager.
+            spriteBatch = new SpriteBatch(GraphicsDevice);
+            font = content.Load<SpriteFont>("Fonts/MenuFont");
+            blankTexture = content.Load<Texture2D>("Textures/blank");
+
+            // Tell each of the screens to load their content.
+            foreach (GameScreen screen in screens)
+            {
+                screen.LoadContent();
+            }
+
+            // update the title-safe area
+            titleSafeArea = new Rectangle(
+                (int)Math.Floor(GraphicsDevice.Viewport.X + 
+                   GraphicsDevice.Viewport.Width * 0.05f),
+                (int)Math.Floor(GraphicsDevice.Viewport.Y + 
+                   GraphicsDevice.Viewport.Height * 0.05f), 
+                (int)Math.Floor(GraphicsDevice.Viewport.Width * 0.9f), 
+                (int)Math.Floor(GraphicsDevice.Viewport.Height * 0.9f));
+        }
+
+
+        /// <summary>
+        /// Unload your graphics content.
+        /// </summary>
+        protected override void UnloadContent()
+        {
+            // Unload content belonging to the screen manager.
+            content.Unload();
+
+            // Tell each of the screens to unload their content.
+            foreach (GameScreen screen in screens)
+            {
+                screen.UnloadContent();
+            }
+        }
+
+
+        #endregion
+
+
+        #region Update and Draw
+
+
+        /// <summary>
+        /// Allows each screen to run logic.
+        /// </summary>
+        public override void Update(GameTime gameTime)
+        {
+            // Read the keyboard and gamepad.
+            input.Update();
+
+            // Make a copy of the master screen list, to avoid confusion if
+            // the process of updating one screen adds or removes others
+            // (or it happens on another thread)
+            screensToUpdate.Clear();
+
+            foreach (GameScreen screen in screens)
+                screensToUpdate.Add(screen);
+
+            bool otherScreenHasFocus = !Game.IsActive;
+            bool coveredByOtherScreen = false;
+
+            // Loop as long as there are screens waiting to be updated.
+            while (screensToUpdate.Count > 0)
+            {
+                // Pop the topmost screen off the waiting list.
+                GameScreen screen = screensToUpdate[screensToUpdate.Count - 1];
+
+                screensToUpdate.RemoveAt(screensToUpdate.Count - 1);
+
+                // Update the screen.
+                screen.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+
+                if (screen.ScreenState == ScreenState.TransitionOn ||
+                    screen.ScreenState == ScreenState.Active)
+                {
+                    // If this is the first active screen we came across,
+                    // give it a chance to handle input and update presence.
+                    if (!otherScreenHasFocus)
+                    {
+                        screen.HandleInput(input);
+
+                        screen.UpdatePresence(); // presence support
+
+                        otherScreenHasFocus = true;
+                    }
+
+                    // If this is an active non-popup, inform any subsequent
+                    // screens that they are covered by it.
+                    if (!screen.IsPopup)
+                        coveredByOtherScreen = true;
+                }
+            }
+
+            // Print debug trace?
+            if (traceEnabled)
+                TraceScreens();
+        }
+
+
+        /// <summary>
+        /// Prints a list of all the screens, for debugging.
+        /// </summary>
+        void TraceScreens()
+        {
+            List<string> screenNames = new List<string>();
+
+            foreach (GameScreen screen in screens)
+                screenNames.Add(screen.GetType().Name);
+
+            Debug.WriteLine(string.Join(", ", screenNames.ToArray()));
+        }
+
+
+        /// <summary>
+        /// Tells each screen to draw itself.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            // Make a copy of the master screen list, to avoid confusion if
+            // the process of drawing one screen adds or removes others
+            // (or it happens on another thread
+            screensToDraw.Clear();
+
+            foreach (GameScreen screen in screens)
+                screensToDraw.Add(screen);
+
+            foreach (GameScreen screen in screensToDraw)
+            {
+                if (screen.ScreenState == ScreenState.Hidden)
+                    continue;
+             
+                screen.Draw(gameTime);
+            }
+        }
+
+        /// <summary>
+        /// Draw an empty rectangle of the given size and color.
+        /// </summary>
+        /// <param name="rectangle">The destination rectangle.</param>
+        /// <param name="color">The color of the rectangle.</param>
+        public void DrawRectangle(Rectangle rectangle, Color color)
+        {
+            //SpriteBatch.Begin();
+			// We changed this to be Opaque
+			spriteBatch.Begin(0,BlendState.Opaque, null, null, null);
+            SpriteBatch.Draw(blankTexture, rectangle, color);
+            SpriteBatch.End();
+        }
+
+
+        #endregion
+
+
+        #region Public Methods
+
+
+        /// <summary>
+        /// Adds a new screen to the screen manager.
+        /// </summary>
+        public void AddScreen(GameScreen screen)
+        {
+            screen.ScreenManager = this;
+
+            // If we have a graphics device, tell the screen to load content.
+            if ((graphicsDeviceService != null) &&
+                (graphicsDeviceService.GraphicsDevice != null))
+            {
+                screen.LoadContent();
+            }
+            
+            screens.Add(screen);
+        }
+
+
+        /// <summary>
+        /// Removes a screen from the screen manager. You should normally
+        /// use GameScreen.ExitScreen instead of calling this directly, so
+        /// the screen can gradually transition off rather than just being
+        /// instantly removed.
+        /// </summary>
+        public void RemoveScreen(GameScreen screen)
+        {
+            // If we have a graphics device, tell the screen to unload content.
+            if ((graphicsDeviceService != null) &&
+                (graphicsDeviceService.GraphicsDevice != null))
+            {
+                screen.UnloadContent();
+            }
+            
+            screens.Remove(screen);
+            screensToUpdate.Remove(screen);
+        }
+
+
+        /// <summary>
+        /// Expose an array holding all the screens. We return a copy rather
+        /// than the real master list, because screens should only ever be added
+        /// or removed using the AddScreen and RemoveScreen methods.
+        /// </summary>
+        public GameScreen[] GetScreens()
+        {
+            return screens.ToArray();
+        }
+
+
+        /// <summary>
+        /// Helper draws a translucent black fullscreen sprite, used for fading
+        /// screens in and out, and for darkening the background behind popups.
+        /// </summary>
+        public void FadeBackBufferToBlack(int alpha)
+        {
+            Viewport viewport = GraphicsDevice.Viewport;
+
+            spriteBatch.Begin();
+
+            spriteBatch.Draw(blankTexture,
+                             new Rectangle(0, 0, viewport.Width, viewport.Height),
+                             new Color(0, 0, 0, (byte)alpha));
+            
+            spriteBatch.End();
+        }
+
+
+        #endregion
+    }
+}

+ 235 - 0
Samples/Linux/NetRumble/Screens/BackgroundScreen.cs

@@ -0,0 +1,235 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// BackgroundScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// The background screen sits behind all the other menu screens.
+    /// It draws a background image that remains fixed in place regardless
+    /// of whatever transitions the screens on top of it may be doing.
+    /// </summary>
+    /// <remarks>
+    /// This public class is somewhat similar to one of the same name in the 
+    /// GameStateManagement sample.
+    /// </remarks>
+    public class BackgroundScreen : GameScreen, IDisposable
+    {
+        #region Constants
+
+
+        /// <summary>
+        /// The period of the parallax motion in the starfield.
+        /// </summary>
+        const float starsParallaxPeriod = 30f;
+
+
+        /// <summary>
+        /// The amplitude of the parallax motion in the starfield.
+        /// </summary>
+        const float starsParallaxAmplitude = 2048f;
+
+
+        #endregion
+
+
+        #region Graphics Data
+
+
+        /// <summary>
+        /// The star field rendering in the background.
+        /// </summary>
+        private Starfield starfield;
+
+        /// <summary>
+        /// Persistent movement tracker, used to slightly parallax the stars.
+        /// </summary>
+        private double movement;
+
+        /// <summary>
+        /// The application's title texture.
+        /// </summary>
+        private Texture2D titleTexture;
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Construct a new BackgroundScreen object.
+        /// </summary>
+        public BackgroundScreen()
+        {
+            TransitionOnTime = TimeSpan.FromSeconds(1.0);
+            TransitionOffTime = TimeSpan.FromSeconds(1.0);
+        }
+
+
+        /// <summary>
+        /// Loads graphics content for this screen. The background texture is quite
+        /// big, so we use our own local ContentManager to load it. This allows us
+        /// to unload before going from the menus into the game itself, wheras if we
+        /// used the shared ContentManager provided by the ScreenManager, the content
+        /// would remain loaded forever.
+        /// </summary>
+        public override void LoadContent()
+        {
+            // load the title texture
+            titleTexture = ScreenManager.Content.Load<Texture2D>("Textures/title");
+            movement = 0f;
+
+            starfield = new Starfield(
+                Vector2.Multiply(new Vector2(
+                    (float)Math.Cos(movement / starsParallaxPeriod),
+                    (float)Math.Sin(movement / starsParallaxPeriod)),
+                    starsParallaxAmplitude), 
+                ScreenManager.GraphicsDevice, ScreenManager.Content);
+            starfield.LoadContent();
+
+            base.LoadContent();
+        }
+
+
+        /// <summary>
+        /// Release graphics data.
+        /// </summary>
+        public override void UnloadContent()
+        {
+            if (starfield != null)
+            {
+                starfield.UnloadContent();
+                starfield = null;
+            }
+
+            base.UnloadContent();
+        }
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+
+        /// <summary>
+        /// Updates the background screen. Unlike most screens, this should not
+        /// transition off even if it has been covered by another screen: it is
+        /// supposed to be covered, after all! This overload forces the
+        /// coveredByOtherScreen parameter to false in order to stop the base
+        /// Update method wanting to transition off.
+        /// </summary>
+        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+                                                       bool coveredByOtherScreen)
+        {
+            base.Update(gameTime, otherScreenHasFocus, false);
+        }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draws the background screen.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            if (starfield != null)
+            {
+                // update the parallax movement
+                movement += gameTime.ElapsedGameTime.TotalSeconds;
+                Vector2 position = Vector2.Multiply(new Vector2(
+                        (float)Math.Cos(movement / starsParallaxPeriod),
+                        (float)Math.Sin(movement / starsParallaxPeriod)),
+                        starsParallaxAmplitude);
+
+                // draw the stars
+                starfield.Draw(position);
+            }
+
+            // draw the title texture
+            if (titleTexture != null)
+            {
+                Vector2 titlePosition = new Vector2(
+                    ScreenManager.TitleSafeArea.X +
+                       (ScreenManager.TitleSafeArea.Width - titleTexture.Width) / 2f,
+                    ScreenManager.TitleSafeArea.Y +
+                       ScreenManager.TitleSafeArea.Height * 0.05f);
+                titlePosition.Y -= (float)Math.Pow(TransitionPosition, 2) * 
+                    titlePosition.Y;
+                ScreenManager.SpriteBatch.Begin();
+                ScreenManager.SpriteBatch.Draw(titleTexture, titlePosition,
+                    new Color(255, 255, 255, TransitionAlpha));
+                ScreenManager.SpriteBatch.End();
+            }
+        }
+
+
+        #endregion
+
+    
+        #region IDisposable Implementation
+
+
+        /// <summary>
+        /// Finalizes the BackgroundScreen object, calls Dispose(false)
+        /// </summary>
+        ~BackgroundScreen()
+        {
+            Dispose(false);
+        }
+
+
+        /// <summary>
+        /// Disposes the BackgroundScreen object.
+        /// </summary>
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        
+        /// <summary>
+        /// Disposes this object.
+        /// </summary>
+        /// <param name="disposing">
+        /// True if this method was called as part of the Dispose method.
+        /// </param>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                lock (this)
+                {
+                    if (starfield != null)
+                    {
+                        starfield.Dispose();
+                        starfield = null;
+                    }
+                }
+            }
+        }
+
+
+        #endregion
+    }
+}

+ 618 - 0
Samples/Linux/NetRumble/Screens/GameplayScreen.cs

@@ -0,0 +1,618 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// GameplayScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.Threading;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.GamerServices;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using Microsoft.Xna.Framework.Net;
+using Microsoft.Xna.Framework.Media;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// This screen implements the actual game logic.
+    /// </summary>
+    /// <remarks>
+    /// This public class is somewhat similar to one of the same name in the 
+    /// GameStateManagement sample.
+    /// </remarks>
+    public class GameplayScreen : GameScreen, IDisposable
+    {
+        #region Gameplay Data
+
+        /// <summary>
+        /// The primary gameplay object.
+        /// </summary>
+        private World world;
+
+        /// <summary>
+        /// The ship for the local player.
+        /// </summary>
+        private Ship localShip;
+
+        /// <summary>
+        /// The game-winner text.
+        /// </summary>
+        private string winnerString = String.Empty;
+
+        /// <summary>
+        /// The position of the game-winner text.
+        /// </summary>
+        private Vector2 winnerStringPosition;
+
+
+        #endregion
+
+
+        #region Graphics Data
+
+
+        /// <summary>
+        /// The bloom component, applied to part of the game world.
+        /// </summary>
+        private BloomComponent bloomComponent;
+
+        /// <summary>
+        /// The starfield, rendering behind the game.
+        /// </summary>
+        private Starfield starfield;
+
+
+        #endregion
+
+
+        #region Networking Data
+
+
+        /// <summary>
+        /// The network session used in this game.
+        /// </summary>
+        private NetworkSession networkSession;
+
+        /// <summary>
+        /// Event handler for the session-ended event.
+        /// </summary>
+        EventHandler<NetworkSessionEndedEventArgs> sessionEndedHandler;
+
+        /// <summary>
+        /// Event handler for the game-ended event.
+        /// </summary>
+        EventHandler<GameEndedEventArgs> gameEndedHandler;
+
+        /// <summary>
+        /// Event handler for the gamer-left event.
+        /// </summary>
+        EventHandler<GamerLeftEventArgs> gamerLeftHandler;
+
+
+        #endregion
+
+
+        #region Initialization Methods
+
+
+        /// <summary>
+        /// Construct a new GameplayScreen object.
+        /// </summary>
+        /// <param name="networkSession">The network session for this game.</param>
+        /// <param name="world">The primary gameplay object.</param>
+        public GameplayScreen(NetworkSession networkSession, World world)
+        {
+            // safety-check the parameters
+            if (networkSession == null)
+            {
+                throw new ArgumentNullException("networkSession");
+            }
+            if (world == null)
+            {
+                throw new ArgumentNullException("world");
+            }
+
+            // apply the parameters
+            this.networkSession = networkSession;
+            this.world = world;
+
+            // set up the network events
+            sessionEndedHandler = new EventHandler<NetworkSessionEndedEventArgs>(
+                networkSession_SessionEnded);
+            networkSession.SessionEnded += sessionEndedHandler;
+            gameEndedHandler = new EventHandler<GameEndedEventArgs>(
+                networkSession_GameEnded);
+            networkSession.GameEnded += gameEndedHandler;
+            gamerLeftHandler = new EventHandler<GamerLeftEventArgs>(
+                networkSession_GamerLeft);
+            networkSession.GamerLeft += gamerLeftHandler;
+                
+
+            // cache the local player's ship object
+            if (networkSession.LocalGamers.Count > 0)
+            {
+                PlayerData playerData = networkSession.LocalGamers[0].Tag as PlayerData;
+                if (playerData != null)
+                {
+                    localShip = playerData.Ship;
+                }
+            }
+
+            // set the transition times
+            TransitionOnTime = TimeSpan.FromSeconds(1.0);
+            TransitionOffTime = TimeSpan.FromSeconds(1.0);
+        }
+
+
+        /// <summary>
+        /// Load graphics content for the game.
+        /// </summary>
+        public override void LoadContent()
+        {
+			
+			
+		// Developers Comment or uncomment the bloomComponent to run with effects or not
+		// ***************************	
+		// Comment or uncomment from here
+		// ***************************	
+            // create and add the bloom effect
+            bloomComponent = new BloomComponent(ScreenManager.Game);
+            bloomComponent.Settings = BloomSettings.PresetSettings[0];
+            ScreenManager.Game.Components.Add(bloomComponent);
+            bloomComponent.Initialize();
+            bloomComponent.Visible = false; // we want to control when bloom component is drawn
+		// ***************************
+		// Comment or uncomment to here
+		// ***************************	
+            // create the starfield
+            starfield = new Starfield(Vector2.Zero, ScreenManager.GraphicsDevice, 
+                ScreenManager.Content);
+            starfield.LoadContent();
+
+            // start the background soundtrack
+            AudioManager.PlaySoundTrack();
+
+            base.LoadContent();
+        }
+
+
+        /// <summary>
+        /// Release graphics data.
+        /// </summary>
+        public override void UnloadContent()
+        {
+            if (starfield != null)
+            {
+                starfield.UnloadContent();
+            }
+
+            base.UnloadContent();
+        }
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+
+        /// <summary>
+        /// Updates the state of the game. This method checks the GameScreen.IsActive
+        /// property, so the game will stop updating when the pause menu is active,
+        /// or if you tab away to a different application.
+        /// </summary>
+        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+                                                       bool coveredByOtherScreen)
+        {
+            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+
+            // if something else has canceled our game, then exit
+            if ((networkSession == null) || (world == null))
+            {
+                if (!IsExiting)
+                {
+                    ExitScreen();
+                }
+                base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+                return;
+            }
+
+            // update the world
+            if (world != null)
+            {
+                if (otherScreenHasFocus || coveredByOtherScreen)
+                {
+                    world.Update((float)gameTime.ElapsedGameTime.TotalSeconds, true);
+                }
+                else if (world.GameExited)
+                {
+                    if (!IsExiting)
+                    {
+                        ExitScreen();
+                    }
+                    networkSession = null;
+                    base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+                    return;
+                }
+                else
+                {
+                    world.Update((float)gameTime.ElapsedGameTime.TotalSeconds, false);
+                    // if the game was just won, then build the winner string
+                    if (world.GameWon && String.IsNullOrEmpty(winnerString) &&
+                        (world.WinnerIndex >= 0) &&
+                        (world.WinnerIndex < networkSession.AllGamers.Count))
+                    {
+                        winnerString =
+                            networkSession.AllGamers[world.WinnerIndex].Gamertag;
+                        winnerString += 
+                            " has won the game!\nPress A to return to the lobby.";
+                        Vector2 winnerStringSize = 
+                            world.PlayerFont.MeasureString(winnerString);
+                        winnerStringPosition = new Vector2(
+                            ScreenManager.GraphicsDevice.Viewport.X + 
+                                ScreenManager.GraphicsDevice.Viewport.Width / 2 - 
+                                (float)Math.Floor(winnerStringSize.X / 2),
+                            ScreenManager.GraphicsDevice.Viewport.Y + 
+                                ScreenManager.GraphicsDevice.Viewport.Height / 2 -
+                                (float)Math.Floor(winnerStringSize.Y / 2));
+                    }
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Lets the game respond to player input. Unlike the Update method,
+        /// this will only be called when the gameplay screen is active.
+        /// </summary>
+        public override void HandleInput(InputState input)
+        {
+            if (input == null)
+                throw new ArgumentNullException("input");
+
+            if (!IsExiting)
+            {
+                if ((world != null) && !world.GameExited)
+                {
+                    if (input.PauseGame && !world.GameWon)
+                    {
+                        // If they pressed pause, bring up the pause menu screen.
+                        const string message = "Exit the game?";
+                        MessageBoxScreen messageBox = new MessageBoxScreen(message, 
+                            false);
+                        messageBox.Accepted += ExitMessageBoxAccepted;
+                        ScreenManager.AddScreen(messageBox);
+                    }
+                    if (input.MenuSelect && world.GameWon)
+                    {
+                        world.GameExited = true;
+                        world = null;
+                        if (!IsExiting)
+                        {
+                            ExitScreen();
+                        }
+                        networkSession = null;
+                    }
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Event handler for when the user selects "yes" on the "are you sure
+        /// you want to exit" message box.
+        /// </summary>
+        private void ExitMessageBoxAccepted(object sender, EventArgs e)
+        {
+            world.GameExited = true;
+            world = null;
+        }
+
+
+        /// <summary>
+        /// Force the end of a network session so that a new one can be joined.
+        /// </summary>
+        public void EndSession()
+        {
+            if (networkSession != null)
+            {
+                networkSession.Dispose();
+                networkSession = null;
+            }
+        }
+
+
+        /// <summary>
+        /// Exit this screen.
+        /// </summary>
+        public override void ExitScreen()
+        {
+            if (bloomComponent != null)
+            {
+                bloomComponent.Visible = false;
+                ScreenManager.Game.Components.Remove(bloomComponent);
+                bloomComponent = null;
+            }
+
+            if (!IsExiting && (networkSession != null))
+            {
+                networkSession.SessionEnded -= sessionEndedHandler;
+                networkSession.GameEnded -= gameEndedHandler;
+                networkSession.GamerLeft -= gamerLeftHandler;
+            }
+            MediaPlayer.Stop();
+            base.ExitScreen();
+        }
+
+
+        /// <summary>
+        /// Screen-specific update to gamer rich presence.
+        /// </summary>
+        public override void UpdatePresence()
+        {
+            if (!IsExiting && (networkSession != null))
+            {
+                bool isTied = (world.HighScorers.Count > 1);
+                for (int i = 0; i < networkSession.AllGamers.Count; ++i)
+                {
+                    NetworkGamer networkGamer = networkSession.AllGamers[i];
+                    if (networkGamer.IsLocal)
+                    {
+                        SignedInGamer signedInGamer = (networkGamer as LocalNetworkGamer).SignedInGamer;
+                        if (signedInGamer.IsSignedInToLive)
+                        {
+                            if (world.HighScorers.Contains(i))
+                            {
+                                if (isTied)
+                                    signedInGamer.Presence.PresenceMode = GamerPresenceMode.ScoreIsTied;
+                                else
+                                    signedInGamer.Presence.PresenceMode = GamerPresenceMode.Winning;
+                            }
+                            else
+                            {
+                                signedInGamer.Presence.PresenceMode = GamerPresenceMode.Losing;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draws the gameplay screen.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
+
+            if (networkSession != null)
+            {
+                // make sure we know what the local ship is
+                if ((localShip == null) && (networkSession.LocalGamers.Count > 0))
+                {
+                    PlayerData playerData = networkSession.LocalGamers[0].Tag
+                        as PlayerData;
+                    if (playerData.Ship != null)
+                    {
+                        localShip = playerData.Ship;
+                        starfield.Reset(localShip.Position);
+                    }
+                }
+
+                if (bloomComponent != null)
+                {
+                    bloomComponent.BeginDraw();
+                }
+
+                // draw the world
+                if ((world != null) && (localShip != null) && !IsExiting)
+                {
+                    Vector2 center = new Vector2(
+                        localShip.Position.X + ScreenManager.GraphicsDevice.Viewport.X -
+                           ScreenManager.GraphicsDevice.Viewport.Width / 2,
+                        localShip.Position.Y + ScreenManager.GraphicsDevice.Viewport.Y -
+                           ScreenManager.GraphicsDevice.Viewport.Height / 2);
+                    starfield.Draw(center);
+                    world.Draw(elapsedTime, center);
+
+                    if (bloomComponent != null)
+                    {
+                        bloomComponent.Draw(gameTime);
+                    }
+                }
+
+                // draw the user-interface elements of the game (scores, etc.)
+                DrawHud((float)gameTime.TotalGameTime.TotalSeconds);
+            }
+
+            // If the game is transitioning on or off, fade it out to black.
+            if (ScreenState == ScreenState.TransitionOn && (TransitionPosition > 0))
+                ScreenManager.FadeBackBufferToBlack(255 - TransitionAlpha);
+        }
+
+
+        /// <summary>
+        /// Draw the user interface elements of the game (scores, etc.).
+        /// </summary>
+        /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
+        private void DrawHud(float totalTime)
+        {
+            if ((networkSession != null) && (world != null))
+            {
+                ScreenManager.SpriteBatch.Begin();
+                // draw players 0 - 3 at the top of the screen
+                Vector2 position = new Vector2(
+                    ScreenManager.GraphicsDevice.Viewport.Width * 0.2f, 
+                    ScreenManager.GraphicsDevice.Viewport.Height * 0.1f);
+                for (int i = 0; i < Math.Min(4, networkSession.AllGamers.Count); i++)
+                {
+                    world.DrawPlayerData(totalTime, networkSession.AllGamers[i], 
+                        position, ScreenManager.SpriteBatch, false);
+                    position.X += ScreenManager.GraphicsDevice.Viewport.Width * 0.2f;
+                }
+                // draw players 4 - 7 at the bottom of the screen
+                position = new Vector2(
+                    ScreenManager.GraphicsDevice.Viewport.Width * 0.2f,
+                    ScreenManager.GraphicsDevice.Viewport.Height * 0.9f);
+                for (int i = 4; i < Math.Min(8, networkSession.AllGamers.Count); i++)
+                {
+                    world.DrawPlayerData(totalTime, networkSession.AllGamers[i],
+                        position, ScreenManager.SpriteBatch, false);
+                    position.X += ScreenManager.GraphicsDevice.Viewport.Width * 0.2f;
+                }
+                // draw players 8 - 11 at the left of the screen
+                position = new Vector2(
+                    ScreenManager.GraphicsDevice.Viewport.Width * 0.13f, 
+                    ScreenManager.GraphicsDevice.Viewport.Height * 0.2f);
+                for (int i = 8; i < Math.Min(12, networkSession.AllGamers.Count); i++)
+                {
+                    world.DrawPlayerData(totalTime, networkSession.AllGamers[i],
+                        position, ScreenManager.SpriteBatch, false);
+                    position.Y += ScreenManager.GraphicsDevice.Viewport.Height * 0.2f;
+                }
+                // draw players 12 - 15 at the right of the screen
+                position = new Vector2(
+                    ScreenManager.GraphicsDevice.Viewport.Width * 0.9f, 
+                    ScreenManager.GraphicsDevice.Viewport.Height * 0.2f);
+                for (int i = 12; i < Math.Min(16, networkSession.AllGamers.Count); i++)
+                {
+                    world.DrawPlayerData(totalTime, networkSession.AllGamers[i],
+                        position, ScreenManager.SpriteBatch, false);
+                    position.Y += ScreenManager.GraphicsDevice.Viewport.Height * 0.2f;
+                }
+                // if the game is over, draw the winner text
+                if (world.GameWon && !String.IsNullOrEmpty(winnerString))
+                {
+                    ScreenManager.SpriteBatch.DrawString(world.PlayerFont, winnerString,
+                        winnerStringPosition, Color.White, 0f, Vector2.Zero, 1.3f, 
+                        SpriteEffects.None, 0f);
+                }
+                ScreenManager.SpriteBatch.End();
+            }
+        }
+
+
+        #endregion
+
+
+        #region Networking Event Handlers
+
+
+        /// <summary>
+        /// Handle the end of the game session.
+        /// </summary>
+        void networkSession_GameEnded(object sender, GameEndedEventArgs e)
+        {
+            if ((world != null) && !world.GameWon && !world.GameExited)
+            {
+                world.GameExited = true;
+            }
+            if (!IsExiting && ((world == null) || world.GameExited))
+            {
+                world = null;
+                ExitScreen();
+                networkSession = null;
+            }
+        }
+
+
+        /// <summary>
+        /// Handle the end of the session.
+        /// </summary>
+        void networkSession_SessionEnded(object sender, NetworkSessionEndedEventArgs e)
+        {
+            if ((world != null) && !world.GameExited)
+            {
+                world.GameExited = true;
+                world = null;
+            }
+            if (!IsExiting)
+            {
+                ExitScreen();
+            }
+            networkSession = null;
+        }
+
+
+        /// <summary>
+        /// Handle a player leaving the game.
+        /// </summary>
+        void networkSession_GamerLeft(object sender, GamerLeftEventArgs e)
+        {
+            PlayerData playerData = e.Gamer.Tag as PlayerData;
+            if ((playerData != null) && (playerData.Ship != null))
+            {
+                playerData.Ship.Die(null, true);
+            }
+        }
+
+
+        #endregion
+
+
+        #region IDisposable Implementation
+
+
+        /// <summary>
+        /// Finalizes the GameplayScreen object, calls Dispose(false)
+        /// </summary>
+        ~GameplayScreen()
+        {
+            Dispose(false);
+        }
+
+
+        /// <summary>
+        /// Disposes the GameplayScreen object.
+        /// </summary>
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        
+        /// <summary>
+        /// Disposes this object.
+        /// </summary>
+        /// <param name="disposing">
+        /// True if this method was called as part of the Dispose method.
+        /// </param>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                lock (this)
+                {
+                    if (bloomComponent != null)
+                    {
+                        bloomComponent.Dispose();
+                        bloomComponent = null;
+                    }
+                    if (starfield != null)
+                    {
+                        starfield.Dispose();
+                        starfield = null;
+                    }
+                }
+            }
+        }
+
+
+        #endregion
+    }
+}

+ 591 - 0
Samples/Linux/NetRumble/Screens/LobbyScreen.cs

@@ -0,0 +1,591 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// LobbyScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.GamerServices;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Net;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// The lobby screen is shows the players in the game, outside the gameplay.
+    /// </summary>
+    public class LobbyScreen : MenuScreen, IDisposable
+    {
+        #region Constants
+
+
+        /// <summary>
+        /// The instructions shown to the player at the bottom of the lobby screen.
+        /// </summary>
+        const string instructions = 
+            "Press X to mark/unmark ready, LB/RB to toggle color, LT/RT to toggle ship";
+
+
+        #endregion
+
+
+        #region Gameplay Data
+
+
+        /// <summary>
+        /// The primary object for this game.
+        /// </summary>
+        private World world;
+
+
+        #endregion
+
+
+        #region Networking Data
+
+
+        /// <summary>
+        /// The network session for this game.
+        /// </summary>
+        private NetworkSession networkSession;
+
+        /// <summary>
+        /// The packet writer used to send data from this screen.
+        /// </summary>
+        private PacketWriter packetWriter = new PacketWriter();
+        
+        /// <summary>
+        /// Event handler for the session-ended event.
+        /// </summary>
+        EventHandler<NetworkSessionEndedEventArgs> sessionEndedHandler;
+
+        /// <summary>
+        /// Event handler for the game-ended event.
+        /// </summary>
+        EventHandler<GameStartedEventArgs> gameStartedHandler;
+
+        /// <summary>
+        /// Event handler for the gamer-left event.
+        /// </summary>
+        EventHandler<GamerJoinedEventArgs> gamerJoinedHandler;
+
+
+        #endregion
+
+
+        #region Initialization
+
+
+        /// <summary>
+        /// Constructs a new LobbyScreen object.
+        /// </summary>
+        public LobbyScreen(NetworkSession networkSession) : base()
+        {
+            // safety-check the parameter
+            if (networkSession == null)
+            {
+                throw new ArgumentNullException("networkSession");
+            }
+
+            // apply the parameters
+            this.networkSession = networkSession;
+
+            // add the single menu entry
+            MenuEntries.Add("");
+
+            // set the transition time
+            TransitionOnTime = TimeSpan.FromSeconds(1.0);
+            TransitionOffTime = TimeSpan.FromSeconds(0.0);
+
+            gamerJoinedHandler = new EventHandler<GamerJoinedEventArgs>(
+                networkSession_GamerJoined);
+            gameStartedHandler = new EventHandler<GameStartedEventArgs>(
+                networkSession_GameStarted);
+            sessionEndedHandler = new EventHandler<NetworkSessionEndedEventArgs>(
+                networkSession_SessionEnded);
+        }
+
+
+        /// <summary>
+        /// Load graphics content for the game.
+        /// </summary>
+        public override void LoadContent()
+        {
+            base.LoadContent();
+
+            // create the world object
+            world = new World(ScreenManager.GraphicsDevice, ScreenManager.Content, 
+                networkSession);
+
+            // set the networking events
+            networkSession.GamerJoined += gamerJoinedHandler;
+            networkSession.GameStarted += gameStartedHandler;
+            networkSession.SessionEnded += sessionEndedHandler;
+        }
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+
+        /// <summary>
+        /// Updates the lobby. This method checks the GameScreen.IsActive
+        /// property, so the game will stop updating when the pause menu is active,
+        /// or if you tab away to a different application.
+        /// </summary>
+        public override void Update(Microsoft.Xna.Framework.GameTime gameTime,
+            bool otherScreenHasFocus, bool coveredByOtherScreen)
+        {
+            if (networkSession != null)
+            {
+                // update the network session
+                try
+                {
+                    networkSession.Update();
+                }
+                catch (NetworkException ne)
+                {
+                    System.Console.WriteLine(
+                        "Network failed to update:  " + ne.ToString());
+                    if (networkSession != null)
+                    {
+                        networkSession.Dispose();
+                        networkSession = null;
+                    }
+                }
+            }
+
+            // update the world
+            if ((world != null) && !otherScreenHasFocus && !coveredByOtherScreen)
+            {
+                if (world.GameWon)
+                {
+                    // unload the existing world
+                    world.Dispose();
+                    world = null;
+                    // make sure that all of the ships have cleaned up
+                    foreach (NetworkGamer networkGamer in networkSession.AllGamers)
+                    {
+                        PlayerData playerData = networkGamer.Tag as PlayerData;
+                        if ((playerData != null) && (playerData.Ship != null))
+                        {
+                            playerData.Ship.Die(null, true);
+                        }
+                    }
+                    // make sure the collision manager is up-to-date
+                    CollisionManager.Collection.ApplyPendingRemovals();
+                    // create a new world
+                    world = new World(ScreenManager.GraphicsDevice,
+                        ScreenManager.Content, networkSession);
+                }
+                else if (world.GameExited)
+                {
+                    if (!IsExiting)
+                    {
+                        ExitScreen();
+                    }
+                    if (world != null)
+                    {
+                        world.Dispose();
+                        world = null;
+                    }
+                    if (networkSession != null)
+                    {
+                        networkSession.Dispose();
+                        networkSession = null;
+                    }
+                    base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+                    return;
+                }
+                else
+                {
+                    world.Update((float)gameTime.ElapsedGameTime.TotalSeconds, true);
+                }
+            }
+
+            // update the menu entry text
+            if (otherScreenHasFocus == false)
+            {
+                if ((networkSession.LocalGamers.Count > 0) && 
+                    (networkSession.SessionState == NetworkSessionState.Lobby))
+                {
+                    if (!networkSession.LocalGamers[0].IsReady)
+                    {
+                        MenuEntries[0] = "Press X to Mark as Ready";
+                    }
+                    else if (!networkSession.IsEveryoneReady)
+                    {
+                        MenuEntries[0] = "Waiting for all players to mark as ready...";
+                    }
+                    else if (!networkSession.IsHost)
+                    {
+                        MenuEntries[0] = "Waiting for the host to start game...";
+                    }
+                    else
+                    {
+                        MenuEntries[0] = "Starting the game...";
+                        networkSession.StartGame();
+                    }
+                }
+                else if (networkSession.SessionState == NetworkSessionState.Playing)
+                {
+                    MenuEntries[0] = "Game starting...";
+                }
+                // if the game is playing and the world is initialized, then start up
+                if ((networkSession.SessionState == NetworkSessionState.Playing) && 
+                    (world != null) && world.Initialized)
+                {
+                    GameplayScreen gameplayScreen = 
+                        new GameplayScreen(networkSession, world);
+                    gameplayScreen.ScreenManager = this.ScreenManager;
+                    ScreenManager.AddScreen(gameplayScreen);
+                }
+            }
+
+            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+        }
+
+
+        /// <summary>
+        /// Lets the game respond to player input. Unlike the Update method,
+        /// this will only be called when the gameplay screen is active.
+        /// </summary>
+        public override void HandleInput(InputState input)
+        {
+            // safety-check the parameter
+            if (input == null)
+            {
+                throw new ArgumentNullException("input");
+            }
+
+            if ((networkSession != null) && (networkSession.LocalGamers.Count > 0))
+            {
+                // update the ready state
+                if (input.MarkReady)
+                {
+                    networkSession.LocalGamers[0].IsReady = 
+                        !networkSession.LocalGamers[0].IsReady;
+                }
+
+                // update the player data
+                PlayerData playerData = networkSession.LocalGamers[0].Tag as PlayerData;
+                if (playerData != null)
+                {
+                    bool playerDataChanged = false;
+                    if (input.ShipColorChangeUp)
+                    {
+                        playerData.ShipColor = Ship.GetNextUniqueColorIndex(
+                            playerData.ShipColor, networkSession);
+                        playerDataChanged = true;
+                    }
+                    else if (input.ShipColorChangeDown)
+                    {
+                        playerData.ShipColor = Ship.GetPreviousUniqueColorIndex(
+                            playerData.ShipColor, networkSession);
+                        playerDataChanged = true;
+                    }
+                    if (input.ShipModelChangeUp)
+                    {
+                        playerData.ShipVariation = 
+                            (byte)((playerData.ShipVariation + 1) % 4);
+                        playerDataChanged = true;
+                    }
+                    else if (input.ShipModelChangeDown)
+                    {
+                        if (playerData.ShipVariation == 0)
+                        {
+                            playerData.ShipVariation = 3;
+                        }
+                        else
+                        {
+                            playerData.ShipVariation--;
+                        }
+                        playerDataChanged = true;
+                    }
+                    // if the data changed, send an update to the others
+                    if (playerDataChanged)
+                    {
+                        packetWriter.Write((int)World.PacketTypes.PlayerData);
+                        playerData.Serialize(packetWriter);
+                        networkSession.LocalGamers[0].SendData(packetWriter, 
+                            SendDataOptions.ReliableInOrder);
+                    }
+                }
+            }
+
+            base.HandleInput(input);
+        }
+
+
+        /// <summary>
+        /// Responds to user menu selections.
+        /// </summary>
+        protected override void OnSelectEntry(int entryIndex) { }
+
+
+        /// <summary>
+        /// Force the end of a network session so that a new one can be joined.
+        /// </summary>
+        public void EndSession()
+        {
+            if (networkSession != null)
+            {
+                networkSession.Dispose();
+                networkSession = null;
+            }
+        }
+
+
+        /// <summary>
+        /// Exit this screen.
+        /// </summary>
+        public override void ExitScreen()
+        {
+            if (!IsExiting && (networkSession != null))
+            {
+                networkSession.GamerJoined -= gamerJoinedHandler;
+                networkSession.GameStarted -= gameStartedHandler;
+                networkSession.SessionEnded -= sessionEndedHandler;
+            }
+            base.ExitScreen();
+        }
+
+
+        /// <summary>
+        /// Screen-specific update to gamer rich presence.
+        /// </summary>
+        public override void UpdatePresence()
+        {
+            if (!IsExiting && (networkSession != null))
+            {
+                foreach (LocalNetworkGamer localGamer in networkSession.LocalGamers)
+                {
+                    SignedInGamer signedInGamer = localGamer.SignedInGamer;
+                    if (signedInGamer.IsSignedInToLive)
+                    {
+                        if (networkSession.IsHost)
+                        {
+                            signedInGamer.Presence.PresenceMode = GamerPresenceMode.WaitingForPlayers;
+                        }
+                        else
+                        {
+                            signedInGamer.Presence.PresenceMode = GamerPresenceMode.WaitingInLobby;
+                        }
+                    }
+                }
+            }
+        }
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draw the lobby screen.
+        /// </summary>
+        /// <param name="gameTime"></param>
+        public override void Draw(Microsoft.Xna.Framework.GameTime gameTime)
+        {
+            // draw in four columns
+            Vector2[] columnPositions = new Vector2[4];
+            columnPositions[0] = new Vector2(
+                ScreenManager.GraphicsDevice.Viewport.Width * 0.2f, 
+                ScreenManager.GraphicsDevice.Viewport.Height * 0.70f);
+            columnPositions[1] = new Vector2(
+                ScreenManager.GraphicsDevice.Viewport.Width * 0.4f, 
+                ScreenManager.GraphicsDevice.Viewport.Height * 0.70f);
+            columnPositions[2] = new Vector2(
+                ScreenManager.GraphicsDevice.Viewport.Width * 0.6f,
+                ScreenManager.GraphicsDevice.Viewport.Height * 0.70f);
+            columnPositions[3] = new Vector2(
+                ScreenManager.GraphicsDevice.Viewport.Width * 0.8f, 
+                ScreenManager.GraphicsDevice.Viewport.Height * 0.70f);
+
+            ScreenManager.SpriteBatch.Begin();
+
+            // draw all of the players data
+            if (networkSession != null)
+            {
+                for (int i = 0; i < networkSession.AllGamers.Count; i++)
+                {
+                    world.DrawPlayerData((float)gameTime.TotalGameTime.TotalSeconds, 
+                        networkSession.AllGamers[i], columnPositions[i % 4], 
+                        ScreenManager.SpriteBatch, true);
+                    columnPositions[i % 4].Y += 
+                        ScreenManager.GraphicsDevice.Viewport.Height * 0.03f;
+                }
+            }
+
+            // draw the instructions
+            ScreenManager.SpriteBatch.DrawString(ScreenManager.Font, instructions, 
+                new Vector2(ScreenManager.TitleSafeArea.X, 
+                ScreenManager.TitleSafeArea.Y + ScreenManager.TitleSafeArea.Height - 
+                ScreenManager.Font.LineSpacing), Color.White);
+
+            ScreenManager.SpriteBatch.End();
+
+            base.Draw(gameTime);
+        }
+
+
+
+        /// <summary>
+        /// When the user cancels the main menu, ask if they want to exit the sample.
+        /// </summary>
+        protected override void OnCancel()
+        {
+            if (!IsExiting)
+            {
+                ExitScreen();
+            }
+            if (world != null)
+            {
+                world.Dispose();
+                world = null;
+            }
+            if (networkSession != null)
+            {
+                networkSession.Dispose();
+                networkSession = null;
+            }
+        }
+
+
+        #endregion
+
+
+        #region Networking Event Handlers
+
+
+        /// <summary>
+        /// Handle the end of the network session.
+        /// </summary>
+        void networkSession_SessionEnded(object sender, NetworkSessionEndedEventArgs e)
+        {
+            if (!IsExiting)
+            {
+                ExitScreen();
+            }
+            if (world != null)
+            {
+                world.Dispose();
+                world = null;
+            }
+            if (networkSession != null)
+            {
+                networkSession.Dispose();
+                networkSession = null;
+            }
+        }
+
+
+        /// <summary>
+        /// Handle the start of the game session.
+        /// </summary>
+        void networkSession_GameStarted(object sender, GameStartedEventArgs e)
+        {
+            // if we're the host, generate the data
+            if ((networkSession != null) && networkSession.IsHost && (world != null))
+            {
+                world.GenerateWorld();
+            }
+        }
+        
+        
+        /// <summary>
+        /// Handle a new player joining the session.
+        /// </summary>
+        void networkSession_GamerJoined(object sender, GamerJoinedEventArgs e)
+        {
+            // make sure the data exists for the new gamer
+            for (int i = 0; i < networkSession.AllGamers.Count; i++)
+            {
+                if (networkSession.AllGamers[i] == e.Gamer)
+                {
+                    PlayerData playerData = new PlayerData();
+                    e.Gamer.Tag = playerData;
+                    playerData.ShipVariation = (byte)(i % 4);
+                    playerData.ShipColor = (byte)i;
+                }
+            }
+
+            // send my own data to the new gamer
+            if ((networkSession.LocalGamers.Count > 0) && !e.Gamer.IsLocal)
+            {
+                PlayerData playerData = networkSession.LocalGamers[0].Tag as PlayerData;
+                if (playerData != null)
+                {
+                    packetWriter.Write((int)World.PacketTypes.PlayerData);
+                    playerData.Serialize(packetWriter);
+                    networkSession.LocalGamers[0].SendData(packetWriter, 
+                        SendDataOptions.ReliableInOrder, e.Gamer);
+                }
+            }
+        }
+
+
+        #endregion
+
+    
+        #region IDisposable Implementation
+
+
+        /// <summary>
+        /// Finalizes the LobbyScreen object, calls Dispose(false)
+        /// </summary>
+        ~LobbyScreen()
+        {
+            Dispose(false);
+        }
+
+
+        /// <summary>
+        /// Disposes the LobbyScreen object.
+        /// </summary>
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        
+        /// <summary>
+        /// Disposes this object.
+        /// </summary>
+        /// <param name="disposing">
+        /// True if this method was called as part of the Dispose method.
+        /// </param>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                lock (this)
+                {
+                    if (world != null)
+                    {
+                        world.Dispose();
+                        world = null;
+                    }
+                    if (packetWriter != null)
+                    {
+                        packetWriter.Close();
+                        packetWriter = null;
+                    }
+                }
+            }
+        }
+
+
+        #endregion
+    }
+}

+ 675 - 0
Samples/Linux/NetRumble/Screens/MainMenuScreen.cs

@@ -0,0 +1,675 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// MainMenuScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.GamerServices;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Net;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// The main menu screen is the first thing displayed when the game starts up.
+    /// </summary>
+    public class MainMenuScreen : MenuScreen
+    {
+        #region State Data
+
+
+        /// <summary>
+        /// The potential states of the main menu.
+        /// </summary>
+        enum MainMenuState
+        {
+            Empty,
+            SignedOut,
+            SignedInLocal,
+            SignedInLive,
+        }
+
+        /// <summary>
+        /// Flag that tracks last known value of IsTrialMode
+        /// </summary>
+        bool trialMode;
+        bool updateState;
+
+        /// <summary>
+        /// The current state of the main menu.
+        /// </summary>
+        MainMenuState state = MainMenuState.Empty;
+        MainMenuState State
+        {
+            get { return state; }
+            set
+            {
+                // exit early from trivial sets
+                if (state == value && trialMode == Guide.IsTrialMode && !updateState)
+                {
+                    return;
+                }
+                updateState = false;  // reset the flag, in case it was set
+                state = value;
+                trialMode = Guide.IsTrialMode;
+                if (MenuEntries != null)
+                {
+                    switch (state)
+                    {
+                        case MainMenuState.SignedInLive:
+                            {
+                                MenuEntries.Clear();
+                                MenuEntries.Add("Quick Match");
+                                MenuEntries.Add("Create Xbox LIVE Session");
+                                MenuEntries.Add("Join Xbox LIVE Session");
+                                MenuEntries.Add("Create System Link Session");
+                                MenuEntries.Add("Join System Link Session");
+                                if (Guide.IsTrialMode)
+                                {
+                                    MenuEntries.Add("Unlock Full Game");
+                                }
+                                else if (ScreenManager.invited != null)
+                                {
+                                    MenuEntries.Add("Join Invited Game");
+                                }
+                                MenuEntries.Add("Exit");
+                                break;
+                            }
+                        case MainMenuState.SignedInLocal:
+                            {
+                                MenuEntries.Clear();
+                                MenuEntries.Add("Create System Link Session");
+                                MenuEntries.Add("Join System Link Session");
+                                MenuEntries.Add("Exit");
+                                break;
+                            }
+                        case MainMenuState.SignedOut:
+                            {
+                                MenuEntries.Clear();
+                                MenuEntries.Add("Sign In");
+                                MenuEntries.Add("Exit");
+                                break;
+                            }
+                    }
+                }
+            }
+        }
+
+
+        #endregion
+
+
+        #region Initialization
+
+
+        /// <summary>
+        /// Constructs a new MainMenu object.
+        /// </summary>
+        public MainMenuScreen() : base()
+        {
+            // set the transition times
+            TransitionOnTime = TimeSpan.FromSeconds(1.0);
+            TransitionOffTime = TimeSpan.FromSeconds(0.0);
+
+            // capture current value of trial mode flag
+            trialMode = Guide.IsTrialMode;
+            updateState = false;
+        }
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+
+        /// <summary>
+        /// Updates the screen. This method checks the GameScreen.IsActive
+        /// property, so the game will stop updating when the pause menu is active,
+        /// or if you tab away to a different application.
+        /// </summary>
+        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+            bool coveredByOtherScreen)
+        {
+            bool signedIntoLive = false;
+            if (Gamer.SignedInGamers.Count > 0)
+            {
+                foreach (SignedInGamer signedInGamer in Gamer.SignedInGamers)
+                {
+                    if (signedInGamer.IsSignedInToLive)
+                    {
+                        signedIntoLive = true;
+                        break;
+                    }
+                }
+                State = signedIntoLive ? MainMenuState.SignedInLive : 
+                    MainMenuState.SignedInLocal;
+            }
+            else
+            {
+                State = MainMenuState.SignedOut;
+            }
+            
+            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+        }
+        
+        
+        /// <summary>
+        /// Responds to user menu selections.
+        /// </summary>
+        protected override void OnSelectEntry(int entryIndex)
+        {
+            switch (state)
+            {
+                case MainMenuState.SignedInLive:
+                    {
+                        switch (entryIndex)
+                        {
+                            case 0: // Quick Match
+                                QuickMatchSession();
+                                break;
+
+                            case 1: // Create Xbox LIVE Session
+                                CreateSession(NetworkSessionType.PlayerMatch);
+                                break;
+
+                            case 2: // Join Xbox LIVE Session
+                                FindSession(NetworkSessionType.PlayerMatch);
+                                break;
+
+                            case 3: // Create System Link Session
+                                CreateSession(NetworkSessionType.SystemLink);
+                                break;
+
+                            case 4: // Join System Link Session
+                                FindSession(NetworkSessionType.SystemLink);
+                                break;
+
+                            case 5: // Exit or Unlock Full Game (depending on trialMode flag)
+                                if (trialMode)
+                                    ShowOffer();
+                                else if (ScreenManager.invited != null)
+                                    JoinInvitedGame();
+                                else
+                                    OnCancel();
+                                break;
+
+                            case 6: // Exit
+                                OnCancel();
+                                break;
+                        }
+                        break;
+                    }
+                case MainMenuState.SignedInLocal:
+                    {
+                        switch (entryIndex)
+                        {
+                            case 0: // Create System Link Session
+                                CreateSession(NetworkSessionType.SystemLink);
+                                break;
+
+                            case 1: // Join System Link Session
+                                FindSession(NetworkSessionType.SystemLink);
+                                break;
+
+                            case 2: // Exit
+                                OnCancel();
+                                break;
+                        }
+                        break;
+                    }
+                case MainMenuState.SignedOut:
+                    {
+                        switch (entryIndex)
+                        {
+                            case 0: // Sign In
+                                if (!Guide.IsVisible)
+                                {
+                                    Guide.ShowSignIn(1, false);
+                                }
+                                break;
+
+                            case 1: // Exit
+                                OnCancel();
+                                break;
+                        }
+                        break;
+                    }
+            }
+        }
+
+        /// <summary>
+        /// Show the marketplace offer for a trial mode game.
+        /// </summary>
+        private void ShowOffer()
+        {
+            // NOTE: This chooses the first signed in gamer, since we don't have any information
+            // about which gamepad clicked on the button.
+            Guide.ShowMarketplace(Gamer.SignedInGamers[0].PlayerIndex);
+        }
+
+
+        /// <summary>
+        /// Attempt to join a session using an invite that was received.
+        /// </summary>
+        public void JoinInvitedGame()
+        {
+            try
+            {
+                // begin to join the game we were invited to
+                IAsyncResult asyncResult = NetworkSession.BeginJoinInvited(1, null, null);
+
+                // create the busy screen
+                NetworkBusyScreen busyScreen = new NetworkBusyScreen("Joining the session...", asyncResult);
+                busyScreen.OperationCompleted += InvitedSessionJoined;
+                ScreenManager.AddScreen(busyScreen);
+            }
+            catch
+            {
+                // could not begin to join invited game, so default to the pre-existing MainMenuScreen
+            }
+
+            ScreenManager.invited = null;
+            updateState = true;
+        }
+
+
+        /// <summary>
+        /// When the user cancels the main menu, ask if they want to exit the sample.
+        /// </summary>
+        protected override void OnCancel()
+        {
+            const string message = "Exit Net Rumble?";
+            MessageBoxScreen messageBox = new MessageBoxScreen(message);
+            messageBox.Accepted += ExitMessageBoxAccepted;
+            ScreenManager.AddScreen(messageBox);
+        }
+
+
+        /// <summary>
+        /// Event handler for when the user selects ok on the "are you sure
+        /// you want to exit" message box.
+        /// </summary>
+        void ExitMessageBoxAccepted(object sender, EventArgs e)
+        {
+            ScreenManager.Game.Exit();
+        }
+
+
+        /// <summary>
+        /// Screen-specific update to gamer rich presence.
+        /// </summary>
+        public override void UpdatePresence()
+        {
+            foreach (SignedInGamer signedInGamer in Gamer.SignedInGamers)
+            {
+                if (signedInGamer.IsSignedInToLive)
+                {
+                    signedInGamer.Presence.PresenceMode = GamerPresenceMode.AtMenu;
+                }
+            }
+        }
+
+        #endregion
+
+
+        #region Networking Methods
+
+
+        private void QuickMatchSession()
+        {
+            // start the search
+            try
+            {
+                IAsyncResult asyncResult = NetworkSession.BeginFind(
+                    NetworkSessionType.PlayerMatch, 1, null, null, null);
+
+                // create the busy screen
+                NetworkBusyScreen busyScreen = new NetworkBusyScreen(
+                    "Searching for a session...", asyncResult);
+                busyScreen.OperationCompleted += QuickMatchSearchCompleted;
+                ScreenManager.AddScreen(busyScreen);
+            }
+            catch (NetworkException ne)
+            {
+                const string message = "Failed searching for the session.";
+                MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+
+                System.Console.WriteLine("Failed to search for session:  " +
+                    ne.Message);
+            }
+            catch (GamerPrivilegeException gpe)
+            {
+                const string message =
+                    "You do not have permission to search for a session.";
+                MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+
+                System.Console.WriteLine(
+                    "Insufficient privilege to search for session:  " + gpe.Message);
+            }
+        }
+
+
+        /// <summary>
+        /// Start creating a session of the given type.
+        /// </summary>
+        /// <param name="sessionType">The type of session to create.</param>
+        void CreateSession(NetworkSessionType sessionType)
+        {
+            // create the session
+            try
+            {
+                IAsyncResult asyncResult = NetworkSession.BeginCreate(sessionType, 1,
+                    World.MaximumPlayers, null, null);
+
+                // create the busy screen
+                NetworkBusyScreen busyScreen = new NetworkBusyScreen(
+                    "Creating a session...", asyncResult);
+                busyScreen.OperationCompleted += SessionCreated;
+                ScreenManager.AddScreen(busyScreen);
+            }
+            catch (NetworkException ne)
+            {
+                const string message = "Failed creating the session.";
+                MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+
+                System.Console.WriteLine("Failed to create session:  " +
+                    ne.Message);
+            }
+            catch (GamerPrivilegeException gpe)
+            {
+                const string message =
+                    "You do not have permission to create a session.";
+                MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+
+                System.Console.WriteLine(
+                    "Insufficient privilege to create session:  " + gpe.Message);
+            }
+        }
+
+
+        /// <summary>
+        /// Start searching for a session of the given type.
+        /// </summary>
+        /// <param name="sessionType">The type of session to look for.</param>
+        void FindSession(NetworkSessionType sessionType)
+        {
+            // create the new screen
+            SearchResultsScreen searchResultsScreen =
+               new SearchResultsScreen(sessionType);
+            searchResultsScreen.ScreenManager = this.ScreenManager;
+            ScreenManager.AddScreen(searchResultsScreen);
+
+            // start the search
+            try
+            {
+                IAsyncResult asyncResult = NetworkSession.BeginFind(sessionType, 1, null,
+                    null, null);
+
+                // create the busy screen
+                NetworkBusyScreen busyScreen = new NetworkBusyScreen(
+                    "Searching for a session...", asyncResult);
+                busyScreen.OperationCompleted += searchResultsScreen.SessionsFound;
+                ScreenManager.AddScreen(busyScreen);
+            }
+            catch (NetworkException ne)
+            {
+                const string message = "Failed searching for the session.";
+                MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+
+                System.Console.WriteLine("Failed to search for session:  " +
+                    ne.Message);
+            }
+            catch (GamerPrivilegeException gpe)
+            {
+                const string message =
+                    "You do not have permission to search for a session.";
+                MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+
+                System.Console.WriteLine(
+                    "Insufficient privilege to search for session:  " + gpe.Message);
+            }
+        }
+
+
+        /// <summary>
+        /// Callback to receive the network-session search results from quick-match.
+        /// </summary>
+        void QuickMatchSearchCompleted(object sender, OperationCompletedEventArgs e)
+        {
+            try
+            {
+                AvailableNetworkSessionCollection availableSessions =
+                    NetworkSession.EndFind(e.AsyncResult);
+                if ((availableSessions != null) && (availableSessions.Count > 0))
+                {
+                    // join the session
+                    try
+                    {
+                        IAsyncResult asyncResult = NetworkSession.BeginJoin(
+                            availableSessions[0], null, null);
+
+                        // create the busy screen
+                        NetworkBusyScreen busyScreen = new NetworkBusyScreen(
+                            "Joining the session...", asyncResult);
+                        busyScreen.OperationCompleted += QuickMatchSessionJoined;
+                        ScreenManager.AddScreen(busyScreen);
+                    }
+                    catch (NetworkException ne)
+                    {
+                        const string message = "Failed joining the session.";
+                        MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                        messageBox.Accepted += FailedMessageBox;
+                        messageBox.Cancelled += FailedMessageBox;
+                        ScreenManager.AddScreen(messageBox);
+
+                        System.Console.WriteLine("Failed to join session:  " +
+                            ne.Message);
+                    }
+                    catch (GamerPrivilegeException gpe)
+                    {
+                        const string message =
+                            "You do not have permission to join a session.";
+                        MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                        messageBox.Accepted += FailedMessageBox;
+                        messageBox.Cancelled += FailedMessageBox;
+                        ScreenManager.AddScreen(messageBox);
+
+                        System.Console.WriteLine(
+                            "Insufficient privilege to join session:  " + gpe.Message);
+                    }
+                }
+                else
+                {
+                    const string message = "No matches were found.";
+                    MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                    messageBox.Accepted += FailedMessageBox;
+                    messageBox.Cancelled += FailedMessageBox;
+                    ScreenManager.AddScreen(messageBox);
+                }
+            }
+            catch (GamerPrivilegeException gpe){
+                MessageBoxScreen messageBox = new MessageBoxScreen(gpe.Message);
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+            }
+        }
+
+
+        /// <summary>
+        /// Callback when a session is created.
+        /// </summary>
+        void SessionCreated(object sender, OperationCompletedEventArgs e)
+        {
+            NetworkSession networkSession = null;
+            try
+            {
+                networkSession = NetworkSession.EndCreate(e.AsyncResult);
+            }
+            catch (NetworkException ne)
+            {
+                const string message = "Failed creating the session.";
+                MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+
+                System.Console.WriteLine("Failed to create session:  " +
+                    ne.Message);
+            }
+            catch (GamerPrivilegeException gpe)
+            {
+                const string message =
+                    "You do not have permission to create a session. ";
+                MessageBoxScreen messageBox = new MessageBoxScreen(message+gpe.Message);
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+
+                System.Console.WriteLine(
+                    "Insufficient privilege to create session:  " + gpe.Message);
+            }
+            if (networkSession != null)
+            {
+                networkSession.AllowHostMigration = true;
+                networkSession.AllowJoinInProgress = false;
+                LoadLobbyScreen(networkSession);
+            }
+        }
+
+
+        /// <summary>
+        /// Callback when a session is quick-matched.
+        /// </summary>
+        void QuickMatchSessionJoined(object sender, OperationCompletedEventArgs e)
+        {
+            NetworkSession networkSession = null;
+            try
+            {
+                networkSession = NetworkSession.EndJoin(e.AsyncResult);
+            }
+            catch (NetworkException ne)
+            {
+                const string message = "Failed joining the session.";
+                MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+
+                System.Console.WriteLine("Failed to join session:  " +
+                    ne.Message);
+            }
+            catch (GamerPrivilegeException gpe)
+            {
+                const string message =
+                    "You do not have permission to join a session.";
+                MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+
+                System.Console.WriteLine(
+                    "Insufficient privilege to join session:  " + gpe.Message);
+            }
+            if (networkSession != null)
+            {
+                LoadLobbyScreen(networkSession);
+            }
+        }
+
+
+        /// <summary>
+        /// Load the lobby screen with the new session.
+        /// </summary>
+        void LoadLobbyScreen(NetworkSession networkSession)
+        {
+            if (networkSession != null)
+            {
+                LobbyScreen lobbyScreen = new LobbyScreen(networkSession);
+                lobbyScreen.ScreenManager = this.ScreenManager;
+                ScreenManager.AddScreen(lobbyScreen);
+            }
+        }
+
+
+        /// <summary>
+        /// Finishes the asynchronous process of joining a game from an invitation,
+        /// joining the lobby of a hosted game if the join was successful.
+        /// </summary>
+        void InvitedSessionJoined(object sender, OperationCompletedEventArgs e)
+        {
+            NetworkSession networkSession = null;
+            try
+            {
+                networkSession = NetworkSession.EndJoinInvited(e.AsyncResult);
+            }
+            catch (NetworkSessionJoinException je)
+            {
+                const string message = "Failed joining the session (";
+                MessageBoxScreen messageBox = new MessageBoxScreen(message + je.JoinError.ToString() + ").");
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+
+                System.Console.WriteLine("Failed to join session:  " +
+                    je.Message);
+            }
+            catch (Exception ge)
+            {
+                const string message = "Failed joining the session (";
+                MessageBoxScreen messageBox = new MessageBoxScreen(message + ge.Message + ").");
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+
+                System.Console.WriteLine("Failed to join session:  " +
+                    ge.Message);
+            }
+
+            // Start the lobby if we got the session!
+            // Otherwise the MainMenuScreen will be available.
+            if (networkSession != null)
+            {
+                LobbyScreen lobbyScreen = new LobbyScreen(networkSession);
+                lobbyScreen.ScreenManager = ScreenManager;
+                ScreenManager.AddScreen(lobbyScreen);
+            }
+        }
+
+
+        /// <summary>
+        /// Event handler for when the user selects ok on the network-operation-failed
+        /// message box.
+        /// </summary>
+        void FailedMessageBox(object sender, EventArgs e) { }
+
+
+        #endregion
+    }
+}

+ 204 - 0
Samples/Linux/NetRumble/Screens/NetworkBusyScreen.cs

@@ -0,0 +1,204 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// NetworkBusyScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// When an asynchronous network operation (for instance searching for or joining a
+    /// session) is in progress, we want to display some sort of busy indicator to let
+    /// the user know the game hasn't just locked up. We also want to make sure they
+    /// can't pick some other menu option before the current operation has finished.
+    /// This screen takes care of both requirements in a single stroke. It monitors
+    /// the IAsyncResult returned by an asynchronous network call, displaying a busy
+    /// indicator for as long as the call is still in progress. When it notices the
+    /// IAsyncResult has completed, it raises an event to let the game know it should
+    /// proceed to the next step, after which the busy screen automatically goes away.
+    /// Because this screen is on top of all others for as long as the asynchronous
+    /// operation is in progress, it automatically takes over all user input,
+    /// preventing any other menu entries being selected until the operation completes.
+    /// </summary>
+    /// <remarks>Based on a class in the Network Game State Management sample.</remarks>
+    class NetworkBusyScreen : GameScreen
+    {
+        #region Constants
+
+
+        const float busyTextureScale = 0.8f;
+
+
+        #endregion
+
+
+        #region Fields
+
+
+        /// <summary>
+        /// The message displayed in the screen.
+        /// </summary>
+        string message;
+
+        /// <summary>
+        /// The async result polled by the screen.
+        /// </summary>
+        IAsyncResult asyncResult;
+
+        /// <summary>
+        /// The rotating "activity" texture in the screen.
+        /// </summary>
+        Texture2D busyTexture;
+
+
+        #endregion
+
+
+        #region Events
+
+
+        public event EventHandler<OperationCompletedEventArgs> OperationCompleted;
+
+
+        #endregion
+
+
+        #region Initialization
+
+
+        /// <summary>
+        /// Constructs a network busy screen for the specified asynchronous operation.
+        /// </summary>
+        public NetworkBusyScreen(string message, IAsyncResult asyncResult)
+        {
+            this.message = message;
+            this.asyncResult = asyncResult;
+
+            IsPopup = true;
+
+            TransitionOnTime = TimeSpan.FromSeconds(0.1);
+            TransitionOffTime = TimeSpan.FromSeconds(0.2);
+        }
+
+        
+        /// <summary>
+        /// Loads graphics content for this screen. This uses the shared ContentManager
+        /// provided by the Game class, so the content will remain loaded forever.
+        /// Whenever a subsequent NetworkBusyScreen tries to load this same content,
+        /// it will just get back another reference to the already loaded data.
+        /// </summary>
+        public override void LoadContent()
+        {
+            ContentManager content = ScreenManager.Game.Content;
+
+            busyTexture = content.Load<Texture2D>("Textures/chatTalking");
+        }
+
+
+        #endregion
+
+
+        #region Update and Draw
+
+
+        /// <summary>
+        /// Updates the NetworkBusyScreen.
+        /// </summary>
+        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
+                                                       bool coveredByOtherScreen)
+        {
+            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+
+            // Has our asynchronous operation completed?
+            if ((asyncResult != null) && asyncResult.IsCompleted)
+            {
+                // If so, raise the OperationCompleted event.
+                if (OperationCompleted != null)
+                {
+                    OperationCompleted(this,
+                                       new OperationCompletedEventArgs(asyncResult));
+                }
+
+                ExitScreen();
+
+                asyncResult = null;
+            }
+        }
+
+
+        /// <summary>
+        /// Draws the NetworkBusyScreen.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
+            SpriteFont font = ScreenManager.Font;
+
+            const int hPad = 32;
+            const int vPad = 16;
+
+            // Center the message text in the viewport.
+            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
+            Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
+            Vector2 textSize = font.MeasureString(message);
+
+            // Add enough room to spin a texture.
+            Vector2 busyTextureSize = new Vector2(busyTexture.Width * busyTextureScale);
+            Vector2 busyTextureOrigin = new Vector2(busyTexture.Width / 2, 
+                busyTexture.Height / 2);
+
+            textSize.X = Math.Max(textSize.X, busyTextureSize.X);
+            textSize.Y += busyTextureSize.Y + vPad;
+
+            Vector2 textPosition = (viewportSize - textSize) / 2;
+
+            // The background includes a border somewhat larger than the text itself.
+            Rectangle backgroundRectangle = new Rectangle((int)textPosition.X - hPad,
+                                                          (int)textPosition.Y - vPad,
+                                                          (int)textSize.X + hPad * 2,
+                                                          (int)textSize.Y + vPad * 2);
+
+            // Fade the popup alpha during transitions.
+            Color color = new Color(255, 255, 255, TransitionAlpha);
+
+            // Draw the background rectangle.
+            Rectangle backgroundRectangle2 = new Rectangle(backgroundRectangle.X - 1, 
+                backgroundRectangle.Y - 1, backgroundRectangle.Width + 2, 
+                backgroundRectangle.Height + 2);
+            ScreenManager.DrawRectangle(backgroundRectangle2, new Color(128, 128, 128,
+                (byte)(192.0f * (float)TransitionAlpha / 255.0f)));
+            ScreenManager.DrawRectangle(backgroundRectangle, new Color(0, 0, 0,
+                (byte)(232.0f * (float)TransitionAlpha / 255.0f)));
+
+            //spriteBatch.Begin(0,BlendState.NonPremultiplied, null, null, null);
+			spriteBatch.Begin();
+            // Draw the message box text.
+            spriteBatch.DrawString(font, message, textPosition, color);
+
+            // Draw the spinning cat progress indicator.
+            float busyTextureRotation = (float)gameTime.TotalGameTime.TotalSeconds * 3;
+
+            Vector2 busyTexturePosition = new Vector2(textPosition.X + textSize.X / 2,
+                textPosition.Y + textSize.Y - busyTextureSize.Y / 2);
+
+            spriteBatch.Draw(busyTexture, busyTexturePosition, null, color,
+                busyTextureRotation, busyTextureOrigin, busyTextureScale, 
+                SpriteEffects.None, 0);
+
+            spriteBatch.End();
+        }
+
+
+        #endregion
+    }
+}

+ 351 - 0
Samples/Linux/NetRumble/Screens/SearchResultsScreen.cs

@@ -0,0 +1,351 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// SearchResultsScreen.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.GamerServices;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Net;
+#endregion
+
+namespace NetRumble
+{
+    /// <summary>
+    /// The search-results screen shows the results of a network-session
+    /// search, allowing the player to pick the game to join.
+    /// </summary>
+    public class SearchResultsScreen : MenuScreen
+    {
+        #region Constants
+
+
+        /// <summary>
+        /// The maximum number of session results to display.
+        /// </summary>
+        const int maximumSessions = 8;
+
+
+        #endregion
+
+
+        #region Networking Data
+
+
+        /// <summary>
+        /// The type of networking session that was requested.
+        /// </summary>
+        private NetworkSessionType sessionType;
+
+
+        /// <summary>
+        /// The collection of search results.
+        /// </summary>
+        private AvailableNetworkSessionCollection availableSessions = null;
+
+
+        #endregion
+
+
+        #region Initialization
+
+
+        /// <summary>
+        /// Constructor fills in the menu contents.
+        /// </summary>
+        /// <param name="sessionType">The type of session searched for.</param>
+        public SearchResultsScreen(NetworkSessionType sessionType) : base()
+        {
+            // apply the parameters
+            this.sessionType = sessionType;
+
+            // set the transition times
+            TransitionOnTime = TimeSpan.FromSeconds(1.0);
+            TransitionOffTime = TimeSpan.FromSeconds(0.0);
+        }
+
+
+        #endregion
+
+
+        #region Updating Methods
+
+
+        /// <summary>
+        /// Updates the screen. This method checks the GameScreen.IsActive
+        /// property, so the game will stop updating when the pause menu is active,
+        /// or if you tab away to a different application.
+        /// </summary>
+        public override void Update(Microsoft.Xna.Framework.GameTime gameTime,
+            bool otherScreenHasFocus, bool coveredByOtherScreen)
+        {
+            bool signedIntoLive = false;
+            if (Gamer.SignedInGamers.Count > 0)
+            {
+                foreach (SignedInGamer signedInGamer in Gamer.SignedInGamers)
+                {
+                    if (signedInGamer.IsSignedInToLive)
+                    {
+                        signedIntoLive = true;
+                        break;
+                    }
+                }
+                if (!signedIntoLive &&
+                    ((sessionType == NetworkSessionType.PlayerMatch) ||
+                     (sessionType == NetworkSessionType.Ranked)) && !IsExiting)
+                {
+                    ExitScreen();
+                }
+            }
+            else if (!IsExiting)
+            {
+                ExitScreen();
+            }
+
+            if (coveredByOtherScreen && !IsExiting)
+            {
+                ExitScreen();
+            }
+
+            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
+        }
+
+
+        /// <summary>
+        /// Responds to user menu selections.
+        /// </summary>
+        protected override void OnSelectEntry(int entryIndex)
+        {
+            if ((availableSessions != null) && (entryIndex >= 0) && 
+                (entryIndex < availableSessions.Count))
+            {
+                // start to join
+                try
+                {
+                    IAsyncResult asyncResult = NetworkSession.BeginJoin(
+                        availableSessions[entryIndex], null, null);
+
+                    // create the busy screen
+                    NetworkBusyScreen busyScreen = new NetworkBusyScreen(
+                        "Joining the session...", asyncResult);
+                    busyScreen.OperationCompleted += LoadLobbyScreen;
+                    ScreenManager.AddScreen(busyScreen);
+                }
+                catch (NetworkException ne)
+                {
+                    const string message = "Failed joining the session.";
+                    MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                    messageBox.Accepted += FailedMessageBox;
+                    messageBox.Cancelled += FailedMessageBox;
+                    ScreenManager.AddScreen(messageBox);
+
+                    System.Console.WriteLine("Failed to join session:  " +
+                        ne.Message);
+                }
+                catch (GamerPrivilegeException gpe)
+                {
+                    const string message =
+                        "You do not have permission to join a session.";
+                    MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                    messageBox.Accepted += FailedMessageBox;
+                    messageBox.Cancelled += FailedMessageBox;
+                    ScreenManager.AddScreen(messageBox);
+
+                    System.Console.WriteLine(
+                        "Insufficient privilege to join session:  " + gpe.Message);
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// When the user cancels the screen.
+        /// </summary>
+        protected override void OnCancel()
+        {
+            if (availableSessions != null)
+            {
+                ExitScreen();
+            }
+        }
+
+
+        #endregion
+
+
+        #region Drawing Methods
+
+
+        /// <summary>
+        /// Draw the screen.
+        /// </summary>
+        public override void Draw(GameTime gameTime)
+        {
+            string alternateString = String.Empty;
+
+            // set an alternate string if there are no search results yet
+            if (availableSessions == null)
+            {
+                alternateString = "Searching...";
+            }
+            else if (availableSessions.Count <= 0)
+            {
+                alternateString = "No sessions found.";
+            }
+
+            if (String.IsNullOrEmpty(alternateString))
+            {
+                base.Draw(gameTime);
+            }
+            else
+            {
+                Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
+                Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
+
+                Vector2 position = new Vector2(0f, viewportSize.Y * 0.65f);
+
+                // 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).
+                float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
+
+                if (ScreenState == ScreenState.TransitionOn)
+                    position.Y += transitionOffset * 256;
+                else
+                    position.Y += transitionOffset * 512;
+
+                // Draw each menu entry in turn.
+                ScreenManager.SpriteBatch.Begin();
+
+                Vector2 origin = new Vector2(0, ScreenManager.Font.LineSpacing / 2);
+                Vector2 size = ScreenManager.Font.MeasureString(alternateString);
+                position.X = viewportSize.X / 2f - size.X / 2f;
+                ScreenManager.SpriteBatch.DrawString(ScreenManager.Font, 
+                                                     alternateString, position, 
+                                                     Color.White, 0, origin, 1.0f,
+                                                     SpriteEffects.None, 0);
+
+                ScreenManager.SpriteBatch.End();
+            }
+        }
+
+
+        #endregion
+
+
+        #region Networking Methods
+
+
+        /// <summary>
+        /// Callback to receive the network-session search results.
+        /// </summary>
+        internal void SessionsFound(object sender, OperationCompletedEventArgs e)
+        {
+            try
+            {
+                availableSessions = NetworkSession.EndFind(e.AsyncResult);
+            }
+            catch (NetworkException ne)
+            {
+                const string message = "Failed searching for the session.";
+                MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+
+                System.Console.WriteLine("Failed to search for session:  " +
+                    ne.Message);
+            }
+            catch (GamerPrivilegeException gpe)
+            {
+                const string message =
+                    "You do not have permission to search for a session. ";
+                MessageBoxScreen messageBox = new MessageBoxScreen(message + gpe.Message);
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+
+                System.Console.WriteLine(
+                    "Insufficient privilege to search for session:  " + gpe.Message);
+            } 
+            MenuEntries.Clear();
+            if (availableSessions != null)
+            {
+                foreach (AvailableNetworkSession availableSession in
+                    availableSessions)
+                {
+                    if (availableSession.CurrentGamerCount < World.MaximumPlayers)
+                    {
+                        MenuEntries.Add(availableSession.HostGamertag + " (" +
+                            availableSession.CurrentGamerCount.ToString() + "/" +
+                            World.MaximumPlayers.ToString() + ")");
+                    }
+                    if (MenuEntries.Count >= maximumSessions)
+                    {
+                        break;
+                    }
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// Callback to load the lobby screen with the new session.
+        /// </summary>
+        private void LoadLobbyScreen(object sender, OperationCompletedEventArgs e)
+        {
+            NetworkSession networkSession = null;
+            try
+            {
+                networkSession = NetworkSession.EndJoin(e.AsyncResult);
+            }
+            catch (NetworkException ne)
+            {
+                const string message = "Failed joining session.";
+                MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+
+                System.Console.WriteLine("Failed joining session:  " + ne.Message);
+            }
+            catch (GamerPrivilegeException gpe)
+            {
+                const string message =
+                    "You do not have permission to join a session.";
+                MessageBoxScreen messageBox = new MessageBoxScreen(message);
+                messageBox.Accepted += FailedMessageBox;
+                messageBox.Cancelled += FailedMessageBox;
+                ScreenManager.AddScreen(messageBox);
+
+                System.Console.WriteLine(
+                    "Insufficient privilege to join session:  " + gpe.Message);
+            }
+            if (networkSession != null)
+            {
+                LobbyScreen lobbyScreen = new LobbyScreen(networkSession);
+                lobbyScreen.ScreenManager = this.ScreenManager;
+                ScreenManager.AddScreen(lobbyScreen);
+            }
+        }
+
+
+        /// <summary>
+        /// Event handler for when the user selects ok on the "are you sure
+        /// you want to exit" message box.
+        /// </summary>
+        private void FailedMessageBox(object sender, EventArgs e)
+        {
+            ExitScreen();
+        }
+
+
+        #endregion
+    }
+}

+ 188 - 0
Samples/Linux/NetworkStateManagement/NetworkStateManagement.csproj

@@ -0,0 +1,188 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{D0E05092-60B2-47FF-B924-D5CDED0C0DD1}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>NetworkStateManagement</RootNamespace>
+    <AssemblyName>NetworkStateManagement</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Game.cs">
+      <Link>Game.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\IMessageDisplay.cs">
+      <Link>IMessageDisplay.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\MessageDisplayComponent.cs">
+      <Link>MessageDisplayComponent.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Networking\AvailableSessionMenuEntry.cs">
+      <Link>Networking\AvailableSessionMenuEntry.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Networking\CreateOrFindSessionScreen.cs">
+      <Link>Networking\CreateOrFindSessionScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Networking\JoinSessionScreen.cs">
+      <Link>Networking\JoinSessionScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Networking\LobbyScreen.cs">
+      <Link>Networking\LobbyScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Networking\NetworkBusyScreen.cs">
+      <Link>Networking\NetworkBusyScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Networking\NetworkErrorScreen.cs">
+      <Link>Networking\NetworkErrorScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Networking\NetworkSessionComponent.cs">
+      <Link>Networking\NetworkSessionComponent.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Networking\OperationCompletedEventArgs.cs">
+      <Link>Networking\OperationCompletedEventArgs.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Networking\ProfileSignInScreen.cs">
+      <Link>Networking\ProfileSignInScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\ScreenManager\GameScreen.cs">
+      <Link>ScreenManager\GameScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\ScreenManager\InputState.cs">
+      <Link>ScreenManager\InputState.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\ScreenManager\ScreenManager.cs">
+      <Link>ScreenManager\ScreenManager.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Screens\BackgroundScreen.cs">
+      <Link>Screens\BackgroundScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Screens\GameplayScreen.cs">
+      <Link>Screens\GameplayScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Screens\LoadingScreen.cs">
+      <Link>Screens\LoadingScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Screens\MainMenuScreen.cs">
+      <Link>Screens\MainMenuScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Screens\MenuEntry.cs">
+      <Link>Screens\MenuEntry.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Screens\MenuScreen.cs">
+      <Link>Screens\MenuScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Screens\MessageBoxScreen.cs">
+      <Link>Screens\MessageBoxScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Screens\PauseMenuScreen.cs">
+      <Link>Screens\PauseMenuScreen.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\NetworkStateManagement\Screens\PlayerIndexEventArgs.cs">
+      <Link>Screens\PlayerIndexEventArgs.cs</Link>
+    </Compile>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\MonoGame.Framework\MonoGame.Framework.Windows.csproj">
+      <Project>{7DE47032-A904-4C29-BD22-2D235E8D91BA}</Project>
+      <Name>MonoGame.Framework.Windows</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="..\..\MacOS\NetworkStateManagement\Content\background.xnb">
+      <Link>Content\background.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\MacOS\NetworkStateManagement\Content\blank.xnb">
+      <Link>Content\blank.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\MacOS\NetworkStateManagement\Content\cat.xnb">
+      <Link>Content\cat.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\MacOS\NetworkStateManagement\Content\chat_able.xnb">
+      <Link>Content\chat_able.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\MacOS\NetworkStateManagement\Content\chat_mute.xnb">
+      <Link>Content\chat_mute.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\MacOS\NetworkStateManagement\Content\chat_ready.xnb">
+      <Link>Content\chat_ready.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\MacOS\NetworkStateManagement\Content\chat_talking.xnb">
+      <Link>Content\chat_talking.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\MacOS\NetworkStateManagement\Content\gamefont.xnb">
+      <Link>Content\gamefont.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\MacOS\NetworkStateManagement\Content\gradient.xnb">
+      <Link>Content\gradient.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="..\..\MacOS\NetworkStateManagement\Content\menufont.xnb">
+      <Link>Content\menufont.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 18 - 0
Samples/Linux/NetworkStateManagement/Program.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace NetworkStateManagement
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            using (NetworkStateManagementGame game = new NetworkStateManagementGame())
+            {
+                game.Run();
+            }
+        }
+    }
+}

+ 36 - 0
Samples/Linux/NetworkStateManagement/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("NetworkStateManagement")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("NetworkStateManagement")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("c5101010-89f6-4096-bd46-893825393de4")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 433 - 0
Samples/Linux/NetworkStateManagement/Resources.Designer.cs

@@ -0,0 +1,433 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.235
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace NetworkStateManagement {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NetworkStateManagement.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Back.
+        /// </summary>
+        internal static string Back {
+            get {
+                return ResourceManager.GetString("Back", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Are you sure you want to end this session?.
+        /// </summary>
+        internal static string ConfirmEndSession {
+            get {
+                return ResourceManager.GetString("ConfirmEndSession", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Are you sure you want to exit this sample?.
+        /// </summary>
+        internal static string ConfirmExitSample {
+            get {
+                return ResourceManager.GetString("ConfirmExitSample", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Are you sure you want to start the game,
+        ///even though not all players are ready?.
+        /// </summary>
+        internal static string ConfirmForceStartGame {
+            get {
+                return ResourceManager.GetString("ConfirmForceStartGame", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Are you sure you want to leave this session?.
+        /// </summary>
+        internal static string ConfirmLeaveSession {
+            get {
+                return ResourceManager.GetString("ConfirmLeaveSession", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Online gameplay is not available in trial mode.
+        ///Would you like to purchase this game?.
+        /// </summary>
+        internal static string ConfirmMarketplace {
+            get {
+                return ResourceManager.GetString("ConfirmMarketplace", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Are you sure you want to quit this game?.
+        /// </summary>
+        internal static string ConfirmQuitGame {
+            get {
+                return ResourceManager.GetString("ConfirmQuitGame", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Create Session.
+        /// </summary>
+        internal static string CreateSession {
+            get {
+                return ResourceManager.GetString("CreateSession", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to End Session.
+        /// </summary>
+        internal static string EndSession {
+            get {
+                return ResourceManager.GetString("EndSession", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Lost connection to the network session.
+        /// </summary>
+        internal static string ErrorDisconnected {
+            get {
+                return ResourceManager.GetString("ErrorDisconnected", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to You must sign in a suitable gamer profile
+        ///in order to access this functionality.
+        /// </summary>
+        internal static string ErrorGamerPrivilege {
+            get {
+                return ResourceManager.GetString("ErrorGamerPrivilege", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Host ended the session.
+        /// </summary>
+        internal static string ErrorHostEndedSession {
+            get {
+                return ResourceManager.GetString("ErrorHostEndedSession", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to There was an error while
+        ///accessing the network.
+        /// </summary>
+        internal static string ErrorNetwork {
+            get {
+                return ResourceManager.GetString("ErrorNetwork", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Networking is turned
+        ///off or not connected.
+        /// </summary>
+        internal static string ErrorNetworkNotAvailable {
+            get {
+                return ResourceManager.GetString("ErrorNetworkNotAvailable", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Host kicked you out of the session.
+        /// </summary>
+        internal static string ErrorRemovedByHost {
+            get {
+                return ResourceManager.GetString("ErrorRemovedByHost", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to This session is already full.
+        /// </summary>
+        internal static string ErrorSessionFull {
+            get {
+                return ResourceManager.GetString("ErrorSessionFull", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Session not found. It may have ended,
+        ///or there may be no network connectivity
+        ///between the local machine and session host.
+        /// </summary>
+        internal static string ErrorSessionNotFound {
+            get {
+                return ResourceManager.GetString("ErrorSessionNotFound", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to You must wait for the host to return to
+        ///the lobby before you can join this session.
+        /// </summary>
+        internal static string ErrorSessionNotJoinable {
+            get {
+                return ResourceManager.GetString("ErrorSessionNotJoinable", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to This functionality is not available in trial mode.
+        /// </summary>
+        internal static string ErrorTrialMode {
+            get {
+                return ResourceManager.GetString("ErrorTrialMode", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to An unknown error occurred.
+        /// </summary>
+        internal static string ErrorUnknown {
+            get {
+                return ResourceManager.GetString("ErrorUnknown", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Exit.
+        /// </summary>
+        internal static string Exit {
+            get {
+                return ResourceManager.GetString("Exit", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Find Sessions.
+        /// </summary>
+        internal static string FindSessions {
+            get {
+                return ResourceManager.GetString("FindSessions", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to  (host).
+        /// </summary>
+        internal static string HostSuffix {
+            get {
+                return ResourceManager.GetString("HostSuffix", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Join Session.
+        /// </summary>
+        internal static string JoinSession {
+            get {
+                return ResourceManager.GetString("JoinSession", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Leave Session.
+        /// </summary>
+        internal static string LeaveSession {
+            get {
+                return ResourceManager.GetString("LeaveSession", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Loading.
+        /// </summary>
+        internal static string Loading {
+            get {
+                return ResourceManager.GetString("Loading", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Lobby.
+        /// </summary>
+        internal static string Lobby {
+            get {
+                return ResourceManager.GetString("Lobby", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Main Menu.
+        /// </summary>
+        internal static string MainMenu {
+            get {
+                return ResourceManager.GetString("MainMenu", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to 
+        ///A button, Space, Enter = ok
+        ///B button, Esc = cancel.
+        /// </summary>
+        internal static string MessageBoxUsage {
+            get {
+                return ResourceManager.GetString("MessageBoxUsage", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to {0} joined.
+        /// </summary>
+        internal static string MessageGamerJoined {
+            get {
+                return ResourceManager.GetString("MessageGamerJoined", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to {0} left.
+        /// </summary>
+        internal static string MessageGamerLeft {
+            get {
+                return ResourceManager.GetString("MessageGamerLeft", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Networking....
+        /// </summary>
+        internal static string NetworkBusy {
+            get {
+                return ResourceManager.GetString("NetworkBusy", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to No sessions found.
+        /// </summary>
+        internal static string NoSessionsFound {
+            get {
+                return ResourceManager.GetString("NoSessionsFound", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Paused.
+        /// </summary>
+        internal static string Paused {
+            get {
+                return ResourceManager.GetString("Paused", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to LIVE.
+        /// </summary>
+        internal static string PlayerMatch {
+            get {
+                return ResourceManager.GetString("PlayerMatch", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Quit Game.
+        /// </summary>
+        internal static string QuitGame {
+            get {
+                return ResourceManager.GetString("QuitGame", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Resume Game.
+        /// </summary>
+        internal static string ResumeGame {
+            get {
+                return ResourceManager.GetString("ResumeGame", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Return to Lobby.
+        /// </summary>
+        internal static string ReturnToLobby {
+            get {
+                return ResourceManager.GetString("ReturnToLobby", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Single Player.
+        /// </summary>
+        internal static string SinglePlayer {
+            get {
+                return ResourceManager.GetString("SinglePlayer", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to System Link.
+        /// </summary>
+        internal static string SystemLink {
+            get {
+                return ResourceManager.GetString("SystemLink", resourceCulture);
+            }
+        }
+    }
+}

+ 250 - 0
Samples/Linux/NetworkStateManagement/Resources.resx

@@ -0,0 +1,250 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="Back" xml:space="preserve">
+    <value>Back</value>
+  </data>
+  <data name="ConfirmEndSession" xml:space="preserve">
+    <value>Are you sure you want to end this session?</value>
+  </data>
+  <data name="ConfirmExitSample" xml:space="preserve">
+    <value>Are you sure you want to exit this sample?</value>
+  </data>
+  <data name="ConfirmForceStartGame" xml:space="preserve">
+    <value>Are you sure you want to start the game,
+even though not all players are ready?</value>
+  </data>
+  <data name="ConfirmLeaveSession" xml:space="preserve">
+    <value>Are you sure you want to leave this session?</value>
+  </data>
+  <data name="ConfirmMarketplace" xml:space="preserve">
+    <value>Online gameplay is not available in trial mode.
+Would you like to purchase this game?</value>
+  </data>
+  <data name="ConfirmQuitGame" xml:space="preserve">
+    <value>Are you sure you want to quit this game?</value>
+  </data>
+  <data name="CreateSession" xml:space="preserve">
+    <value>Create Session</value>
+  </data>
+  <data name="EndSession" xml:space="preserve">
+    <value>End Session</value>
+  </data>
+  <data name="ErrorDisconnected" xml:space="preserve">
+    <value>Lost connection to the network session</value>
+  </data>
+  <data name="ErrorGamerPrivilege" xml:space="preserve">
+    <value>You must sign in a suitable gamer profile
+in order to access this functionality</value>
+  </data>
+  <data name="ErrorHostEndedSession" xml:space="preserve">
+    <value>Host ended the session</value>
+  </data>
+  <data name="ErrorNetwork" xml:space="preserve">
+    <value>There was an error while
+accessing the network</value>
+  </data>
+  <data name="ErrorNetworkNotAvailable" xml:space="preserve">
+    <value>Networking is turned
+off or not connected</value>
+  </data>
+  <data name="ErrorRemovedByHost" xml:space="preserve">
+    <value>Host kicked you out of the session</value>
+  </data>
+  <data name="ErrorSessionFull" xml:space="preserve">
+    <value>This session is already full</value>
+  </data>
+  <data name="ErrorSessionNotFound" xml:space="preserve">
+    <value>Session not found. It may have ended,
+or there may be no network connectivity
+between the local machine and session host</value>
+  </data>
+  <data name="ErrorSessionNotJoinable" xml:space="preserve">
+    <value>You must wait for the host to return to
+the lobby before you can join this session</value>
+  </data>
+  <data name="ErrorTrialMode" xml:space="preserve">
+    <value>This functionality is not available in trial mode</value>
+  </data>
+  <data name="ErrorUnknown" xml:space="preserve">
+    <value>An unknown error occurred</value>
+  </data>
+  <data name="Exit" xml:space="preserve">
+    <value>Exit</value>
+  </data>
+  <data name="FindSessions" xml:space="preserve">
+    <value>Find Sessions</value>
+  </data>
+  <data name="HostSuffix" xml:space="preserve">
+    <value> (host)</value>
+  </data>
+  <data name="JoinSession" xml:space="preserve">
+    <value>Join Session</value>
+  </data>
+  <data name="LeaveSession" xml:space="preserve">
+    <value>Leave Session</value>
+  </data>
+  <data name="Loading" xml:space="preserve">
+    <value>Loading</value>
+  </data>
+  <data name="Lobby" xml:space="preserve">
+    <value>Lobby</value>
+  </data>
+  <data name="MainMenu" xml:space="preserve">
+    <value>Main Menu</value>
+  </data>
+  <data name="MessageBoxUsage" xml:space="preserve">
+    <value>
+A button, Space, Enter = ok
+B button, Esc = cancel</value>
+  </data>
+  <data name="MessageGamerJoined" xml:space="preserve">
+    <value>{0} joined</value>
+  </data>
+  <data name="MessageGamerLeft" xml:space="preserve">
+    <value>{0} left</value>
+  </data>
+  <data name="NetworkBusy" xml:space="preserve">
+    <value>Networking...</value>
+  </data>
+  <data name="NoSessionsFound" xml:space="preserve">
+    <value>No sessions found</value>
+  </data>
+  <data name="Paused" xml:space="preserve">
+    <value>Paused</value>
+  </data>
+  <data name="PlayerMatch" xml:space="preserve">
+    <value>LIVE</value>
+  </data>
+  <data name="QuitGame" xml:space="preserve">
+    <value>Quit Game</value>
+  </data>
+  <data name="ResumeGame" xml:space="preserve">
+    <value>Resume Game</value>
+  </data>
+  <data name="ReturnToLobby" xml:space="preserve">
+    <value>Return to Lobby</value>
+  </data>
+  <data name="SinglePlayer" xml:space="preserve">
+    <value>Single Player</value>
+  </data>
+  <data name="SystemLink" xml:space="preserve">
+    <value>System Link</value>
+  </data>
+</root>

+ 77 - 0
Samples/Linux/Peer2PeerSample/MonoGame.Samples.Peer2PeerSample.Linux.csproj

@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{86A619E2-C8D0-452B-B762-C69D5BB07C98}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>Peer2PeerSample</RootNamespace>
+    <AssemblyName>Peer2PeerSample</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <DebugType>none</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Drawing" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\..\MacOS\Peer2PeerSample\PeerToPeerGame.cs">
+      <Link>PeerToPeerGame.cs</Link>
+    </Compile>
+    <Compile Include="..\..\MacOS\Peer2PeerSample\Tank.cs">
+      <Link>Tank.cs</Link>
+    </Compile>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="..\..\MacOS\Peer2PeerSample\Content\Font.spritefont">
+      <Link>Content\Font.spritefont</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\MacOS\Peer2PeerSample\Content\Font.xnb">
+      <Link>Content\Font.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\MacOS\Peer2PeerSample\Content\Tank.xnb">
+      <Link>Content\Tank.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\MacOS\Peer2PeerSample\Content\Turret.xnb">
+      <Link>Content\Turret.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <None Include="app.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\MonoGame.Framework\MonoGame.Framework.Linux.csproj">
+      <Project>{35253CE1-C864-4CD3-8249-4D1319748E8F}</Project>
+      <Name>MonoGame.Framework.Linux</Name>
+    </ProjectReference>
+  </ItemGroup>
+</Project>

+ 15 - 0
Samples/Linux/Peer2PeerSample/Program.cs

@@ -0,0 +1,15 @@
+using System;
+
+namespace Peer2Peer
+{
+	class Program
+	{
+		public static void Main(string[] args)
+		{
+			using ( PeerToPeer.PeerToPeerGame game = new  PeerToPeer.PeerToPeerGame())
+			{
+				game.Run();
+			}
+		}
+	}
+}

+ 32 - 0
Samples/Linux/Peer2PeerSample/Properties/AssemblyInfo.cs

@@ -0,0 +1,32 @@
+#region Using directives
+
+using System;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+#endregion
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Peer2PeerSample")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Peer2PeerSample")]
+[assembly: AssemblyCopyright("Copyright 2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// This sets the default COM visibility of types in the assembly to invisible.
+// If you need to expose a type to COM, use [ComVisible(true)] on that type.
+[assembly: ComVisible(false)]
+
+// The assembly version has following format :
+//
+// Major.Minor.Build.Revision
+//
+// You can specify all the values or you can use the default the Revision and 
+// Build Numbers by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.*")]
+[assembly: GuidAttribute("15a16f67-bfbd-4299-8f2e-831a990d4cb3")]

+ 3 - 0
Samples/Linux/Peer2PeerSample/app.config

@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration><startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" /></startup>
+</configuration>

+ 134 - 0
Samples/Linux/Sound/Game1.cs

@@ -0,0 +1,134 @@
+using System;
+using System.Collections.Generic;
+
+#if ANDROID
+using Android.App;
+#endif
+
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using Microsoft.Xna.Framework.Storage;
+using Microsoft.Xna.Framework.Audio;
+
+namespace Microsoft.Xna.Samples.Sound
+{
+	/// <summary>
+	/// This is the main type for your game
+	/// </summary>
+	public class Game1 : Microsoft.Xna.Framework.Game
+	{
+		GraphicsDeviceManager graphics;	
+		KeyboardState oldSate;
+		SoundEffect sound;
+		SpriteBatch spriteBatch;
+		SoundEffectInstance soundInst;
+		SpriteFont font;
+		
+#if ANDROID 
+		public Game1 (Activity activity) : base (activity)
+#else 
+        public Game1 ()  
+#endif
+		{
+			graphics = new GraphicsDeviceManager (this);
+			
+			Content.RootDirectory = "Content";
+			
+			graphics.PreferMultiSampling = true;
+			graphics.IsFullScreen = false;	
+
+			Window.AllowUserResizing = false;
+
+			graphics.SupportedOrientations = DisplayOrientation.Portrait | DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight | DisplayOrientation.PortraitUpsideDown;
+		}
+		
+		/// <summary>
+		/// Allows the game to perform any initialization it needs to before starting to run.
+		/// This is where it can query for any required services and load any non-graphic
+		/// related content.  Calling base.Initialize will enumerate through any components
+		/// and initialize them as well.
+		/// </summary>
+		protected override void Initialize ()
+		{
+			// TODO: Add your initialization logic here
+			
+			base.Initialize ();
+		}
+
+		/// <summary>
+		/// LoadContent will be called once per game and is the place to load
+		/// all of your content.
+		/// </summary>
+		protected override void LoadContent ()
+		{
+			// Create a new SpriteBatch, which can be used to draw textures.
+			spriteBatch = new SpriteBatch(GraphicsDevice);
+
+			sound = Content.Load<SoundEffect>("Explosion1");
+			soundInst = sound.CreateInstance();
+			
+			font = Content.Load<SpriteFont>("spriteFont1");
+		}
+
+		/// <summary>
+		/// Allows the game to run logic such as updating the world,
+		/// checking for collisions, gathering input, and playing audio.
+		/// </summary>
+		/// <param name="gameTime">Provides a snapshot of timing values.</param>
+		protected override void Update (GameTime gameTime)
+		{
+			KeyboardState ks = Keyboard.GetState();
+			
+			
+			if (ks[Keys.Escape] == KeyState.Down)
+				base.Exit();
+			
+			if (ks.IsKeyDown(Keys.A) && oldSate.IsKeyUp(Keys.A))
+				soundInst.Play();
+			
+			if (ks.IsKeyDown(Keys.B) && oldSate.IsKeyUp(Keys.B))
+				soundInst.Stop();
+			
+			if (ks.IsKeyDown(Keys.C) && oldSate.IsKeyUp(Keys.C))
+				soundInst.Pause();
+			
+			if (ks.IsKeyDown(Keys.D) && oldSate.IsKeyUp(Keys.D))
+				soundInst.IsLooped = !soundInst.IsLooped;
+			
+			if (ks.IsKeyDown(Keys.E) && oldSate.IsKeyUp(Keys.E))
+				soundInst.Stop(true);			
+			
+			if (ks.IsKeyDown(Keys.X))
+				soundInst.Volume = MathHelper.Clamp(soundInst.Volume + 0.01f, 0f, 1f);
+			else if (ks.IsKeyDown(Keys.Z))
+				soundInst.Volume = MathHelper.Clamp(soundInst.Volume - 0.01f, 0f, 1f);;
+			
+			oldSate = ks;
+
+			base.Update (gameTime);
+		}
+
+		/// <summary>
+		/// This is called when the game should draw itself.
+		/// </summary>
+		/// <param name="gameTime">Provides a snapshot of timing values.</param>
+		protected override void Draw (GameTime gameTime)
+		{
+			graphics.GraphicsDevice.Clear (Color.CornflowerBlue);
+
+			spriteBatch.Begin();
+
+			spriteBatch.DrawString(font, "A: play\nB: stop\nC: pause\nD: toggle looping\nE: immediate stop\nX/Z volume\nStatus: " +
+			                       soundInst.State.ToString() + "\nLooping: " +
+			                       soundInst.IsLooped.ToString() + "\nVolume: " +
+			                       soundInst.Volume.ToString()
+			                       , Vector2.Zero, Color.White);
+			
+			base.Draw(gameTime);
+			
+			spriteBatch.End();
+		}
+	}
+}

+ 82 - 0
Samples/Linux/Sound/MonoGame.Samples.Sound.Linux.csproj

@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{8CFEF2EE-5E32-43EB-A730-EB3AACDC77B1}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Draw2D</RootNamespace>
+    <AssemblyName>Draw2D</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE;WINDOWS</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE;WINDOWS</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="Game1.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="..\..\iOS\Draw2D\Content\monogameicon.png">
+      <Link>Content\monogameicon.png</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\iOS\Draw2D\Content\purpleBall.xnb">
+      <Link>Content\purpleBall.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\iOS\Draw2D\Content\spriteFont1.xnb">
+      <Link>Content\spriteFont1.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="..\..\iOS\Draw2D\Default.png">
+      <Link>Default.png</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="..\..\iOS\Draw2D\Default.png">
+      <Link>Default.png</Link>
+    </Content>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\MonoGame.Framework\MonoGame.Framework.Linux.csproj">
+      <Project>{35253CE1-C864-4CD3-8249-4D1319748E8F}</Project>
+      <Name>MonoGame.Framework.Linux</Name>
+    </ProjectReference>
+  </ItemGroup>
+</Project>

+ 21 - 0
Samples/Linux/Sound/Program.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Microsoft.Xna.Samples.Sound
+{
+    static class Program
+    {
+        private static Game1 game;
+
+        /// <summary>
+        /// The main entry point for the application.
+        /// </summary>
+        [STAThread]
+        static void Main()
+        {
+            game = new Game1();
+            game.Run();
+        }
+    }
+}

+ 57 - 0
Samples/Linux/SpriteEffects/DesaturateEffect.cs

@@ -0,0 +1,57 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework;
+
+#if !LINUX
+
+using MonoMac.Foundation;
+using MonoMac.AppKit;
+
+#endif
+
+namespace SpriteEffects
+{
+	public class DesaturateEffect : Effect
+	{
+		public DesaturateEffect (GraphicsDevice graphicsDevice) : base (graphicsDevice)
+		{
+			LoadShaderFromFile ("desaturate.fsh");
+			DefineTechnique ("Desaturate", "Pass1", 0, 0);
+			CurrentTechnique = Techniques ["Desaturate"];
+		}
+
+		protected void LoadShaderFromFile (string sourceFile)
+		{
+			string path;
+#if !LINUX
+			path = Path.Combine (NSBundle.MainBundle.ResourcePath, "Content");
+#else
+			path = "Content";
+#endif
+			sourceFile = Path.Combine (path, sourceFile);
+
+			// Load the source into a string
+			string shaderSource = LoadShaderSource (sourceFile);
+
+			CreateFragmentShaderFromSource (shaderSource);				
+
+		}
+
+		// Load the source code of a GLSL program from the content
+		private string LoadShaderSource (string name)
+		{
+
+			StreamReader streamReader = new StreamReader (name);
+			string text = streamReader.ReadToEnd ();
+			streamReader.Close ();
+
+			return text;
+
+		}		
+
+	}
+}
+

+ 102 - 0
Samples/Linux/SpriteEffects/DisappearEffect.cs

@@ -0,0 +1,102 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework;
+
+#if !LINUX
+
+using MonoMac.Foundation;
+using MonoMac.AppKit;
+
+#endif
+
+namespace SpriteEffects
+{
+	public class DisappearEffect : Effect
+	{
+		public DisappearEffect (GraphicsDevice graphicsDevice) : base (graphicsDevice)
+		{
+			// We do not need this but here for test
+//			CreateVertexShaderFromSource("void main(void) { " +
+//				"gl_FrontColor = gl_Color; " +
+//				"gl_TexCoord[0] = gl_MultiTexCoord0;" +
+//				"gl_TexCoord[1] = gl_MultiTexCoord1;" +
+//				"gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;" +
+//				"}");
+			LoadShaderFromFile ("disappear.fsh");
+			
+			DefineTechnique ("Disappear", "Pass1", 0, 0);
+			CurrentTechnique = Techniques ["Disappear"];
+		}
+
+		protected void LoadShaderFromFile (string sourceFile)
+		{
+			string path;
+#if !LINUX
+			path = Path.Combine (NSBundle.MainBundle.ResourcePath, "Content");
+#else
+			path = "Content";
+#endif
+			sourceFile = Path.Combine (path, sourceFile);
+
+			// Load the source into a string
+			string shaderSource = LoadShaderSource (sourceFile);
+
+			CreateFragmentShaderFromSource (shaderSource);				
+
+		}
+
+		// Load the source code of a GLSL program from the content
+		private string LoadShaderSource (string name)
+		{
+
+			StreamReader streamReader = new StreamReader (name);
+			string text = streamReader.ReadToEnd ();
+			streamReader.Close ();
+
+			return text;
+
+		}
+		
+//void main(void){	
+//	gl_TexCoord[0] = gl_MultiTexCoord0;	
+//	gl_TexCoord[1] = gl_MultiTexCoord1;		
+//	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
+//}
+//
+//uniform sampler2D keke;
+//uniform sampler2D smee;
+//
+//void main (void){	
+//vec2 src = vec2(gl_TexCoord[0]);	
+//vec4 dest = texture2D(keke, src);		
+//vec2 src2 = vec2(gl_TexCoord[1]);	
+//vec4 dest2 = texture2D(smee, src2);			
+//gl_FragColor = 0.5 * (dest + dest2);  
+//}
+//
+//ARBShaderObjects.glUseProgramObjectARB(shader.getProgramID());		
+//int location = shader.getUniformLocation(shader.getProgramID(), "keke");
+//int location2 = shader.getUniformLocation(shader.getProgramID(), "smee");
+//ARBMultitexture.glActiveTextureARB(ARBMultitexture.GL_TEXTURE0_ARB);
+//GL11.glBindTexture(GL11.GL_TEXTURE_2D, TestEngine.cID);
+//GL11.glEnable(GL11.GL_TEXTURE_2D);
+//ARBShaderObjects.glUniform1iARB(location, 0);
+//ARBMultitexture.glActiveTextureARB(ARBMultitexture.GL_TEXTURE1_ARB);
+//GL11.glBindTexture(GL11.GL_TEXTURE_2D, sprite.getTextureID());
+//GL11.glEnable(GL11.GL_TEXTURE_2D);	
+//ARBShaderObjects.glUniform1iARB(location2, 1);
+//EngineFunc.translate(origin.x, origin.y);
+//EngineFunc.drawQuads(sprite.getPoints());		
+//ARBShaderObjects.glUseProgramObjectARB(0);		
+//ARBMultitexture.glActiveTextureARB(ARBMultitexture.GL_TEXTURE1_ARB);
+//GL11.glDisable(GL11.GL_TEXTURE_2D);		
+//ARBMultitexture.glActiveTextureARB(ARBMultitexture.GL_TEXTURE0_ARB);
+//GL11.glDisable(GL11.GL_TEXTURE_2D);
+		
+
+	}
+}
+

+ 119 - 0
Samples/Linux/SpriteEffects/MonoGame.Samples.SpriteEffects.Linux.csproj

@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{86A919E2-D7F0-452B-B762-C69D5BB07C98}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>SpriteEffects</RootNamespace>
+    <AssemblyName>SpriteEffects</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug</OutputPath>
+    <DefineConstants>DEBUG LINUX</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <DebugType>none</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Release</OutputPath>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <ConsolePause>false</ConsolePause>
+  </PropertyGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Xml" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Drawing" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\MacOS\SpriteEffects\Content\waterfall.xnb">
+      <Link>Content\waterfall.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\MacOS\SpriteEffects\Content\refraction.fx">
+      <Link>Content\refraction.fx</Link>
+    </None>
+    <None Include="..\..\MacOS\SpriteEffects\Content\refraction.fsh">
+      <Link>Content\refraction.fsh</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\MacOS\SpriteEffects\Content\normalmap.fx">
+      <Link>Content\normalmap.fx</Link>
+    </None>
+    <None Include="..\..\MacOS\SpriteEffects\Content\normalmap.fsh">
+      <Link>Content\normalmap.fsh</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\MacOS\SpriteEffects\Content\glacier.xnb">
+      <Link>Content\glacier.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\MacOS\SpriteEffects\Content\disappear.fx">
+      <Link>Content\disappear.fx</Link>
+    </None>
+    <None Include="..\..\MacOS\SpriteEffects\Content\disappear.fsh">
+      <Link>Content\disappear.fsh</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\MacOS\SpriteEffects\Content\desaturate.fx">
+      <Link>Content\desaturate.fx</Link>
+    </None>
+    <None Include="..\..\MacOS\SpriteEffects\Content\desaturate.fsh">
+      <Link>Content\desaturate.fsh</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\MacOS\SpriteEffects\Content\cat_normalmap.xnb">
+      <Link>Content\cat_normalmap.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\MacOS\SpriteEffects\Content\cat_depth.jpg">
+      <Link>Content\cat_depth.jpg</Link>
+    </None>
+    <None Include="..\..\MacOS\SpriteEffects\Content\cat_alpha.jpg">
+      <Link>Content\cat_alpha.jpg</Link>
+    </None>
+    <None Include="..\..\MacOS\SpriteEffects\Content\cat.xnb">
+      <Link>Content\cat.xnb</Link>
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="..\..\MacOS\SpriteEffects\Content\cat.jpg">
+      <Link>Content\cat.jpg</Link>
+    </None>
+    <None Include="..\..\MacOS\SpriteEffects\Info.plist">
+      <Link>Info.plist</Link>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Content\" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="..\..\MacOS\SpriteEffects\SpriteEffects.cs">
+      <Link>SpriteEffects.cs</Link>
+    </Compile>
+    <Compile Include="RefractionEffect.cs" />
+    <Compile Include="NormalmapEffect.cs" />
+    <Compile Include="DisappearEffect.cs" />
+    <Compile Include="DesaturateEffect.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\MonoGame.Framework\MonoGame.Framework.Linux.csproj">
+      <Project>{35253CE1-C864-4CD3-8249-4D1319748E8F}</Project>
+      <Name>MonoGame.Framework.Linux</Name>
+    </ProjectReference>
+  </ItemGroup>
+</Project>

+ 63 - 0
Samples/Linux/SpriteEffects/NormalmapEffect.cs

@@ -0,0 +1,63 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework;
+
+#if !LINUX
+
+using MonoMac.Foundation;
+using MonoMac.AppKit;
+
+#endif
+
+namespace SpriteEffects
+{
+	public class NormalmapEffect : Effect
+	{
+		public NormalmapEffect (GraphicsDevice graphicsDevice) : base (graphicsDevice)
+		{
+//			CreateVertexShaderFromSource("void main(void) { " +
+//				"gl_FrontColor = gl_Color; " +
+//				"gl_TexCoord[0] = gl_MultiTexCoord0;" +
+//				"gl_TexCoord[1] = gl_MultiTexCoord1;" +
+//				"gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;" +
+//				"}");
+			LoadShaderFromFile ("normalmap.fsh");
+			
+			DefineTechnique ("Normalmap", "Pass1", 0, 0);
+			CurrentTechnique = Techniques ["Normalmap"];
+		}
+
+		protected void LoadShaderFromFile (string sourceFile)
+		{
+			string path;
+#if !LINUX
+			path = Path.Combine (NSBundle.MainBundle.ResourcePath, "Content");
+#else
+			path = "Content";
+#endif
+			sourceFile = Path.Combine (path, sourceFile);
+
+			// Load the source into a string
+			string shaderSource = LoadShaderSource (sourceFile);
+
+			CreateFragmentShaderFromSource (shaderSource);				
+
+		}
+
+		// Load the source code of a GLSL program from the content
+		private string LoadShaderSource (string name)
+		{
+
+			StreamReader streamReader = new StreamReader (name);
+			string text = streamReader.ReadToEnd ();
+			streamReader.Close ();
+
+			return text;
+
+		}
+	}
+}
+

+ 16 - 0
Samples/Linux/SpriteEffects/Program.cs

@@ -0,0 +1,16 @@
+namespace SpriteEffects
+{
+	static class Program
+	{
+		/// <summary>
+		/// The main entry point for the application.
+		/// </summary>
+		static void Main (string[] args)
+		{
+			using (SpriteEffectsGame game = new SpriteEffectsGame ()) {
+				game.Run ();
+			}
+		}
+	}		
+}
+

+ 63 - 0
Samples/Linux/SpriteEffects/RefractionEffect.cs

@@ -0,0 +1,63 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework;
+
+#if !LINUX
+
+using MonoMac.Foundation;
+using MonoMac.AppKit;
+
+#endif
+
+namespace SpriteEffects
+{
+	public class RefractionEffect : Effect
+	{
+		public RefractionEffect (GraphicsDevice graphicsDevice) : base (graphicsDevice)
+		{
+//			CreateVertexShaderFromSource("void main(void) { " +
+//				"gl_FrontColor = gl_Color; " +
+//				"gl_TexCoord[0] = gl_MultiTexCoord0;" +
+//				"gl_TexCoord[1] = gl_MultiTexCoord1;" +
+//				"gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;" +
+//				"}");
+			LoadShaderFromFile ("refraction.fsh");
+			
+			DefineTechnique ("Refraction", "Pass1", 0, 0);
+			CurrentTechnique = Techniques ["Refraction"];
+		}
+
+		protected void LoadShaderFromFile (string sourceFile)
+		{
+			string path;
+#if !LINUX
+			path = Path.Combine (NSBundle.MainBundle.ResourcePath, "Content");
+#else
+			path = "Content";
+#endif
+			sourceFile = Path.Combine (path, sourceFile);
+
+			// Load the source into a string
+			string shaderSource = LoadShaderSource (sourceFile);
+
+			CreateFragmentShaderFromSource (shaderSource);				
+
+		}
+
+		// Load the source code of a GLSL program from the content
+		private string LoadShaderSource (string name)
+		{
+
+			StreamReader streamReader = new StreamReader (name);
+			string text = streamReader.ReadToEnd ();
+			streamReader.Close ();
+
+			return text;
+
+		}
+	}
+}
+

Some files were not shown because too many files changed in this diff