servicepoint-tanks/tanks-backend/TanksServer/GameLogic/CollideBullets.cs

108 lines
3 KiB
C#
Raw Normal View History

2024-04-28 18:44:03 +02:00
using TanksServer.Graphics;
2024-04-17 19:34:19 +02:00
namespace TanksServer.GameLogic;
internal sealed class CollideBullets(
MapEntityManager entityManager,
MapService map,
IOptions<GameRules> options,
TankSpawnQueue tankSpawnQueue
) : ITickStep
{
2024-04-28 18:44:03 +02:00
private readonly Sprite _explosiveSprite = Sprite.FromImageFile("assets/explosion.png");
2024-04-17 19:34:19 +02:00
2024-04-28 15:34:32 +02:00
public ValueTask TickAsync(TimeSpan _)
2024-04-17 19:34:19 +02:00
{
2024-04-22 19:44:28 +02:00
entityManager.RemoveWhere(BulletHitsTank);
entityManager.RemoveWhere(BulletHitsWall);
entityManager.RemoveWhere(BulletTimesOut);
2024-04-28 15:34:32 +02:00
return ValueTask.CompletedTask;
2024-04-17 19:34:19 +02:00
}
2024-04-22 19:44:28 +02:00
private bool BulletTimesOut(Bullet bullet)
2024-04-19 13:32:41 +02:00
{
if (bullet.Timeout > DateTime.Now)
return false;
2024-04-28 18:44:03 +02:00
ExplodeAt(bullet.Position.ToPixelPosition(), bullet.IsExplosive, bullet.Owner);
2024-04-19 13:32:41 +02:00
return true;
}
2024-04-22 19:44:28 +02:00
private bool BulletHitsWall(Bullet bullet)
2024-04-17 19:34:19 +02:00
{
var pixel = bullet.Position.ToPixelPosition();
if (!map.Current.IsWall(pixel))
return false;
2024-04-28 18:44:03 +02:00
ExplodeAt(pixel, bullet.IsExplosive, bullet.Owner);
2024-04-17 19:34:19 +02:00
return true;
}
private bool BulletHitsTank(Bullet bullet)
{
2024-04-28 18:44:03 +02:00
var hitTank = GetTankAt(bullet.Position, bullet.Owner, DateTime.Now > bullet.OwnerCollisionAfter);
if (hitTank == null)
2024-04-17 19:34:19 +02:00
return false;
2024-04-28 18:44:03 +02:00
ExplodeAt(bullet.Position.ToPixelPosition(), bullet.IsExplosive, bullet.Owner);
2024-04-17 19:34:19 +02:00
return true;
}
2024-04-28 18:44:03 +02:00
private Tank? GetTankAt(FloatPosition position, Player owner, bool canHitOwnTank)
2024-04-17 19:34:19 +02:00
{
foreach (var tank in entityManager.Tanks)
{
2024-04-21 20:20:30 +02:00
var hitsOwnTank = owner == tank.Owner;
if (hitsOwnTank && !canHitOwnTank)
continue;
2024-04-17 19:34:19 +02:00
var (topLeft, bottomRight) = tank.Bounds;
if (position.X < topLeft.X || position.X > bottomRight.X ||
position.Y < topLeft.Y || position.Y > bottomRight.Y)
continue;
2024-04-28 18:44:03 +02:00
return tank;
2024-04-17 19:34:19 +02:00
}
2024-04-28 18:44:03 +02:00
return null;
2024-04-17 19:34:19 +02:00
}
2024-04-28 18:44:03 +02:00
private void ExplodeAt(PixelPosition pixel, bool isExplosive, Player owner)
2024-04-17 19:34:19 +02:00
{
2024-04-28 18:44:03 +02:00
if (!isExplosive)
{
Core(pixel);
return;
}
pixel = pixel.GetPixelRelative(-4, -4);
for (short dx = 0; dx < _explosiveSprite.Width; dx++)
for (short dy = 0; dy < _explosiveSprite.Height; dy++)
{
if (!_explosiveSprite[dx, dy].HasValue)
continue;
Core(pixel.GetPixelRelative(dx, dy));
}
return;
void Core(PixelPosition position)
2024-04-17 19:34:19 +02:00
{
2024-04-28 18:44:03 +02:00
if (options.Value.DestructibleWalls && map.Current.TryDestroyWallAt(position))
2024-04-19 13:34:56 +02:00
owner.Scores.WallsDestroyed++;
2024-04-28 18:44:03 +02:00
var tank = GetTankAt(position.ToFloatPosition(), owner, true);
if (tank == null)
return;
if (tank.Owner == owner)
owner.Scores.Kills++;
tank.Owner.Scores.Deaths++;
entityManager.Remove(tank);
tankSpawnQueue.EnqueueForDelayedSpawn(tank.Owner);
2024-04-17 19:34:19 +02:00
}
}
}