Initial commit: Theriapolis baseline at port/godot branch point
Captures the pre-Godot-port state of the codebase. This is the rollback anchor for the Godot port (M0 of theriapolis-rpg-implementation-plan-godot-port.md). All Phase 0 through Phase 6.5 work is included; Phase 7 is in flight. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Theriapolis.Core;
|
||||
using Theriapolis.Core.World;
|
||||
using Theriapolis.Core.World.Generation;
|
||||
|
||||
namespace Theriapolis.Game.Rendering;
|
||||
|
||||
/// <summary>
|
||||
/// Renders the world map: biome tiles, rivers, roads, rail, and settlement icons.
|
||||
/// Draw order: terrain → roads → rivers → rail → settlements.
|
||||
/// </summary>
|
||||
public sealed class WorldMapRenderer : IMapView, IDisposable
|
||||
{
|
||||
private readonly WorldGenContext _ctx;
|
||||
private readonly TileAtlas _atlas;
|
||||
private readonly LineFeatureRenderer _lineRenderer;
|
||||
private bool _disposed;
|
||||
|
||||
// Zoom level below which settlement labels are hidden to avoid clutter
|
||||
private const float LabelMinZoom = 0.5f;
|
||||
// Min tier to show at low zoom (hide tier 4 villages when zoomed out)
|
||||
private const float SettleHideZoom = 0.08f;
|
||||
|
||||
public WorldMapRenderer(WorldGenContext ctx, TileAtlas atlas)
|
||||
{
|
||||
_ctx = ctx;
|
||||
_atlas = atlas;
|
||||
_lineRenderer = new LineFeatureRenderer(atlas.GraphicsDevice, ctx);
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch sb, Camera2D camera, GameTime gameTime)
|
||||
{
|
||||
DrawTerrain(sb, camera);
|
||||
_lineRenderer.Draw(sb, camera);
|
||||
DrawSettlements(sb, camera);
|
||||
}
|
||||
|
||||
private void DrawTerrain(SpriteBatch sb, Camera2D camera)
|
||||
{
|
||||
var (x0, y0, x1, y1) = camera.VisibleTileRect();
|
||||
int tilePixels = C.WORLD_TILE_PIXELS;
|
||||
|
||||
sb.Begin(
|
||||
transformMatrix: camera.TransformMatrix,
|
||||
samplerState: SamplerState.PointClamp,
|
||||
sortMode: SpriteSortMode.Deferred);
|
||||
|
||||
for (int ty = y0; ty <= y1; ty++)
|
||||
for (int tx = x0; tx <= x1; tx++)
|
||||
{
|
||||
ref var tile = ref _ctx.World.TileAt(tx, ty);
|
||||
var tex = _atlas.GetTile(tile.Biome);
|
||||
var dest = new Rectangle(tx * tilePixels, ty * tilePixels, tilePixels, tilePixels);
|
||||
sb.Draw(tex, dest, Color.White);
|
||||
}
|
||||
|
||||
sb.End();
|
||||
}
|
||||
|
||||
private void DrawSettlements(SpriteBatch sb, Camera2D camera)
|
||||
{
|
||||
if (_ctx.World.Settlements.Count == 0) return;
|
||||
|
||||
sb.Begin(
|
||||
transformMatrix: camera.TransformMatrix,
|
||||
samplerState: SamplerState.LinearClamp,
|
||||
sortMode: SpriteSortMode.Deferred,
|
||||
blendState: BlendState.AlphaBlend);
|
||||
|
||||
bool hideSmall = camera.Zoom < SettleHideZoom;
|
||||
|
||||
foreach (var s in _ctx.World.Settlements)
|
||||
{
|
||||
if (hideSmall && s.Tier >= 4) continue;
|
||||
|
||||
var icon = _atlas.GetSettlementIcon(s.Tier);
|
||||
float wx = s.TileX * C.WORLD_TILE_PIXELS + C.WORLD_TILE_PIXELS * 0.5f;
|
||||
float wy = s.TileY * C.WORLD_TILE_PIXELS + C.WORLD_TILE_PIXELS * 0.5f;
|
||||
var origin = new Vector2(icon.Width * 0.5f, icon.Height * 0.5f);
|
||||
|
||||
sb.Draw(icon,
|
||||
position: new Vector2(wx, wy),
|
||||
sourceRectangle: null,
|
||||
color: Color.White,
|
||||
rotation: 0f,
|
||||
origin: origin,
|
||||
scale: 1f,
|
||||
effects: SpriteEffects.None,
|
||||
layerDepth: 0f);
|
||||
}
|
||||
|
||||
sb.End();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
_lineRenderer.Dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user