diff --git a/DisplayCommands/Cp437Grid.cs b/DisplayCommands/Cp437Grid.cs index 3dd6e99..0602d15 100644 --- a/DisplayCommands/Cp437Grid.cs +++ b/DisplayCommands/Cp437Grid.cs @@ -8,6 +8,7 @@ public sealed class Cp437Grid(ushort width, ushort height) private readonly ByteGrid _byteGrid = new(width, height); public ushort Height { get; } = height; + public ushort Width { get; } = width; internal Memory Data => _byteGrid.Data; diff --git a/DisplayCommands/IDisplayConnection.cs b/DisplayCommands/IDisplayConnection.cs index db53477..0e16af1 100644 --- a/DisplayCommands/IDisplayConnection.cs +++ b/DisplayCommands/IDisplayConnection.cs @@ -6,9 +6,9 @@ public interface IDisplayConnection ValueTask SendCp437DataAsync(ushort x, ushort y, Cp437Grid grid); - ValueTask SendCharBrightnessAsync(ushort x, ushort y, ByteGrid luma); - ValueTask SendBrightnessAsync(byte brightness); + + ValueTask SendCharBrightnessAsync(ushort x, ushort y, ByteGrid luma); ValueTask SendHardResetAsync(); diff --git a/DisplayCommands/Internals/DisplayCommand.cs b/DisplayCommands/Internals/DisplayCommand.cs index 9574dc9..42c96ba 100644 --- a/DisplayCommands/Internals/DisplayCommand.cs +++ b/DisplayCommands/Internals/DisplayCommand.cs @@ -1,6 +1,6 @@ namespace DisplayCommands.Internals; -internal enum DisplayCommand: ushort +internal enum DisplayCommand : ushort { Clear = 0x0002, Cp437Data = 0x0003, @@ -8,10 +8,10 @@ internal enum DisplayCommand: ushort Brightness = 0x0007, HardReset = 0x000b, FadeOut = 0x000d, - BitmapLegacy = 0x0010, + [Obsolete("ignored by display code")] BitmapLegacy = 0x0010, BitmapLinear = 0x0012, BitmapLinearWin = 0x0013, BitmapLinearAnd = 0x0014, BitmapLinearOr = 0x0015, BitmapLinearXor = 0x0016, -} +} \ No newline at end of file diff --git a/TanksServer/GameLogic/CollideBulletsWithTanks.cs b/TanksServer/GameLogic/CollideBulletsWithTanks.cs index bd1ac06..7ccafd0 100644 --- a/TanksServer/GameLogic/CollideBulletsWithTanks.cs +++ b/TanksServer/GameLogic/CollideBulletsWithTanks.cs @@ -14,7 +14,7 @@ internal sealed class CollideBulletsWithTanks( { foreach (var tank in tanks) { - var (topLeft, bottomRight) = tank.GetBounds(); + var (topLeft, bottomRight) = TankManager.GetTankBounds(tank.Position.ToPixelPosition()); if (bullet.Position.X < topLeft.X || bullet.Position.X > bottomRight.X || bullet.Position.Y < topLeft.Y || bullet.Position.Y > bottomRight.Y) continue; diff --git a/TanksServer/GameLogic/MapService.cs b/TanksServer/GameLogic/MapService.cs index cfff6c4..0666cdd 100644 --- a/TanksServer/GameLogic/MapService.cs +++ b/TanksServer/GameLogic/MapService.cs @@ -2,15 +2,15 @@ namespace TanksServer.GameLogic; internal sealed class MapService { - public const int TilesPerRow = 44; - public const int TilesPerColumn = 20; - public const int TileSize = 8; - public const int PixelsPerRow = TilesPerRow * TileSize; - public const int PixelsPerColumn = TilesPerColumn * TileSize; + public const ushort TilesPerRow = 44; + public const ushort TilesPerColumn = 20; + public const ushort TileSize = 8; + public const ushort PixelsPerRow = TilesPerRow * TileSize; + public const ushort PixelsPerColumn = TilesPerColumn * TileSize; private readonly string _map = """ - ############################################ + #############..###################.######### #...................##.....................# #...................##.....................# #.....####......................####.......# @@ -29,7 +29,7 @@ internal sealed class MapService #.....####......................####.......# #...................##.....................# #...................##.....................# - ############################################ + #############..###################.######### """ .ReplaceLineEndings(string.Empty); diff --git a/TanksServer/GameLogic/MoveBullets.cs b/TanksServer/GameLogic/MoveBullets.cs index 950cb5a..6338bd8 100644 --- a/TanksServer/GameLogic/MoveBullets.cs +++ b/TanksServer/GameLogic/MoveBullets.cs @@ -1,6 +1,6 @@ namespace TanksServer.GameLogic; -internal sealed class MoveBullets(BulletManager bullets) : ITickStep +internal sealed class MoveBullets(BulletManager bullets, IOptions config) : ITickStep { public Task TickAsync() { @@ -10,12 +10,12 @@ internal sealed class MoveBullets(BulletManager bullets) : ITickStep return Task.CompletedTask; } - private static void MoveBullet(Bullet bullet) + private void MoveBullet(Bullet bullet) { - var angle = bullet.Rotation / 16 * 2 * Math.PI; + var angle = bullet.Rotation * 2 * Math.PI; bullet.Position = new FloatPosition( - X: bullet.Position.X + Math.Sin(angle) * 3, - Y: bullet.Position.Y - Math.Cos(angle) * 3 + x: bullet.Position.X + Math.Sin(angle) * config.Value.BulletSpeed, + y: bullet.Position.Y - Math.Cos(angle) * config.Value.BulletSpeed ); } -} +} \ No newline at end of file diff --git a/TanksServer/GameLogic/MoveTanks.cs b/TanksServer/GameLogic/MoveTanks.cs index 3c289e3..3c241f9 100644 --- a/TanksServer/GameLogic/MoveTanks.cs +++ b/TanksServer/GameLogic/MoveTanks.cs @@ -36,26 +36,30 @@ internal sealed class MoveTanks( return false; } - var angle = tank.Rotation / 16d * 2d * Math.PI; + var angle = tank.Rotation * 2d * Math.PI; var newX = tank.Position.X + Math.Sin(angle) * speed; var newY = tank.Position.Y - Math.Cos(angle) * speed; return TryMoveTankTo(tank, new FloatPosition(newX, newY)) - || TryMoveTankTo(tank, tank.Position with { X = newX }) - || TryMoveTankTo(tank, tank.Position with { Y = newY }); + || TryMoveTankTo(tank, new FloatPosition(newX, tank.Position.Y)) + || TryMoveTankTo(tank, new FloatPosition(tank.Position.X, newY)); } private bool TryMoveTankTo(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) }; + var (topLeft, bottomRight) = TankManager.GetTankBounds(newPosition.ToPixelPosition()); + TilePosition[] positions = [ + topLeft.ToTilePosition(), + new PixelPosition(bottomRight.X, topLeft.Y).ToTilePosition(), + new PixelPosition(topLeft.X, bottomRight.Y).ToTilePosition(), + bottomRight.ToTilePosition(), + ]; + if (positions.Any(map.IsCurrentlyWall)) return false; + // TODO: check tanks + tank.Position = newPosition; return true; } diff --git a/TanksServer/GameLogic/RotateTanks.cs b/TanksServer/GameLogic/RotateTanks.cs index b36af8b..168f86c 100644 --- a/TanksServer/GameLogic/RotateTanks.cs +++ b/TanksServer/GameLogic/RotateTanks.cs @@ -11,9 +11,9 @@ internal sealed class RotateTanks(TankManager tanks, IOptions candidates = []; - for (var x = 0; x < MapService.TilesPerRow; x++) - for (var y = 0; y < MapService.TilesPerColumn; y++) + for (ushort x = 0; x < MapService.TilesPerRow; x++) + for (ushort y = 0; y < MapService.TilesPerColumn; y++) { var tile = new TilePosition(x, y); diff --git a/TanksServer/GameLogic/TankManager.cs b/TanksServer/GameLogic/TankManager.cs index a8cd345..c22eb55 100644 --- a/TanksServer/GameLogic/TankManager.cs +++ b/TanksServer/GameLogic/TankManager.cs @@ -20,4 +20,12 @@ internal sealed class TankManager(ILogger logger) : IEnumerable new( - X: (ushort)((int)position.X % MapService.PixelsPerRow), - Y: (ushort)((int)position.Y % MapService.PixelsPerRow) + x: (ushort)((int)position.X % MapService.PixelsPerRow), + y: (ushort)((int)position.Y % MapService.PixelsPerRow) ); public static TilePosition ToTilePosition(this PixelPosition position) => new( - X: position.X / MapService.TileSize, - Y: position.Y / MapService.TileSize + x: (ushort)(position.X / MapService.TileSize), + y: (ushort)(position.Y / MapService.TileSize) ); } \ No newline at end of file diff --git a/TanksServer/Models/Tank.cs b/TanksServer/Models/Tank.cs index bc45529..551e5c2 100644 --- a/TanksServer/Models/Tank.cs +++ b/TanksServer/Models/Tank.cs @@ -1,20 +1,23 @@ +using System.Diagnostics; using TanksServer.GameLogic; namespace TanksServer.Models; -internal sealed class Tank(Player player, FloatPosition spawnPosition): IMapEntity +internal sealed class Tank(Player player, FloatPosition spawnPosition) : IMapEntity { private double _rotation; public Player Owner { get; } = player; - /// - /// Bounds: 0 (inclusive) .. 16 (exclusive) - /// public double Rotation { get => _rotation; - set => _rotation = (value + 16d) % 16d; + set + { + var newRotation = (value % 1d + 1d) % 1d; + Debug.Assert(newRotation is >= 0 and < 1); + _rotation = newRotation; + } } public FloatPosition Position { get; set; } = spawnPosition; @@ -22,12 +25,4 @@ internal sealed class Tank(Player player, FloatPosition spawnPosition): IMapEnti public DateTime NextShotAfter { get; set; } public bool Moved { get; set; } - - public (FloatPosition TopLeft, FloatPosition BottomRight) GetBounds() - { - return ( - Position, - new FloatPosition(Position.X + MapService.TileSize , Position.Y + MapService.TileSize ) - ); - } -} +} \ No newline at end of file diff --git a/TanksServer/Models/TilePosition.cs b/TanksServer/Models/TilePosition.cs index d68d44a..d4cd3d6 100644 --- a/TanksServer/Models/TilePosition.cs +++ b/TanksServer/Models/TilePosition.cs @@ -1,3 +1,9 @@ +using TanksServer.GameLogic; + namespace TanksServer.Models; -internal record struct TilePosition(int X, int Y); +internal readonly struct TilePosition(ushort x, ushort y) +{ + public ushort X { get; } = (ushort)((x + MapService.TilesPerRow) % MapService.TilesPerRow); + public ushort Y { get; } = (ushort)((y + MapService.TilesPerColumn) % MapService.TilesPerColumn); +} \ No newline at end of file