basic scrolling world!

GitOrigin-RevId: 6c08535f1ace172f9f08479ced5e9dc8b0663102
This commit is contained in:
Colin McMillen 2019-12-17 15:37:32 -05:00
parent 873d35dcfb
commit 22db0ee696
5 changed files with 78 additions and 38 deletions

View File

@ -1,10 +1,24 @@
using System; using Microsoft.Xna.Framework;
using System.Collections.Generic; using System;
using System.Text;
namespace Jumpy { namespace Jumpy {
class Camera { class Camera {
public const int Width = 1920 / 6; private Rectangle bbox = new Rectangle(0, 0, 1920 / 6, 1080 / 6);
public const int Height = 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}");
}
} }
} }

View File

@ -18,6 +18,11 @@ namespace Jumpy {
public static bool Enabled; public static bool Enabled;
static List<DebugRect> rects = new List<DebugRect>(); static List<DebugRect> rects = new List<DebugRect>();
static Texture2D whiteTexture; static Texture2D whiteTexture;
static string toast = null;
public static void Toast(string s) {
toast = s;
}
public static void WriteLine(string s) { public static void WriteLine(string s) {
System.Diagnostics.Debug.WriteLine(s); System.Diagnostics.Debug.WriteLine(s);
@ -40,12 +45,22 @@ namespace Jumpy {
rects.Add(new DebugRect(rect, color)); 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) { if (!Enabled) {
return; return;
} }
foreach (var debugRect in rects) { foreach (var debugRect in rects) {
var rect = debugRect.rect; var rect = debugRect.rect;
rect.Offset(-camera.Left, 0);
var color = debugRect.color; var color = debugRect.color;
// top side // top side
spriteBatch.Draw( spriteBatch.Draw(

View File

@ -29,6 +29,7 @@ namespace Jumpy {
Player player; Player player;
World world; World world;
Camera camera = new Camera();
public JumpyGame() { public JumpyGame() {
graphics = new GraphicsDeviceManager(this); graphics = new GraphicsDeviceManager(this);
@ -46,7 +47,7 @@ namespace Jumpy {
for (int i = 0; i < renderTargets.Length; i++) { for (int i = 0; i < renderTargets.Length; i++) {
renderTargets[i] = new RenderTarget2D( renderTargets[i] = new RenderTarget2D(
GraphicsDevice, Camera.Width, Camera.Height, false /* mipmap */, GraphicsDevice, camera.Width, camera.Height, false /* mipmap */,
GraphicsDevice.PresentationParameters.BackBufferFormat, DepthFormat.Depth24); GraphicsDevice.PresentationParameters.BackBufferFormat, DepthFormat.Depth24);
} }
@ -95,6 +96,8 @@ namespace Jumpy {
List<Rectangle> collisionTargets = world.CollisionTargets(); List<Rectangle> collisionTargets = world.CollisionTargets();
player.Update(gameTime, gamePad, collisionTargets); player.Update(gameTime, gamePad, collisionTargets);
camera.Update(gameTime, player.Position);
base.Update(gameTime); base.Update(gameTime);
} }
@ -109,23 +112,25 @@ namespace Jumpy {
renderTargetIdx = (renderTargetIdx + 1) % renderTargets.Length; renderTargetIdx = (renderTargetIdx + 1) % renderTargets.Length;
GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.Clear(Color.CornflowerBlue); GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(); spriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.LinearWrap, null, null);
// Draw background. // Draw background.
Rectangle bgSource = new Rectangle( Rectangle bgSource = new Rectangle(
0, grasslandBg1.Height - Camera.Height, 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); Rectangle bgTarget = new Rectangle(0, 0, camera.Width, camera.Height);
spriteBatch.Draw(grasslandBg2, bgTarget, bgSource, Color.White); 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); spriteBatch.Draw(grasslandBg1, bgTarget, bgSource, Color.White);
// Draw player. // Draw player.
player.Draw(gameTime, spriteBatch); player.Draw(spriteBatch, camera, gameTime);
// Draw foreground tiles. // Draw foreground tiles.
world.Draw(spriteBatch); world.Draw(spriteBatch, camera);
// Draw debug rects. // Draw debug rects.
Debug.Draw(spriteBatch); Debug.Draw(spriteBatch, camera);
// Aaaaand we're done. // Aaaaand we're done.
spriteBatch.End(); spriteBatch.End();
@ -143,9 +148,11 @@ namespace Jumpy {
if (Debug.Enabled) { if (Debug.Enabled) {
string fpsText = $"{GraphicsDevice.Viewport.Width}x{GraphicsDevice.Viewport.Height}, " + string fpsText = $"{GraphicsDevice.Viewport.Width}x{GraphicsDevice.Viewport.Height}, " +
$"{fpsCounter.Fps} FPS"; $"{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(); spriteBatch.End();
base.Draw(gameTime); base.Draw(gameTime);

View File

@ -17,7 +17,7 @@ namespace Jumpy {
private const int jumpSpeed = 600; private const int jumpSpeed = 600;
private const int gravity = 2400; 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 Facing facing = Facing.Right;
private Pose pose = Pose.Standing; private Pose pose = Pose.Standing;
private AirState airState = AirState.Ground; private AirState airState = AirState.Ground;
@ -29,6 +29,8 @@ namespace Jumpy {
this.texture = texture; this.texture = texture;
} }
public Point Position { get { return position; } }
private Rectangle Bbox(Point position) { private Rectangle Bbox(Point position) {
return new Rectangle(position.X - spriteWidth, position.Y - 7, spriteWidth * 2, 26); return new Rectangle(position.X - spriteWidth, position.Y - 7, spriteWidth * 2, 26);
} }
@ -150,7 +152,8 @@ namespace Jumpy {
pose = Pose.Jumping; 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) { 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. // TODO: don't create so many "new" things that could be cached / precomputed.
int index = spritePosition(pose, time); int index = spritePosition(pose, time);
Rectangle textureSource = new Rectangle(index * spriteSize, 0, spriteSize, spriteSize); Rectangle textureSource = new Rectangle(index * spriteSize, 0, spriteSize, spriteSize);
Vector2 spriteCenter = new Vector2(spriteSize / 2, spriteSize / 2); Vector2 spriteCenter = new Vector2(spriteSize / 2, spriteSize / 2);
SpriteEffects effect = facing == Facing.Right ? SpriteEffects effect = facing == Facing.Right ?
SpriteEffects.FlipHorizontally : SpriteEffects.None; 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, spriteBatch.Draw(texture, drawPos, textureSource, Color.White, 0f, spriteCenter,
Vector2.One, effect, 0f); Vector2.One, effect, 0f);
} }

View File

@ -27,33 +27,34 @@ namespace Jumpy {
public Rectangle Position { get { return position; } } public Rectangle Position { get { return position; } }
public Terrain Terrain { get { return terrain; } } public Terrain Terrain { get { return terrain; } }
public void Draw(SpriteBatch spriteBatch) { public void Draw(SpriteBatch spriteBatch, Camera camera) {
int size = World.TileSize; int size = World.TileSize;
Vector2 drawPos = new Vector2(position.Left - camera.Left, position.Top);
switch (terrain) { switch (terrain) {
case Terrain.Grass: { case Terrain.Grass: {
// TODO: hold these rectangles statically instead of making them anew constantly. // TODO: hold these rectangles statically instead of making them anew constantly.
Rectangle source = new Rectangle(3 * size, 0 * size, size, size); 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; break;
} }
case Terrain.GrassL: { case Terrain.GrassL: {
Rectangle source = new Rectangle(2 * size, 0 * size, size, size); 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; break;
} }
case Terrain.GrassR: { case Terrain.GrassR: {
Rectangle source = new Rectangle(4 * size, 0 * size, size, size); 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; break;
} }
case Terrain.Rock: { case Terrain.Rock: {
Rectangle source = new Rectangle(3 * size, 1 * size, size, size); 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; break;
} }
case Terrain.Water: { case Terrain.Water: {
Rectangle source = new Rectangle(9 * size, 2 * size, size, size); 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; break;
} }
case Terrain.Empty: case Terrain.Empty:
@ -74,18 +75,18 @@ namespace Jumpy {
public int Height { get; } public int Height { get; }
string[] worldDesc = new string[] { string[] worldDesc = new string[] {
" ", " .",
" ", " .",
" ", " .",
" <=> ", " <=> === .",
" ", " .",
" ", " .",
" <=> <=> ", " <=> <=> ======== == .",
" = ", " = == .",
" ", " == .",
" ", " .",
"=============> <===", "=============> <==================================================================.",
"..............~~~~~." }; "..............~~~~~................................................................." };
public World(Texture2D texture) { public World(Texture2D texture) {
// TODO: better error handling for if the string[] isn't rectangular. // 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 j = 0; j < height; j++) {
for (int i = 0; i < width; i++) { for (int i = 0; i < width; i++) {
tiles[i, j].Draw(spriteBatch); tiles[i, j].Draw(spriteBatch, camera);
} }
} }
} }