?? gamemain.cs
字號:
//---------------------------------------------------------------------
// This file is part of the Microsoft .NET Framework SDK Code Samples.
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//This source code is intended only as a supplement to Microsoft
//Development Tools and/or on-line documentation. See these other
//materials for detailed information regarding Microsoft code samples.
//
//THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
//KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//PARTICULAR PURPOSE.
//---------------------------------------------------------------------
using System;
using System.Data;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using System.Diagnostics;
using System.Drawing;
using System.Threading;
using System.Globalization;
using GraphicsLibrary;
using InputLibrary;
using Timer;
namespace GameApp
{
/// <summary>
/// Encapsulates loading and runnig of the game. This class contains the
/// game loop and initialization and is the top-level entry point to the
/// game.
/// </summary>
public class GameMain : IDisposable
{
/// <summary>
/// Minimum seconds that one frame can take i.e., the fastest
/// framerate.
/// </summary>
private const float MinSecondsPerFrame = 1.0F / 50.0F;
/// <summary>
/// Maximum seconds that one frame can take i.e., the slowest
/// framerate.
/// </summary>
private const float MaxSecondsPerFrame = 1.0F / 10.0F;
/// <summary>
/// The initial estimate of the framerate. This value will only be
/// used until enough frames have been rendered that we can make
/// reasonable estimates of the true framerate.
/// </summary>
private const float InitialSecondsPerFrame = 1.0F / 25.0F;
/// <summary>
/// Total length of time to count down after loading level,
/// before level is playable.
/// </summary>
private const float TotalCountDownTime = 3.5F;
/// <summary>
/// Minimum length of time to display the splash screen.
/// </summary>
private const float TotalSplashTime = 2.0F;
/// <summary>
/// Current frame time in seconds. This is provided as a static
/// method accessible throughout the game because the rate can be
/// variable.
/// </summary>
public static float SecondsPerFrame
{ get { return currentSecondsPerFrame; } }
/// <summary>
/// Current frame time in seconds.
/// </summary>
private static float currentSecondsPerFrame =
InitialSecondsPerFrame;
/// <summary>
/// Specifies if the game is done. When done, the game exits.
/// </summary>
private bool done = false;
/// <summary>
/// Graphics instance used by the game.
/// </summary>
private IGraphics graphics = null;
/// <summary>
/// Input instance used by the game.
/// </summary>
private Input gi = null;
/// <summary>
/// Stopwatch used by the game for timing the frames.
/// </summary>
private Timer.Stopwatch sw = null;
/// <summary>
/// Level that is currently loaded in the game.
/// </summary>
private Level level = null;
/// <summary>
/// User interface that is currently loaded in the game.
/// </summary>
private UserInterface ui = null;
/// <summary>
/// Intro data displayed before the current level. This is only valid
/// once loaded and until the level starts.
/// </summary>
private Intro intro = null;
/// <summary>
/// Defines the current update method. This is determined by which
/// state the game is in.
/// </summary>
private UpdateDelegate update = null;
private delegate void UpdateDelegate();
/// <summary>
/// This enum is set by update delegates when the game needs to switch
/// to a different update mode. This is not done from within the
/// update methods because problems can occur when delegate is
/// modified from within a call to that delegate.
/// </summary>
private enum ModeSwitch
{
UpdateCountdown,
UpdateLevel,
UpdateIntro,
None
}
private ModeSwitch mode = ModeSwitch.None;
/// <summary>
/// Splash screen image. This is only valid while the splash
/// screen is displayed at the start of the game.
/// </summary>
private IBitmap splash = null;
/// <summary>
/// Shared instance of the game's random number generator.
/// </summary>
private static Random rnd = null;
/// <summary>
/// Number of frames since the last auto-update check.
/// </summary>
public static Int64 CurrentFrame { get { return numFrames; } }
private static Int64 numFrames = 0;
/// <summary>
/// The number of seconds which have passed for 'numFrames'
/// number of frames to have been rendered
/// </summary>
private float secondsElapsedForCurrentFrames;
/// <summary>
/// Specifies if the intro has finished loading.
/// </summary>
private bool introLoaded = false;
/// <summary>
/// Specifies if the level has finished loading.
/// </summary>
private bool levelLoaded = false;
/// <summary>
/// Total time left to countdown before starting the game.
/// </summary>
private float countDown = TotalCountDownTime;
/// <summary>
/// Rectangle cached for drawing routines to reduce memory
/// allocations.
/// </summary>
Rectangle src = new Rectangle();
/// <summary>
/// Specifies if the countdown to start the level should begin.
/// </summary>
private bool startCountDown = false;
/// <summary>
/// Initializes the game libraries.
/// </summary>
/// <param name="owner">Control (Form) that owns the game</param>
public GameMain(Control owner)
{
// Create a Graphics instance
#if USE_GDI
graphics = new GdiGraphics(owner);
#else
graphics = new DirectXGraphics(owner);
#endif
Debug.Assert(graphics != null,
"GameMain.GameMain: Failed to initialize Graphics object");
// Create a Input instance
gi = new Input(owner);
Debug.Assert(gi != null,
"GameMain.GameMain: Failed to initialize Input object");
// Register the hardware buttons
gi.RegisterAllHardwareKeys();
// Initialize the random number generator
rnd = new Random();
// Create a stopwatch instance for timing the frames
sw = new Timer.Stopwatch();
Debug.Assert(sw != null,
"GameMain.Run: Failed to initialize StopWatch");
}
/// <summary>
/// Get a random float from 0-1.
/// </summary>
/// <returns>Random float from 0-1</returns>
public static float Random()
{
return (float)rnd.NextDouble();
}
/// <summary>
/// Get a random number in the specified range.
/// </summary>
/// <param name="min">Minimum number to return</param>
/// <param name="max">Maximum number to return</param>
/// <returns>Random int in range</returns>
public static int Random(int min, int max)
{
return rnd.Next(min, max);
}
/// <summary>
/// Get the full path to the specified file by prepending it
/// with the directory of the executable.
/// </summary>
/// <param name="fileName">Name of file</param>
/// <returns>Full path of the file</returns>
public static string GetFullPath(string fileName)
{
Debug.Assert(fileName != null && fileName.Length > 0,
"GameMain.GetFullPath: Invalid string");
Assembly asm = Assembly.GetExecutingAssembly();
string str = asm.GetName().CodeBase;
string fullName = Path.GetDirectoryName(str);
// the full name can be a URI (eg file://...) but some of the
// loader functions can't parse that type of path. Hence we get
// a path that starts with a drive letter.
Uri uri = new Uri(Path.Combine(fullName, fileName));
return uri.LocalPath;
}
/// <summary>
/// Reset the current level.
/// </summary>
private void Reset()
{
// Reset the game
level.ResetAll();
// Clear any latent key presses
gi.ClearKeyPresses();
// Do one update of the level so it can be drawn
level.Update(gi);
startCountDown = false;
update = new UpdateDelegate(UpdateCountdown);
countDown = TotalCountDownTime;
numFrames = 0;
secondsElapsedForCurrentFrames = 0;
}
/// <summary>
/// Start the game. This method loads the game resources and
/// runs the main game loop.
/// </summary>
public void Run()
{
// Load and validate the splash screen
splash = graphics.CreateBitmap(GetFullPath(@"Data\Splash\splash.bmp"), false);
Debug.Assert(splash != null,
"GameMain.Run: Failed to initialized splash screen");
Debug.Assert(splash.Width <= graphics.ScreenWidth &&
splash.Height <= graphics.ScreenHeight,
"GameMain.Run: Splash screen has invalid dimensions");
// Load the game ui now because it has font information that is
// needed for drawing the 'Loading...' tag
DataSet dsUI = new DataSet();
Debug.Assert(dsUI != null,
"GameMain.LoadLevel: Failed to initialize UI DataSet");
dsUI.Locale = CultureInfo.InvariantCulture;
// Load the ui xml file
dsUI.ReadXml(GetFullPath(@"Data\UI\ui.xml"));
// Load the resources specified in the xml file
ui = new UserInterface(dsUI, graphics, level);
Debug.Assert(ui != null,
"GameMain.LoadLevel: Failed to initialize UI");
// Set the current update method as the splash screen updater
update = new UpdateDelegate(UpdateSplash);
// Loop until the game is done
while (!done)
{
// Switch the update delegate if a switch was requested.
switch (mode)
{
case ModeSwitch.UpdateLevel:
gi.ClearKeyPresses();
update = new UpdateDelegate(UpdateLevel);
numFrames = 0;
secondsElapsedForCurrentFrames = 0;
break;
case ModeSwitch.UpdateCountdown:
intro.Dispose();
intro = null;
level.Update(gi);
update = new UpdateDelegate(UpdateCountdown);
break;
case ModeSwitch.UpdateIntro:
LoadLevel();
update = new UpdateDelegate(UpdateIntro);
splash.Dispose();
splash = null;
break;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -