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,75 @@
|
||||
extends Node2D
|
||||
|
||||
# Entity renderer — manages entity sprites under the Entities node
|
||||
# Creates/updates/removes Sprite2D children based on entity data
|
||||
|
||||
var entity_nodes: Dictionary = {} # id -> Node2D mapping
|
||||
|
||||
func _ready() -> void:
|
||||
print("EntityRenderer: Initialized")
|
||||
|
||||
# Update entities from snapshot data
|
||||
func update_entities(entities: Array) -> void:
|
||||
var active_ids: Array = []
|
||||
|
||||
# Create or update entities
|
||||
for entity_data in entities:
|
||||
if not entity_data.has("id"):
|
||||
continue
|
||||
|
||||
var entity_id = entity_data.id
|
||||
active_ids.append(entity_id)
|
||||
|
||||
# Create entity node if it doesn't exist
|
||||
if not entity_nodes.has(entity_id):
|
||||
_create_entity_node(entity_id, entity_data)
|
||||
else:
|
||||
_update_entity_node(entity_id, entity_data)
|
||||
|
||||
# Remove entities that are no longer visible
|
||||
var ids_to_remove: Array = []
|
||||
for entity_id in entity_nodes.keys():
|
||||
if entity_id not in active_ids:
|
||||
ids_to_remove.append(entity_id)
|
||||
|
||||
for entity_id in ids_to_remove:
|
||||
_remove_entity_node(entity_id)
|
||||
|
||||
# Create a new entity node (placeholder visual)
|
||||
func _create_entity_node(entity_id: int, entity_data: Dictionary) -> void:
|
||||
var entity_node = ColorRect.new()
|
||||
entity_node.name = "Entity_" + str(entity_id)
|
||||
entity_node.size = Vector2(32, 32)
|
||||
entity_node.pivot_offset = Vector2(16, 16)
|
||||
|
||||
# Color based on type
|
||||
if entity_data.get("type") == "npc":
|
||||
entity_node.color = Color(0.3, 0.6, 0.9) # Blue for NPCs
|
||||
else:
|
||||
entity_node.color = Color(0.8, 0.8, 0.8) # Gray for unknown
|
||||
|
||||
add_child(entity_node)
|
||||
entity_nodes[entity_id] = entity_node
|
||||
|
||||
_update_entity_node(entity_id, entity_data)
|
||||
|
||||
# Update an existing entity node
|
||||
func _update_entity_node(entity_id: int, entity_data: Dictionary) -> void:
|
||||
if not entity_nodes.has(entity_id):
|
||||
return
|
||||
|
||||
var entity_node = entity_nodes[entity_id]
|
||||
|
||||
# Update position
|
||||
if entity_data.has("position"):
|
||||
var pos = entity_data.position
|
||||
entity_node.position = Vector2(pos[0] * 32, pos[1] * 32) # 32px grid
|
||||
|
||||
# Remove an entity node
|
||||
func _remove_entity_node(entity_id: int) -> void:
|
||||
if not entity_nodes.has(entity_id):
|
||||
return
|
||||
|
||||
var entity_node = entity_nodes[entity_id]
|
||||
entity_node.queue_free()
|
||||
entity_nodes.erase(entity_id)
|
||||
@@ -0,0 +1 @@
|
||||
uid://civev5c8xvtc3
|
||||
@@ -0,0 +1,16 @@
|
||||
extends Node2D
|
||||
|
||||
# Fog renderer — manages fog of war overlay
|
||||
# Controls visibility based on player position and fog radius
|
||||
|
||||
func _ready() -> void:
|
||||
print("FogRenderer: Initialized")
|
||||
|
||||
# Update fog visibility (stub for now)
|
||||
func update_fog(fog_data: Dictionary, player_pos: Vector2) -> void:
|
||||
# TODO: Implement fog of war rendering
|
||||
# This will control what the player can see based on:
|
||||
# - fog_data.radius (visibility radius)
|
||||
# - player_pos (center of visible area)
|
||||
# - Perception mode state (affects visibility)
|
||||
pass
|
||||
@@ -0,0 +1 @@
|
||||
uid://cfyv4qt7yybib
|
||||
@@ -0,0 +1,20 @@
|
||||
extends Node2D
|
||||
|
||||
# World renderer — manages all visual representation from GameState
|
||||
# Attached to the World node in main.tscn
|
||||
|
||||
@onready var entity_renderer = $Entities
|
||||
@onready var fog_renderer = $FogOverlay
|
||||
|
||||
func _ready() -> void:
|
||||
print("WorldRenderer: Initialized")
|
||||
|
||||
# Called each frame to update visuals from game state
|
||||
func update_from_state() -> void:
|
||||
# Update entity sprites
|
||||
if entity_renderer and entity_renderer.has_method("update_entities"):
|
||||
entity_renderer.update_entities(GameState.visible_entities)
|
||||
|
||||
# Update fog overlay
|
||||
if fog_renderer and fog_renderer.has_method("update_fog"):
|
||||
fog_renderer.update_fog(GameState.fog_state, GameState.player_position)
|
||||
@@ -0,0 +1 @@
|
||||
uid://djon0gnkn6sh2
|
||||
Reference in New Issue
Block a user