diff --git a/Jumpy.Shared/Camera.cs b/Jumpy.Shared/Camera.cs index 8ce1a7c..48fa65d 100644 --- a/Jumpy.Shared/Camera.cs +++ b/Jumpy.Shared/Camera.cs @@ -1,10 +1,24 @@ -using System; -using System.Collections.Generic; -using System.Text; +using Microsoft.Xna.Framework; +using System; namespace Jumpy { class Camera { - public const int Width = 1920 / 6; - public const int Height = 1080 / 6; + private Rectangle bbox = new Rectangle(0, 0, 1920 / 6, 1080 / 6); + + public int Width { get => bbox.Width; } + public int Height { get => bbox.Height; } + public int Left { get => bbox.Left; } + + public void Update(GameTime time, Point player) { + int diff = player.X - bbox.Center.X; + // TODO: use the actual center of the player's bbox. + if (Math.Abs(diff) > 16) { + bbox.Offset((int) (diff * 0.1), 0); + } + if (bbox.Left < 0) { + bbox.Offset(-bbox.Left, 0); + } + Debug.Toast($"p: {player.X} c: {bbox.Center.X}"); + } } } diff --git a/Jumpy.Shared/Debug.cs b/Jumpy.Shared/Debug.cs index 1cce112..5710d6f 100644 --- a/Jumpy.Shared/Debug.cs +++ b/Jumpy.Shared/Debug.cs @@ -18,6 +18,11 @@ namespace Jumpy { public static bool Enabled; static List rects = new List(); static Texture2D whiteTexture; + static string toast = null; + + public static void Toast(string s) { + toast = s; + } public static void WriteLine(string s) { System.Diagnostics.Debug.WriteLine(s); @@ -40,12 +45,22 @@ namespace Jumpy { rects.Add(new DebugRect(rect, color)); } - public static void Draw(SpriteBatch spriteBatch) { + public static void DrawToast(SpriteBatch spriteBatch, SpriteFont font) { + // TODO: this use of toast isn't thread-safe. + if (toast == null) { + return; + } + spriteBatch.DrawString(font, toast, new Vector2(10, 10), Color.YellowGreen); + toast = null; + } + + public static void Draw(SpriteBatch spriteBatch, Camera camera) { if (!Enabled) { return; } foreach (var debugRect in rects) { var rect = debugRect.rect; + rect.Offset(-camera.Left, 0); var color = debugRect.color; // top side spriteBatch.Draw( diff --git a/Jumpy.Shared/JumpyGame.cs b/Jumpy.Shared/JumpyGame.cs index d1ce09c..3b8fb4f 100644 --- a/Jumpy.Shared/JumpyGame.cs +++ b/Jumpy.Shared/JumpyGame.cs @@ -29,6 +29,7 @@ namespace Jumpy { Player player; World world; + Camera camera = new Camera(); public JumpyGame() { graphics = new GraphicsDeviceManager(this); @@ -46,7 +47,7 @@ namespace Jumpy { for (int i = 0; i < renderTargets.Length; i++) { renderTargets[i] = new RenderTarget2D( - GraphicsDevice, Camera.Width, Camera.Height, false /* mipmap */, + GraphicsDevice, camera.Width, camera.Height, false /* mipmap */, GraphicsDevice.PresentationParameters.BackBufferFormat, DepthFormat.Depth24); } @@ -95,6 +96,8 @@ namespace Jumpy { List collisionTargets = world.CollisionTargets(); player.Update(gameTime, gamePad, collisionTargets); + camera.Update(gameTime, player.Position); + base.Update(gameTime); } @@ -109,23 +112,25 @@ namespace Jumpy { renderTargetIdx = (renderTargetIdx + 1) % renderTargets.Length; GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.Clear(Color.CornflowerBlue); - spriteBatch.Begin(); + spriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.LinearWrap, null, null); // Draw background. Rectangle bgSource = new Rectangle( - 0, grasslandBg1.Height - Camera.Height, Camera.Width, Camera.Height); - Rectangle bgTarget = new Rectangle(0, 0, Camera.Width, Camera.Height); + (int) (camera.Left * 0.25), grasslandBg1.Height - camera.Height, camera.Width, camera.Height); + Rectangle bgTarget = new Rectangle(0, 0, camera.Width, camera.Height); spriteBatch.Draw(grasslandBg2, bgTarget, bgSource, Color.White); + bgSource = new Rectangle( + (int) (camera.Left * 0.5), grasslandBg1.Height - camera.Height, camera.Width, camera.Height); spriteBatch.Draw(grasslandBg1, bgTarget, bgSource, Color.White); // Draw player. - player.Draw(gameTime, spriteBatch); + player.Draw(spriteBatch, camera, gameTime); // Draw foreground tiles. - world.Draw(spriteBatch); + world.Draw(spriteBatch, camera); // Draw debug rects. - Debug.Draw(spriteBatch); + Debug.Draw(spriteBatch, camera); // Aaaaand we're done. spriteBatch.End(); @@ -143,9 +148,11 @@ namespace Jumpy { if (Debug.Enabled) { string fpsText = $"{GraphicsDevice.Viewport.Width}x{GraphicsDevice.Viewport.Height}, " + $"{fpsCounter.Fps} FPS"; - spriteBatch.DrawString(font, fpsText, new Vector2(10, 10), Color.White); + spriteBatch.DrawString(font, fpsText, new Vector2(10, 40), Color.YellowGreen); } + Debug.DrawToast(spriteBatch, font); + spriteBatch.End(); base.Draw(gameTime); diff --git a/Jumpy.Shared/Player.cs b/Jumpy.Shared/Player.cs index 182502f..2f7e3ef 100644 --- a/Jumpy.Shared/Player.cs +++ b/Jumpy.Shared/Player.cs @@ -17,7 +17,7 @@ namespace Jumpy { private const int jumpSpeed = 600; private const int gravity = 2400; - private Point position = new Point(Camera.Width / 2, 10); + private Point position = new Point(64, 16); private Facing facing = Facing.Right; private Pose pose = Pose.Standing; private AirState airState = AirState.Ground; @@ -29,6 +29,8 @@ namespace Jumpy { this.texture = texture; } + public Point Position { get { return position; } } + private Rectangle Bbox(Point position) { return new Rectangle(position.X - spriteWidth, position.Y - 7, spriteWidth * 2, 26); } @@ -150,7 +152,8 @@ namespace Jumpy { pose = Pose.Jumping; } - position.X = Math.Min(Math.Max(position.X, 0 + spriteWidth), Camera.Width - spriteWidth); + // TODO: also bound player position by the right edge of the World? + position.X = Math.Max(position.X, 0 + spriteWidth); } private int spritePosition(Pose pose, GameTime time) { @@ -187,14 +190,14 @@ namespace Jumpy { } } - public void Draw(GameTime time, SpriteBatch spriteBatch) { + public void Draw(SpriteBatch spriteBatch, Camera camera, GameTime time) { // TODO: don't create so many "new" things that could be cached / precomputed. int index = spritePosition(pose, time); Rectangle textureSource = new Rectangle(index * spriteSize, 0, spriteSize, spriteSize); Vector2 spriteCenter = new Vector2(spriteSize / 2, spriteSize / 2); SpriteEffects effect = facing == Facing.Right ? SpriteEffects.FlipHorizontally : SpriteEffects.None; - Vector2 drawPos = new Vector2(position.X, position.Y); + Vector2 drawPos = new Vector2(position.X - camera.Left, position.Y); spriteBatch.Draw(texture, drawPos, textureSource, Color.White, 0f, spriteCenter, Vector2.One, effect, 0f); } diff --git a/Jumpy.Shared/World.cs b/Jumpy.Shared/World.cs index 42f4037..2cc9072 100644 --- a/Jumpy.Shared/World.cs +++ b/Jumpy.Shared/World.cs @@ -27,33 +27,34 @@ namespace Jumpy { public Rectangle Position { get { return position; } } public Terrain Terrain { get { return terrain; } } - public void Draw(SpriteBatch spriteBatch) { + public void Draw(SpriteBatch spriteBatch, Camera camera) { int size = World.TileSize; + Vector2 drawPos = new Vector2(position.Left - camera.Left, position.Top); switch (terrain) { case Terrain.Grass: { // TODO: hold these rectangles statically instead of making them anew constantly. Rectangle source = new Rectangle(3 * size, 0 * size, size, size); - spriteBatch.Draw(texture, position, source, Color.White); + spriteBatch.Draw(texture, drawPos, source, Color.White); break; } case Terrain.GrassL: { Rectangle source = new Rectangle(2 * size, 0 * size, size, size); - spriteBatch.Draw(texture, position, source, Color.White); + spriteBatch.Draw(texture, drawPos, source, Color.White); break; } case Terrain.GrassR: { Rectangle source = new Rectangle(4 * size, 0 * size, size, size); - spriteBatch.Draw(texture, position, source, Color.White); + spriteBatch.Draw(texture, drawPos, source, Color.White); break; } case Terrain.Rock: { Rectangle source = new Rectangle(3 * size, 1 * size, size, size); - spriteBatch.Draw(texture, position, source, Color.White); + spriteBatch.Draw(texture, drawPos, source, Color.White); break; } case Terrain.Water: { Rectangle source = new Rectangle(9 * size, 2 * size, size, size); - spriteBatch.Draw(texture, position, source, Color.White); + spriteBatch.Draw(texture, drawPos, source, Color.White); break; } case Terrain.Empty: @@ -74,18 +75,18 @@ namespace Jumpy { public int Height { get; } string[] worldDesc = new string[] { -" ", -" ", -" ", -" <=> ", -" ", -" ", -" <=> <=> ", -" = ", -" ", -" ", -"=============> <===", -"..............~~~~~." }; +" .", +" .", +" .", +" <=> === .", +" .", +" .", +" <=> <=> ======== == .", +" = == .", +" == .", +" .", +"=============> <==================================================================.", +"..............~~~~~................................................................." }; public World(Texture2D texture) { // TODO: better error handling for if the string[] isn't rectangular. @@ -122,10 +123,10 @@ namespace Jumpy { } } - public void Draw(SpriteBatch spriteBatch) { + public void Draw(SpriteBatch spriteBatch, Camera camera) { for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { - tiles[i, j].Draw(spriteBatch); + tiles[i, j].Draw(spriteBatch, camera); } } }