feat: merge Schritt 13 — Charakter-Capsules (manual conflict resolution)
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
# Ruf der Pilze — Projektstatus
|
||||
|
||||
Zuletzt aktualisiert: 2026-04-16 (Schritt 12 abgeschlossen — Lite Charakterbogen)
|
||||
|
||||
Zuletzt aktualisiert: 2026-04-16 (Schritt 13 abgeschlossen — Charakter-Capsules)
|
||||
---
|
||||
|
||||
## Aktueller Stand
|
||||
@@ -20,7 +19,6 @@ Zuletzt aktualisiert: 2026-04-16 (Schritt 12 abgeschlossen — Lite Charakterbog
|
||||
Spieler-Positionsmarker (etagen-gefiltert), Live-Cam-Feeds pro Spieler, Overlay-Toggle-Panel
|
||||
- **Lite Charakterbogen** — Rasse/Klasse OptionButtons, 6 Ability-Modifier SpinBoxen, 6 Archetype-Quick-Fill-Buttons;
|
||||
Auto-Sync via `request_update_character` RPC, `character_updated` Signal in NetworkManager
|
||||
|
||||
### 🔄 In Arbeit
|
||||
|
||||
— (nichts aktiv)
|
||||
@@ -50,7 +48,7 @@ Zuletzt aktualisiert: 2026-04-16 (Schritt 12 abgeschlossen — Lite Charakterbog
|
||||
### Charaktere + Assets
|
||||
|
||||
12. ✅ Lite Charakterbogen in Lobby — Rasse/Klasse OptionButtons, 6 Modifier-SpinBoxen, 6 Archetype-Buttons; RPC-Sync
|
||||
13. ⏳ Charakter-Platzhalter — farbige Capsules pro Archetyp, austauschbar
|
||||
13. ✅ Charakter-Platzhalter — farbige Capsule-Avatare in der Lobby, 5 LobbySpots, Farbe aus Klasse
|
||||
14. ⏳ Tavern Art Pass — echte Props (Tische, Stühle, Tresen, Betten, Fässer, Kerzen) via Polyhaven/Sketchfab/Meshy
|
||||
|
||||
### Klosterwelt
|
||||
@@ -75,7 +73,6 @@ Zuletzt aktualisiert: 2026-04-16 (Schritt 12 abgeschlossen — Lite Charakterbog
|
||||
26. ⏳ Aktions-Selektor — klassen-spezifische Zauber/Angriff-Effekte (rein visuell, Atmosphäre)
|
||||
27. ⏳ Full Spore Effects — Nebel-Partikel vom Boden/Decke, Bewegungsverzerrung
|
||||
28. ⏳ Soundscape + Spieluhr-Melodie — direktionaler Audio, Annas Lied im Sanctum
|
||||
|
||||
---
|
||||
|
||||
## Design-Entscheidungen (festgelegt)
|
||||
|
||||
28
ruf-der-pilze/scenes/character_placeholder.tscn
Normal file
28
ruf-der-pilze/scenes/character_placeholder.tscn
Normal file
@@ -0,0 +1,28 @@
|
||||
[gd_scene load_steps=5 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://scripts/character_placeholder.gd" id="1"]
|
||||
|
||||
[sub_resource type="CapsuleMesh" id="2"]
|
||||
height = 1.8
|
||||
radius = 0.3
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="3"]
|
||||
albedo_color = Color(0.65, 0.65, 0.65, 1)
|
||||
|
||||
[sub_resource type="LabelSettings" id="4"]
|
||||
font_size = 48
|
||||
|
||||
[node name="CharacterPlaceholder" type="Node3D"]
|
||||
script = ExtResource("1")
|
||||
|
||||
[node name="Capsule" type="MeshInstance3D" parent="."]
|
||||
mesh = SubResource("2")
|
||||
material_override = SubResource("3")
|
||||
|
||||
[node name="NameLabel" type="Label3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.2, 0)
|
||||
text = ""
|
||||
font_size = 48
|
||||
billboard = 1
|
||||
no_depth_test = true
|
||||
label_settings = SubResource("4")
|
||||
@@ -148,3 +148,18 @@ text = "Druide"
|
||||
|
||||
[node name="BtnBarbar" type="Button" parent="CanvasLayer/WaitPanel/CharSheet/ArchetypeRow"]
|
||||
text = "Barbar"
|
||||
|
||||
[node name="LobbySpot0" type="Marker3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.0, 0.0, 1.0)
|
||||
|
||||
[node name="LobbySpot1" type="Marker3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.0, 0.0, 1.5)
|
||||
|
||||
[node name="LobbySpot2" type="Marker3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0, 0.0, 1.8)
|
||||
|
||||
[node name="LobbySpot3" type="Marker3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.0, 0.0, 1.5)
|
||||
|
||||
[node name="LobbySpot4" type="Marker3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.0, 0.0, 1.0)
|
||||
19
ruf-der-pilze/scripts/character_placeholder.gd
Normal file
19
ruf-der-pilze/scripts/character_placeholder.gd
Normal file
@@ -0,0 +1,19 @@
|
||||
extends Node3D
|
||||
|
||||
const CLASS_COLORS: Dictionary = {
|
||||
"Krieger": Color(0.80, 0.20, 0.20), # Rot
|
||||
"Magier": Color(0.20, 0.20, 0.90), # Blau
|
||||
"Kleriker": Color(0.90, 0.85, 0.20), # Gelb
|
||||
"Schurke": Color(0.20, 0.65, 0.20), # Grün
|
||||
"Druide": Color(0.40, 0.75, 0.30), # Hellgrün
|
||||
"Barbar": Color(0.75, 0.40, 0.10), # Orange
|
||||
}
|
||||
const DEFAULT_COLOR := Color(0.65, 0.65, 0.65) # Grau
|
||||
|
||||
func set_color(class_name: String) -> void:
|
||||
var mat := StandardMaterial3D.new()
|
||||
mat.albedo_color = CLASS_COLORS.get(class_name, DEFAULT_COLOR)
|
||||
($Capsule as MeshInstance3D).material_override = mat
|
||||
|
||||
func set_label(player_name: String) -> void:
|
||||
($NameLabel as Label3D).text = player_name
|
||||
@@ -1,7 +1,11 @@
|
||||
extends Node3D
|
||||
|
||||
const CharacterPlaceholder := preload("res://scenes/character_placeholder.tscn")
|
||||
|
||||
var _local_role: String = ""
|
||||
var _pending_player_name: String = ""
|
||||
var _capsules: Dictionary = {} # peer_id: int → Node3D
|
||||
var _lobby_spots: Array[Marker3D] = []
|
||||
|
||||
const ARCHETYPES := {
|
||||
"Krieger": {"race": "Mensch", "class": "Krieger", "STR": 3, "DEX": 1, "CON": 2, "INT": 0, "WIS": 0, "CHA": 0},
|
||||
@@ -75,6 +79,18 @@ func _ready() -> void:
|
||||
NetworkManager.player_list_synced.connect(_rebuild_player_list)
|
||||
_setup_char_sheet()
|
||||
|
||||
_lobby_spots = [
|
||||
$LobbySpot0 as Marker3D,
|
||||
$LobbySpot1 as Marker3D,
|
||||
$LobbySpot2 as Marker3D,
|
||||
$LobbySpot3 as Marker3D,
|
||||
$LobbySpot4 as Marker3D,
|
||||
]
|
||||
NetworkManager.player_joined.connect(_on_player_joined_capsule)
|
||||
NetworkManager.player_left.connect(_on_player_left_capsule)
|
||||
if NetworkManager.has_signal("character_updated"):
|
||||
NetworkManager.character_updated.connect(_on_character_updated_capsule)
|
||||
|
||||
|
||||
func _on_join_pressed() -> void:
|
||||
var player_name: String = ($CanvasLayer/JoinPanel/NameInput as LineEdit).text.strip_edges()
|
||||
@@ -99,6 +115,10 @@ func _exit_tree() -> void:
|
||||
NetworkManager.player_joined.disconnect(_on_player_joined)
|
||||
NetworkManager.player_left.disconnect(_on_player_left)
|
||||
NetworkManager.player_list_synced.disconnect(_rebuild_player_list)
|
||||
NetworkManager.player_joined.disconnect(_on_player_joined_capsule)
|
||||
NetworkManager.player_left.disconnect(_on_player_left_capsule)
|
||||
if NetworkManager.has_signal("character_updated") and NetworkManager.character_updated.is_connected(_on_character_updated_capsule):
|
||||
NetworkManager.character_updated.disconnect(_on_character_updated_capsule)
|
||||
|
||||
|
||||
func _on_connection_failed() -> void:
|
||||
@@ -125,3 +145,29 @@ func _rebuild_player_list() -> void:
|
||||
|
||||
func _on_start_pressed() -> void:
|
||||
NetworkManager.request_start_game.rpc_id(1)
|
||||
|
||||
|
||||
func _on_player_joined_capsule(peer_id: int, _player_name: String, _role: String) -> void:
|
||||
if _capsules.has(peer_id):
|
||||
return
|
||||
var spot_index := _capsules.size() % _lobby_spots.size()
|
||||
var capsule: Node3D = CharacterPlaceholder.instantiate()
|
||||
add_child(capsule)
|
||||
capsule.global_position = _lobby_spots[spot_index].global_position
|
||||
var player_data: Dictionary = NetworkManager.players.get(peer_id, {})
|
||||
capsule.set_label(player_data.get("name", "???"))
|
||||
capsule.set_color(player_data.get("char", {}).get("class", ""))
|
||||
_capsules[peer_id] = capsule
|
||||
|
||||
|
||||
func _on_player_left_capsule(peer_id: int) -> void:
|
||||
if not _capsules.has(peer_id):
|
||||
return
|
||||
(_capsules[peer_id] as Node3D).queue_free()
|
||||
_capsules.erase(peer_id)
|
||||
|
||||
|
||||
func _on_character_updated_capsule(peer_id: int, data: Dictionary) -> void:
|
||||
if not _capsules.has(peer_id):
|
||||
return
|
||||
(_capsules[peer_id] as Node3D).set_color(data.get("class", ""))
|
||||
|
||||
Reference in New Issue
Block a user