// Project: XnaGraphicEngineVs2005, File: BaseGame.cs // Namespace: XnaGraphicEngine.Game, Class: BaseGame // Path: C:\code\XnaBook\XnaGraphicEngine\Game, Author: Abi // Code lines: 728, Size of file: 21,72 KB // Creation date: 26.11.2006 12:22 // Last modified: 27.11.2006 07:11 // Generated with Commenter by abi.exDream.com #region Using directives using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; using System.Text; using XnaGraphicEngine.Graphics; using XnaGraphicEngine.Helpers; #endregion namespace XnaGraphicEngine.Game { /// /// Base game class for all the basic game support. /// Connects all our helper classes together and makes our live easier! /// public class BaseGame : Microsoft.Xna.Framework.Game { #region Constants /// /// Background color /// protected static readonly Color BackgroundColor = Color.Black; /// /// Field of view and near and far plane distances for the /// ProjectionMatrix creation. /// private const float FieldOfView = (float)Math.PI / 2, NearPlane = 1.0f, FarPlane = 500.0f; #endregion #region Variables /// /// Graphics /// protected GraphicsDeviceManager graphics; /// /// Content /// protected static ContentManager content; /// /// Remember graphics device and allow the useage wherever needed via /// the Device property. /// private static GraphicsDevice device; /// /// Resolution of our game. /// protected static int width, height; /// /// Aspect ratio of our current resolution /// private static float aspectRatio = 1.0f; /// /// Render delegate for rendering methods, also used for many other /// methods. /// public delegate void RenderDelegate(); /// /// Matrices for shaders. Used in a similar way than in Rocket Commander, /// but since we don't have a fixed function pipeline here we just use /// these values in the shader. Make sure to set all matrices before /// calling a shader. Inside a shader you have to update the shader /// parameter too, just setting the WorldMatrix alone does not work. /// private static Matrix worldMatrix, viewMatrix, projectionMatrix; /// /// Line manager 2D /// private static LineManager2D lineManager2D = null; /// /// Line manager 3D /// private static LineManager3D lineManager3D = null; /// /// Texture font to render text on the screen. /// private static TextureFont font; #endregion #region Properties #region Calc rectangle helpers /// /// XToRes helper method to convert 1024x640 to the current /// screen resolution. Used to position UI elements. /// /// X in 1024px width resolution /// Int public static int XToRes(int xIn1024px) { return (int)Math.Round(xIn1024px * BaseGame.Width / 1024.0f); } // XToRes(xIn1024px) /// /// YToRes helper method to convert 1024x640 to the current /// screen resolution. Used to position UI elements. /// /// Y in 640px height /// Int public static int YToRes(int yIn640px) { return (int)Math.Round(yIn640px * BaseGame.Height / 640.0f); } // YToRes(yIn768px) /// /// YTo res 768 /// /// Y in 768px /// Int public static int YToRes768(int yIn768px) { return (int)Math.Round(yIn768px * BaseGame.Height / 768.0f); } // YToRes768(yIn768px) /// /// XTo res 1600 /// /// X in 1600px /// Int public static int XToRes1600(int xIn1600px) { return (int)Math.Round(xIn1600px * BaseGame.Width / 1600.0f); } // XToRes1600(xIn1600px) /// /// YTo res 1200 /// /// Y in 1200px /// Int public static int YToRes1200(int yIn1200px) { return (int)Math.Round(yIn1200px * BaseGame.Height / 1200.0f); } // YToRes1200(yIn1200px) /// /// XTo res 1400 /// /// X in 1400px /// Int public static int XToRes1400(int xIn1400px) { return (int)Math.Round(xIn1400px * BaseGame.Width / 1400.0f); } // XToRes1400(xIn1400px) /// /// YTo res 1200 /// /// Y in 1050px /// Int public static int YToRes1050(int yIn1050px) { return (int)Math.Round(yIn1050px * BaseGame.Height / 1050.0f); } // YToRes1050(yIn1050px) /// /// Calc rectangle, helper method to convert from our images (1024) /// to the current resolution. Everything will stay in the 16/9 /// format of the textures. /// /// X /// Y /// Width /// Height /// Rectangle public static Rectangle CalcRectangle( int relX, int relY, int relWidth, int relHeight) { float widthFactor = width / 1024.0f; float heightFactor = height / 640.0f; return new Rectangle( (int)Math.Round(relX * widthFactor), (int)Math.Round(relY * heightFactor), (int)Math.Round(relWidth * widthFactor), (int)Math.Round(relHeight * heightFactor)); } // CalcRectangle(x, y, width) /// /// Calc rectangle with bounce effect, same as CalcRectangle, but sizes /// the resulting rect up and down depending on the bounceEffect value. /// /// Rel x /// Rel y /// Rel width /// Rel height /// Bounce effect /// Rectangle public static Rectangle CalcRectangleWithBounce( int relX, int relY, int relWidth, int relHeight, float bounceEffect) { float widthFactor = width / 1024.0f; float heightFactor = height / 640.0f; float middleX = (relX + relWidth / 2) * widthFactor; float middleY = (relY + relHeight / 2) * heightFactor; float retWidth = relWidth * widthFactor * bounceEffect; float retHeight = relHeight * heightFactor * bounceEffect; return new Rectangle( (int)Math.Round(middleX - retWidth / 2), (int)Math.Round(middleY - retHeight / 2), (int)Math.Round(retWidth), (int)Math.Round(retHeight)); } // CalcRectangleWithBounce(relX, relY, relWidth) /// /// Calc rectangle, same method as CalcRectangle, but keep the 4 to 3 /// ratio for the image. The Rect will take same screen space in /// 16:9 and 4:3 modes. E.g. Buttons should be displayed this way. /// Should be used for 1024px width graphics. /// /// Rel x /// Rel y /// Rel width /// Rel height /// Rectangle public static Rectangle CalcRectangleKeep4To3( int relX, int relY, int relWidth, int relHeight) { float widthFactor = width / 1024.0f; float heightFactor = height / 768.0f; return new Rectangle( (int)Math.Round(relX * widthFactor), (int)Math.Round(relY * heightFactor), (int)Math.Round(relWidth * widthFactor), (int)Math.Round(relHeight * heightFactor)); } // CalcRectangleKeep4To3(relX, relY, relWidth) /// /// Calc rectangle, same method as CalcRectangle, but keep the 4 to 3 /// ratio for the image. The Rect will take same screen space in /// 16:9 and 4:3 modes. E.g. Buttons should be displayed this way. /// Should be used for 1024px width graphics. /// /// Gfx rectangle /// Rectangle public static Rectangle CalcRectangleKeep4To3( Rectangle gfxRect) { float widthFactor = width / 1024.0f; float heightFactor = height / 768.0f; return new Rectangle( (int)Math.Round(gfxRect.X * widthFactor), (int)Math.Round(gfxRect.Y * heightFactor), (int)Math.Round(gfxRect.Width * widthFactor), (int)Math.Round(gfxRect.Height * heightFactor)); } // CalcRectangleKeep4To3(gfxRect) /// /// Calc rectangle for 1600px width graphics. /// /// Rel x /// Rel y /// Rel width /// Rel height /// Rectangle public static Rectangle CalcRectangle1600( int relX, int relY, int relWidth, int relHeight) { float widthFactor = width / 1600.0f; // keep height factor: float heightFactor = height / 1200.0f; float heightFactor = (height / 1200.0f);// / (aspectRatio / (16 / 9)); return new Rectangle( (int)Math.Round(relX * widthFactor), (int)Math.Round(relY * heightFactor), (int)Math.Round(relWidth * widthFactor), (int)Math.Round(relHeight * heightFactor)); } // CalcRectangle1600(relX, relY, relWidth) /// /// Calc rectangle 2000px, just a helper to scale stuff down /// /// Rel x /// Rel y /// Rel width /// Rel height /// Rectangle public static Rectangle CalcRectangle2000( int relX, int relY, int relWidth, int relHeight) { float widthFactor = width / 2000.0f; float heightFactor = (height / 1500.0f); return new Rectangle( (int)Math.Round(relX * widthFactor), (int)Math.Round(relY * heightFactor), (int)Math.Round(relWidth * widthFactor), (int)Math.Round(relHeight * heightFactor)); } // CalcRectangle2000(relX, relY, relWidth) /*unused /// /// Calc rectangle for 1920px width graphics. /// /// Rel x /// Rel y /// Rel width /// Rel height /// Rectangle public static Rectangle CalcRectangle1920( int relX, int relY, int relWidth, int relHeight) { float widthFactor = width / 1920.0f; // keep height factor: float heightFactor = height / 1200.0f; float heightFactor = (height / 1200.0f);// / (aspectRatio / (16 / 9)); return new Rectangle( (int)Math.Round(relX * widthFactor), (int)Math.Round(relY * heightFactor), (int)Math.Round(relWidth * widthFactor), (int)Math.Round(relHeight * heightFactor)); } // CalcRectangle1920(relX, relY, relWidth) */ /// /// Calc rectangle keep 4 to 3 align bottom /// /// Rel x /// Rel y /// Rel width /// Rel height /// Rectangle public static Rectangle CalcRectangleKeep4To3AlignBottom( int relX, int relY, int relWidth, int relHeight) { float widthFactor = width / 1024.0f; float heightFactor16To9 = height / 640.0f; float heightFactor4To3 = height / 768.0f; return new Rectangle( (int)(relX * widthFactor), (int)(relY * heightFactor16To9) - (int)Math.Round(relHeight * heightFactor4To3), (int)Math.Round(relWidth * widthFactor), (int)Math.Round(relHeight * heightFactor4To3)); } // CalcRectangleKeep4To3AlignBottom(relX, relY, relWidth) /// /// Calc rectangle keep 4 to 3 align bottom right /// /// Rel x /// Rel y /// Rel width /// Rel height /// Rectangle public static Rectangle CalcRectangleKeep4To3AlignBottomRight( int relX, int relY, int relWidth, int relHeight) { float widthFactor = width / 1024.0f; float heightFactor16To9 = height / 640.0f; float heightFactor4To3 = height / 768.0f; return new Rectangle( (int)(relX * widthFactor) - (int)Math.Round(relWidth * widthFactor), (int)(relY * heightFactor16To9) - (int)Math.Round(relHeight * heightFactor4To3), (int)Math.Round(relWidth * widthFactor), (int)Math.Round(relHeight * heightFactor4To3)); } // CalcRectangleKeep4To3AlignBottomRight(relX, relY, relWidth) /// /// Calc rectangle centered with given height. /// This one uses relX and relY points as the center for our rect. /// The relHeight is then calculated and we align everything /// with help of gfxRect (determinating the width). /// Very useful for buttons, logos and other centered UI textures. /// /// Rel x /// Rel y /// Rel height /// Gfx rectangle /// Rectangle public static Rectangle CalcRectangleCenteredWithGivenHeight( int relX, int relY, int relHeight, Rectangle gfxRect) { float widthFactor = width / 1024.0f; float heightFactor = height / 640.0f; int rectHeight = (int)Math.Round(relHeight * heightFactor); // Keep aspect ratio int rectWidth = (int)Math.Round( gfxRect.Width * rectHeight / (float)gfxRect.Height); return new Rectangle( Math.Max(0, (int)Math.Round(relX * widthFactor) - rectWidth / 2), Math.Max(0, (int)Math.Round(relY * heightFactor) - rectHeight / 2), rectWidth, rectHeight); } // CalcRectangleCenteredWithGivenHeight(relX, relY, relHeight) #endregion /// /// Graphics device access for the whole the engine. /// /// Graphics device public static GraphicsDevice Device { get { return device; } // get } // Device /// /// Content manager access for the whole the engine. /// /// Content manager public static ContentManager Content { get { return content; } // get } // Content /// /// Width of our backbuffer we render into. /// /// Int public static int Width { get { return width; } // get } // Width /// /// Height of our backbuffer we render into. /// /// Int public static int Height { get { return height; } // get } // Height /// /// Resolution rectangle /// /// Rectangle public static Rectangle ResolutionRect { get { return new Rectangle(0, 0, width, height); } // get } // ResolutionRect /// /// Alpha blending /// /// Bool public static bool AlphaBlending { set { if (value) { device.RenderState.AlphaBlendEnable = true; device.RenderState.SourceBlend = Blend.SourceAlpha; device.RenderState.DestinationBlend = Blend.InverseSourceAlpha; } // if (value) else device.RenderState.AlphaBlendEnable = false; } // set } // AlphaBlending /// /// World matrix /// /// Matrix public static Matrix WorldMatrix { get { return worldMatrix; } // get set { worldMatrix = value; // Update worldViewProj here? } // set } // WorldMatrix /// /// View matrix /// /// Matrix public static Matrix ViewMatrix { get { return viewMatrix; } // get set { // Set view matrix, usually only done in ChaseCamera.Update! viewMatrix = value; // Update camera pos and rotation, used all over the game! invViewMatrix = Matrix.Invert(ViewMatrix); CameraPos = invViewMatrix.Translation; cameraRotation = Vector3.TransformNormal( new Vector3(0, 0, 1), invViewMatrix); } // set } // ViewMatrix /// /// Projection matrix /// /// Matrix public static Matrix ProjectionMatrix { get { return projectionMatrix; } // get set { projectionMatrix = value; // Update worldViewProj here? } // set } // ProjectionMatrix /// /// Camera pos, updated each loop in Update()! /// Public to allow easy access from everywhere, will be called a lot each /// frame, for example Model.Render uses this for distance checks. /// public static Vector3 CameraPos; /// /// Camera rotation, used to compare objects for visibility. /// private static Vector3 cameraRotation = new Vector3(0, 0, 1); /// /// Camera rotation /// /// Vector 3 public static Vector3 CameraRotation { get { return cameraRotation; } // get } // CameraRotation /// /// Remember inverse view matrix. /// private static Matrix invViewMatrix; /// /// Inverse view matrix /// /// Matrix public static Matrix InverseViewMatrix { get { return invViewMatrix;//Matrix.Invert(ViewMatrix); } // get } // InverseViewMatrix /// /// View projection matrix /// /// Matrix public static Matrix ViewProjectionMatrix { get { return ViewMatrix * ProjectionMatrix; } // get } // ViewProjectionMatrix /// /// World view projection matrix /// /// Matrix public static Matrix WorldViewProjectionMatrix { get { return WorldMatrix * ViewMatrix * ProjectionMatrix; } // get } // WorldViewProjectionMatrix public static Vector3 LightDirection { get { // Note: Not really used here yet, only for the Model.Render method! // Note2: Because we have no valid tangent data, the model will // not look right yet, read Chapter 7 on how to fix that. return new Vector3(0, 0, 1); } // get } // LightDirection /// /// Move factor per second /// public static float MoveFactorPerSecond { get { // Not really implemented here. This is just a quick hack. // See later chapters for the full implementation! return 1.0f / FpsCounter.Fps; } // get } // MoveFactorPerSecond #endregion #region Constructor /// /// Create base game /// public BaseGame() { graphics = new GraphicsDeviceManager(this); content = new ContentManager(Services); #if !XBOX360 this.Components.Add(new ScreenshotCapturer(this)); #endif } // BaseGame() /// /// Initialize /// protected override void Initialize() { // Remember device device = graphics.GraphicsDevice; // Remember resolution width = graphics.GraphicsDevice.Viewport.Width; height = graphics.GraphicsDevice.Viewport.Height; // Create matrices for our shaders, this makes it much easier to manage // all the required matrices and we have to do this ourselfs since there // is no fixed function support and theirfore no Device.Transform class. WorldMatrix = Matrix.Identity; aspectRatio = (float)width / (float)height; ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView( FieldOfView, aspectRatio, NearPlane, FarPlane); // ViewMatrix is updated in camera class ViewMatrix = Matrix.CreateLookAt( new Vector3(0, 0, 15), Vector3.Zero, Vector3.Up); // Init global manager classes, which will be used all over the place ^^ lineManager2D = new LineManager2D(); lineManager3D = new LineManager3D(); // Create font font = new TextureFont(); base.Initialize(); } // Initialize() /// /// Graphic content container, just holds a link to every resource we /// create. /// static List graphicContent = new List(); /// /// Register a IGraphicContent object to our internal graphicContent /// container in case we need to recreate the graphic content later. /// /// Graphic object internal static void RegisterGraphicContentObject(IGraphicContent obj) { graphicContent.Add(obj); } // RegisterGraphicContentObject(obj) /// /// Load all graphics content (just our background texture). /// Use this method to make sure a device reset event is handled correctly. /// /// Load everything? protected override void LoadGraphicsContent(bool loadAllContent) { if (loadAllContent) { // Remember device device = graphics.GraphicsDevice; // Recreate all content files foreach (IGraphicContent contentItem in // Create a new temporary list to prevent direct modification new List(graphicContent)) contentItem.Load(); } // if base.LoadGraphicsContent(loadAllContent); } // LoadGraphicsContent(loadAllContent) /// /// Unload graphic content if the device gets lost. /// /// Unload everything? protected override void UnloadGraphicsContent(bool unloadAllContent) { if (unloadAllContent == true) { // Dispose everything, but start with the stuff we create. foreach (IGraphicContent contentItem in graphicContent) contentItem.Dispose(); SpriteHelper.Dispose(); // Make sure there is nothing left content.Unload(); } // if base.UnloadGraphicsContent(unloadAllContent); } // UnloadGraphicsContent(loadAllContent) #endregion #region Update /// /// Update /// /// Game time protected override void Update(GameTime gameTime) { //unused: Sound.Update(); Input.Update(); if (Input.KeyboardEscapeJustPressed || Input.GamePadBackJustPressed) this.Exit(); base.Update(gameTime); } // Update(gameTime) #endregion #region Draw /// /// Draw /// /// Game time protected override void Draw(GameTime gameTime) { // Draw all sprites and fonts SpriteHelper.DrawSprites(width, height); font.WriteAll(); lineManager2D.Render(); lineManager3D.Render(); base.Draw(gameTime); // Allow clearing background next frame clearedYet = false; } // Draw(gameTime) #endregion #region ClearBackground private bool clearedYet = false; /// /// Clear background, will only be executed once per frame, so /// it is save to call it multiple times. /// public void ClearBackground() { if (clearedYet == false) graphics.GraphicsDevice.Clear(BackgroundColor); clearedYet = true; } // ClearBackground() #endregion #region Line helper methods /// /// Draw line /// /// Start point /// End point /// Color public static void DrawLine(Point startPoint, Point endPoint, Color color) { lineManager2D.AddLine(startPoint, endPoint, color); } // DrawLine(startPoint, endPoint, color) /// /// Draw line /// /// Start point /// End point public static void DrawLine(Point startPoint, Point endPoint) { lineManager2D.AddLine(startPoint, endPoint, Color.White); } // DrawLine(startPoint, endPoint) /// /// Draw line /// /// Start position /// End position /// Color public static void DrawLine(Vector3 startPos, Vector3 endPos, Color color) { lineManager3D.AddLine(startPos, endPos, color); } // DrawLine(startPos, endPos, color) /// /// Draw line /// /// Start position /// End position /// Start color /// End color public static void DrawLine(Vector3 startPos, Vector3 endPos, Color startColor, Color endColor) { lineManager3D.AddLine(startPos, startColor, endPos, endColor); } // DrawLine(startPos, endPos, startColor) /// /// Draw line /// /// Start position /// End position public static void DrawLine(Vector3 startPos, Vector3 endPos) { lineManager3D.AddLine(startPos, endPos, Color.White); } // DrawLine(startPos, endPos) /// /// Flush line manager 2D. Renders all lines and allows more lines /// to be rendered. Used to render lines into textures and stuff. /// public static void FlushLineManager2D() { lineManager2D.Render(); } // FlushLineManager2D() /// /// Flush line manager 3D. Renders all lines and allows more lines /// to be rendered. /// public static void FlushLineManager3D() { lineManager3D.Render(); } // FlushLineManager3D() #endregion } // class BaseGame } // namespace XnaGraphicEngine.Game