Label über Spieler

This commit is contained in:
torsten 2026-02-16 14:26:33 +01:00
parent 69a5616ae9
commit 680c6243c6
6 changed files with 107 additions and 2 deletions

View file

@ -2,6 +2,14 @@
"weltenauge" ist ein von Neverwinter Nights (NWN) inspiriertes Multiplayer-Rollenspiel. Das Kernstück ist eine robuste Client/Server-Architektur, die in einer einzigen Godot-Codebase umgesetzt wird.
Dies ist ein "Ewigkeits-Projekt", das nichtkommerziell ist, und
vom Entwickler immer wieder für längere Zeit weggelegt wird. Fokus liegt auf 3D Welten und Weltensimulation.
Dadurch ist es notwendig, dass das gesamte System so modular und
selbsterklärend aufgebaut wird, dass eine Rückkehr zum Projekt nach
langer Pause immer noch machbar ist. Features sind daher soweit einzuschränken,
dass ein absolut Minimaler Prototyp in einem vernünftigen Zeitraum erstellbar wird.
Ausserdem ist Modularität und einfache Testbarkeit Pflicht.
## 2. Kernkonzepte der Architektur
### Client/Server-Modell

View file

@ -161,6 +161,7 @@ func _spawn_player_in_world(id, spawn_target_node):
var player_scene = load("res://systems/player/player.tscn")
var player = player_scene.instantiate()
player.name = str(id)
player.get_node("PlayerNameLabel").text = str(id)
#player.set_multiplayer_authority(id)
player.set_multiplayer_authority(1)

View file

