diff --git a/PongFE/Components/PlayAreaComponent.cs b/PongFE/Components/PlayAreaComponent.cs new file mode 100644 index 0000000..a7f66ac --- /dev/null +++ b/PongFE/Components/PlayAreaComponent.cs @@ -0,0 +1,16 @@ +using Encompass; + +namespace PongFE.Components +{ + public struct PlayAreaComponent : IComponent + { + public int Width { get; } + public int Height { get; } + + public PlayAreaComponent(int width, int height) + { + Width = width; + Height = height; + } + } +} diff --git a/PongFE/PongFEGame.cs b/PongFE/PongFEGame.cs index 1a630bc..eb7012f 100644 --- a/PongFE/PongFEGame.cs +++ b/PongFE/PongFEGame.cs @@ -1,7 +1,9 @@ using System.IO; using Encompass; +using IndependentResolutionRendering; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using PongFE.Components; using PongFE.Engines; using PongFE.Enums; using PongFE.Messages; @@ -20,29 +22,42 @@ namespace PongFE SpriteBatch SpriteBatch { get; set; } Texture2D WhitePixel { get; set; } + RenderTarget2D GameRenderTarget { get; set; } DynamicSpriteFont ScoreFont { get; set; } + const int PLAY_AREA_WIDTH = 1280; + const int PLAY_AREA_HEIGHT = 720; + public PongFEGame() { graphics = new GraphicsDeviceManager(this); - graphics.PreferredBackBufferWidth = 1280; - graphics.PreferredBackBufferHeight = 720; + graphics.PreferredBackBufferWidth = 1680; + graphics.PreferredBackBufferHeight = 1050; graphics.PreferMultiSampling = true; Content.RootDirectory = "Content"; - Window.AllowUserResizing = true; + Window.AllowUserResizing = false; IsMouseVisible = true; IsFixedTimeStep = true; } protected override void LoadContent() { + Resolution.Init( + GraphicsDevice.PresentationParameters.BackBufferWidth, + GraphicsDevice.PresentationParameters.BackBufferHeight, + PLAY_AREA_WIDTH, + PLAY_AREA_HEIGHT + ); + SpriteBatch = new SpriteBatch(GraphicsDevice); WhitePixel = new Texture2D(GraphicsDevice, 1, 1); WhitePixel.SetData(new Color[] { Color.White }); + GameRenderTarget = new RenderTarget2D(GraphicsDevice, PLAY_AREA_WIDTH, PLAY_AREA_HEIGHT); + ScoreFont = DynamicSpriteFont.FromTtf( File.ReadAllBytes(@"Content/Fonts/SquaredDisplay.ttf"), 128 @@ -80,7 +95,7 @@ namespace PongFE WorldBuilder.SendMessage( new PaddleSpawnMessage( - new MoonTools.Structs.Position2D(1255, 5), + new MoonTools.Structs.Position2D(PLAY_AREA_WIDTH - 25, 5), Enums.PlayerIndex.Two, PaddleControl.Computer, 20, @@ -90,7 +105,7 @@ namespace PongFE WorldBuilder.SendMessage( new BallSpawnMessage( - new MoonTools.Structs.Position2D(640, 360), + new MoonTools.Structs.Position2D(PLAY_AREA_WIDTH / 2, PLAY_AREA_HEIGHT / 2), 300, 16, 16 @@ -101,7 +116,7 @@ namespace PongFE WorldBuilder.SendMessage( new BoundarySpawnMessage( new MoonTools.Structs.Position2D(0, -6), - 1280, + PLAY_AREA_WIDTH, 6 ) ); @@ -109,8 +124,8 @@ namespace PongFE // bottom boundary WorldBuilder.SendMessage( new BoundarySpawnMessage( - new MoonTools.Structs.Position2D(0, 720), - 1280, + new MoonTools.Structs.Position2D(0, PLAY_AREA_HEIGHT), + PLAY_AREA_WIDTH, 6 ) ); @@ -119,9 +134,9 @@ namespace PongFE WorldBuilder.SendMessage( new GoalBoundarySpawnMessage( Enums.PlayerIndex.One, - new MoonTools.Structs.Position2D(1280, 0), + new MoonTools.Structs.Position2D(PLAY_AREA_WIDTH, 0), 6, - 720 + PLAY_AREA_HEIGHT ) ); @@ -131,10 +146,13 @@ namespace PongFE Enums.PlayerIndex.Two, new MoonTools.Structs.Position2D(-6, 0), 6, - 720 + PLAY_AREA_HEIGHT ) ); + var playAreaEntity = WorldBuilder.CreateEntity(); + WorldBuilder.SetComponent(playAreaEntity, new PlayAreaComponent(PLAY_AREA_WIDTH, PLAY_AREA_HEIGHT)); + World = WorldBuilder.Build(); } @@ -152,12 +170,34 @@ namespace PongFE protected override void Draw(GameTime gameTime) { + GraphicsDevice.SetRenderTarget(GameRenderTarget); GraphicsDevice.Clear(Color.Black); SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied); World.Draw(); SpriteBatch.End(); + GraphicsDevice.SetRenderTarget(null); + GraphicsDevice.Clear(Color.Black); + + SpriteBatch.Begin( + SpriteSortMode.Deferred, + null, + null, + null, + null, + null, + Resolution.TransformMatrix + ); + + SpriteBatch.Draw( + GameRenderTarget, + Vector2.Zero, + Color.White + ); + + SpriteBatch.End(); + base.Draw(gameTime); } } diff --git a/PongFE/Renderers/ScoreRenderer.cs b/PongFE/Renderers/ScoreRenderer.cs index 3ac89e5..f55f40a 100644 --- a/PongFE/Renderers/ScoreRenderer.cs +++ b/PongFE/Renderers/ScoreRenderer.cs @@ -25,6 +25,8 @@ namespace PongFE.Renderers int? playerOneScore = null; int? playerTwoScore = null; + ref readonly var playAreaComponent = ref ReadComponent(); + foreach (ref readonly var entity in ReadEntities()) { ref readonly var scoreComponent = ref GetComponent(entity); @@ -45,7 +47,7 @@ namespace PongFE.Renderers SpriteBatch.DrawString( Font, playerOneScore.Value.ToString(), - new Vector2(640 - SpacingFromCenter, SpacingFromTop), + new Vector2(playAreaComponent.Width / 2 - SpacingFromCenter, SpacingFromTop), Color.White ); } @@ -55,7 +57,7 @@ namespace PongFE.Renderers SpriteBatch.DrawString( Font, playerTwoScore.Value.ToString(), - new Vector2(640 + SpacingFromCenter - (Font.Size / 2), SpacingFromTop), + new Vector2(playAreaComponent.Width / 2 + SpacingFromCenter - (Font.Size / 2), SpacingFromTop), Color.White ); } diff --git a/PongFE/Utility/Resolution.cs b/PongFE/Utility/Resolution.cs new file mode 100644 index 0000000..514b105 --- /dev/null +++ b/PongFE/Utility/Resolution.cs @@ -0,0 +1,69 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace IndependentResolutionRendering +{ + static class Resolution + { + static private int s_virtual_width; + static private int s_virtual_height; + static private int s_screen_width; + static private int s_screen_height; + + static private Matrix s_transform_matrix; + static private bool s_dirtyMatrix = true; + + static public void Init(int screenWidth, int screenHeight, int virtualWidth, int virtualHeight) + { + s_screen_width = screenWidth; + s_screen_height = screenHeight; + s_virtual_width = virtualWidth; + s_virtual_height = virtualHeight; + s_dirtyMatrix = true; + } + + static public Matrix TransformMatrix + { + get + { + if (s_dirtyMatrix) RecreateScaleMatrix(); + return s_transform_matrix; + } + } + + static public void SetScreenResolution(int width, int height) + { + s_screen_width = width; + s_screen_height = height; + s_dirtyMatrix = true; + } + + static public void SetVirtualResolution(int width, int height) + { + s_virtual_width = width; + s_virtual_height = height; + s_dirtyMatrix = true; + } + + static private void RecreateScaleMatrix() + { + var scaleUniform = System.Math.Min( + (float)s_screen_width / s_virtual_width, + (float)s_screen_height / s_virtual_height + ); + + var scaleMatrix = Matrix.CreateScale( + (float)scaleUniform, + (float)scaleUniform, + 1f + ); + + var offX = (s_screen_width - scaleUniform * s_virtual_width) / 2; + var offY = (s_screen_height - scaleUniform * s_virtual_height) / 2; + var translationMatrix = Matrix.CreateTranslation(offX, offY, 0); + + s_transform_matrix = scaleMatrix * translationMatrix; + s_dirtyMatrix = false; + } + } +}