improve spawn position checks
This commit is contained in:
parent
91ab911f9c
commit
ad211433fb
16 changed files with 147 additions and 80 deletions
|
@ -1,7 +1,7 @@
|
|||
namespace TanksServer.GameLogic;
|
||||
|
||||
internal sealed class CollideBulletsWithTanks(
|
||||
BulletManager bullets, TankManager tanks, SpawnQueueProvider spawnQueueProvider
|
||||
BulletManager bullets, TankManager tanks, SpawnQueue spawnQueue
|
||||
) : ITickStep
|
||||
{
|
||||
public Task TickAsync()
|
||||
|
@ -24,7 +24,7 @@ internal sealed class CollideBulletsWithTanks(
|
|||
tank.Owner.Deaths++;
|
||||
|
||||
tanks.Remove(tank);
|
||||
spawnQueueProvider.Queue.Enqueue(tank.Owner);
|
||||
spawnQueue.EnqueueForDelayedSpawn(tank.Owner);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
6
TanksServer/GameLogic/PlayersConfiguration.cs
Normal file
6
TanksServer/GameLogic/PlayersConfiguration.cs
Normal file
|
@ -0,0 +1,6 @@
|
|||
namespace TanksServer.GameLogic;
|
||||
|
||||
public class PlayersConfiguration
|
||||
{
|
||||
public int SpawnDelayMs { get; set; }
|
||||
}
|
|
@ -1,25 +1,29 @@
|
|||
namespace TanksServer.GameLogic;
|
||||
|
||||
internal sealed class SpawnNewTanks(TankManager tanks, MapService map, SpawnQueueProvider queueProvider) : ITickStep
|
||||
internal sealed class SpawnNewTanks(
|
||||
TankManager tanks,
|
||||
MapService map,
|
||||
SpawnQueue queue,
|
||||
BulletManager bullets
|
||||
) : ITickStep
|
||||
{
|
||||
public Task TickAsync()
|
||||
{
|
||||
while (queueProvider.Queue.TryDequeue(out var player))
|
||||
if (!queue.TryDequeueNext(out var player))
|
||||
return Task.CompletedTask;
|
||||
|
||||
tanks.Add(new Tank(player, ChooseSpawnPosition())
|
||||
{
|
||||
var tank = new Tank(player, ChooseSpawnPosition())
|
||||
{
|
||||
Rotation = Random.Shared.Next(0, 16)
|
||||
};
|
||||
tanks.Add(tank);
|
||||
}
|
||||
Rotation = Random.Shared.Next(0, 16)
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private FloatPosition ChooseSpawnPosition()
|
||||
{
|
||||
List<TilePosition> candidates = new();
|
||||
|
||||
Dictionary<TilePosition, double> candidates = [];
|
||||
|
||||
for (var x = 0; x < MapService.TilesPerRow; x++)
|
||||
for (var y = 0; y < MapService.TilesPerColumn; y++)
|
||||
{
|
||||
|
@ -27,15 +31,24 @@ internal sealed class SpawnNewTanks(TankManager tanks, MapService map, SpawnQueu
|
|||
|
||||
if (map.IsCurrentlyWall(tile))
|
||||
continue;
|
||||
|
||||
var tilePixelCenter = tile.GetPixelRelative(4, 4);
|
||||
|
||||
var minDistance = bullets.GetAll()
|
||||
.Cast<IMapEntity>()
|
||||
.Concat(tanks)
|
||||
.Select(entity => Math.Sqrt(
|
||||
Math.Pow(entity.Position.X - tilePixelCenter.X, 2) +
|
||||
Math.Pow(entity.Position.Y - tilePixelCenter.Y, 2)))
|
||||
.Aggregate(double.MaxValue, Math.Min);
|
||||
|
||||
// TODO: check tanks and bullets
|
||||
candidates.Add(tile);
|
||||
candidates.Add(tile, minDistance);
|
||||
}
|
||||
|
||||
var chosenTile = candidates[Random.Shared.Next(candidates.Count)];
|
||||
var min = candidates.MaxBy(kvp => kvp.Value).Key;
|
||||
return new FloatPosition(
|
||||
chosenTile.X * MapService.TileSize,
|
||||
chosenTile.Y * MapService.TileSize
|
||||
min.X * MapService.TileSize,
|
||||
min.Y * MapService.TileSize
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
36
TanksServer/GameLogic/SpawnQueue.cs
Normal file
36
TanksServer/GameLogic/SpawnQueue.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace TanksServer.GameLogic;
|
||||
|
||||
internal sealed class SpawnQueue(
|
||||
IOptions<PlayersConfiguration> options
|
||||
)
|
||||
{
|
||||
private ConcurrentQueue<Player> _queue = new();
|
||||
private ConcurrentDictionary<Player, DateTime> _spawnTimes = new();
|
||||
private readonly TimeSpan _spawnDelay = TimeSpan.FromMilliseconds(options.Value.SpawnDelayMs);
|
||||
|
||||
public void EnqueueForImmediateSpawn(Player player)
|
||||
{
|
||||
_queue.Enqueue(player);
|
||||
}
|
||||
|
||||
public void EnqueueForDelayedSpawn(Player player)
|
||||
{
|
||||
_queue.Enqueue(player);
|
||||
_spawnTimes.AddOrUpdate(player, DateTime.MinValue, (_, _) => DateTime.Now + _spawnDelay);
|
||||
}
|
||||
|
||||
public bool TryDequeueNext([MaybeNullWhen(false)] out Player player)
|
||||
{
|
||||
if (!_queue.TryDequeue(out player))
|
||||
return false;
|
||||
|
||||
var now = DateTime.Now;
|
||||
if (_spawnTimes.GetOrAdd(player, DateTime.MinValue) <= now)
|
||||
return true;
|
||||
|
||||
_queue.Enqueue(player);
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
namespace TanksServer.GameLogic;
|
||||
|
||||
internal sealed class SpawnQueueProvider
|
||||
{
|
||||
public ConcurrentQueue<Player> Queue { get; } = new();
|
||||
}
|
9
TanksServer/GameLogic/TanksConfiguration.cs
Normal file
9
TanksServer/GameLogic/TanksConfiguration.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace TanksServer.GameLogic;
|
||||
|
||||
public class TanksConfiguration
|
||||
{
|
||||
public double MoveSpeed { get; set; }
|
||||
public double TurnSpeed { get; set; }
|
||||
public double ShootDelayMs { get; set; }
|
||||
public double BulletSpeed { get; set; }
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue