wall collision
This commit is contained in:
		
							parent
							
								
									54b840da3e
								
							
						
					
					
						commit
						dd6b0fffc1
					
				
					 6 changed files with 68 additions and 39 deletions
				
			
		|  | @ -1,6 +1,7 @@ | ||||||
| using System.Collections.Concurrent; | using System.Collections.Concurrent; | ||||||
| using System.Diagnostics; | using System.Diagnostics; | ||||||
| using System.Net.WebSockets; | using System.Net.WebSockets; | ||||||
|  | using System.Threading.Channels; | ||||||
| using Microsoft.Extensions.Hosting; | using Microsoft.Extensions.Hosting; | ||||||
| using Microsoft.Extensions.Logging; | using Microsoft.Extensions.Logging; | ||||||
| using TanksServer.Helpers; | using TanksServer.Helpers; | ||||||
|  | @ -76,7 +77,14 @@ internal sealed class ClientScreenServer( | ||||||
|             if (await _wantedFrames.WaitAsync(TimeSpan.Zero)) |             if (await _wantedFrames.WaitAsync(TimeSpan.Zero)) | ||||||
|             { |             { | ||||||
|                 _logger.LogTrace("sending"); |                 _logger.LogTrace("sending"); | ||||||
|                 await _channel.Writer.WriteAsync(buf.Data); |                 try | ||||||
|  |                 { | ||||||
|  |                     await _channel.Writer.WriteAsync(buf.Data); | ||||||
|  |                 } | ||||||
|  |                 catch (ChannelClosedException) | ||||||
|  |                 { | ||||||
|  |                     _logger.LogWarning("send failed, channel is closed"); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|  | @ -87,9 +95,7 @@ internal sealed class ClientScreenServer( | ||||||
|         private async Task ReceiveAsync() |         private async Task ReceiveAsync() | ||||||
|         { |         { | ||||||
|             await foreach (var _ in _channel.Reader.ReadAllAsync())  |             await foreach (var _ in _channel.Reader.ReadAllAsync())  | ||||||
|             { |  | ||||||
|                 _wantedFrames.Release(); |                 _wantedFrames.Release(); | ||||||
|             } |  | ||||||
|              |              | ||||||
|             _logger.LogTrace("done receiving"); |             _logger.LogTrace("done receiving"); | ||||||
|             _server.Remove(this); |             _server.Remove(this); | ||||||
|  |  | ||||||
|  | @ -1,3 +1,8 @@ | ||||||
|  | using TanksServer.Services; | ||||||
|  | 
 | ||||||
| namespace TanksServer.Models; | namespace TanksServer.Models; | ||||||
| 
 | 
 | ||||||
| internal record struct FloatPosition(double X, double Y); | internal readonly record struct FloatPosition(double X, double Y) | ||||||
|  | { | ||||||
|  |     public PixelPosition ToPixelPosition() => new((int)X % MapService.PixelsPerRow, (int)Y % MapService.PixelsPerRow); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -6,10 +6,13 @@ internal sealed class Tank(Player player, FloatPosition spawnPosition) | ||||||
| 
 | 
 | ||||||
|     public Player Owner { get; } = player; |     public Player Owner { get; } = player; | ||||||
| 
 | 
 | ||||||
|  |     /// <summary> | ||||||
|  |     /// Bounds: 0 (inclusive) .. 16 (exclusive) | ||||||
|  |     /// </summary> | ||||||
|     public double Rotation |     public double Rotation | ||||||
|     { |     { | ||||||
|         get => _rotation; |         get => _rotation; | ||||||
|         set => _rotation = value % 16d; |         set => _rotation = (value + 16d) % 16d; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public FloatPosition Position { get; set; } = spawnPosition; |     public FloatPosition Position { get; set; } = spawnPosition; | ||||||
|  |  | ||||||
|  | @ -75,7 +75,7 @@ internal sealed class PixelDrawer : ITickStep | ||||||
|     { |     { | ||||||
|         foreach (var tank in _tanks) |         foreach (var tank in _tanks) | ||||||
|         { |         { | ||||||
|             var pos = new PixelPosition((int)tank.Position.X, (int)tank.Position.Y); |             var pos = tank.Position.ToPixelPosition(); | ||||||
|             var rotationVariant = (int)Math.Floor(tank.Rotation); |             var rotationVariant = (int)Math.Floor(tank.Rotation); | ||||||
|             for (var dy = 0; dy < MapService.TileSize; dy++) |             for (var dy = 0; dy < MapService.TileSize; dy++) | ||||||
|             { |             { | ||||||
|  | @ -83,9 +83,11 @@ internal sealed class PixelDrawer : ITickStep | ||||||
| 
 | 
 | ||||||
|                 for (var dx = 0; dx < MapService.TileSize; dx++) |                 for (var dx = 0; dx < MapService.TileSize; dx++) | ||||||
|                 { |                 { | ||||||
|  |                     if (!TankSpriteAt(dx, dy, rotationVariant)) | ||||||
|  |                         continue; | ||||||
|  |                      | ||||||
|                     var i = rowStartIndex + pos.X + dx; |                     var i = rowStartIndex + pos.X + dx; | ||||||
|                     if (TankSpriteAt(dx, dy, rotationVariant)) |                     buf.Pixels[i] = true; | ||||||
|                         buf.Pixels[i] = true; |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ using TanksServer.Models; | ||||||
| 
 | 
 | ||||||
| namespace TanksServer.Services; | namespace TanksServer.Services; | ||||||
| 
 | 
 | ||||||
| internal sealed class TankManager(ILogger<TankManager> logger, IOptions<TanksConfiguration> options) | internal sealed class TankManager(ILogger<TankManager> logger, IOptions<TanksConfiguration> options, MapService map) | ||||||
|     : ITickStep, IEnumerable<Tank> |     : ITickStep, IEnumerable<Tank> | ||||||
| { | { | ||||||
|     private readonly ConcurrentBag<Tank> _tanks = new(); |     private readonly ConcurrentBag<Tank> _tanks = new(); | ||||||
|  | @ -33,38 +33,51 @@ internal sealed class TankManager(ILogger<TankManager> logger, IOptions<TanksCon | ||||||
|         logger.LogTrace("moving tank for player {}", tank.Owner.Id); |         logger.LogTrace("moving tank for player {}", tank.Owner.Id); | ||||||
|         var player = tank.Owner; |         var player = tank.Owner; | ||||||
| 
 | 
 | ||||||
|         // move turret |         if (player.Controls.TurnLeft) | ||||||
|         if (player.Controls.TurnLeft) Rotate(tank, -_config.TurnSpeed); |             tank.Rotation -= _config.TurnSpeed; | ||||||
|         if (player.Controls.TurnRight) Rotate(tank, +_config.TurnSpeed); |         if (player.Controls.TurnRight) | ||||||
|  |             tank.Rotation += _config.TurnSpeed; | ||||||
| 
 | 
 | ||||||
|         if (player.Controls is { Forward: false, Backward: false }) |         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; |             return false; | ||||||
| 
 | 
 | ||||||
|         var direction = player.Controls.Forward ? 1 : -1; |         tank.Position = newPosition; | ||||||
|         var angle = tank.Rotation / 16d * 2d * Math.PI; |  | ||||||
|         var newX = tank.Position.X + Math.Sin(angle) * direction * _config.MoveSpeed; |  | ||||||
|         var newY = tank.Position.Y - Math.Cos(angle) * direction * _config.MoveSpeed; |  | ||||||
| 
 |  | ||||||
|         return TryMove(tank, newX, newY) |  | ||||||
|                || TryMove(tank, newX, tank.Position.Y) |  | ||||||
|                || TryMove(tank, tank.Position.X, newY); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private static bool TryMove(Tank tank, double newX, double newY) |  | ||||||
|     { |  | ||||||
|         // TODO implement |  | ||||||
| 
 |  | ||||||
|         tank.Position = new FloatPosition(newX, newY); |  | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void Rotate(Tank t, double speed) |  | ||||||
|     { |  | ||||||
|         var newRotation = (t.Rotation + speed + 16) % 16; |  | ||||||
|         logger.LogTrace("rotating tank for {} from {} to {}", t.Owner.Id, t.Rotation, newRotation); |  | ||||||
|         t.Rotation = newRotation; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); |     IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | ||||||
|     public IEnumerator<Tank> GetEnumerator() => _tanks.GetEnumerator(); |     public IEnumerator<Tank> GetEnumerator() => _tanks.GetEnumerator(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ | ||||||
|         "LogLevel": { |         "LogLevel": { | ||||||
|             "Default": "Information", |             "Default": "Information", | ||||||
|             "Microsoft.AspNetCore": "Warning", |             "Microsoft.AspNetCore": "Warning", | ||||||
|             "TanksServer": "Trace" |             "TanksServer": "Debug" | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|     "AllowedHosts": "*", |     "AllowedHosts": "*", | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Vinzenz Schroeter
						Vinzenz Schroeter