diff --git a/Sledgemapper.Api/Commands/PingCommand.cs b/Sledgemapper.Api/Commands/PingCommand.cs new file mode 100644 index 0000000..ef4db06 --- /dev/null +++ b/Sledgemapper.Api/Commands/PingCommand.cs @@ -0,0 +1,13 @@ +// using Sledgemapper.Shared.Entities; + +// namespace Sledgemapper.Api.Commands +// { +// public class PingCommand : BaseCommand +// { +// public Ping Location { get; private set; } +// public PingCommand(string sessionName, Ping location, int userId) : base(sessionName, userId) +// { +// Location = location; +// } +// } +// } diff --git a/Sledgemapper.Api/Controllers/SessionController.cs b/Sledgemapper.Api/Controllers/SessionController.cs index 2638ac5..4926ba2 100644 --- a/Sledgemapper.Api/Controllers/SessionController.cs +++ b/Sledgemapper.Api/Controllers/SessionController.cs @@ -2,6 +2,7 @@ using MediatR; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Sledgemapper.Api.Commands; +using Sledgemapper.Api.Notifications; using Sledgemapper.Shared.Entities; using System.Threading.Tasks; @@ -30,6 +31,12 @@ namespace Sledgemapper.Api.Controllers return result; } + // [HttpPost("ping")] + // public async Task Post(string sessionName, [FromBody] Ping pingLocation) + // { + // await _mediator.Send(new PingCommand(sessionName, pingLocation, UserId)); + // } + [HttpPost("snapshot")] public async Task Post(string sessionName, [FromBody] Session session) { @@ -60,13 +67,13 @@ namespace Sledgemapper.Api.Controllers await _mediator.Send(new NewNoteCommand(sessionName, note, UserId)); } - [HttpPost("room")] + [HttpPost("room")] public async Task Post(string sessionName, [FromBody] Room room) { await _mediator.Send(new NewRoomCommand(sessionName, room, UserId)); } - [HttpPost("line")] + [HttpPost("line")] public async Task Post(string sessionName, [FromBody] Line line) { await _mediator.Send(new NewLineCommand(sessionName, line, UserId)); diff --git a/Sledgemapper.Api/Handlers/NewTileCommandHandler.cs b/Sledgemapper.Api/Handlers/NewTileCommandHandler.cs index 3169384..6b0a55c 100644 --- a/Sledgemapper.Api/Handlers/NewTileCommandHandler.cs +++ b/Sledgemapper.Api/Handlers/NewTileCommandHandler.cs @@ -35,7 +35,5 @@ namespace Sledgemapper.Api.Commands await _mediator.Publish(new NewTileNotification(session, notification.Tile, notification.UserId)); return true; } - - } } diff --git a/Sledgemapper.Api/Handlers/PingCommandHandler.cs b/Sledgemapper.Api/Handlers/PingCommandHandler.cs new file mode 100644 index 0000000..efc9325 --- /dev/null +++ b/Sledgemapper.Api/Handlers/PingCommandHandler.cs @@ -0,0 +1,28 @@ +// using MediatR; +// using Sledgemapper.Api.Data; +// using System.Threading; +// using System.Threading.Tasks; +// using Sledgemapper.Api.Notifications; +// using System.Linq; + +// namespace Sledgemapper.Api.Commands +// { +// public class PingCommandHandler : IRequestHandler +// { +// private readonly MyDbContext _dbcontext; +// private readonly IMediator _mediator; + +// public PingCommandHandler(IMediator mediator, MyDbContext dbcontext) { _dbcontext = dbcontext; _mediator = mediator; } + +// public async Task Handle(PingCommand notification, CancellationToken cancellationToken) +// { +// var session = _dbcontext.Sessions.First(m => m.SessionName == notification.SessionName); + + +// await _mediator.Publish(new PingNotification(session, notification.Location, notification.UserId)); +// return true; +// } + + +// } +// } diff --git a/Sledgemapper.Api/Handlers/SendPingMessage.cs b/Sledgemapper.Api/Handlers/SendPingMessage.cs new file mode 100644 index 0000000..9b7f0d9 --- /dev/null +++ b/Sledgemapper.Api/Handlers/SendPingMessage.cs @@ -0,0 +1,23 @@ +// using MediatR; +// using Microsoft.AspNetCore.SignalR; +// using Sledgemapper.Api.Notifications; +// using Sledgemapper.Clients; +// using System.Threading; +// using System.Threading.Tasks; +// using Sledgemapper.Api.Hubs; + +// namespace Sledgemapper.Api.Handlers +// { +// public class SendPingMessage : INotificationHandler +// { +// private readonly IHubContext _hub; + +// public SendPingMessage(IHubContext hub) => _hub = hub; + +// public async Task Handle(PingNotification notification, CancellationToken cancellationToken) +// { + +// await _hub.Clients.Groups(notification.Session.SessionName).Ping(notification.Location, notification.UserId); +// } +// } +// } diff --git a/Sledgemapper.Api/Hubs/SledgemapperHub.cs b/Sledgemapper.Api/Hubs/SledgemapperHub.cs index c356461..235af86 100644 --- a/Sledgemapper.Api/Hubs/SledgemapperHub.cs +++ b/Sledgemapper.Api/Hubs/SledgemapperHub.cs @@ -51,7 +51,7 @@ namespace Sledgemapper.Api.Hubs await Clients.Group(sessionName).NewRoom(room); } - public async Task NewLine(string sessionName, Line line) + public async Task NewLine(string sessionName, Line line) { await Clients.Group(sessionName).NewLine(line); } @@ -86,6 +86,15 @@ namespace Sledgemapper.Api.Hubs await Clients.Group(sessionName).DeleteOverlay(tile); } + public async Task Ping(string sessionName, Tile location) + { + var userId = int.Parse(Context.User.Identity.Name); + var user = _datacontext.Users.First(u => u.Id == userId); + + var player = new Player { UserId = userId, Initials = user.Initials, Position = new Tile { X = 0, Y = 0 }, Color = UserColors[userId] }; + await Clients.Group(sessionName).Ping(new Ping{X=location.X, Y=location.Y, Player=player}); + } + public async Task JoinSession(string sessionName) { var session = _dbContext.Sessions.FirstOrDefault(s => s.SessionName == sessionName); diff --git a/Sledgemapper.Api/Notifications/PingNotification.cs b/Sledgemapper.Api/Notifications/PingNotification.cs new file mode 100644 index 0000000..e14c965 --- /dev/null +++ b/Sledgemapper.Api/Notifications/PingNotification.cs @@ -0,0 +1,14 @@ +// using Sledgemapper.Shared.Entities; + +// namespace Sledgemapper.Api.Notifications +// { +// public class PingNotification : BaseNotification +// { +// public Ping Location { get; private set; } + +// public PingNotification(Models.Session session, Ping location, int userId) : base(session, userId) +// { +// Location = location; +// } +// } +// } diff --git a/Sledgemapper.Shared/Clients/ISledgemapperClient.cs b/Sledgemapper.Shared/Clients/ISledgemapperClient.cs index a1ec349..4e8bc07 100644 --- a/Sledgemapper.Shared/Clients/ISledgemapperClient.cs +++ b/Sledgemapper.Shared/Clients/ISledgemapperClient.cs @@ -20,5 +20,6 @@ namespace Sledgemapper.Clients Task UpdateMap(Session player); Task RefreshPlayers(); Task NewLine(Line line); + Task Ping(Ping ping); } } diff --git a/Sledgemapper.Shared/Easings.cs b/Sledgemapper.Shared/Easings.cs new file mode 100644 index 0000000..b82cd35 --- /dev/null +++ b/Sledgemapper.Shared/Easings.cs @@ -0,0 +1,450 @@ + +using System; +#if UNITY +using UnityEngine; +using Math = UnityEngine.Mathf; +#endif + +static public class Easings +{ + /// + /// Constant Pi. + /// + private const float PI = (float)(float)Math.PI; + + /// + /// Constant Pi / 2. + /// + private const float HALFPI =(float) (float)Math.PI / 2.0f; + + /// + /// Easing Functions enumeration + /// + public enum Functions + { + Linear, + QuadraticEaseIn, + QuadraticEaseOut, + QuadraticEaseInOut, + CubicEaseIn, + CubicEaseOut, + CubicEaseInOut, + QuarticEaseIn, + QuarticEaseOut, + QuarticEaseInOut, + QuinticEaseIn, + QuinticEaseOut, + QuinticEaseInOut, + SineEaseIn, + SineEaseOut, + SineEaseInOut, + CircularEaseIn, + CircularEaseOut, + CircularEaseInOut, + ExponentialEaseIn, + ExponentialEaseOut, + ExponentialEaseInOut, + ElasticEaseIn, + ElasticEaseOut, + ElasticEaseInOut, + BackEaseIn, + BackEaseOut, + BackEaseInOut, + BounceEaseIn, + BounceEaseOut, + BounceEaseInOut + } + + /// + /// Interpolate using the specified function. + /// + static public float Interpolate(float p, Functions function) + { + switch(function) + { + default: + case Functions.Linear: return Linear(p); + case Functions.QuadraticEaseOut: return QuadraticEaseOut(p); + case Functions.QuadraticEaseIn: return QuadraticEaseIn(p); + case Functions.QuadraticEaseInOut: return QuadraticEaseInOut(p); + case Functions.CubicEaseIn: return CubicEaseIn(p); + case Functions.CubicEaseOut: return CubicEaseOut(p); + case Functions.CubicEaseInOut: return CubicEaseInOut(p); + case Functions.QuarticEaseIn: return QuarticEaseIn(p); + case Functions.QuarticEaseOut: return QuarticEaseOut(p); + case Functions.QuarticEaseInOut: return QuarticEaseInOut(p); + case Functions.QuinticEaseIn: return QuinticEaseIn(p); + case Functions.QuinticEaseOut: return QuinticEaseOut(p); + case Functions.QuinticEaseInOut: return QuinticEaseInOut(p); + case Functions.SineEaseIn: return SineEaseIn(p); + case Functions.SineEaseOut: return SineEaseOut(p); + case Functions.SineEaseInOut: return SineEaseInOut(p); + case Functions.CircularEaseIn: return CircularEaseIn(p); + case Functions.CircularEaseOut: return CircularEaseOut(p); + case Functions.CircularEaseInOut: return CircularEaseInOut(p); + case Functions.ExponentialEaseIn: return ExponentialEaseIn(p); + case Functions.ExponentialEaseOut: return ExponentialEaseOut(p); + case Functions.ExponentialEaseInOut: return ExponentialEaseInOut(p); + case Functions.ElasticEaseIn: return ElasticEaseIn(p); + case Functions.ElasticEaseOut: return ElasticEaseOut(p); + case Functions.ElasticEaseInOut: return ElasticEaseInOut(p); + case Functions.BackEaseIn: return BackEaseIn(p); + case Functions.BackEaseOut: return BackEaseOut(p); + case Functions.BackEaseInOut: return BackEaseInOut(p); + case Functions.BounceEaseIn: return BounceEaseIn(p); + case Functions.BounceEaseOut: return BounceEaseOut(p); + case Functions.BounceEaseInOut: return BounceEaseInOut(p); + } + } + + /// + /// Modeled after the line y = x + /// + static public float Linear(float p) + { + return p; + } + + /// + /// Modeled after the parabola y = x^2 + /// + static public float QuadraticEaseIn(float p) + { + return p * p; + } + + /// + /// Modeled after the parabola y = -x^2 + 2x + /// + static public float QuadraticEaseOut(float p) + { + return -(p * (p - 2)); + } + + /// + /// Modeled after the piecewise quadratic + /// y = (1/2)((2x)^2) ; [0, 0.5) + /// y = -(1/2)((2x-1)*(2x-3) - 1) ; [0.5, 1] + /// + static public float QuadraticEaseInOut(float p) + { + if(p < 0.5f) + { + return 2 * p * p; + } + else + { + return (-2 * p * p) + (4 * p) - 1; + } + } + + /// + /// Modeled after the cubic y = x^3 + /// + static public float CubicEaseIn(float p) + { + return p * p * p; + } + + /// + /// Modeled after the cubic y = (x - 1)^3 + 1 + /// + static public float CubicEaseOut(float p) + { + float f = (p - 1); + return f * f * f + 1; + } + + /// + /// Modeled after the piecewise cubic + /// y = (1/2)((2x)^3) ; [0, 0.5) + /// y = (1/2)((2x-2)^3 + 2) ; [0.5, 1] + /// + static public float CubicEaseInOut(float p) + { + if(p < 0.5f) + { + return 4 * p * p * p; + } + else + { + float f = ((2 * p) - 2); + return 0.5f * f * f * f + 1; + } + } + + /// + /// Modeled after the quartic x^4 + /// + static public float QuarticEaseIn(float p) + { + return p * p * p * p; + } + + /// + /// Modeled after the quartic y = 1 - (x - 1)^4 + /// + static public float QuarticEaseOut(float p) + { + float f = (p - 1); + return f * f * f * (1 - p) + 1; + } + + /// + // Modeled after the piecewise quartic + // y = (1/2)((2x)^4) ; [0, 0.5) + // y = -(1/2)((2x-2)^4 - 2) ; [0.5, 1] + /// + static public float QuarticEaseInOut(float p) + { + if(p < 0.5f) + { + return 8 * p * p * p * p; + } + else + { + float f = (p - 1); + return -8 * f * f * f * f + 1; + } + } + + /// + /// Modeled after the quintic y = x^5 + /// + static public float QuinticEaseIn(float p) + { + return p * p * p * p * p; + } + + /// + /// Modeled after the quintic y = (x - 1)^5 + 1 + /// + static public float QuinticEaseOut(float p) + { + float f = (p - 1); + return f * f * f * f * f + 1; + } + + /// + /// Modeled after the piecewise quintic + /// y = (1/2)((2x)^5) ; [0, 0.5) + /// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1] + /// + static public float QuinticEaseInOut(float p) + { + if(p < 0.5f) + { + return 16 * p * p * p * p * p; + } + else + { + float f = ((2 * p) - 2); + return 0.5f * f * f * f * f * f + 1; + } + } + + /// + /// Modeled after quarter-cycle of sine wave + /// + static public float SineEaseIn(float p) + { + return (float)(float)Math.Sin((p - 1) * HALFPI) + 1; + } + + /// + /// Modeled after quarter-cycle of sine wave (different phase) + /// + static public float SineEaseOut(float p) + { + return (float)(float)Math.Sin(p * HALFPI); + } + + /// + /// Modeled after half sine wave + /// + static public float SineEaseInOut(float p) + { + return 0.5f * (1 - (float)(float)Math.Cos(p * PI)); + } + + /// + /// Modeled after shifted quadrant IV of unit circle + /// + static public float CircularEaseIn(float p) + { + return 1 - (float)Math.Sqrt(1 - (p * p)); + } + + /// + /// Modeled after shifted quadrant II of unit circle + /// + static public float CircularEaseOut(float p) + { + return (float)Math.Sqrt((2 - p) * p); + } + + /// + /// Modeled after the piecewise circular function + /// y = (1/2)(1 - (float)Math.Sqrt(1 - 4x^2)) ; [0, 0.5) + /// y = (1/2)((float)Math.Sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1] + /// + static public float CircularEaseInOut(float p) + { + if(p < 0.5f) + { + return 0.5f * (1 - (float)Math.Sqrt(1 - 4 * (p * p))); + } + else + { + return 0.5f * ((float)Math.Sqrt(-((2 * p) - 3) * ((2 * p) - 1)) + 1); + } + } + + /// + /// Modeled after the exponential function y = 2^(10(x - 1)) + /// + static public float ExponentialEaseIn(float p) + { + return (p == 0.0f) ? p : (float)Math.Pow(2, 10 * (p - 1)); + } + + /// + /// Modeled after the exponential function y = -2^(-10x) + 1 + /// + static public float ExponentialEaseOut(float p) + { + return (p == 1.0f) ? p : 1 - (float)Math.Pow(2, -10 * p); + } + + /// + /// Modeled after the piecewise exponential + /// y = (1/2)2^(10(2x - 1)) ; [0,0.5) + /// y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1] + /// + static public float ExponentialEaseInOut(float p) + { + if(p == 0.0 || p == 1.0) return p; + + if(p < 0.5f) + { + return 0.5f * (float)Math.Pow(2, (20 * p) - 10); + } + else + { + return -0.5f * (float)Math.Pow(2, (-20 * p) + 10) + 1; + } + } + + /// + /// Modeled after the damped sine wave y = sin(13pi/2*x)*(float)Math.Pow(2, 10 * (x - 1)) + /// + static public float ElasticEaseIn(float p) + { + return (float)Math.Sin(13 * HALFPI * p) * (float)Math.Pow(2, 10 * (p - 1)); + } + + /// + /// Modeled after the damped sine wave y = sin(-13pi/2*(x + 1))*(float)Math.Pow(2, -10x) + 1 + /// + static public float ElasticEaseOut(float p) + { + return (float)Math.Sin(-13 * HALFPI * (p + 1)) * (float)Math.Pow(2, -10 * p) + 1; + } + + /// + /// Modeled after the piecewise exponentially-damped sine wave: + /// y = (1/2)*sin(13pi/2*(2*x))*(float)Math.Pow(2, 10 * ((2*x) - 1)) ; [0,0.5) + /// y = (1/2)*(sin(-13pi/2*((2x-1)+1))*(float)Math.Pow(2,-10(2*x-1)) + 2) ; [0.5, 1] + /// + static public float ElasticEaseInOut(float p) + { + if(p < 0.5f) + { + return 0.5f * (float)Math.Sin(13 * HALFPI * (2 * p)) * (float)Math.Pow(2, 10 * ((2 * p) - 1)); + } + else + { + return 0.5f * ((float)Math.Sin(-13 * HALFPI * ((2 * p - 1) + 1)) * (float)Math.Pow(2, -10 * (2 * p - 1)) + 2); + } + } + + /// + /// Modeled after the overshooting cubic y = x^3-x*sin(x*pi) + /// + static public float BackEaseIn(float p) + { + return p * p * p - p * (float)Math.Sin(p * PI); + } + + /// + /// Modeled after overshooting cubic y = 1-((1-x)^3-(1-x)*sin((1-x)*pi)) + /// + static public float BackEaseOut(float p) + { + float f = (1 - p); + return 1 - (f * f * f - f * (float)Math.Sin(f * PI)); + } + + /// + /// Modeled after the piecewise overshooting cubic function: + /// y = (1/2)*((2x)^3-(2x)*sin(2*x*pi)) ; [0, 0.5) + /// y = (1/2)*(1-((1-x)^3-(1-x)*sin((1-x)*pi))+1) ; [0.5, 1] + /// + static public float BackEaseInOut(float p) + { + if(p < 0.5f) + { + float f = 2 * p; + return 0.5f * (f * f * f - f * (float)Math.Sin(f * PI)); + } + else + { + float f = (1 - (2*p - 1)); + return 0.5f * (1 - (f * f * f - f * (float)Math.Sin(f * PI))) + 0.5f; + } + } + + /// + /// + static public float BounceEaseIn(float p) + { + return 1 - BounceEaseOut(1 - p); + } + + /// + /// + static public float BounceEaseOut(float p) + { + if(p < 4/11.0f) + { + return (121 * p * p)/16.0f; + } + else if(p < 8/11.0f) + { + return (363/40.0f * p * p) - (99/10.0f * p) + 17/5.0f; + } + else if(p < 9/10.0f) + { + return (4356/361.0f * p * p) - (35442/1805.0f * p) + 16061/1805.0f; + } + else + { + return (54/5.0f * p * p) - (513/25.0f * p) + 268/25.0f; + } + } + + /// + /// + static public float BounceEaseInOut(float p) + { + if(p < 0.5f) + { + return 0.5f * BounceEaseIn(p*2); + } + else + { + return 0.5f * BounceEaseOut(p * 2 - 1) + 0.5f; + } + } +} + \ No newline at end of file diff --git a/Sledgemapper.Shared/Entities/Session.cs b/Sledgemapper.Shared/Entities/Session.cs index 42c74fe..4ded5e6 100644 --- a/Sledgemapper.Shared/Entities/Session.cs +++ b/Sledgemapper.Shared/Entities/Session.cs @@ -27,10 +27,11 @@ namespace Sledgemapper.Shared.Entities Overlays = new ConcurrentDictionary(); Walls = new ConcurrentDictionary(); Notes = new ConcurrentDictionary(); - Lines=new ConcurrentDictionary(); - Rooms=new ConcurrentDictionary(); + Lines = new ConcurrentDictionary(); + Rooms = new ConcurrentDictionary(); Players = new List(); Colors = new List(); + Pings = new ConcurrentDictionary(); } public ConcurrentDictionary Map { get; set; } @@ -39,189 +40,190 @@ namespace Sledgemapper.Shared.Entities public ConcurrentDictionary Notes { get; set; } public bool IsValid { get; set; } public List Players { get; set; } - public List Colors { get; set; } - public string SessionName { get; set; } - public int SessionId { get; set; } - public ConcurrentDictionary Lines { get; set; } - public ConcurrentDictionary Rooms { get; set; } + public ConcurrentDictionary Pings { get; set; } + public List Colors { get; set; } + public string SessionName { get; set; } + public int SessionId { get; set; } + public ConcurrentDictionary Lines { get; set; } + public ConcurrentDictionary Rooms { get; set; } - public void NewTile(Tile selectedTile, string tileId) + public void NewTile(Tile selectedTile, string tileId) + { + if (selectedTile is null || string.IsNullOrWhiteSpace(tileId)) { - if (selectedTile is null || string.IsNullOrWhiteSpace(tileId)) - { - return; - } - - var tileExist = Map.TryGetValue(selectedTile.ToString(), out var tile); - var newTile = new Tile { X = selectedTile.X, Y = selectedTile.Y, ID = tileId }; - if (tileExist) - { - Map.TryRemove(tile.ToString(), out var _); - if (tile.ID == tileId) - { - newTile.Rotation = (tile.Rotation + 1) % 4; - } - } - - Map.TryAdd(newTile.ToString(), newTile); - OnRaiseMapEntityAddedEvent(new MapEntityAddedEventArgs(newTile)); + return; } - public void NewOverlay(Overlay selectedOverlay, string overlayId) + var tileExist = Map.TryGetValue(selectedTile.ToString(), out var tile); + var newTile = new Tile { X = selectedTile.X, Y = selectedTile.Y, ID = tileId }; + if (tileExist) { - if (selectedOverlay is null || string.IsNullOrWhiteSpace(overlayId)) + Map.TryRemove(tile.ToString(), out var _); + if (tile.ID == tileId) { - return; - } - var overlayExist = Overlays.TryGetValue(selectedOverlay.ToString(), out var overlay); - var newOverlay = new Overlay { X = selectedOverlay.X, Y = selectedOverlay.Y, ID = overlayId, Intersection = selectedOverlay.Intersection }; - if (overlayExist) - { - Overlays.TryRemove(overlay.ToString(), out var _); - if (overlay.ID == overlayId) - { - newOverlay.Rotation = (overlay.Rotation + 1) % 4; - } - } - - Overlays.TryAdd(newOverlay.ToString(), newOverlay); - OnRaiseMapEntityAddedEvent(new MapEntityAddedEventArgs(newOverlay)); - } - - public void NewWall(Wall selectedWall, string wallId) - { - if (selectedWall is null || string.IsNullOrWhiteSpace(wallId)) - { - return; - } - var tileExist = Walls.TryGetValue(selectedWall.ToString(), out var wall); - var newWall = new Wall { X = selectedWall.X, Y = selectedWall.Y, ID = wallId, Rotation = selectedWall.Rotation }; - if (tileExist) - { - Walls.TryRemove(wall.ToString(), out var _); - } - - Walls.TryAdd(newWall.ToString(), newWall); - OnRaiseMapEntityAddedEvent(new MapEntityAddedEventArgs(newWall)); - } - - public void NewNote(Note selectedNote) - { - if (selectedNote is null) - { - return; - } - var noteExists = Notes.TryGetValue(selectedNote.ToString(), out var note); - var newNote = new Note { X = selectedNote.X, Y = selectedNote.Y, Text=selectedNote.Text }; - if (noteExists) - { - Walls.TryRemove(note.ToString(), out var _); - } - - Notes.TryAdd(newNote.ToString(), newNote); - OnRaiseMapEntityAddedEvent(new MapEntityAddedEventArgs(newNote)); - } - - public void DeleteWall(Wall wall) - { - if (wall is null) - { - return; - } - var removed = Walls.TryRemove(wall.ToString(), out var _); - if (removed) - { - OnRaiseMapEntityDeletedEvent(new MapEntityDeletedEventArgs(wall)); + newTile.Rotation = (tile.Rotation + 1) % 4; } } - public void DeleteNote(Note note) + Map.TryAdd(newTile.ToString(), newTile); + OnRaiseMapEntityAddedEvent(new MapEntityAddedEventArgs(newTile)); + } + + public void NewOverlay(Overlay selectedOverlay, string overlayId) + { + if (selectedOverlay is null || string.IsNullOrWhiteSpace(overlayId)) { - if (note is null) + return; + } + var overlayExist = Overlays.TryGetValue(selectedOverlay.ToString(), out var overlay); + var newOverlay = new Overlay { X = selectedOverlay.X, Y = selectedOverlay.Y, ID = overlayId, Intersection = selectedOverlay.Intersection }; + if (overlayExist) + { + Overlays.TryRemove(overlay.ToString(), out var _); + if (overlay.ID == overlayId) { - return; - } - var removed = Notes.TryRemove(note.ToString(), out var _); - if (removed) - { - OnRaiseMapEntityDeletedEvent(new MapEntityDeletedEventArgs(note)); + newOverlay.Rotation = (overlay.Rotation + 1) % 4; } } - public void DeleteOverlay(Overlay overlay) + Overlays.TryAdd(newOverlay.ToString(), newOverlay); + OnRaiseMapEntityAddedEvent(new MapEntityAddedEventArgs(newOverlay)); + } + + public void NewWall(Wall selectedWall, string wallId) + { + if (selectedWall is null || string.IsNullOrWhiteSpace(wallId)) { - if (overlay is null) - { - return; - } - var removed = Overlays.TryRemove(overlay.ToString(), out var _); - if (removed) - { - OnRaiseMapEntityDeletedEvent(new MapEntityDeletedEventArgs(overlay)); - } + return; + } + var tileExist = Walls.TryGetValue(selectedWall.ToString(), out var wall); + var newWall = new Wall { X = selectedWall.X, Y = selectedWall.Y, ID = wallId, Rotation = selectedWall.Rotation }; + if (tileExist) + { + Walls.TryRemove(wall.ToString(), out var _); } - public void DeleteTile(Tile tile) + Walls.TryAdd(newWall.ToString(), newWall); + OnRaiseMapEntityAddedEvent(new MapEntityAddedEventArgs(newWall)); + } + + public void NewNote(Note selectedNote) + { + if (selectedNote is null) { - if (tile is null) - { - return; - } - var removed = Map.TryRemove(tile.ToString(), out var _); - if (removed) - { - OnRaiseMapEntityDeletedEvent(new MapEntityDeletedEventArgs(tile)); - } + return; + } + var noteExists = Notes.TryGetValue(selectedNote.ToString(), out var note); + var newNote = new Note { X = selectedNote.X, Y = selectedNote.Y, Text = selectedNote.Text }; + if (noteExists) + { + Walls.TryRemove(note.ToString(), out var _); } - protected virtual void OnRaiseMapEntityAddedEvent(MapEntityAddedEventArgs e) + Notes.TryAdd(newNote.ToString(), newNote); + OnRaiseMapEntityAddedEvent(new MapEntityAddedEventArgs(newNote)); + } + + public void DeleteWall(Wall wall) + { + if (wall is null) { - MapEntityAdded?.Invoke(this, e); + return; } - - protected virtual void OnRaiseMapEntityDeletedEvent(MapEntityDeletedEventArgs e) + var removed = Walls.TryRemove(wall.ToString(), out var _); + if (removed) { - MapEntityDeleted?.Invoke(this, e); - } - - public void NewLine(Line line) - { - if (line is null) - { - return; - } - - var lineExist = Lines.TryGetValue(line.ToString(), out var tile); - var newLine = new Line { Start=line.Start, End=line.End, Width=line.Width}; - if (lineExist) - { - Lines.TryRemove(line.ToString(), out var _); - } - - Lines.TryAdd(newLine.ToString(), newLine); - - //TODO fix this - OnRaiseMapEntityAddedEvent(new MapEntityAddedEventArgs(newLine)); - } - - public void NewRoom(Room line) - { - if (line is null) - { - return; - } - - var lineExist = Rooms.TryGetValue(line.ToString(), out var tile); - var newLine = new Room { Start=line.Start, End=line.End, Delete=line.Delete}; - if (lineExist) - { - Rooms.TryRemove(line.ToString(), out var _); - } - - Rooms.TryAdd(newLine.ToString(), newLine); - - //TODO fix this - OnRaiseMapEntityAddedEvent(new MapEntityAddedEventArgs(newLine)); + OnRaiseMapEntityDeletedEvent(new MapEntityDeletedEventArgs(wall)); } } + + public void DeleteNote(Note note) + { + if (note is null) + { + return; + } + var removed = Notes.TryRemove(note.ToString(), out var _); + if (removed) + { + OnRaiseMapEntityDeletedEvent(new MapEntityDeletedEventArgs(note)); + } + } + + public void DeleteOverlay(Overlay overlay) + { + if (overlay is null) + { + return; + } + var removed = Overlays.TryRemove(overlay.ToString(), out var _); + if (removed) + { + OnRaiseMapEntityDeletedEvent(new MapEntityDeletedEventArgs(overlay)); + } + } + + public void DeleteTile(Tile tile) + { + if (tile is null) + { + return; + } + var removed = Map.TryRemove(tile.ToString(), out var _); + if (removed) + { + OnRaiseMapEntityDeletedEvent(new MapEntityDeletedEventArgs(tile)); + } + } + + protected virtual void OnRaiseMapEntityAddedEvent(MapEntityAddedEventArgs e) + { + MapEntityAdded?.Invoke(this, e); + } + + protected virtual void OnRaiseMapEntityDeletedEvent(MapEntityDeletedEventArgs e) + { + MapEntityDeleted?.Invoke(this, e); + } + + public void NewLine(Line line) + { + if (line is null) + { + return; + } + + var lineExist = Lines.TryGetValue(line.ToString(), out var tile); + var newLine = new Line { Start = line.Start, End = line.End, Width = line.Width }; + if (lineExist) + { + Lines.TryRemove(line.ToString(), out var _); + } + + Lines.TryAdd(newLine.ToString(), newLine); + + //TODO fix this + OnRaiseMapEntityAddedEvent(new MapEntityAddedEventArgs(newLine)); + } + + public void NewRoom(Room line) + { + if (line is null) + { + return; + } + + var lineExist = Rooms.TryGetValue(line.ToString(), out var tile); + var newLine = new Room { Start = line.Start, End = line.End, Delete = line.Delete }; + if (lineExist) + { + Rooms.TryRemove(line.ToString(), out var _); + } + + Rooms.TryAdd(newLine.ToString(), newLine); + + //TODO fix this + OnRaiseMapEntityAddedEvent(new MapEntityAddedEventArgs(newLine)); + } +} } diff --git a/Sledgemapper.Shared/Entities/Tile.cs b/Sledgemapper.Shared/Entities/Tile.cs index 0b622d2..f1e21e1 100644 --- a/Sledgemapper.Shared/Entities/Tile.cs +++ b/Sledgemapper.Shared/Entities/Tile.cs @@ -21,6 +21,13 @@ namespace Sledgemapper.Shared.Entities public double Timestamp { get; set; } } + public class Ping : BaseMapEntity + { + public Player Player { get; set; } + public int Iterations {get;set;} + public double StartTime {get;set;} + } + public class Tile : BaseMapEntity { diff --git a/Sledgemapper/CommunicationManager.cs b/Sledgemapper/CommunicationManager.cs index 0fc37b6..ccb35e9 100644 --- a/Sledgemapper/CommunicationManager.cs +++ b/Sledgemapper/CommunicationManager.cs @@ -155,6 +155,11 @@ namespace Sledgemapper p.Position = player.Position; } }); + + Connection.On("Ping", (ping) => + { + SessionData.Pings.TryAdd(Guid.NewGuid(), ping); + }); } private Task GetToken() @@ -233,6 +238,14 @@ namespace Sledgemapper } } + + internal async Task Ping(Tile location) + { + if (Connection!=null && Connection.State == HubConnectionState.Connected) + { + await Connection.InvokeAsync("Ping",SessionData.SessionName, location); + } + } } class AuthenticatedHttpClientHandler : HttpClientHandler diff --git a/Sledgemapper/Content/Content.mgcb b/Sledgemapper/Content/Content.mgcb index d40c401..7b85633 100644 --- a/Sledgemapper/Content/Content.mgcb +++ b/Sledgemapper/Content/Content.mgcb @@ -93,6 +93,23 @@ /processorParam:TextureFormat=Compressed /build:fonts/font99.spritefont +#begin handcursors +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:handcursors + +#begin handcursorsIndex +/importer:XmlImporter +/processor: +/build:handcursorsIndex + #begin icon_delete.png /importer:TextureImporter /processor:TextureProcessor @@ -141,6 +158,23 @@ /processorParam:TextureFormat=Color /build:location.png +#begin rippleSpriteIndex +/importer:XmlImporter +/processor:PassThroughProcessor +/build:rippleSpriteIndex + +#begin rippleSpriteMap +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:rippleSpriteMap + #begin shaders/OutlineShader.fx /importer:EffectImporter /processor:EffectProcessor @@ -380,30 +414,6 @@ /processorParam:TextureFormat=Color /build:walls/wall01.png -#begin walls/wall01.png -/importer:TextureImporter -/processor:TextureProcessor -/processorParam:ColorKeyColor=255,0,255,255 -/processorParam:ColorKeyEnabled=True -/processorParam:GenerateMipmaps=False -/processorParam:PremultiplyAlpha=True -/processorParam:ResizeToPowerOfTwo=False -/processorParam:MakeSquare=False -/processorParam:TextureFormat=Color -/build:walls/wall01.png - -#begin walls/wall02.png -/importer:TextureImporter -/processor:TextureProcessor -/processorParam:ColorKeyColor=255,0,255,255 -/processorParam:ColorKeyEnabled=True -/processorParam:GenerateMipmaps=False -/processorParam:PremultiplyAlpha=True -/processorParam:ResizeToPowerOfTwo=False -/processorParam:MakeSquare=False -/processorParam:TextureFormat=Color -/build:walls/wall02.png - #begin walls/wall02.png /importer:TextureImporter /processor:TextureProcessor @@ -428,18 +438,6 @@ /processorParam:TextureFormat=Color /build:walls/wall03.png -#begin walls/wall03.png -/importer:TextureImporter -/processor:TextureProcessor -/processorParam:ColorKeyColor=255,0,255,255 -/processorParam:ColorKeyEnabled=True -/processorParam:GenerateMipmaps=False -/processorParam:PremultiplyAlpha=True -/processorParam:ResizeToPowerOfTwo=False -/processorParam:MakeSquare=False -/processorParam:TextureFormat=Color -/build:walls/wall03.png - #begin walls/wall04.png /importer:TextureImporter /processor:TextureProcessor @@ -452,30 +450,6 @@ /processorParam:TextureFormat=Color /build:walls/wall04.png -#begin walls/wall04.png -/importer:TextureImporter -/processor:TextureProcessor -/processorParam:ColorKeyColor=255,0,255,255 -/processorParam:ColorKeyEnabled=True -/processorParam:GenerateMipmaps=False -/processorParam:PremultiplyAlpha=True -/processorParam:ResizeToPowerOfTwo=False -/processorParam:MakeSquare=False -/processorParam:TextureFormat=Color -/build:walls/wall04.png - -#begin walls/wall05.png -/importer:TextureImporter -/processor:TextureProcessor -/processorParam:ColorKeyColor=255,0,255,255 -/processorParam:ColorKeyEnabled=True -/processorParam:GenerateMipmaps=False -/processorParam:PremultiplyAlpha=True -/processorParam:ResizeToPowerOfTwo=False -/processorParam:MakeSquare=False -/processorParam:TextureFormat=Color -/build:walls/wall05.png - #begin walls/wall05.png /importer:TextureImporter /processor:TextureProcessor diff --git a/Sledgemapper/Content/handcursors b/Sledgemapper/Content/handcursors new file mode 100644 index 0000000..ef1ac08 Binary files /dev/null and b/Sledgemapper/Content/handcursors differ diff --git a/Sledgemapper/Content/handcursors.png b/Sledgemapper/Content/handcursors.png new file mode 100644 index 0000000..c31f80a Binary files /dev/null and b/Sledgemapper/Content/handcursors.png differ diff --git a/Sledgemapper/Content/handcursorsIndex b/Sledgemapper/Content/handcursorsIndex new file mode 100644 index 0000000..9f60bbe --- /dev/null +++ b/Sledgemapper/Content/handcursorsIndex @@ -0,0 +1,7 @@ + + + +handcursor_000 0 60 60 +handcursor_0161 0 60 60 + + diff --git a/Sledgemapper/Content/rippleSpriteIndex b/Sledgemapper/Content/rippleSpriteIndex new file mode 100644 index 0000000..e345a97 --- /dev/null +++ b/Sledgemapper/Content/rippleSpriteIndex @@ -0,0 +1,24 @@ + + + +ripple_000 0 128 128 +ripple_01129 0 128 128 +ripple_02258 0 128 128 +ripple_030 129 128 128 +ripple_04129 129 128 128 +ripple_050 258 128 128 +ripple_06129 258 128 128 +ripple_07258 129 128 128 +ripple_08258 258 128 128 +ripple_09387 0 128 128 +ripple_10387 129 128 128 +ripple_11516 0 128 128 +ripple_12387 258 128 128 +ripple_13516 129 128 128 +ripple_14645 0 128 128 +ripple_15774 0 128 128 +ripple_16645 129 128 128 +ripple_17516 258 128 128 +ripple_18645 258 128 128 + + diff --git a/Sledgemapper/Content/rippleSpriteMap b/Sledgemapper/Content/rippleSpriteMap new file mode 100644 index 0000000..0e76603 Binary files /dev/null and b/Sledgemapper/Content/rippleSpriteMap differ diff --git a/Sledgemapper/Settings.cs b/Sledgemapper/Settings.cs index 25b39f6..3188725 100644 --- a/Sledgemapper/Settings.cs +++ b/Sledgemapper/Settings.cs @@ -12,6 +12,7 @@ namespace Sledgemapper public Color NoteColor { get; set; } public string MachineName { get; set; } public int TileDeleteDivider { get; set; } + public int PingDuration {get;set;} public Settings() { @@ -19,7 +20,8 @@ namespace Sledgemapper GridColor = Color.Black; NoteColor = Color.DarkRed; OverlayTintColor = new Color(24, 118, 157); -TileDeleteDivider=14; + TileDeleteDivider = 14; + PingDuration = 4000; try { MachineName = Environment.MachineName; diff --git a/Sledgemapper/Sledgemapper.cs b/Sledgemapper/Sledgemapper.cs index 5b81ac8..07b9220 100644 --- a/Sledgemapper/Sledgemapper.cs +++ b/Sledgemapper/Sledgemapper.cs @@ -6,6 +6,7 @@ using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using MonoGame.Extended; +using MonoGame.Extended.VectorDraw; using Myra; using Myra.Graphics2D.Brushes; using Myra.Graphics2D.TextureAtlases; @@ -24,6 +25,7 @@ using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using AsyncAwaitBestPractices; namespace Sledgemapper { @@ -152,7 +154,6 @@ namespace Sledgemapper { var indexX = 0; var indexY = 0; - //foreach (var item in spriteSheet.index) grid.Widgets.Clear(); _mainWidget.ScrOverlay.ResetScroll(); foreach (var item in spriteSheet.index.Where(t => String.IsNullOrWhiteSpace(e) || t.Key.ToLower().Contains(e.ToLower()))) @@ -177,6 +178,7 @@ namespace Sledgemapper _lblOverlayName.Visible = false; } + private SpriteSheet _rippleSpriteSheet; Label _lblOverlayName; private void OnTileButtonTouchEntered(object sender, EventArgs e) @@ -187,7 +189,6 @@ namespace Sledgemapper _lblOverlayName.Visible = true; _lblOverlayName.Text = ((ImageButton)sender).Id; _desktop.ShowContextMenu(_lblOverlayName, mouseState); - // _lblOverlayName.true; } protected override void LoadContent() @@ -221,7 +222,10 @@ namespace Sledgemapper _wallsContent = Content.LoadContentFolder("walls"); _spriteSheet = new SpriteSheet(); - _spriteSheet.LoadContent(Content); + _spriteSheet.LoadContent(Content, "spriteIndex", "sprites"); + _rippleSpriteSheet = new SpriteSheet(); + _rippleSpriteSheet.LoadContent(Content, "handcursorsIndex", "handcursors"); + _lblOverlayName = new Label(); _lblOverlayName.Background = new SolidBrush(Color.SlateGray); _lblOverlayName.Padding = new Myra.Graphics2D.Thickness(4); @@ -249,20 +253,7 @@ namespace Sledgemapper private void OnTxtOverlaySearchChange(object sender, ValueChangedEventArgs e) { - // var filteredWidget = _mainWidget.GridOverlays.Widgets.Where(m => m.Id.ToLower().Contains(e.NewValue.ToLower())).ToArray(); - // foreach (var w in _mainWidget.GridOverlays.Widgets) - // { - // w. - // w.Visible = false; - // } - - // foreach (var w in filteredWidget) - // { - // w.Visible = true; - // } - AddItemToToolGrid(_mainWidget.GridOverlays, OnOverlayButtonClicked, _spriteSheet, e.NewValue); - } private void OnBtnToolbarDeleteClicked(object sender, EventArgs e) @@ -449,6 +440,8 @@ namespace Sledgemapper var newNoteButton = new TextButton { Text = "New Note", Width = 80, Height = 20, Padding = new Myra.Graphics2D.Thickness(2), HorizontalAlignment = HorizontalAlignment.Left }; newNoteButton.Click += OnContextMenuNewNoteClick; popup.AddChild(newNoteButton); + + } else { @@ -463,6 +456,11 @@ namespace Sledgemapper popup.AddChild(deleteNoteButton); } + var pingButton = new TextButton { Text = "Ping", Width = 80, Height = 20, Padding = new Myra.Graphics2D.Thickness(2), HorizontalAlignment = HorizontalAlignment.Left }; + var location = new Tile { X = _state.HoveredTile.X, Y = _state.HoveredTile.Y }; + pingButton.Click += (s, e) => OnContextMenuPingClick(s, e, location); + popup.AddChild(pingButton); + _desktop.ShowContextMenu(popup, mouseState.Position); } @@ -619,6 +617,11 @@ namespace Sledgemapper } } + if (oldState.IsKeyDown(Keys.P) && newState.IsKeyUp(Keys.P)) + { + _communicationManager.Ping(_state.HoveredTile).SafeFireAndForget(); + } + foreach (var key in newState.GetPressedKeys()) { switch (key) @@ -670,10 +673,17 @@ namespace Sledgemapper var center = new Point((Window.ClientBounds.Width + 200) / 2 - _state.TileSize / 2, Window.ClientBounds.Height / 2 - _state.TileSize / 2); var dx = center.X - x * _state.TileSize - _viewportCenter.X; var dy = center.Y - y * _state.TileSize - _viewportCenter.Y; + _viewportCenter.X += dx; _viewportCenter.Y += dy; } + private void OnContextMenuPingClick(object sender, EventArgs e, Tile location) + { + _desktop.HideContextMenu(); + _communicationManager.Ping(location).SafeFireAndForget(); + } + protected override void Draw(GameTime gameTime) { if (_spriteBatch is null) @@ -688,7 +698,7 @@ namespace Sledgemapper _spriteBatch.Begin( transformMatrix: Matrix.CreateTranslation(_viewportCenter), - sortMode: SpriteSortMode.Texture); + sortMode: SpriteSortMode.Texture, samplerState: SamplerState.PointClamp); DrawTiles(); @@ -714,6 +724,8 @@ namespace Sledgemapper _spriteBatch.End(); + DrawRipple(gameTime); + try { _desktop?.Render(); @@ -725,6 +737,81 @@ namespace Sledgemapper base.Draw(gameTime); } + private void DrawRipple(GameTime gameTime) + { + _spriteBatch.Begin( + blendState: BlendState.NonPremultiplied, + transformMatrix: Matrix.CreateTranslation(_viewportCenter)); + + var durationMs = 2000; + var baseRadius = _state.TileSize / 4f; + var baseOuterRadius = (float)_state.TileSize; + var iterations = 3f; + var guids = _sessionData.Pings.Keys.ToArray(); + + foreach (var guid in guids) + { + var pingFound = _sessionData.Pings.TryGetValue(guid, out var ping); + if (!pingFound) + { + continue; + } + + if (ping.StartTime == 0) + { + ping.StartTime = gameTime.TotalGameTime.TotalMilliseconds; + } + + var x = ping.X * _state.TileSize + _state.TileSize / 2f; + var y = ping.Y * _state.TileSize + _state.TileSize / 2f; + + if (IsOffscreen(new Tile { X = ping.X, Y = ping.Y })) + { + DrawPingPointer(ping, gameTime); + } + else + { + + _spriteBatch.DrawCircle( + center: new Vector2(x, y), + radius: baseRadius, + sides: 20, + color: ping.Player.Color.ToColor(), + thickness: baseRadius); + + for (var i = 0; i < iterations; i++) + { + var cycleTime = (((float)gameTime.TotalGameTime.TotalMilliseconds + (float)i * durationMs / iterations) % durationMs) / durationMs; + var easing = Easings.Interpolate(cycleTime, Easings.Functions.SineEaseInOut); + _spriteBatch.DrawCircle( + center: new Vector2(x, y), + radius: baseRadius + baseOuterRadius * easing, + sides: 20, + color: new Color(ping.Player.Color.ToColor(), (1 - easing)), + thickness: 2 + 5 * (1 - easing)); + + + } + } + } + foreach (var guid in guids) + { + var pingFound = _sessionData.Pings.TryGetValue(guid, out var ping); + if (!pingFound) + { + continue; + } + + if ((gameTime.TotalGameTime.TotalMilliseconds - ping.StartTime) > _settings.PingDuration) + { + _sessionData.Pings.TryRemove(guid, out var _); + } + } + + + _spriteBatch.End(); + } + private void DrawRoomPreview() { if ((_state.InsertMode == InsertMode.NewRoom || _state.InsertMode == InsertMode.NewDelete) && _state.SelectedSnapPoint != null) @@ -992,88 +1079,16 @@ namespace Sledgemapper var isoffscreen = IsOffscreen(_state.SelectedTile); if (isoffscreen) { - var center = new Point((Window.ClientBounds.Width + 200) / 2 - (int)_viewportCenter.X, Window.ClientBounds.Height / 2 - (int)_viewportCenter.Y); - - var cx = center.X / _state.TileSize; - var cy = center.Y / _state.TileSize; - - var p1 = new Vector2(cx * _state.TileSize, cy * _state.TileSize); - var p2 = new Vector2(_state.SelectedTile.X * _state.TileSize, _state.SelectedTile.Y * _state.TileSize); - - var p3 = new Vector2(Window.ClientBounds.Width - _viewportCenter.X, 0 - _viewportCenter.Y); - var p4 = new Vector2(Window.ClientBounds.Width - _viewportCenter.X, Window.ClientBounds.Height - _viewportCenter.Y); - var ua1 = ((p4.X - p3.X) * (p1.Y - p3.Y) - (p4.Y - p3.Y) * (p1.X - p3.X)) / ((p4.Y - p3.Y) * (p2.X - p1.X) - (p4.X - p3.X) * (p2.Y - p1.Y)); - - p3 = new Vector2(200 - _viewportCenter.X, 0 - _viewportCenter.Y); - p4 = new Vector2(Window.ClientBounds.Width - _viewportCenter.X, 0 - _viewportCenter.Y); - var ua2 = ((p4.X - p3.X) * (p1.Y - p3.Y) - (p4.Y - p3.Y) * (p1.X - p3.X)) / ((p4.Y - p3.Y) * (p2.X - p1.X) - (p4.X - p3.X) * (p2.Y - p1.Y)); - - p3 = new Vector2(200 - _viewportCenter.X, 0 - _viewportCenter.Y); - p4 = new Vector2(200 - _viewportCenter.X, Window.ClientBounds.Height - _viewportCenter.Y); - var ua3 = ((p4.X - p3.X) * (p1.Y - p3.Y) - (p4.Y - p3.Y) * (p1.X - p3.X)) / ((p4.Y - p3.Y) * (p2.X - p1.X) - (p4.X - p3.X) * (p2.Y - p1.Y)); - - p3 = new Vector2(200 - _viewportCenter.X, Window.ClientBounds.Height - _viewportCenter.Y); - p4 = new Vector2(Window.ClientBounds.Width - _viewportCenter.X, Window.ClientBounds.Height - _viewportCenter.Y); - var ua4 = ((p4.X - p3.X) * (p1.Y - p3.Y) - (p4.Y - p3.Y) * (p1.X - p3.X)) / ((p4.Y - p3.Y) * (p2.X - p1.X) - (p4.X - p3.X) * (p2.Y - p1.Y)); - - var uas = new float[] { ua1, ua2, ua3, ua4 }; - if (uas.Any(u => u > 0 && u < 1)) + var validPointer = GetPointerVector(new Point(_state.SelectedTile.X, _state.SelectedTile.Y), out var points); + if (validPointer) { - var ua = uas.Where(u => u > 0 && u < 1).Min(); - - int i = 0; - for (var j = 0; j < 4; j++) - { - if (uas[j] == ua) - { - i = j; - } - } - - - var x = (p1.X + ua * (p2.X - p1.X)); - var y = (p1.Y + ua * (p2.Y - p1.Y)); - - - var v = _vector2Pool.Rent(4); - switch (i) - { - case 0: - v[0] = new Vector2(x, y); - v[1] = new Vector2(x - 20, y + 10); - v[2] = new Vector2(x - 20, y - 10); - v[3] = new Vector2(x, y); - break; - case 1: - v[0] = new Vector2(x, y); - v[1] = new Vector2(x - 10, y + 20); - v[2] = new Vector2(x + 10, y + 20); - v[3] = new Vector2(x, y); - y += 20; - break; - case 2: - x += 0; - v[0] = new Vector2(x, y); - v[1] = new Vector2(x + 20, y + 10); - v[2] = new Vector2(x + 20, y - 10); - v[3] = new Vector2(x, y); - break; - case 3: - y -= 20; - v[0] = new Vector2(x, y); - v[1] = new Vector2(x - 10, y - 20); - v[2] = new Vector2(x + 10, y - 20); - v[3] = new Vector2(x, y); - break; - } - _spriteBatch.DrawPolygon(Vector2.Zero, v, Color.Red, 2); - _vector2Pool.Return(v); - + _spriteBatch.DrawPolygon(Vector2.Zero, points, Color.Red, 2); } } - - - _spriteBatch.DrawRectangle(new Rectangle((_state.SelectedTile.X * _state.TileSize) - 2, (_state.SelectedTile.Y * _state.TileSize) - 2, _state.TileSize + 3, _state.TileSize + 3), Color.Red, 2); + else + { + _spriteBatch.DrawRectangle(new Rectangle((_state.SelectedTile.X * _state.TileSize) - 2, (_state.SelectedTile.Y * _state.TileSize) - 2, _state.TileSize + 3, _state.TileSize + 3), Color.Red, 2); + } } } @@ -1309,11 +1324,12 @@ namespace Sledgemapper var playerCells = _sessionData.Players.Select(m => m.Position).Distinct().ToList(); - foreach (var cell in playerCells) + foreach (var cell in playerCells.Where(c => !IsOffscreen(c))) { var playersInCell = _sessionData.Players.Where(m => m.Position == cell).ToList(); var i = 0; foreach (var player in playersInCell) + { var color = player.Color.ToColor(); @@ -1331,7 +1347,7 @@ namespace Sledgemapper _state.TileSize - 1, _state.TileSize - 1); stringPosition = new Vector2( - player.Position.X * _state.TileSize, + player.Position.X * _state.TileSize + 1, player.Position.Y * _state.TileSize + _state.TileSize - measure.Y * fscale); } else if (playersInCell.Count == 2) @@ -1346,7 +1362,7 @@ namespace Sledgemapper _state.TileSize / 2 - 1, _state.TileSize - 1); stringPosition = new Vector2( - player.Position.X * _state.TileSize, + player.Position.X * _state.TileSize + 1, player.Position.Y * _state.TileSize + _state.TileSize - measure.Y * fscale); } else @@ -1357,7 +1373,7 @@ namespace Sledgemapper _state.TileSize / 2 - 1, _state.TileSize - 1); stringPosition = new Vector2( - player.Position.X * _state.TileSize + _state.TileSize / 2, + player.Position.X * _state.TileSize + _state.TileSize / 2 + 1, player.Position.Y * _state.TileSize + _state.TileSize - measure.Y * fscale); } i++; @@ -1374,7 +1390,7 @@ namespace Sledgemapper _state.TileSize / 2 - 1, _state.TileSize / 2 - 1); stringPosition = new Vector2( - player.Position.X * _state.TileSize, + player.Position.X * _state.TileSize + 1, player.Position.Y * _state.TileSize + _state.TileSize / 2 - measure.Y * fscale); break; @@ -1385,7 +1401,7 @@ namespace Sledgemapper _state.TileSize / 2 - 1, _state.TileSize / 2 - 1); stringPosition = new Vector2( - player.Position.X * _state.TileSize + _state.TileSize / 2, + player.Position.X * _state.TileSize + _state.TileSize / 2 + 1, player.Position.Y * _state.TileSize + _state.TileSize / 2 - measure.Y * fscale); break; @@ -1396,7 +1412,7 @@ namespace Sledgemapper _state.TileSize / 2 - 1, _state.TileSize / 2 - 1); stringPosition = new Vector2( - player.Position.X * _state.TileSize, + player.Position.X * _state.TileSize + 1, player.Position.Y * _state.TileSize + _state.TileSize - measure.Y * fscale); break; @@ -1408,7 +1424,7 @@ namespace Sledgemapper _state.TileSize / 2 - 1, _state.TileSize / 2 - 1); stringPosition = new Vector2( - player.Position.X * _state.TileSize + _state.TileSize / 2, + player.Position.X * _state.TileSize + _state.TileSize / 2 + 1, player.Position.Y * _state.TileSize + _state.TileSize - measure.Y * fscale); break; @@ -1440,30 +1456,88 @@ namespace Sledgemapper } } - private void DrawPlayerPointer(Player player) + private void DrawPingPointer(Ping ping, GameTime gameTime) { - var center = new Point((Window.ClientBounds.Width + 200) / 2 - (int)_viewportCenter.X, Window.ClientBounds.Height / 2 - (int)_viewportCenter.Y); + var durationMs = 2000f; + var baseRadius = _state.TileSize / 4f; + var baseOuterRadius = (float)_state.TileSize; + var iterations = 3f; + var validPointer = GetPointerVector(new Point(ping.X, ping.Y), out var points); - var cx = center.X / _state.TileSize; - var cy = center.Y / _state.TileSize; + if (validPointer) + { + _spriteBatch.DrawPolygon(Vector2.Zero, points, ping.Player.Color.ToColor(), 4); - var p1 = new Vector2(cx * _state.TileSize, cy * _state.TileSize); - var p2 = new Vector2(player.Position.X * _state.TileSize, player.Position.Y * _state.TileSize); - var p3 = new Vector2(Window.ClientBounds.Width - _viewportCenter.X, 0 - _viewportCenter.Y); - var p4 = new Vector2(Window.ClientBounds.Width - _viewportCenter.X, Window.ClientBounds.Height - _viewportCenter.Y); + for (var j = 0; j < iterations; j++) + { + var cycleTime = (((float)gameTime.TotalGameTime.TotalMilliseconds + (float)j * durationMs / iterations) % durationMs) / durationMs; + var easing = Easings.Interpolate(cycleTime, Easings.Functions.SineEaseInOut); + var v2 = new Vector2[points.Length]; + + + var tCenter = new Vector2((points[0].X + points[1].X + points[2].X) / 3f, (points[0].Y + points[1].Y + points[2].Y) / 3f); + + + for (int i1 = 0; i1 < v2.Length; i1++) + { + + var svx = ((points[i1].X - tCenter.X) * (1 + (2 * easing))) + tCenter.X; + var svy = ((points[i1].Y - tCenter.Y) * (1 + (2 * easing))) + tCenter.Y; + v2[i1] = new Vector2(svx, svy); + } + + _spriteBatch.DrawPolygon( + offset: Vector2.Zero, + points: v2, + color: new Color(ping.Player.Color.ToColor(), 1f - easing), + thickness: 2 + 2 * (1 - easing)); + + } + + } + } + + private bool GetPointerVector(Point target, out Vector2[] points) + { + var offset = _state.TileSize / 2; + var leftBound = 200 + offset; + var topBound = 75 + offset; + var bottomBound = 25 + offset; + var rightBound = offset; + points = new Vector2[0]; + var center = new Point((Window.ClientBounds.Width + leftBound) / 2 - (int)_viewportCenter.X, Window.ClientBounds.Height / 2 - (int)_viewportCenter.Y); + + // center + var p1 = new Vector2(center.X, center.Y); + + // point + var p2 = new Vector2( + target.X * _state.TileSize + offset, + target.Y * _state.TileSize + offset); + + // top right + var p3 = new Vector2( + Window.ClientBounds.Width - _viewportCenter.X - rightBound, + topBound - _viewportCenter.Y); + + //bottom right + var p4 = new Vector2( + Window.ClientBounds.Width - _viewportCenter.X - rightBound, + Window.ClientBounds.Height - _viewportCenter.Y - bottomBound); + var ua1 = ((p4.X - p3.X) * (p1.Y - p3.Y) - (p4.Y - p3.Y) * (p1.X - p3.X)) / ((p4.Y - p3.Y) * (p2.X - p1.X) - (p4.X - p3.X) * (p2.Y - p1.Y)); - p3 = new Vector2(200 - _viewportCenter.X, 0 - _viewportCenter.Y); - p4 = new Vector2(Window.ClientBounds.Width - _viewportCenter.X, 0 - _viewportCenter.Y); + p3 = new Vector2(leftBound - _viewportCenter.X, topBound - _viewportCenter.Y); + p4 = new Vector2(Window.ClientBounds.Width - _viewportCenter.X, topBound - _viewportCenter.Y); var ua2 = ((p4.X - p3.X) * (p1.Y - p3.Y) - (p4.Y - p3.Y) * (p1.X - p3.X)) / ((p4.Y - p3.Y) * (p2.X - p1.X) - (p4.X - p3.X) * (p2.Y - p1.Y)); - p3 = new Vector2(200 - _viewportCenter.X, 0 - _viewportCenter.Y); - p4 = new Vector2(200 - _viewportCenter.X, Window.ClientBounds.Height - _viewportCenter.Y); + p3 = new Vector2(leftBound - _viewportCenter.X, topBound - _viewportCenter.Y); + p4 = new Vector2(leftBound - _viewportCenter.X, Window.ClientBounds.Height - _viewportCenter.Y - bottomBound); var ua3 = ((p4.X - p3.X) * (p1.Y - p3.Y) - (p4.Y - p3.Y) * (p1.X - p3.X)) / ((p4.Y - p3.Y) * (p2.X - p1.X) - (p4.X - p3.X) * (p2.Y - p1.Y)); - p3 = new Vector2(200 - _viewportCenter.X, Window.ClientBounds.Height - _viewportCenter.Y); - p4 = new Vector2(Window.ClientBounds.Width - _viewportCenter.X, Window.ClientBounds.Height - _viewportCenter.Y); + p3 = new Vector2(leftBound - _viewportCenter.X, Window.ClientBounds.Height - _viewportCenter.Y - bottomBound); + p4 = new Vector2(Window.ClientBounds.Width - _viewportCenter.X, Window.ClientBounds.Height - _viewportCenter.Y - bottomBound); var ua4 = ((p4.X - p3.X) * (p1.Y - p3.Y) - (p4.Y - p3.Y) * (p1.X - p3.X)) / ((p4.Y - p3.Y) * (p2.X - p1.X) - (p4.X - p3.X) * (p2.Y - p1.Y)); var uas = new List { ua1, ua2, ua3, ua4 }; @@ -1473,26 +1547,37 @@ namespace Sledgemapper var i = uas.IndexOf(ua); var x = (p1.X + ua * (p2.X - p1.X)); var y = (p1.Y + ua * (p2.Y - p1.Y)); - Vector2[] vertexes = new Vector2[0]; + switch (i) { case 0: - vertexes = new Vector2[] { new Vector2(x, y), new Vector2(x - 20, y + 10), new Vector2(x - 20, y - 10), new Vector2(x, y) }; + x += offset; + points = new Vector2[] { new Vector2(x, y), new Vector2(x - 20, y - 10), new Vector2(x - 20, y + 10), new Vector2(x, y) }; break; case 1: - y += 20; - vertexes = new Vector2[] { new Vector2(x, y), new Vector2(x - 10, y + 20), new Vector2(x + 10, y + 20), new Vector2(x, y) }; + y -= offset; + points = new Vector2[] { new Vector2(x, y), new Vector2(x - 10, y + 20), new Vector2(x + 10, y + 20), new Vector2(x, y) }; break; case 2: - x += 0; - vertexes = new Vector2[] { new Vector2(x, y), new Vector2(x + 20, y + 10), new Vector2(x + 20, y - 10), new Vector2(x, y) }; + x -= offset; + points = new Vector2[] { new Vector2(x, y), new Vector2(x + 20, y + 10), new Vector2(x + 20, y - 10), new Vector2(x, y) }; break; case 3: - y -= 20; - vertexes = new Vector2[] { new Vector2(x, y), new Vector2(x - 10, y - 20), new Vector2(x + 10, y - 20), new Vector2(x, y) }; + y += offset; + points = new Vector2[] { new Vector2(x, y), new Vector2(x + 10, y - 20), new Vector2(x - 10, y - 20), new Vector2(x, y) }; break; } - _spriteBatch.DrawPolygon(Vector2.Zero, vertexes, player.Color.ToColor(), 2); + return true; + } + return false; + } + + private void DrawPlayerPointer(Player player) + { + var validPointer = GetPointerVector(new Point(player.Position.X, player.Position.Y), out var points); + if (validPointer) + { + _spriteBatch.DrawPolygon(Vector2.Zero, points, player.Color.ToColor(), 2); } } @@ -1500,20 +1585,18 @@ namespace Sledgemapper private bool IsOffscreen(Tile position) { - var visibleTilesX = GraphicsDevice.Viewport.Width / _state.TileSize + 1; - var visibleTilesY = GraphicsDevice.Viewport.Height / _state.TileSize + 1; + var boxTL = new Point(200 - _state.TileSize / 2, 75 - _state.TileSize / 2); + var boxBR = new Point(GraphicsDevice.Viewport.Width + _state.TileSize / 2, GraphicsDevice.Viewport.Height - 25 + _state.TileSize / 2); - var screenPositionTopLeft = new Point(200 - _state.TileSize + 0 * _state.TileSize - (int)_viewportCenter.X, 0 * _state.TileSize + _state.TileSize - (int)_viewportCenter.Y); - var screenPositionBottomRight = new Point(visibleTilesX * _state.TileSize - (int)_viewportCenter.X, visibleTilesY * _state.TileSize - 20 - (int)_viewportCenter.Y); - var tileTopLeft = new Point(screenPositionTopLeft.X / _state.TileSize, screenPositionTopLeft.Y / _state.TileSize); - var tileBottomRight = new Point(screenPositionBottomRight.X / _state.TileSize, screenPositionBottomRight.Y / _state.TileSize); + var tileTL = new Point(position.X * _state.TileSize + (int)_viewportCenter.X, position.Y * _state.TileSize + (int)_viewportCenter.Y); + var tileBR = new Point(position.X * _state.TileSize + (int)_viewportCenter.X + _state.TileSize, position.Y * _state.TileSize + (int)_viewportCenter.Y + _state.TileSize); - if (position.X < tileTopLeft.X || position.Y < tileTopLeft.Y || position.X > tileBottomRight.X || position.Y > tileBottomRight.Y) + if (tileTL.X <= boxTL.X || tileTL.Y <= boxTL.Y || tileBR.X >= boxBR.X || tileBR.Y >= boxBR.Y) { return true; } - return false; + return false; } private int _borderWidth => (_state.TileSize / 6) % 2 == 0 ? (_state.TileSize / 6) : (_state.TileSize / 6) + 1; @@ -2107,6 +2190,8 @@ namespace Sledgemapper noteWindow.NoteText.SetKeyboardFocus(); } + + private void OnContextMenuDeleteNoteClick(object sender, EventArgs e) { _desktop.HideContextMenu(); @@ -2328,10 +2413,10 @@ namespace Sledgemapper internal Texture2D Texture; internal Dictionary index; - public void LoadContent(ContentManager content) + public void LoadContent(ContentManager content, string spriteIndex, string texture) { - index = content.Load>("spriteIndex"); - Texture = content.Load("sprites"); + index = content.Load>(spriteIndex); + Texture = content.Load(texture); } internal Rectangle? SourceRectangle(string spriteName) @@ -2349,4 +2434,6 @@ namespace Sledgemapper } } } + + }