@ -5,15 +5,16 @@
[sub_resource type="CylinderShape3D" id="CylinderShape3D_ktl23"]
[sub_resource type="SystemFont" id="SystemFont_ktl23"]
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_fqfg4"]
[node name="CharacterBody3D" type="CharacterBody3D" unique_id=682006733 groups=["players"]]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.26067275)
script = ExtResource("1_ktl23")
interpolation_speed = 5.0
[node name="CollisionShape3D" type="CollisionShape3D" parent="." unique_id=159496934]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0185384, 0)
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0185384, -0.18054307)
shape = SubResource("CylinderShape3D_ktl23")
[node name="Visuals" type="Node3D" parent="." unique_id=1840405751]
@ -24,6 +25,13 @@ transform = Transform3D(-0.99988204, 0, 0.015358234, 0, 1, 0, -0.015358234, 0, -
[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=1343500738]
root_node = NodePath("../..")
[node name="PlayerNameLabel" type="Label3D" parent="." unique_id=461683617]
transform = Transform3D(-1, 0, -8.742278e-08, 0, 1, 0, 8.742278e-08, 0, -1, 0, 0.73133814, 0)
text = "-label-"
font = SubResource("SystemFont_ktl23")
vertical_alignment = 2
uppercase = true
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." unique_id=656518492]
replication_interval = 0.05
replication_config = SubResource("SceneReplicationConfig_fqfg4")

View file

@ -28,6 +28,7 @@ func _ready():
# 'sync_position': Der Name der Eigenschaft.
config.add_property(NodePath(":sync_position"))
config.add_property(NodePath(":sync_rotation"))
config.add_property(NodePath("PlayerNameLabel:text"))
# Die generierte Konfiguration dem Synchronizer zuweisen. Dies überschreibt alle Editor-Einstellungen.
synchronizer.replication_config = config
# --- ENDE: Dynamische Replikations-Konfiguration ---
@ -36,6 +37,7 @@ func _ready():
# Wir schalten die automatische Physik-Synchronisation aus
set_physics_process(multiplayer.is_server())
func _physics_process(delta):
# Dieser Teil läuft NUR auf dem Server
if path.size() > 0:

View file

@ -0,0 +1,85 @@
# test_player_movement.gd
extends Node
#@onready var multiplayer = MultiplayerPeerExtension.new()
var player: CharacterBody3D
var initial_position: Vector3
func _ready():
# 1. Szene laden
var test_scene = load("res://maps/outdoor/grass/keuwin_grasland.tscn").instantiate()
add_child(test_scene)
# 2. MultiplayerSpawner finden und Player erstellen
var spawner = test_scene.get_node("AreaSpawner")
if not spawner:
printerr("Kein Spawner gefunden!")
queue_free() # Test beenden
# Test-Spieler erstellen
var player_scene = load("res://systems/player/player.tscn")
player = player_scene.instantiate()
player.name = "TestPlayer"
spawner.get_parent().add_child(player)
# Initialen Zustand speichern
initial_position = player.global_position
print("Initial position: ", initial_position)
# 3. Test starten (verzögert, damit alles geladen ist)
call_deferred("start_test")
func start_test():
print("Starte Bewegungstest...")
# Simulieren eines Klicks
var target_position = Vector3(5, 0, 5) # Irgendein Punkt in der Nähe
print("Simuliere Klick auf: ", target_position)
# Hier MÜSSEN wir den RPC direkt aufrufen. InputEvent geht nicht.
player.request_move.rpc_id(1, target_position) # 1 = Server
# Auf Bewegung warten (etwas unsauber, aber für den Moment ok)
await get_tree().create_timer(1.0).timeout # Warte 1 Sekunde
# Ergebnis überprüfen
var new_position = player.global_position
print("Neue Position: ", new_position)
# Toleranz, da die Bewegung nicht exakt sein muss
var tolerance = 0.5
if new_position.distance_to(initial_position) > tolerance:
print("Test erfolgreich! Avatar hat sich bewegt.")
else:
printerr("Test fehlgeschlagen! Avatar hat sich nicht bewegt.")
# Test beenden (optional)
queue_free()
"""Erläuterungen:
1.) Szene laden: Lädt eine Test-Szene (keuwin_grasland.tscn). Das heisst, diese muss eine Spawner Instanz mit dem Namen AreaSpawner enthalten.
2.) Avatar erzeugen: Sucht den Spawner und erzeugt einen Avatar (keinen Multiplayer, nur lokal für den Test).
3.) Test starten (deferred): Startet den Test in start_test(), um sicherzustellen, dass alles geladen ist.
4.) Simulierter Klick: Sendet den request_move-RPC direkt an den Avatar.
5.) Warten: Wartet 1 Sekunde (eine sehr einfache, blockierende Methode).
6.) Ergebnis prüfen: Vergleicht die neue Position mit der alten.
Wie man diesen Test benutzt:
1.) Erstelle eine neue Szene (z.B. test_scene.tscn).
2.) Füge einen Node vom Typ Node als Root hinzu.
3.) Speichere das obige Skript (test_player_movement.gd) im Ordner /systems/player/.
3.) Füge ein Script Node hinzu und weise ihm das Skript test_player_movement.gd zu.
4.) Starte die Szene test_scene.tscn.
5.) Das Skript sollte automatisch ablaufen, die Ergebnisse in der Konsole ausgeben und sich dann selbst beenden.
Wichtige Einschränkungen:
Kein echter Multiplayer: Dies ist ein reiner Einzelspieler-Test. Er prüft nur, ob sich der lokale Avatar bewegt.
Blockierendes Warten: Die Verwendung von create_timer(1.0).timeout.await blockiert den Haupt-Thread. Für einen echten Test wäre das schlecht, aber für unseren einfachen Zweck ist es akzeptabel.
Geringe Präzision: Der Toleranzwert von 0.5 bedeutet, dass kleine Bewegungen möglicherweise nicht erkannt werden.
Keine Fehlerbehandlung: Wenn irgendetwas schiefgeht (kein Spawner, keine Szene, falscher Node-Name), bricht der Test einfach ab.
Auch mit diesen Einschränkungen ist dieser Test extrem wertvoll. Er gibt uns eine schnelle und einfache Möglichkeit, um sicherzustellen, dass die grundlegende Click-to-Move-Mechanik weiterhin funktioniert, wenn wir Änderungen am Code vornehmen."""

View file

@ -0,0 +1 @@
uid://c8p3yn461hle1