Files

140 lines
4.9 KiB
C#
Raw Permalink Normal View History

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Theriapolis.Core.Data;
using Theriapolis.Core.World;
namespace Theriapolis.Game.Rendering;
/// <summary>
/// Manages the biome tile textures used by the world-map renderer.
/// For Phase 0/1, all tiles are generated at runtime as flat-colour 32×32 squares
/// with a 1px darker border and a single centered letter.
/// Final art will replace these by swapping file contents; no code changes needed.
/// </summary>
public sealed class TileAtlas : IDisposable
{
private readonly GraphicsDevice _gd;
private readonly Dictionary<BiomeId, Texture2D> _textures = new();
private readonly Dictionary<int, Texture2D> _settlementIcons = new(); // keyed by tier
private SpriteFont? _font;
private bool _disposed;
public GraphicsDevice GraphicsDevice => _gd;
// Fallback solid-color texture for any biome that has no dedicated entry
private Texture2D? _fallback;
public TileAtlas(GraphicsDevice gd)
{
_gd = gd;
}
/// <summary>
/// Generate all placeholder textures from the loaded BiomeDef array.
/// Call once after content is loaded.
/// </summary>
public void GeneratePlaceholders(BiomeDef[] biomes, SpriteFont? font = null)
{
_font = font;
foreach (var def in biomes)
{
var biomeId = BiomeAssignHelper.ParseBiomeId(def.Id);
if (_textures.ContainsKey(biomeId)) continue;
_textures[biomeId] = MakeTile(def);
}
_fallback = MakeSolidColor(Color.HotPink); // obvious "missing art" colour
GenerateSettlementIcons();
}
/// <summary>Returns the settlement icon texture for the given tier (15).</summary>
public Texture2D GetSettlementIcon(int tier)
{
if (_settlementIcons.TryGetValue(tier, out var tex)) return tex;
return _fallback ?? _textures.Values.First();
}
private void GenerateSettlementIcons()
{
// Tier 1: large gold diamond (capital)
_settlementIcons[1] = MakeSettlementIcon(20, new Color(255, 215, 0), diamond: true);
// Tier 2: white square (city)
_settlementIcons[2] = MakeSettlementIcon(14, new Color(230, 230, 230), diamond: false);
// Tier 3: light-blue circle (town)
_settlementIcons[3] = MakeSettlementIcon(10, new Color(150, 200, 255), diamond: false);
// Tier 4: pale dot (village)
_settlementIcons[4] = MakeSettlementIcon(6, new Color(200, 200, 200), diamond: false);
// Tier 5 (PoI): small red circle
_settlementIcons[5] = MakeSettlementIcon(5, new Color(200, 60, 60), diamond: false);
}
private Texture2D MakeSettlementIcon(int size, Color fill, bool diamond)
{
var tex = new Texture2D(_gd, size, size);
var pixels = new Color[size * size];
float cx = (size - 1) * 0.5f;
float cy = (size - 1) * 0.5f;
for (int py = 0; py < size; py++)
for (int px = 0; px < size; px++)
{
float nx = px - cx, ny = py - cy;
bool inside = diamond
? (MathF.Abs(nx) + MathF.Abs(ny)) <= size * 0.5f
: (nx * nx + ny * ny) <= (cx * cx);
pixels[py * size + px] = inside ? fill : Color.Transparent;
}
tex.SetData(pixels);
return tex;
}
/// <summary>Returns the texture for the given biome, falling back to the error texture.</summary>
public Texture2D GetTile(BiomeId biome)
{
if (_textures.TryGetValue(biome, out var tex)) return tex;
return _fallback ?? _textures.Values.First();
}
// ── Texture generation helpers ────────────────────────────────────────────
private Texture2D MakeTile(BiomeDef def)
{
int size = Theriapolis.Core.C.WORLD_TILE_PIXELS;
var (r, g, b) = def.ParsedColor();
var fillColor = new Color(r, g, b);
var tex = new Texture2D(_gd, size, size);
var pixels = new Color[size * size];
Array.Fill(pixels, fillColor);
tex.SetData(pixels);
return tex;
}
private Texture2D MakeSolidColor(Color color)
{
int size = Theriapolis.Core.C.WORLD_TILE_PIXELS;
var tex = new Texture2D(_gd, size, size);
var pixels = new Color[size * size];
Array.Fill(pixels, color);
tex.SetData(pixels);
return tex;
}
public void Dispose()
{
if (_disposed) return;
_disposed = true;
foreach (var tex in _textures.Values) tex.Dispose();
foreach (var tex in _settlementIcons.Values) tex.Dispose();
_fallback?.Dispose();
}
}
/// <summary>Internal helper to avoid exposing the private static method on BiomeAssignStage.</summary>
internal static class BiomeAssignHelper
{
public static BiomeId ParseBiomeId(string id)
=> Theriapolis.Core.World.Generation.Stages.BiomeAssignStage.ParseBiomeId(id);
}