fix bullet cannot hit close to tank
This commit is contained in:
parent
6045de0c7d
commit
19e1792307
|
@ -108,4 +108,3 @@ There are other commands implemented as well, e.g. for changing the brightness.
|
||||||
## Backlog: Bugs, Wishes, Ideas
|
## Backlog: Bugs, Wishes, Ideas
|
||||||
- Generalize drawing of entities as there are multiple classes with pretty much the same code
|
- Generalize drawing of entities as there are multiple classes with pretty much the same code
|
||||||
- Generalize hit box collision
|
- Generalize hit box collision
|
||||||
- BUG: when standing next to a wall, the bullet sometimes misses the first pixel
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{12DB7D
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
global.json = global.json
|
global.json = global.json
|
||||||
shared.props = shared.props
|
shared.props = shared.props
|
||||||
|
Dockerfile = Dockerfile
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
|
|
|
@ -41,7 +41,7 @@ internal sealed class CollideBullets(
|
||||||
|
|
||||||
private bool BulletHitsTank(Bullet bullet)
|
private bool BulletHitsTank(Bullet bullet)
|
||||||
{
|
{
|
||||||
if (!TryHitTankAt(bullet.Position, bullet.Owner))
|
if (!TryHitTankAt(bullet.Position, bullet.Owner, DateTime.Now > bullet.OwnerCollisionAfter))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (bullet.IsExplosive)
|
if (bullet.IsExplosive)
|
||||||
|
@ -49,16 +49,20 @@ internal sealed class CollideBullets(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryHitTankAt(FloatPosition position, Player owner)
|
private bool TryHitTankAt(FloatPosition position, Player owner, bool canHitOwnTank)
|
||||||
{
|
{
|
||||||
foreach (var tank in entityManager.Tanks)
|
foreach (var tank in entityManager.Tanks)
|
||||||
{
|
{
|
||||||
|
var hitsOwnTank = owner == tank.Owner;
|
||||||
|
if (hitsOwnTank && !canHitOwnTank)
|
||||||
|
continue;
|
||||||
|
|
||||||
var (topLeft, bottomRight) = tank.Bounds;
|
var (topLeft, bottomRight) = tank.Bounds;
|
||||||
if (position.X < topLeft.X || position.X > bottomRight.X ||
|
if (position.X < topLeft.X || position.X > bottomRight.X ||
|
||||||
position.Y < topLeft.Y || position.Y > bottomRight.Y)
|
position.Y < topLeft.Y || position.Y > bottomRight.Y)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (owner != tank.Owner)
|
if (!hitsOwnTank)
|
||||||
owner.Scores.Kills++;
|
owner.Scores.Kills++;
|
||||||
tank.Owner.Scores.Deaths++;
|
tank.Owner.Scores.Deaths++;
|
||||||
|
|
||||||
|
@ -79,7 +83,7 @@ internal sealed class CollideBullets(
|
||||||
if (options.Value.DestructibleWalls && map.Current.TryDestroyWallAt(offsetPixel))
|
if (options.Value.DestructibleWalls && map.Current.TryDestroyWallAt(offsetPixel))
|
||||||
owner.Scores.WallsDestroyed++;
|
owner.Scores.WallsDestroyed++;
|
||||||
|
|
||||||
TryHitTankAt(offsetPixel.ToFloatPosition(), owner);
|
TryHitTankAt(offsetPixel.ToFloatPosition(), owner, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,15 @@ internal sealed class MapEntityManager(
|
||||||
.Concat(PowerUps);
|
.Concat(PowerUps);
|
||||||
|
|
||||||
public void SpawnBullet(Player tankOwner, FloatPosition position, double rotation, bool isExplosive)
|
public void SpawnBullet(Player tankOwner, FloatPosition position, double rotation, bool isExplosive)
|
||||||
=> _bullets.Add(new Bullet(tankOwner, position, rotation, isExplosive, DateTime.Now + _bulletTimeout));
|
=> _bullets.Add(new Bullet
|
||||||
|
{
|
||||||
|
Owner = tankOwner,
|
||||||
|
Position = position,
|
||||||
|
Rotation = rotation,
|
||||||
|
IsExplosive = isExplosive,
|
||||||
|
Timeout = DateTime.Now + _bulletTimeout,
|
||||||
|
OwnerCollisionAfter = DateTime.Now + TimeSpan.FromSeconds(1),
|
||||||
|
});
|
||||||
|
|
||||||
public void RemoveBulletsWhere(Predicate<Bullet> predicate) => _bullets.RemoveWhere(predicate);
|
public void RemoveBulletsWhere(Predicate<Bullet> predicate) => _bullets.RemoveWhere(predicate);
|
||||||
|
|
||||||
|
|
|
@ -26,33 +26,10 @@ internal sealed class ShootFromTanks(
|
||||||
|
|
||||||
tank.NextShotAfter = DateTime.Now.AddMilliseconds(_config.ShootDelayMs);
|
tank.NextShotAfter = DateTime.Now.AddMilliseconds(_config.ShootDelayMs);
|
||||||
|
|
||||||
var rotation = tank.Orientation / 16d;
|
var explosive = tank.ExplosiveBullets > 0;
|
||||||
var angle = rotation * 2d * Math.PI;
|
if (explosive)
|
||||||
|
|
||||||
/* 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")
|
|
||||||
};
|
|
||||||
|
|
||||||
var position = new FloatPosition(
|
|
||||||
tank.Position.X + Math.Sin(angle) * distance,
|
|
||||||
tank.Position.Y - Math.Cos(angle) * distance
|
|
||||||
);
|
|
||||||
|
|
||||||
var explosive = false;
|
|
||||||
if (tank.ExplosiveBullets > 0)
|
|
||||||
{
|
|
||||||
tank.ExplosiveBullets--;
|
tank.ExplosiveBullets--;
|
||||||
explosive = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
entityManager.SpawnBullet(tank.Owner, position, rotation, explosive);
|
entityManager.SpawnBullet(tank.Owner, tank.Position, tank.Orientation / 16d, explosive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
namespace TanksServer.Models;
|
namespace TanksServer.Models;
|
||||||
|
|
||||||
internal sealed class Bullet(Player tankOwner, FloatPosition position, double rotation, bool isExplosive, DateTime timeout) : IMapEntity
|
internal sealed class Bullet : IMapEntity
|
||||||
{
|
{
|
||||||
public Player Owner { get; } = tankOwner;
|
public required Player Owner { get; init; }
|
||||||
|
|
||||||
public double Rotation { get; } = rotation;
|
public required double Rotation { get; init; }
|
||||||
|
|
||||||
public FloatPosition Position { get; set; } = position;
|
public required FloatPosition Position { get; set; }
|
||||||
|
|
||||||
public bool IsExplosive { get; } = isExplosive;
|
public required bool IsExplosive { get; init; }
|
||||||
|
|
||||||
public DateTime Timeout { get; } = timeout;
|
public required DateTime Timeout { get; init; }
|
||||||
|
|
||||||
public PixelBounds Bounds => new (Position.ToPixelPosition(), Position.ToPixelPosition());
|
public PixelBounds Bounds => new(Position.ToPixelPosition(), Position.ToPixelPosition());
|
||||||
|
|
||||||
|
internal required DateTime OwnerCollisionAfter { get; init; }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue