//----------------------------------------------------------------------------- // RacingGameManager.cs // // Microsoft XNA Community Game Platform // Copyright (C) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using System; using System.Collections.Generic; using System.Threading; using RacingGame.GameLogic; using RacingGame.GameScreens; using RacingGame.Graphics; using RacingGame.Helpers; using RacingGame.Landscapes; using RacingGame.Sounds; using Model = RacingGame.Graphics.Model; using Texture = RacingGame.Graphics.Texture; using RacingGame.Properties; using RacingGame.Shaders; using System.Threading.Tasks; namespace RacingGame { /// /// This is the main entry class our game. Handles all game screens, /// which themself handle all the game logic. /// As you can see this class is very simple, which is really cool. /// public class RacingGameManager : BaseGame { /// /// Game screens stack. We can easily add and remove game screens /// and they follow the game logic automatically. Very cool. /// private static Stack gameScreens = new Stack(); /// /// Player for the game, also allows us to control the car and contains /// all the required code for the car physics, chase camera and basic /// player values and the game time because this is the top class /// of many derived classes. Player, car and camera position is set /// when the game starts depending on the selected level. /// private static Player player = new Player(new Vector3(0, 0, 0)); /// /// Car model and selection plate for the car selection screen. /// private static Model carModel = null, carSelectionPlate = null; /// /// Car textures we exchange for our car model. /// private static Texture[] carTextures = null; /// /// The player can select between the 3 cars: 0 (white), 1 (red) and /// 2 (yellow). /// public static int currentCarNumber = 0; /// /// The player can also select a car color, which will be used to /// recolor the car. Looks best for the first car (white). /// public static int currentCarColor;// Color carColor = Color.White; /// /// Helper texture for color selection /// public static Texture colorSelectionTexture = null; /// /// Material for brake tracks on the road. /// private static Material brakeTrackMaterial = null; /// /// Car colors for the car selection screen. /// public static List CarColors = new List( new Color[] { Color.White, Color.Yellow, Color.Blue, Color.Purple, Color.Red, Color.Green, Color.Teal, Color.Gray, Color.Chocolate, Color.MonoGameOrange, Color.SeaGreen, }); /// /// Landscape we are currently using. /// private static Landscape landscape = null; /// /// Level we use for our track and landscape /// public enum Level { Beginner, Advanced, Expert, } /// /// Load level /// /// Set new level public static void LoadLevel(Level setNewLevel) { landscape.ReloadLevel(setNewLevel); } public static event EventHandler LoadEvent; /// /// In menu /// /// Bool public static bool InMenu { get { return gameScreens.Count > 0 && gameScreens.Peek().GetType() != typeof(GameScreen); } } /// /// In game? /// public static bool InGame { get { return gameScreens.Count > 0 && gameScreens.Peek().GetType() == typeof(GameScreen); } } /// /// ShowMouseCursor /// /// Bool public static bool ShowMouseCursor { get { // Only if not in Game, not in splash screen! return gameScreens.Count > 0 && gameScreens.Peek().GetType() != typeof(GameScreen) && gameScreens.Peek().GetType() != typeof(SplashScreen) && gameScreens.Peek().GetType() != typeof(LoadingScreen); } } /// /// In car selection screen /// /// Bool public static bool InCarSelectionScreen { get { return gameScreens.Count > 0 && gameScreens.Peek().GetType() == typeof(CarSelection); } } /// /// Player for the game, also allows us to control the car and contains /// all the required code for the car physics, chase camera and basic /// player values and the game time because this is the top class /// of many derived classes. /// Easy access here with a static property in case we need the player /// somewhere in the game. /// /// Player public static Player Player { get { return player; } } /// /// Car model /// /// Model public static Model CarModel { get { return carModel; } } /// /// Car color /// /// Color public static Color CarColor { get { return CarColors[currentCarColor % CarColors.Count]; } } /// /// Number of car colors /// /// Int public static int NumberOfCarColors { get { return CarColors.Count; } } /// /// Number of car texture types /// /// Int public static int NumberOfCarTextureTypes { get { return carTextures.Length; } } /// /// Car texture /// /// Car number /// Texture public static Texture CarTexture(int carNumber) { return carTextures[carNumber % carTextures.Length]; } /// /// Brake track material /// /// Material public static Material BrakeTrackMaterial { get { return brakeTrackMaterial; } } /// /// Car selection plate /// /// Model public static Model CarSelectionPlate { get { return carSelectionPlate; } } /// /// Landscape we are currently using, used for several things (menu /// background, the game, some other classes outside the landscape class). /// /// Landscape public static Landscape Landscape { get { return landscape; } } /// /// The Task that will load most of the content for this game /// in the background, while the loading screen is shown. /// private static Task loadingTask; public static Task LoadingTask { get { return loadingTask; } set { loadingTask = value; } } public static bool ContentLoaded { get { return loadingTask?.IsCompleted == true; } } /// /// Create Racing game /// public RacingGameManager() : base("RacingGame") { Sound.Initialize(); // Start playing the menu music //Sound.Play(Sound.Sounds.MenuMusic); // Create main menu at our main entry point gameScreens.Push(new MainMenu()); // But start with splash screen, if user clicks or presses Start, // we are back in the main menu. gameScreens.Push(new SplashScreen()); //We want to initially show the loading screen while things start. gameScreens.Push(new LoadingScreen()); } /// /// Create Racing game for unit tests, not used for anything else. /// public RacingGameManager(string unitTestName) : base(unitTestName) { // Don't add game screens here } /// /// Load car stuff /// protected override void Initialize() { base.Initialize(); } /// /// Initializes and loads some content, previously referred to as the /// "car stuff". /// public static void LoadResources() { LoadEvent("Models...", null); // Load models carModel = new Model("Car"); carSelectionPlate = new Model("CarSelectionPlate"); LoadEvent("Landscape...", null); // Load landscape landscape = new Landscape(Level.Beginner); LoadEvent("Textures...", null); // Load textures, first one is grabbed from the imported one through // the car.x model, the other two are loaded seperately. carTextures = new Texture[3]; carTextures[0] = new Texture("RacerCar"); carTextures[1] = new Texture("RacerCar2"); carTextures[2] = new Texture("RacerCar3"); colorSelectionTexture = new Texture("ColorSelection"); brakeTrackMaterial = new Material("Track"); LoadEvent("All systems go!", null); Task.Delay(1000).Wait(); } /// /// Add game screen /// /// Game screen public static void AddGameScreen(IGameScreen gameScreen) { // Play sound for screen click Sound.Play(Sound.Sounds.ScreenClick); // Add the game screen gameScreens.Push(gameScreen); } /// /// Update /// protected override void Update(GameTime gameTime) { // Update game engine base.Update(gameTime); if (gameScreens.Count > 0) { if (gameScreens.Peek().GetType() != typeof(LoadingScreen)) { // Update player and game logic player.Update(); } //Update the game screen gameScreens.Peek().Update(gameTime); } } /// /// Render /// protected override void Render() { // No more game screens? if (gameScreens.Count == 0) { // Before quiting, stop music and play crash sound :) Sound.PlayCrashSound(true); Sound.StopMusic(); // Then quit Exit(); return; } // Handle current screen if (gameScreens.Peek().Render()) { // If this was the options screen and the resolution has changed, // apply the changes if (gameScreens.Peek().GetType() == typeof(Options) && (BaseGame.Width != GameSettings.Default.ResolutionWidth || BaseGame.Height != GameSettings.Default.ResolutionHeight || BaseGame.Fullscreen != GameSettings.Default.Fullscreen)) { BaseGame.ApplyResolutionChange(); } // Play sound for screen back Sound.Play(Sound.Sounds.ScreenBack); gameScreens.Pop(); } } /// /// Post user interface rendering, in case we need it. /// Used for rendering the car selection 3d stuff after the UI. /// protected override void PostUIRender() { // Enable depth buffer again BaseGame.Device.DepthStencilState = DepthStencilState.Default; // Currently in car selection screen? if (gameScreens.Count > 0 && gameScreens.Peek().GetType() == typeof(CarSelection)) ((CarSelection)gameScreens.Peek()).PostUIRender(); // Do menu shader after everything if (BaseGame.UsePostScreenShaders && PostScreenMenu.Started) UI.PostScreenMenuShader.Show(); } } }