using System.Collections; using System.Collections.Concurrent; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using TanksServer.Models; namespace TanksServer.Services; internal sealed class TankManager(ILogger logger, IOptions options, MapService map) : ITickStep, IEnumerable { private readonly ConcurrentBag _tanks = new(); private readonly TanksConfiguration _config = options.Value; public void Add(Tank tank) { logger.LogInformation("Tank added for player {}", tank.Owner.Id); _tanks.Add(tank); } public Task TickAsync() { foreach (var tank in _tanks) { TryMoveTank(tank); } return Task.CompletedTask; } private bool TryMoveTank(Tank tank) { logger.LogTrace("moving tank for player {}", tank.Owner.Id); var player = tank.Owner; if (player.Controls.TurnLeft) tank.Rotation -= _config.TurnSpeed; if (player.Controls.TurnRight) tank.Rotation += _config.TurnSpeed; double speed; switch (player.Controls) { case { Forward: false, Backward: false }: case { Forward: true, Backward: true }: return false; case { Forward: true }: speed = +_config.MoveSpeed; break; case { Backward: true }: speed = -_config.MoveSpeed; break; default: return false; } var angle = tank.Rotation / 16d * 2d * Math.PI; var newX = tank.Position.X + Math.Sin(angle) * speed; var newY = tank.Position.Y - Math.Cos(angle) * speed; return TryMove(tank, new FloatPosition(newX, newY)) || TryMove(tank, tank.Position with { X = newX }) || TryMove(tank, tank.Position with { Y = newY }); } private bool TryMove(Tank tank, FloatPosition newPosition) { var x0 = (int)Math.Floor(newPosition.X / MapService.TileSize); var x1 = (int)Math.Ceiling(newPosition.X / MapService.TileSize); var y0 = (int)Math.Floor(newPosition.Y / MapService.TileSize); var y1 = (int)Math.Ceiling(newPosition.Y / MapService.TileSize); TilePosition[] positions = { new(x0, y0), new(x0, y1), new(x1, y0), new(x1, y1) }; if (positions.Any(map.IsCurrentlyWall)) return false; tank.Position = newPosition; return true; } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() => _tanks.GetEnumerator(); }