feat(client): initialize Godot 4 project boilerplate (epic #277)
Set up the complete Godot 4.6 client foundation as a pure renderer (D-020): - project.godot with 2D rendering, autoloads, input actions - Main scene: Game > World (TileMapLayer, Entities, FogOverlay) + Camera2D + UILayer - Autoloads: SimBridge (connection state machine + test mode), GameState, InputMapper - Rendering stubs: WorldRenderer, EntityRenderer, FogRenderer - UI stubs: HUD (health/perception/time), Minimap, MonologueDisplay - Input mapping: WASD/arrows, E (interact), Tab (perception), Esc (menu), Space (pause) - gdUnit4 smoke tests: scene loads, autoloads registered (2/2 passing) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
extends Control
|
||||
|
||||
# HUD — displays player health, perception mode, time, etc.
|
||||
|
||||
@onready var health_label: Label = $MarginContainer/VBoxContainer/HealthLabel
|
||||
@onready var perception_label: Label = $MarginContainer/VBoxContainer/PerceptionLabel
|
||||
@onready var time_label: Label = $MarginContainer/VBoxContainer/TimeLabel
|
||||
|
||||
func _ready() -> void:
|
||||
print("HUD: Initialized")
|
||||
|
||||
# Update HUD from snapshot data
|
||||
func update_from_hud_data(data: Dictionary) -> void:
|
||||
# Update perception mode display
|
||||
if data.has("perception_mode"):
|
||||
perception_label.text = "Mode: " + data.perception_mode.capitalize()
|
||||
|
||||
# Update time display (per D-031)
|
||||
if data.has("time"):
|
||||
time_label.text = "Time: " + data.time
|
||||
|
||||
# Update player health (from player data, not hud_data)
|
||||
func update_health(health: int) -> void:
|
||||
health_label.text = "Health: " + str(health)
|
||||
@@ -0,0 +1 @@
|
||||
uid://dgy4mkke84c70
|
||||
@@ -0,0 +1,38 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://cq1y5w3hmxr8b"]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/hud.gd" id="1_hud"]
|
||||
|
||||
[node name="HUD" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
script = ExtResource("1_hud")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
offset_bottom = 100.0
|
||||
grow_horizontal = 2
|
||||
theme_override_constants/margin_left = 16
|
||||
theme_override_constants/margin_top = 16
|
||||
theme_override_constants/margin_right = 16
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="HealthLabel" type="Label" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Health: 100"
|
||||
|
||||
[node name="PerceptionLabel" type="Label" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Mode: Baseline"
|
||||
|
||||
[node name="TimeLabel" type="Label" parent="MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
text = "Time: 08:00"
|
||||
@@ -0,0 +1,15 @@
|
||||
extends Control
|
||||
|
||||
# Minimap — small viewport showing local area
|
||||
# Placeholder implementation for now
|
||||
|
||||
@onready var viewport_container: SubViewportContainer = $SubViewportContainer
|
||||
|
||||
func _ready() -> void:
|
||||
print("Minimap: Initialized")
|
||||
|
||||
# Update minimap view (stub)
|
||||
func update_minimap(player_pos: Vector2, entities: Array) -> void:
|
||||
# TODO: Render minimap view
|
||||
# This will show a top-down view of the local area
|
||||
pass
|
||||
@@ -0,0 +1 @@
|
||||
uid://b6bqe4ydk8evo
|
||||
@@ -0,0 +1,32 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://b5x7k2mwpq3vc"]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/minimap.gd" id="1_minimap"]
|
||||
|
||||
[node name="Minimap" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 1
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
offset_left = -200.0
|
||||
offset_bottom = 200.0
|
||||
grow_horizontal = 0
|
||||
mouse_filter = 2
|
||||
script = ExtResource("1_minimap")
|
||||
|
||||
[node name="SubViewportContainer" type="SubViewportContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="Background" type="ColorRect" parent="SubViewportContainer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_right = 200.0
|
||||
offset_bottom = 200.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
color = Color(0.1, 0.1, 0.1, 0.7)
|
||||
@@ -0,0 +1,43 @@
|
||||
extends Control
|
||||
|
||||
# Internal monologue display (per D-015)
|
||||
# Shows character's internal thoughts as text overlay
|
||||
|
||||
@onready var text_panel: PanelContainer = $PanelContainer
|
||||
@onready var text_label: RichTextLabel = $PanelContainer/MarginContainer/RichTextLabel
|
||||
|
||||
var fade_timer: float = 0.0
|
||||
var fade_duration: float = 5.0 # Display duration before fade
|
||||
var is_visible: bool = false
|
||||
|
||||
func _ready() -> void:
|
||||
print("MonologueDisplay: Initialized")
|
||||
text_panel.modulate.a = 0.0
|
||||
is_visible = false
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
# Auto-fade after display
|
||||
if is_visible:
|
||||
fade_timer += delta
|
||||
if fade_timer >= fade_duration:
|
||||
_fade_out()
|
||||
|
||||
# Show internal monologue text
|
||||
func show_monologue(text: String, duration: float = 5.0) -> void:
|
||||
text_label.text = text
|
||||
fade_duration = duration
|
||||
fade_timer = 0.0
|
||||
is_visible = true
|
||||
|
||||
# Fade in
|
||||
var tween = create_tween()
|
||||
tween.tween_property(text_panel, "modulate:a", 1.0, 0.3)
|
||||
|
||||
# Fade out the monologue
|
||||
func _fade_out() -> void:
|
||||
if not is_visible:
|
||||
return
|
||||
|
||||
is_visible = false
|
||||
var tween = create_tween()
|
||||
tween.tween_property(text_panel, "modulate:a", 0.0, 0.5)
|
||||
@@ -0,0 +1 @@
|
||||
uid://befq2r47mmw08
|
||||
@@ -0,0 +1,38 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://bj8y4v2nx7k5m"]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/monologue_display.gd" id="1_monologue"]
|
||||
|
||||
[node name="MonologueDisplay" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 12
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_top = -150.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
mouse_filter = 2
|
||||
script = ExtResource("1_monologue")
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
offset_left = 100.0
|
||||
offset_right = -100.0
|
||||
offset_bottom = 120.0
|
||||
grow_horizontal = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="PanelContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 16
|
||||
theme_override_constants/margin_top = 12
|
||||
theme_override_constants/margin_right = 16
|
||||
theme_override_constants/margin_bottom = 12
|
||||
|
||||
[node name="RichTextLabel" type="RichTextLabel" parent="PanelContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
bbcode_enabled = true
|
||||
text = "Internal monologue will appear here..."
|
||||
fit_content = true
|
||||
scroll_active = false
|
||||
Reference in New Issue
Block a user