diff options
| -rw-r--r-- | DungeonSlime/Game1.cs | 390 |
1 files changed, 125 insertions, 265 deletions
diff --git a/DungeonSlime/Game1.cs b/DungeonSlime/Game1.cs index 387f6b5..abb6559 100644 --- a/DungeonSlime/Game1.cs +++ b/DungeonSlime/Game1.cs @@ -1,4 +1,7 @@ using System; +using System.Collections.Generic; +using System.Net; +using System.Runtime.Serialization; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; @@ -7,338 +10,195 @@ using MonoGameLibrary; namespace DungeonSlime; -internal enum GameState +enum Direction { - MenuState, - WaitingState, - PollingState, - GameOverState + Up, + Down, + Left, + Right } -internal class GameStateMachine +static class DirectionHelper { - private GameState _state; - - public GameStateMachine(GameState startState) - { - if (!IsValidState(startState)) - { - throw new ArgumentOutOfRangeException($"{startState}"); - } - - _state = startState; - } - - public GameState State - { - get => _state; - set - { - if (!IsValidState(value)) - { - throw new ArgumentOutOfRangeException($"{value}"); - } - - if (!IsValidStateTransition(value)) - { - throw new InvalidOperationException($"Cannot go from {State} to {value}!"); - } - - _state = value; - } - } - - private static bool IsValidState(GameState state) - { - return state is - GameState.MenuState or - GameState.WaitingState or - GameState.PollingState or - GameState.GameOverState; - } - - private bool IsValidStateTransition(GameState targetState) - { - return State switch + /// <summary> + /// Returns a normalized vector which indicates where + /// the direction points to in world space + /// </summary> + /// <param name="direction">The direction</param> + public static Vector2 ToNormalVector(Direction direction) + { + return direction switch { - GameState.MenuState => targetState == GameState.WaitingState, - GameState.WaitingState => targetState == GameState.PollingState || targetState == GameState.GameOverState, - GameState.PollingState => targetState == GameState.GameOverState, - GameState.GameOverState => targetState == GameState.MenuState || targetState == GameState.WaitingState, - _ => false + Direction.Up => new Vector2(0, -1), + Direction.Down => new Vector2(0, 1), + Direction.Left => new Vector2(-1, 0), + Direction.Right => new Vector2(1, 0), + _ => throw new ArgumentOutOfRangeException($"Invalid direction {direction}") }; } } -internal class MouseInputManager -{ - private MouseState _currentState; - private MouseState _pastState; - public MouseState MouseState { get => _currentState; } +struct Segment { + public Vector2 pastPosition; + public Vector2 targetPosition; - public MouseInputManager(MouseState startMouseState) + public Vector2 GetPosition(float portionTraveled) { - _pastState = _currentState = startMouseState; + return Vector2.Lerp(pastPosition, targetPosition, portionTraveled); } +} - public bool IsMouseClicked - { - get - { - if (_currentState.LeftButton == ButtonState.Pressed && _pastState.LeftButton == ButtonState.Released) - { - return true; - } +class Snake +{ + public static readonly Point SegmentSize = new Point(100, 100); + public Direction Heading { get; set; } + List<Segment> tail = []; + Segment head; - return false; - } - } + float portionTraveled = 0; + Texture2D whitePixel; + public float Speed { get; set; } - public void Update(MouseState mouseState) + public Snake(Point postionOnGrid, Direction heading, Texture2D whitePixel) { - _pastState = _currentState; - _currentState = mouseState; - } -} + this.Heading = heading; -public class Game1 : Core -{ - private const int MinTimeToReactMilis = 50; - private const int MaxTimeToReactMillis = 400; - - private GameStateMachine _stateMachine; - private SpriteFont _arial; - private MouseInputManager _mouseInput; - private Random _random; - private Vector2 WindowCenter - { - get + head = new Segment { - return new Vector2( - Window.ClientBounds.Width, - Window.ClientBounds.Height - ) * 0.5f; - } - } - private Color ClearColor - { - get - { - return _stateMachine.State switch - { - GameState.MenuState => Color.Green, - GameState.WaitingState => Color.CornflowerBlue, - GameState.PollingState => Color.Red, - GameState.GameOverState => Color.Green, - _ => throw new ArgumentOutOfRangeException($"{_stateMachine.State}"), - }; - } - } - - //Gameplay fields - private TimeSpan _timeToReact; - private bool _clickedTooEarly; + pastPosition = (postionOnGrid * SegmentSize).ToVector2() + }; + head.targetPosition = head.pastPosition + GetHeadTargetOffset(); - public Game1() : base("Reaction Test", 1280, 720, false) - { - IsFixedTimeStep = false; //For fastest possible updates - } + tail.Add(new Segment + { + pastPosition = (postionOnGrid * SegmentSize).ToVector2(), + targetPosition = head.pastPosition + }); - protected override void Initialize() - { - base.Initialize(); + this.whitePixel = whitePixel; - _stateMachine = new GameStateMachine(GameState.MenuState); - _mouseInput = new MouseInputManager(Mouse.GetState()); - _random = new Random(); + Speed = 2.0f; } - protected override void LoadContent() + private Vector2 GetHeadTargetOffset() { - _arial = Content.Load<SpriteFont>("Fonts/Ariel"); + return DirectionHelper.ToNormalVector(Heading) * SegmentSize.ToVector2(); } - protected override void Update(GameTime gameTime) + public void Update(float dt) { - base.Update(gameTime); - _mouseInput.Update(Mouse.GetState()); + portionTraveled += Speed * dt; - switch (_stateMachine.State) + //Keep leftover for consistent movment + if (portionTraveled >= 1f) { - case GameState.MenuState: - UpdateMenu(); - break; - case GameState.WaitingState: - UpdateWaiting(gameTime); - break; - case GameState.GameOverState: - UpdateGameOver(); - break; - case GameState.PollingState: - UpdatePolling(gameTime); - break; - } - } + portionTraveled -= 1f; - protected override void Draw(GameTime gameTime) - { - GraphicsDevice.Clear(ClearColor); + //Snap all segments in tail to next grid position + if (tail.Count > 0) + { + for (int i = tail.Count - 1; i > 0; i--) + { + tail[i] = tail[i-1]; + } - switch (_stateMachine.State) - { - case GameState.MenuState: - DrawMenu(); - break; - case GameState.WaitingState: - DrawWaiting(); - break; - case GameState.GameOverState: - DrawGameOver(); - break; - } + Segment tailSegment = tail[0]; - base.Draw(gameTime); - } + tailSegment.pastPosition = head.pastPosition; + tailSegment.targetPosition = head.targetPosition; - private void StartPlaying() - { - _stateMachine.State = GameState.WaitingState; - _timeToReact = TimeSpan.FromMilliseconds( - MinTimeToReactMilis + _random.Next() % (MaxTimeToReactMillis - MinTimeToReactMilis + 1) - ); - _clickedTooEarly = false; - } + tail[0] = tailSegment; + } - private void UpdateMenu() - { - if (_mouseInput.IsMouseClicked) - { - StartPlaying(); + //Snap head to next grid position + head.pastPosition = head.targetPosition; + head.targetPosition = head.pastPosition + GetHeadTargetOffset(); } } - private void DrawMenu() + public void DrawSegment(Segment s, SpriteBatch spriteBatch) { - SpriteBatch.Begin(); - - //Draw the menu header - string header = "Welcome to the reaction time test!"; - SpriteBatch.DrawString( - _arial, - header, - WindowCenter, - Color.White, - 0f, - _arial.MeasureString(header) * 0.5f, - 1.5f, - SpriteEffects.None, - 0f + spriteBatch.Draw( + whitePixel, + new Rectangle( + s.GetPosition(portionTraveled).ToPoint(), + SegmentSize + ), + Color.White ); + } - //Draw the menu subheader - string subheader = "Click to play!"; - SpriteBatch.DrawString( - _arial, - subheader, - new Vector2( - Window.ClientBounds.Width * 0.5f, - Window.ClientBounds.Height * 0.6f + public void Draw(SpriteBatch spriteBatch) + { + spriteBatch.Draw( + whitePixel, + new Rectangle( + head.GetPosition(portionTraveled).ToPoint(), + SegmentSize ), - Color.White, - 0f, - _arial.MeasureString(subheader) * 0.5f, - 0.75f, - SpriteEffects.None, - 0f + Color.Red ); - SpriteBatch.End(); + foreach (var i in tail) + { + + } } +} - private void ClickedTooEarly() - { - _clickedTooEarly = true; - _stateMachine.State = GameState.GameOverState; - } +public class Game1 : Core +{ + Texture2D whitePixel; + Snake snake; - private void StartPolling() + public Game1() : base("Reaction Test", 1280, 720, false) { - _stateMachine.State = GameState.PollingState; - _timeToReact = TimeSpan.Zero; + } - private void UpdateWaiting(GameTime gameTime) + protected override void Initialize() { - _timeToReact -= gameTime.ElapsedGameTime; + base.Initialize(); - if (_timeToReact.CompareTo(TimeSpan.Zero) <= 0) - { - StartPolling(); - return; - } + whitePixel = new Texture2D(GraphicsDevice, 1, 1); + whitePixel.SetData<Color>([Color.White]); - if (_mouseInput.IsMouseClicked) - { - ClickedTooEarly(); - } + snake = new Snake(new Point(2, 2), Direction.Right, whitePixel); } - private void DrawWaiting() + protected override void LoadContent() { - SpriteBatch.Begin(); - - string message = "Click when the background turns red!"; - SpriteBatch.DrawString( - _arial, - message, - WindowCenter, - Color.White, - 0f, - _arial.MeasureString(message) * 0.5f, - 1f, - SpriteEffects.None, - 0f - ); - - SpriteBatch.End(); } - private void UpdatePolling(GameTime gameTime) + protected override void Update(GameTime gameTime) { - _timeToReact += gameTime.ElapsedGameTime; + base.Update(gameTime); - if (_mouseInput.IsMouseClicked) + if (Keyboard.GetState().IsKeyDown(Keys.Down)) { - _stateMachine.State = GameState.GameOverState; - } - } - - private void UpdateGameOver() - { - if (_mouseInput.IsMouseClicked) + snake.Heading = Direction.Down; + } else if (Keyboard.GetState().IsKeyDown(Keys.Up)) { - _stateMachine.State = GameState.MenuState; + snake.Heading = Direction.Up; + } else if (Keyboard.GetState().IsKeyDown(Keys.Left)) + { + snake.Heading = Direction.Left; + } else if (Keyboard.GetState().IsKeyDown(Keys.Right)) + { + snake.Heading = Direction.Right; } + + snake.Update((float)gameTime.ElapsedGameTime.TotalSeconds); } - private void DrawGameOver() + protected override void Draw(GameTime gameTime) { - string header = _clickedTooEarly ? "Too Early!" : $"You reacted in {Math.Round(_timeToReact.TotalMilliseconds)}ms!"; + GraphicsDevice.Clear(Color.CornflowerBlue); SpriteBatch.Begin(); - - SpriteBatch.DrawString( - _arial, - header, - WindowCenter, - Color.White, - 0f, - _arial.MeasureString(header) * 0.5f, - 1f, - SpriteEffects.None, - 0f - ); - + snake.Draw(SpriteBatch); SpriteBatch.End(); + + base.Draw(gameTime); } } |
