destructible walls

This commit is contained in:
Vinzenz Schroeter 2024-04-16 18:55:34 +02:00
parent a0a0762f84
commit dec571d8c1
5 changed files with 72 additions and 55 deletions

View file

@ -4,10 +4,17 @@ internal sealed class CollideBulletsWithMap(BulletManager bullets, MapService ma
{ {
public Task TickAsync() public Task TickAsync()
{ {
bullets.RemoveWhere(BulletHitsWall); bullets.RemoveWhere(TryHitAndDestroyWall);
return Task.CompletedTask; return Task.CompletedTask;
} }
private bool BulletHitsWall(Bullet bullet) => private bool TryHitAndDestroyWall(Bullet bullet)
map.Current.IsWall(bullet.Position.ToPixelPosition()); {
var pixel = bullet.Position.ToPixelPosition();
if (!map.Current.IsWall(pixel))
return false;
map.Current.DestroyWallAt(pixel);
return true;
}
} }

View file

@ -12,20 +12,25 @@ internal sealed class MapService
public const ushort PixelsPerRow = TilesPerRow * TileSize; public const ushort PixelsPerRow = TilesPerRow * TileSize;
public const ushort PixelsPerColumn = TilesPerColumn * TileSize; public const ushort PixelsPerColumn = TilesPerColumn * TileSize;
public Map[] All { get; } private readonly Dictionary<string, bool[,]> _maps = new();
public Map Current { get; set; } public IEnumerable<string> MapNames => _maps.Keys;
public Map Current { get; private set; }
public MapService() public MapService()
{ {
var textMaps = Directory.EnumerateFiles("./assets/maps/", "*.txt").Select(LoadMapString); foreach (var file in Directory.EnumerateFiles("./assets/maps/", "*.txt"))
var pngMaps = Directory.EnumerateFiles("./assets/maps/", "*.png").Select(LoadMapPng); LoadMapString(file);
foreach (var file in Directory.EnumerateFiles("./assets/maps/", "*.png"))
LoadMapPng(file);
All = textMaps.Concat(pngMaps).ToArray(); var chosenMapIndex = Random.Shared.Next(_maps.Count);
Current = All[Random.Shared.Next(All.Length)]; var chosenMapName = _maps.Keys.Skip(chosenMapIndex).First();
Current = new Map(chosenMapName, _maps[chosenMapName]);
} }
private static Map LoadMapPng(string file) private void LoadMapPng(string file)
{ {
using var image = Image.Load<Rgba32>(file); using var image = Image.Load<Rgba32>(file);
@ -39,10 +44,10 @@ internal sealed class MapService
for (var x = 0; x < image.Width; x++) for (var x = 0; x < image.Width; x++)
walls[x, y] = image[x, y] == whitePixel; walls[x, y] = image[x, y] == whitePixel;
return new Map(Path.GetFileName(file),walls); _maps.Add(Path.GetFileName(file), walls);
} }
private static Map LoadMapString(string file) private void LoadMapString(string file)
{ {
var map = File.ReadAllText(file).ReplaceLineEndings(string.Empty).Trim(); var map = File.ReadAllText(file).ReplaceLineEndings(string.Empty).Trim();
if (map.Length != TilesPerColumn * TilesPerRow) if (map.Length != TilesPerColumn * TilesPerRow)
@ -65,7 +70,15 @@ internal sealed class MapService
} }
} }
return new Map(Path.GetFileName(file), walls); _maps.Add(Path.GetFileName(file), walls);
}
public bool TrySwitchTo(string name)
{
if (!_maps.TryGetValue(name, out var mapData))
return false;
Current = new Map(name, mapData);
return true;
} }
} }
@ -90,4 +103,6 @@ internal sealed class Map(string name, bool[,] walls)
return false; return false;
} }
public void DestroyWallAt(PixelPosition pixel) => walls[pixel.X, pixel.Y] = false;
} }

View file

@ -6,5 +6,5 @@ namespace TanksServer.Interactivity;
[JsonSerializable(typeof(IEnumerable<Player>))] [JsonSerializable(typeof(IEnumerable<Player>))]
[JsonSerializable(typeof(Guid))] [JsonSerializable(typeof(Guid))]
[JsonSerializable(typeof(NameId))] [JsonSerializable(typeof(NameId))]
[JsonSerializable(typeof(Dictionary<int, string>))] [JsonSerializable(typeof(IEnumerable<string>))]
internal sealed partial class AppSerializerContext : JsonSerializerContext; internal sealed partial class AppSerializerContext : JsonSerializerContext;

View file

@ -73,19 +73,14 @@ public static class Program
return Results.Empty; return Results.Empty;
}); });
app.MapGet("/map", () => app.MapGet("/map", () =>mapService.MapNames);
{
var dict = mapService.All
.Select((m, i) => (m.Name, i))
.ToDictionary(pair => pair.i, pair => pair.Name);
return dict;
});
app.MapPost("/map", ([FromQuery] int index) => app.MapPost("/map", ([FromQuery] string name) =>
{ {
if (index < 0 || index >= mapService.All.Length) if (string.IsNullOrWhiteSpace(name))
return Results.NotFound("index does not exist"); return Results.BadRequest("invalid map name");
mapService.Current = mapService.All[index]; if (!mapService.TrySwitchTo(name))
return Results.NotFound("map with name not found");
return Results.Ok(); return Results.Ok();
}); });

View file

@ -1,33 +1,33 @@
{ {
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"Default": "Information", "Default": "Information",
"Microsoft.AspNetCore": "Warning", "Microsoft.AspNetCore": "Warning",
"TanksServer": "Debug", "TanksServer": "Debug",
"Microsoft.AspNetCore.HttpLogging": "Information" "Microsoft.AspNetCore.HttpLogging": "Information"
}
},
"AllowedHosts": "*",
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:3000"
}
}
},
"ServicePointDisplay": {
"Enable": true,
"Hostname": "172.23.42.29",
"Port": 2342
},
"Tanks": {
"MoveSpeed": 1.5,
"TurnSpeed": 0.02,
"ShootDelayMs": 450,
"BulletSpeed":4
},
"Players": {
"SpawnDelayMs": 3000,
"IdleTimeoutMs": 30000
} }
},
"AllowedHosts": "*",
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:3000"
}
}
},
"ServicePointDisplay": {
"Enable": true,
"Hostname": "172.23.42.29",
"Port": 2342
},
"Tanks": {
"MoveSpeed": 1.5,
"TurnSpeed": 0.02,
"ShootDelayMs": 450,
"BulletSpeed": 3
},
"Players": {
"SpawnDelayMs": 3000,
"IdleTimeoutMs": 30000
}
} }