servicepoint-tanks/TanksServer/GameLogic/ShootFromTanks.cs

53 lines
1.6 KiB
C#
Raw Normal View History

2024-04-16 20:24:29 +02:00
using System.Diagnostics;
2024-04-10 19:25:45 +02:00
namespace TanksServer.GameLogic;
2024-04-07 19:52:16 +02:00
internal sealed class ShootFromTanks(
2024-04-09 22:38:56 +02:00
TankManager tanks,
IOptions<TanksConfiguration> options,
BulletManager bulletManager
2024-04-07 19:52:16 +02:00
) : ITickStep
{
private readonly TanksConfiguration _config = options.Value;
2024-04-16 19:40:08 +02:00
public Task TickAsync(TimeSpan _)
2024-04-07 19:52:16 +02:00
{
foreach (var tank in tanks.Where(t => !t.Moved))
Shoot(tank);
return Task.CompletedTask;
}
private void Shoot(Tank tank)
{
if (!tank.Owner.Controls.Shoot)
return;
if (tank.NextShotAfter >= DateTime.Now)
return;
tank.NextShotAfter = DateTime.Now.AddMilliseconds(_config.ShootDelayMs);
2024-04-13 18:35:36 +02:00
var rotation = tank.Orientation / 16d;
var angle = rotation * 2d * Math.PI;
2024-04-16 20:24:29 +02:00
/* TODO: when standing next to a wall, the bullet sometimes misses the first pixel.
Spawning the bullet to close to the tank instead means the tank instantly hits itself.
Because the tank has a float position, but hit boxes are based on pixels, this problem has been deemed complex
enough to do later. These values mostly work. */
var distance = (tank.Orientation % 4) switch
{
0 => 4.4d,
1 or 3 => 5.4d,
2 => 6d,
_ => throw new UnreachableException("this should not be possible")
};
2024-04-07 19:52:16 +02:00
var position = new FloatPosition(
2024-04-16 20:24:29 +02:00
tank.Position.X + Math.Sin(angle) * distance,
tank.Position.Y - Math.Cos(angle) * distance
2024-04-07 19:52:16 +02:00
);
2024-04-16 20:24:29 +02:00
bulletManager.Spawn(tank.Owner, position, rotation);
2024-04-07 19:52:16 +02:00
}
}