From 0ba801ccff6abc7b99f560103c44a2045c8c5909 Mon Sep 17 00:00:00 2001 From: jme9 Date: Tue, 18 Mar 2025 09:37:01 -0700 Subject: [PATCH] Implemented RenderHandler class with zoom. This zoom is pretty garbage but on the right track I think. --- LunaLightGame.cs | 102 +++++++++++-------------- RenderHandler.cs | 96 +++++++++++++++++++++++ UpdateNotes/{Camera.md => Camera2D.md} | 0 UpdateNotes/RenderHandler.md | 20 +++++ 4 files changed, 162 insertions(+), 56 deletions(-) create mode 100644 RenderHandler.cs rename UpdateNotes/{Camera.md => Camera2D.md} (100%) create mode 100644 UpdateNotes/RenderHandler.md diff --git a/LunaLightGame.cs b/LunaLightGame.cs index ac32ec4..0751c79 100644 --- a/LunaLightGame.cs +++ b/LunaLightGame.cs @@ -24,9 +24,8 @@ namespace LunaLightXMG private int retroWidth = 320; private int retroHeight = 180; - // Test Render Target - private RenderTarget2D renderTarget; - private Rectangle renderDestination; + // Test Render Target Handler + private RenderHandler renderHandler; bool resizing; // Test sprites - eventually handle in a sprite manager? @@ -59,7 +58,7 @@ namespace LunaLightXMG IsMouseVisible = true; // Test player input and movement with abstracted player class - Vector2 initPlayerPosition = new Vector2(163, 0); + Vector2 initPlayerPosition = new Vector2(163, 0); player = new Player(initPlayerPosition); playerInput = new PlayerInput(); enemies = new List(); @@ -85,9 +84,9 @@ namespace LunaLightXMG // Initialize camera camera2D = new Camera2D(retroWidth, retroHeight); // camera test - set level bounds - camera2D.SetLevelBounds(new Rectangle(0,0,480,270)); // default 320x180 + camera2D.SetLevelBounds(new Rectangle(0,0,480,270)); // Testing - default 320x180 - CalculateRenderDestination(); + renderHandler.CalculateRenderDestination(); // Play music // PlayBackgroundMusic(sinkBeats); @@ -95,14 +94,17 @@ namespace LunaLightXMG platforms = PlatformGenerator.CreatePlatforms(numOfPlatforms); } - // Testing camera ------------------------ + // Testing camera and render target handler ------------------------ private void TestCameraWhilePlaying() { KeyboardState keyboardState = Keyboard.GetState(); - var KeyI = keyboardState.IsKeyDown(Keys.I) ? true : false; - var KeyO = keyboardState.IsKeyDown(Keys.O) ? true : false; - var KeyK = keyboardState.IsKeyDown(Keys.K) ? true : false; - var KeyL = keyboardState.IsKeyDown(Keys.L) ? true : false; + var KeyI = keyboardState.IsKeyDown(Keys.I); + var KeyO = keyboardState.IsKeyDown(Keys.O); + var KeyK = keyboardState.IsKeyDown(Keys.K); + var KeyL = keyboardState.IsKeyDown(Keys.L); + var KeyB = keyboardState.IsKeyDown(Keys.B); + var KeyN = keyboardState.IsKeyDown(Keys.N); + var KeyM = keyboardState.IsKeyDown(Keys.M); if (KeyI) { @@ -120,6 +122,18 @@ namespace LunaLightXMG { camera2D.Rotation += 0.01f; } + if (KeyB) + { + renderHandler.ZoomIn(); + } + if (KeyN) + { + renderHandler.ZoomNormalize(); + } + if (KeyM) + { + renderHandler.ZoomOut(); + } } // --------------------------------------- protected override void LoadContent() @@ -137,8 +151,8 @@ namespace LunaLightXMG // Spawn 10 enemies at the start of the level enemies = SpawnEnemies(numOfEnemies); - // Test Render Target - renderTarget = new RenderTarget2D(GraphicsDevice, retroWidth, retroHeight); + // Test Render Target Handler + renderHandler = new RenderHandler(GraphicsDevice, spriteBatch, retroWidth, retroHeight); // Debugging debugFont = Content.Load("fonts/debugFont"); @@ -161,7 +175,8 @@ namespace LunaLightXMG foreach (var enemy in enemies) { enemy.Update(gameTime, player, platforms); } - + // test render handler zoom + renderHandler.UpdateZoom(); // Update camera position camera2D.Follow(player.position); // camera testing @@ -174,18 +189,8 @@ namespace LunaLightXMG { GraphicsDevice.Clear(Color.CornflowerBlue); - // Test Render Target - Draw sprites to the render target - GraphicsDevice.SetRenderTarget(renderTarget); - - // Add camera to draw batch - spriteBatch.Begin( - transformMatrix: camera2D.GetViewMatrix(), - samplerState: SamplerState.PointClamp - ); - - // Debug Grid - // spriteBatch.Draw(debugGrid, new Vector2(0, 0), Color.Blue); - // spriteBatch.Draw(sinkArea, new Vector2(0, 0), Color.White); + // // Test Render Target Handler - Draw sprites to the render (target + renderHandler.BeginRenderTarget(camera2D.GetViewMatrix()); // Test draw tiles foreach (var platform in platforms) @@ -200,15 +205,9 @@ namespace LunaLightXMG { enemy.Draw(spriteBatch); } - - spriteBatch.End(); - - - // Test Render Target - Draw render target to the screen - GraphicsDevice.SetRenderTarget(null); - spriteBatch.Begin(samplerState: SamplerState.PointClamp); - spriteBatch.Draw(renderTarget, renderDestination, Color.White); - spriteBatch.End(); + + renderHandler.EndRenderTarget(); + renderHandler.DrawRenderTarget(); // Debugging DrawDebugInfo(); @@ -249,30 +248,10 @@ namespace LunaLightXMG if (!resizing && Window.ClientBounds.Width > 0 && Window.ClientBounds.Height > 0) { resizing = true; - CalculateRenderDestination(); + renderHandler.CalculateRenderDestination(); resizing = false; } } - - private void CalculateRenderDestination() - { - Point size = GraphicsDevice.Viewport.Bounds.Size; - - // Calculate the integer scale factor - int scaleX = size.X / renderTarget.Width; - int scaleY = size.Y / renderTarget.Height; - int scale = Math.Min(scaleX, scaleY); - - // Ensure the scale is at least 1 - scale = Math.Max(scale, 1); - - // Set renderDestination - renderDestination.Width = (int)(renderTarget.Width * scale); - renderDestination.Height = (int)(renderTarget.Height * scale); - - renderDestination.X = (size.X - renderDestination.Width) / 2; - renderDestination.Y = (size.Y - renderDestination.Height) / 2; - } private void DrawDebugInfo() { @@ -286,6 +265,13 @@ namespace LunaLightXMG spriteBatch.DrawString(debugFont, $"Camera Position: {camera2D.Position}", new Vector2(10, 90), Color.White); spriteBatch.DrawString(debugFont, $"Camera Zoom: {camera2D.Zoom}", new Vector2(10, 110), Color.White); spriteBatch.DrawString(debugFont, $"Camera Rotation: {camera2D.Rotation}", new Vector2(10, 130), Color.White); + spriteBatch.DrawString(debugFont, $"Render Target Zoom: {renderHandler.ZoomLevel}", new Vector2(10, 150), Color.White); + + + spriteBatch.DrawString(debugFont, $"Camera Zoom Control - Zoom in: I, Zoom out: O", new Vector2(10, 170), Color.White); + spriteBatch.DrawString(debugFont, $"Camera Rotation Control - Rotate left: K, Rotate right: L", new Vector2(10, 190), Color.White); + + spriteBatch.DrawString(debugFont, $"Render Target Zoom Control - Zoom in: B, Zoom normal: N, Zoom out: M", new Vector2(10, 210), Color.White); spriteBatch.End(); } @@ -296,6 +282,10 @@ namespace LunaLightXMG } private void ResetGame() { + // reset cam + camera2D.Rotation = 0; + camera2D.Zoom = 1f; + // Reset player position player.Reset(new Vector2(163, 0)); diff --git a/RenderHandler.cs b/RenderHandler.cs new file mode 100644 index 0000000..0a0026d --- /dev/null +++ b/RenderHandler.cs @@ -0,0 +1,96 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace LunaLightXMG +{ + public class RenderHandler + { + // fields + private GraphicsDevice graphicsDevice; + private SpriteBatch spriteBatch; + private RenderTarget2D renderTarget; + private Rectangle renderDestination; + + private int retroWidth; + private int retroHeight; + private float zoomLevel = 1.0f; + private float zoomTarget = 1.0f; + private readonly float zoomMin = 0.75f; + private readonly float zoomNorm = 1.0f; + private readonly float zoomMax = 1.25f; + private readonly float zoomSpeed = 0.1f; + public float ZoomLevel {get => zoomLevel;} + + // constructor + public RenderHandler(GraphicsDevice graphicsDevice, SpriteBatch spriteBatch, int retroWidth, int retroHeight) + { + this.graphicsDevice = graphicsDevice; + this.spriteBatch = spriteBatch; + this.retroWidth = retroWidth; + this.retroHeight = retroHeight; + + renderTarget = new RenderTarget2D(graphicsDevice, retroWidth, retroHeight); + + CalculateRenderDestination(); + } + + public void ZoomIn() + { + zoomTarget = zoomMin; + } + + public void ZoomNormalize() + { + zoomTarget = zoomNorm; + } + + public void ZoomOut() + { + zoomTarget = zoomMax; + } + + public void UpdateZoom() + { + zoomLevel = MathHelper.Lerp(zoomLevel, zoomTarget, zoomSpeed); + zoomLevel = MathHelper.Clamp(zoomLevel, zoomMin, zoomMax); + CalculateRenderDestination(); + } + + public void CalculateRenderDestination() + { + Point screenSize = graphicsDevice.Viewport.Bounds.Size; + // Calculate the integer scale factor + int scaleX = screenSize.X / (int)(retroWidth * zoomLevel); + int scaleY = screenSize.Y / (int)(retroHeight * zoomLevel); + + // Set renderDestination + renderDestination.Width = retroWidth * scaleX; + renderDestination.Height = retroHeight * scaleY; + renderDestination.X = (screenSize.X - renderDestination.Width) / 2; + renderDestination.Y = (screenSize.Y - renderDestination.Height) / 2; + } + + public void BeginRenderTarget(Matrix cameraMatrix) + { + graphicsDevice.SetRenderTarget(renderTarget); + graphicsDevice.Clear(Color.Black); + + spriteBatch.Begin(transformMatrix: cameraMatrix, samplerState: SamplerState.PointClamp); + } + + public void EndRenderTarget() + { + spriteBatch.End(); + graphicsDevice.SetRenderTarget(null); + } + + public void DrawRenderTarget() + { + spriteBatch.Begin(samplerState: SamplerState.PointClamp); + spriteBatch.Draw(renderTarget, renderDestination, Color.White); + spriteBatch.End(); + } + + } +} \ No newline at end of file diff --git a/UpdateNotes/Camera.md b/UpdateNotes/Camera2D.md similarity index 100% rename from UpdateNotes/Camera.md rename to UpdateNotes/Camera2D.md diff --git a/UpdateNotes/RenderHandler.md b/UpdateNotes/RenderHandler.md new file mode 100644 index 0000000..b1a14ca --- /dev/null +++ b/UpdateNotes/RenderHandler.md @@ -0,0 +1,20 @@ +## March 17th, 2025 - JME + +Abstracting the render target code to its own class will help clean up our main game class as well as create a space for fullscreen effects. The first will be zoom. + +Here's what the render handler can do. + +- Create and manage the Render Target +- Handle scaling and fitting to the screen - CalculateRenderDestination() +- USe a method to apply changes to zoom - use integer increments for pixel perfect scaling +- Encapsulate the render pipeline - sprite batch beginning to end for the render target + +## March 18th, 2025 - JME + +**Render Handler Zoom** + +Trying out zoom using the render target. The render target is set by retroWidth and retroHeight (320x180). + +- ZoomIn() should smoothly zoom to 75% retroWidth x retroHeight, 240x135 + +- ZoomOut() should smoothly zoom to 125% retroWidth x retroHeight, 400x225 \ No newline at end of file