From 1f89b5b29a9e6552da09b4675fcee90a795848e8 Mon Sep 17 00:00:00 2001 From: joncloud Date: Fri, 31 Jan 2020 21:10:25 -0800 Subject: [PATCH] Implemented alert service --- src/Tetrominoes.OpenGL/Program.cs | 2 + src/Tetrominoes/Graphics/AlertComponent.cs | 138 ++++++++++++++++++ src/Tetrominoes/Graphics/IAlertService.cs | 7 + .../Input/EnabledWrapperInputMapper.cs | 3 + src/Tetrominoes/Input/GamePadInputMapper.cs | 2 +- src/Tetrominoes/Input/InputComponent.cs | 9 +- src/Tetrominoes/Input/KeyboardInputMapper.cs | 2 +- .../Options/OptionEditorComponent.cs | 3 + 8 files changed, 160 insertions(+), 6 deletions(-) create mode 100644 src/Tetrominoes/Graphics/AlertComponent.cs create mode 100644 src/Tetrominoes/Graphics/IAlertService.cs diff --git a/src/Tetrominoes.OpenGL/Program.cs b/src/Tetrominoes.OpenGL/Program.cs index 9fad0e7..9608161 100644 --- a/src/Tetrominoes.OpenGL/Program.cs +++ b/src/Tetrominoes.OpenGL/Program.cs @@ -3,6 +3,7 @@ using Microsoft.Xna.Framework.Input; using System; using Tetrominoes.Audio; +using Tetrominoes.Graphics; using Tetrominoes.Input; using Tetrominoes.Options; @@ -58,6 +59,7 @@ protected override void Initialize() OptionEditorComponent.AddTo(this); MenuComponent.AddTo(this); MatchComponent.AddTo(this); + AlertComponent.AddTo(this); base.Initialize(); } diff --git a/src/Tetrominoes/Graphics/AlertComponent.cs b/src/Tetrominoes/Graphics/AlertComponent.cs new file mode 100644 index 0000000..66464c7 --- /dev/null +++ b/src/Tetrominoes/Graphics/AlertComponent.cs @@ -0,0 +1,138 @@ +#nullable disable +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tetrominoes.Graphics +{ + public class AlertComponent : DrawableGameComponent, IAlertService + { + public AlertComponent(Game game) : base(game) + { + Enabled = Visible = false; + } + + public static AlertComponent AddTo(Game game) + { + var component = new AlertComponent(game); + game.Components.Add(component); + game.Services.AddService(component); + return component; + } + + UIFonts _uiFonts; + SpriteBatch _spriteBatch; + protected override void LoadContent() + { + _uiFonts = new UIFonts(FontSize.Small, Game.Content); + _spriteBatch = new SpriteBatch(GraphicsDevice); + + base.LoadContent(); + } + + readonly Queue _messages = new Queue(); + Message _current; + + public override void Update(GameTime gameTime) + { + if (_current == default) + { + if (!_messages.TryDequeue(out _current)) + { + Enabled = Visible = false; + } + } + else + { + if (_current.TryUpdate(gameTime)) + { + _current = default; + } + } + base.Update(gameTime); + } + + public override void Draw(GameTime gameTime) + { + if (_current == default) return; + + var pp = GraphicsDevice.PresentationParameters; + var tx = Matrix.CreateTranslation( + pp.BackBufferWidth, + pp.BackBufferHeight, + 0 + ); + _spriteBatch.Begin(transformMatrix: tx, samplerState: SamplerState.PointClamp); + _current.Draw(_spriteBatch); + _spriteBatch.End(); + + base.Draw(gameTime); + } + + public void Display(string text) + { + _messages.Enqueue( + new Message( + text, + _uiFonts.BoldWeight + ) + ); + Enabled = Visible = true; + } + + class Message + { + readonly string _source; + readonly StringBuilder _stringBuilder; + readonly SpriteFont _font; + int _position; + public Message(string text, SpriteFont font) + { + _source = text ?? throw new ArgumentNullException(nameof(text)); + _font = font ?? throw new ArgumentOutOfRangeException(nameof(font)); + _stringBuilder = new StringBuilder(text.Length); + } + + TimeSpan _timer; + int _target = 50; + public bool TryUpdate(GameTime gameTime) + { + _timer += gameTime.ElapsedGameTime; + while (_timer.TotalMilliseconds > _target) + { + _timer -= TimeSpan.FromMilliseconds(_target); + + if (_position < _source.Length) + { + _stringBuilder.Append(_source[_position]); + _position++; + } + else if (_position == _source.Length) + { + _target = 2000; + _position++; + } + else if (_position > _source.Length) + { + return true; + } + } + + return false; + } + + public void Draw(SpriteBatch batch) + { + var measurement = _font.MeasureString(_stringBuilder); + batch.DrawString( + _font, + _stringBuilder, + -measurement, + Color.Black + ); + } + } + } +} diff --git a/src/Tetrominoes/Graphics/IAlertService.cs b/src/Tetrominoes/Graphics/IAlertService.cs new file mode 100644 index 0000000..d9f736c --- /dev/null +++ b/src/Tetrominoes/Graphics/IAlertService.cs @@ -0,0 +1,7 @@ +namespace Tetrominoes.Graphics +{ + public interface IAlertService + { + void Display(string text); + } +} diff --git a/src/Tetrominoes/Input/EnabledWrapperInputMapper.cs b/src/Tetrominoes/Input/EnabledWrapperInputMapper.cs index b5cce70..d4f0943 100644 --- a/src/Tetrominoes/Input/EnabledWrapperInputMapper.cs +++ b/src/Tetrominoes/Input/EnabledWrapperInputMapper.cs @@ -27,5 +27,8 @@ public InputConnection Update(GameTime gameTime) => _enabled(_options) ? _inner.Update(gameTime) : InputConnection.Disconnected; + + public override string ToString() => + _inner.ToString() ?? ""; } } diff --git a/src/Tetrominoes/Input/GamePadInputMapper.cs b/src/Tetrominoes/Input/GamePadInputMapper.cs index ee1683d..bbfcfc0 100644 --- a/src/Tetrominoes/Input/GamePadInputMapper.cs +++ b/src/Tetrominoes/Input/GamePadInputMapper.cs @@ -61,6 +61,6 @@ public InputConnection GetConnectionState() } public override string ToString() => - $"CONTROLLER {GamePadOptions.PlayerIndex.ToString().ToUpper()}"; + $"Controller {GamePadOptions.PlayerIndex}"; } } diff --git a/src/Tetrominoes/Input/InputComponent.cs b/src/Tetrominoes/Input/InputComponent.cs index 7538822..74cb02c 100644 --- a/src/Tetrominoes/Input/InputComponent.cs +++ b/src/Tetrominoes/Input/InputComponent.cs @@ -2,6 +2,7 @@ using Microsoft.Xna.Framework; using System.Collections.Generic; +using Tetrominoes.Graphics; using Tetrominoes.Options; namespace Tetrominoes.Input @@ -23,12 +24,12 @@ public static InputComponent AddTo(Game game) } IOptionService _options; - //IAlertService _alertService; + IAlertService _alert; readonly List _enabled = new List(); readonly List _disabled = new List(); public override void Initialize() { - //_alertService = Game.Services.GetService(); + _alert = Game.Services.GetService(); _options = Game.Services.GetService(); _enabled.Add( new KeyboardInputMapper(_options) @@ -56,7 +57,7 @@ public override void Update(GameTime gameTime) _enabled.RemoveAt(index); _disabled.Add(mapper); - //_alertService.Display($"{mapper} DISCONNECTED", default); + _alert.Display($"{mapper} DISCONNECTED"); } else { @@ -74,7 +75,7 @@ public override void Update(GameTime gameTime) _disabled.RemoveAt(index); _enabled.Add(mapper); - //_alertService.Display($"{mapper} CONNECTED", default); + _alert.Display($"{mapper} CONNECTED"); } } diff --git a/src/Tetrominoes/Input/KeyboardInputMapper.cs b/src/Tetrominoes/Input/KeyboardInputMapper.cs index 48f20da..c33ff2b 100644 --- a/src/Tetrominoes/Input/KeyboardInputMapper.cs +++ b/src/Tetrominoes/Input/KeyboardInputMapper.cs @@ -50,6 +50,6 @@ public InputConnection GetConnectionState() => InputConnection.Connected; public override string ToString() => - "KEYBOARD"; + "Keyboard"; } } diff --git a/src/Tetrominoes/Options/OptionEditorComponent.cs b/src/Tetrominoes/Options/OptionEditorComponent.cs index fc9661f..f55ab8d 100644 --- a/src/Tetrominoes/Options/OptionEditorComponent.cs +++ b/src/Tetrominoes/Options/OptionEditorComponent.cs @@ -48,6 +48,7 @@ public void Show() IMenuService _menu; IAudioService _audio; IOptionService _options; + IAlertService _alert; GraphicsDeviceManager _manager; public override void Initialize() { @@ -55,6 +56,7 @@ public override void Initialize() _menu = Game.Services.GetService(); _audio = Game.Services.GetService(); _options = Game.Services.GetService(); + _alert = Game.Services.GetService(); _manager = Game.Services.GetService(); base.Initialize(); @@ -576,6 +578,7 @@ void HandleOptionValue(InputState state) Hide(); _menu.Show(); + _alert.Display("Options saved"); } break;