bf0041605f
Lands the M7 plan's first two sub-milestones on port/godot. theriapolis-rpg-implementation-plan-godot-port-m7.md is the design doc (six screens collapse to four scenes + a camera mode, with per-screen behavioural contracts and a six-step sub-milestone breakdown). M7.1 — WorldGenProgressScreen + GameSession autoload + wizard hand-off rewrite. GameSession holds the cross-scene state that outlives any single screen: seed, post-worldgen Ctx, pending character (from the M6 wizard) and pending save snapshot (for M7.3's load path). Wizard forwards StepReview.CharacterConfirmed upward, and TitleScreen swaps to the progress screen instead of just printing the build summary. The progress screen runs the 23-stage pipeline on a background thread, drives a ProgressBar from ctx.ProgressCallback, and writes the full exception trace to user://worldgen_error.log on failure. Escape cancels at the next stage boundary and returns to title. M7.2 — PlayScreen with a walking character. Extracted WorldRenderNode from the M2+M4 WorldView demo so PlayScreen and WorldView mount the same renderer (biome image + polylines + bridges + settlement dots + tactical chunk lifecycle + PanZoomCamera + per-frame layer visibility + line-width counter-scaling). PlayScreen owns the streamer (M7.3 save needs it), composes ContentResolver + ActorManager + WorldClock + AnchorRegistry + PlayerController, spawns the player at the Tier-1 anchor, and wires resident + non-resident NPC spawning from chunk-load events with allegiance-tinted markers. PlayerController ported engine-agnostic to Theriapolis.Godot/Input/. Takes pre-resolved dx/dy/dt/isTactical/isFocused instead of poking MonoGame InputManager + Camera2D, so the arithmetic that advances PlayerActor.Position and WorldClock.InGameSeconds is bit-identical to the MonoGame version — saves round-trip cleanly. Click-to-travel in world-map mode (camera zoom < TacticalRenderZoomMin), WASD step in tactical mode with axis- separated motion + encumbrance + sub-second clock carry. HUD overlay top-left shows HP/AC/seed/tile/biome/view-mode/time. Esc returns to title (M7.4 replaces this with a pause menu). Namespace gotcha: Theriapolis.GodotHost.Input shadows the engine's Godot.Input static class for any file under the GodotHost namespace tree. Files needing keyboard polls (WorldView, PlayScreen) fully qualify as Godot.Input.IsKeyPressed. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
43 lines
1.6 KiB
C#
43 lines
1.6 KiB
C#
using Godot;
|
|
using Theriapolis.Core;
|
|
|
|
namespace Theriapolis.GodotHost.Rendering;
|
|
|
|
/// <summary>
|
|
/// Player marker — small dot with a thin facing tick. Drawn at
|
|
/// <see cref="C.PLAYER_MARKER_SCREEN_PX"/>/2 wp; the owner sets
|
|
/// <see cref="Node2D.Scale"/> = 1/zoom every frame so the on-screen size
|
|
/// stays constant across the seamless zoom range.
|
|
///
|
|
/// Mirrors the MonoGame PlayerSprite's visual vocabulary — dark outline,
|
|
/// faction-red fill, optional facing tick. Phase-7-styled `PlayerSprite`
|
|
/// proper (walking animation frames) lands later.
|
|
/// </summary>
|
|
public partial class PlayerMarker : Node2D
|
|
{
|
|
private const float RadiusWorldPx = C.PLAYER_MARKER_SCREEN_PX * 0.5f;
|
|
private const float FacingTickPx = RadiusWorldPx * 1.4f;
|
|
|
|
/// <summary>Facing direction in radians; 0 = +X. Drives the optional
|
|
/// tick rendered on the body's leading edge.</summary>
|
|
public float FacingAngleRad { get; set; }
|
|
|
|
/// <summary>When true, draws a small tick at the leading edge so the
|
|
/// player can read facing without a full sprite. Hidden at low zoom
|
|
/// to avoid clutter.</summary>
|
|
public bool ShowFacingTick { get; set; } = true;
|
|
|
|
public override void _Draw()
|
|
{
|
|
DrawCircle(Vector2.Zero, RadiusWorldPx, new Color(0, 0, 0, 0.78f));
|
|
DrawCircle(Vector2.Zero, RadiusWorldPx * 0.85f, new Color(0.86f, 0.31f, 0.24f));
|
|
|
|
if (ShowFacingTick)
|
|
{
|
|
var dir = new Vector2(Mathf.Cos(FacingAngleRad), Mathf.Sin(FacingAngleRad));
|
|
DrawLine(dir * (RadiusWorldPx * 0.4f), dir * FacingTickPx,
|
|
new Color(1f, 0.96f, 0.86f), width: RadiusWorldPx * 0.18f, antialiased: false);
|
|
}
|
|
}
|
|
}
|