Add Apparance tab in escape menu

- Appearance (name and color) can be changed
- Appearance is synced to other players
- Split tabs into multiple scripts
- Use nameof() where applicable
main
copygirl 5 years ago
parent d302a56855
commit 7b76d44b43
  1. 195
      scene/EscapeMenu.tscn
  2. 2
      scene/LocalPlayer.tscn
  3. 21
      scene/Player.tscn
  4. 90
      src/EscapeMenu.cs
  5. 103
      src/EscapeMenuAppearance.cs
  6. 94
      src/EscapeMenuMultiplayer.cs
  7. 1
      src/Game.cs
  8. 36
      src/Network.cs

@ -1,9 +1,12 @@
[gd_scene load_steps=3 format=2]
[gd_scene load_steps=6 format=2]
[ext_resource path="res://ui_theme.tres" type="Theme" id=1]
[ext_resource path="res://src/EscapeMenu.cs" type="Script" id=2]
[ext_resource path="res://gfx/player.png" type="Texture" id=3]
[ext_resource path="res://src/EscapeMenuMultiplayer.cs" type="Script" id=4]
[ext_resource path="res://src/EscapeMenuAppearance.cs" type="Script" id=5]
[node name="EscapeMenu" type="Container"]
[node name="EscapeMenu" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
theme = ExtResource( 1 )
@ -11,11 +14,6 @@ script = ExtResource( 2 )
__meta__ = {
"_edit_use_anchors_": false
}
StatusPath = NodePath("CenterContainer/PanelContainer/VBoxContainer/ContainerStatus/Status")
ServerStartStopPath = NodePath("CenterContainer/PanelContainer/VBoxContainer/ContainerServer/ServerStartStop")
ServerPortPath = NodePath("CenterContainer/PanelContainer/VBoxContainer/ContainerServer/ServerPort")
ClientDisConnectPath = NodePath("CenterContainer/PanelContainer/VBoxContainer/ContainerClient/ClientDisConnect")
ClientAddressPath = NodePath("CenterContainer/PanelContainer/VBoxContainer/ContainerClient/ClientAddress")
ReturnPath = NodePath("CenterContainer/PanelContainer/VBoxContainer/Return")
[node name="ColorRect" type="ColorRect" parent="."]
@ -26,26 +24,29 @@ color = Color( 0, 0, 0, 0.501961 )
[node name="CenterContainer" type="CenterContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PanelContainer" type="PanelContainer" parent="CenterContainer"]
margin_left = 522.0
margin_top = 274.0
margin_right = 757.0
margin_bottom = 446.0
margin_left = 518.0
margin_top = 258.0
margin_right = 761.0
margin_bottom = 461.0
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer/PanelContainer"]
margin_left = 7.0
margin_top = 7.0
margin_right = 228.0
margin_bottom = 165.0
margin_right = 236.0
margin_bottom = 196.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer"]
margin_right = 221.0
margin_right = 229.0
margin_bottom = 9.0
text = "Pause Menu"
text = "Escape Menu"
align = 1
__meta__ = {
"_edit_use_anchors_": false
@ -53,15 +54,108 @@ __meta__ = {
[node name="HSeparator" type="HSeparator" parent="CenterContainer/PanelContainer/VBoxContainer"]
margin_top = 13.0
margin_right = 221.0
margin_right = 229.0
margin_bottom = 17.0
[node name="ContainerStatus" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer"]
[node name="TabContainer" type="TabContainer" parent="CenterContainer/PanelContainer/VBoxContainer"]
margin_top = 21.0
margin_right = 229.0
margin_bottom = 139.0
custom_constants/side_margin = 4
tab_align = 0
use_hidden_tabs_for_min_size = true
[node name="Appearance" type="CenterContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer"]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 4.0
margin_top = 27.0
margin_right = -4.0
margin_bottom = -4.0
script = ExtResource( 5 )
PlayerNamePath = NodePath("VBoxContainer/ContainerName/Name")
ColorPreviewPath = NodePath("VBoxContainer/ContainerColor/Preview")
ColorSliderPath = NodePath("VBoxContainer/ContainerColor/HSlider")
[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance"]
margin_left = 19.0
margin_top = 24.0
margin_right = 201.0
margin_bottom = 63.0
[node name="ContainerName" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer"]
margin_right = 182.0
margin_bottom = 19.0
[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer/ContainerName"]
margin_top = 5.0
margin_right = 36.0
margin_bottom = 14.0
rect_min_size = Vector2( 36, 0 )
text = "Name:"
align = 2
[node name="Name" type="LineEdit" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer/ContainerName"]
margin_left = 40.0
margin_right = 182.0
margin_bottom = 19.0
rect_min_size = Vector2( 142, 0 )
size_flags_horizontal = 3
align = 1
max_length = 20
caret_blink = true
[node name="ContainerColor" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer"]
margin_top = 23.0
margin_right = 182.0
margin_bottom = 39.0
[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer/ContainerColor"]
margin_top = 3.0
margin_right = 36.0
margin_bottom = 12.0
rect_min_size = Vector2( 36, 0 )
text = "Color:"
align = 2
[node name="Preview" type="TextureRect" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer/ContainerColor"]
margin_left = 40.0
margin_right = 56.0
margin_bottom = 16.0
texture = ExtResource( 3 )
[node name="HSlider" type="HSlider" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer/ContainerColor"]
margin_left = 60.0
margin_right = 182.0
margin_bottom = 16.0
size_flags_horizontal = 3
max_value = 1.0
step = 0.0
scrollable = false
[node name="Multiplayer" type="VBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer"]
visible = false
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 4.0
margin_top = 27.0
margin_right = -4.0
margin_bottom = -4.0
script = ExtResource( 4 )
StatusPath = NodePath("ContainerStatus/Status")
ServerStartStopPath = NodePath("ContainerServer/ServerStartStop")
ServerPortPath = NodePath("ContainerServer/ServerPort")
ClientDisConnectPath = NodePath("ContainerClient/ClientDisConnect")
ClientAddressPath = NodePath("ContainerClient/ClientAddress")
[node name="ContainerStatus" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer"]
margin_right = 221.0
margin_bottom = 34.0
margin_bottom = 13.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/ContainerStatus"]
[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/ContainerStatus"]
margin_top = 2.0
margin_right = 36.0
margin_bottom = 11.0
@ -69,7 +163,7 @@ rect_min_size = Vector2( 36, 0 )
text = "Status:"
align = 2
[node name="Status" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/ContainerStatus"]
[node name="Status" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/ContainerStatus"]
modulate = Color( 1, 0, 0, 1 )
margin_left = 40.0
margin_right = 221.0
@ -84,12 +178,12 @@ __meta__ = {
"_edit_use_anchors_": false
}
[node name="ContainerServer" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer"]
margin_top = 38.0
[node name="ContainerServer" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer"]
margin_top = 17.0
margin_right = 221.0
margin_bottom = 57.0
margin_bottom = 36.0
[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/ContainerServer"]
[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/ContainerServer"]
margin_top = 5.0
margin_right = 36.0
margin_bottom = 14.0
@ -97,7 +191,7 @@ rect_min_size = Vector2( 36, 0 )
text = "Port:"
align = 2
[node name="ServerPort" type="LineEdit" parent="CenterContainer/PanelContainer/VBoxContainer/ContainerServer"]
[node name="ServerPort" type="LineEdit" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/ContainerServer"]
margin_left = 40.0
margin_right = 90.0
margin_bottom = 19.0
@ -109,7 +203,7 @@ __meta__ = {
"_edit_use_anchors_": false
}
[node name="ServerStartStop" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer/ContainerServer"]
[node name="ServerStartStop" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/ContainerServer"]
margin_left = 94.0
margin_right = 221.0
margin_bottom = 19.0
@ -119,12 +213,12 @@ __meta__ = {
"_edit_use_anchors_": false
}
[node name="ContainerClient" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer"]
margin_top = 61.0
[node name="ContainerClient" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer"]
margin_top = 40.0
margin_right = 221.0
margin_bottom = 80.0
margin_bottom = 59.0
[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/ContainerClient"]
[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/ContainerClient"]
margin_top = 5.0
margin_right = 36.0
margin_bottom = 14.0
@ -132,7 +226,7 @@ rect_min_size = Vector2( 36, 0 )
text = "Address:"
align = 2
[node name="ClientAddress" type="LineEdit" parent="CenterContainer/PanelContainer/VBoxContainer/ContainerClient"]
[node name="ClientAddress" type="LineEdit" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/ContainerClient"]
margin_left = 40.0
margin_right = 160.0
margin_bottom = 19.0
@ -140,7 +234,7 @@ rect_min_size = Vector2( 120, 0 )
align = 1
caret_blink = true
[node name="ClientDisConnect" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer/ContainerClient"]
[node name="ClientDisConnect" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/ContainerClient"]
margin_left = 164.0
margin_right = 221.0
margin_bottom = 19.0
@ -148,17 +242,17 @@ rect_min_size = Vector2( 57, 0 )
size_flags_horizontal = 3
text = "Connect"
[node name="HBoxContainer" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer"]
margin_top = 84.0
[node name="ContainerHideAddress" type="HBoxContainer" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer"]
margin_top = 63.0
margin_right = 221.0
margin_bottom = 108.0
margin_bottom = 87.0
[node name="HideAddress" type="CheckBox" parent="CenterContainer/PanelContainer/VBoxContainer/HBoxContainer"]
[node name="HideAddress" type="CheckBox" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/ContainerHideAddress"]
margin_right = 82.0
margin_bottom = 24.0
text = "Hide Address"
[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/HBoxContainer"]
[node name="Label" type="Label" parent="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/ContainerHideAddress"]
margin_left = 86.0
margin_top = 7.0
margin_right = 173.0
@ -167,14 +261,14 @@ custom_colors/font_color = Color( 0.6, 0.6, 0.6, 1 )
text = "(for streamers etc.)"
[node name="HSeparator2" type="HSeparator" parent="CenterContainer/PanelContainer/VBoxContainer"]
margin_top = 112.0
margin_right = 221.0
margin_bottom = 116.0
margin_top = 143.0
margin_right = 229.0
margin_bottom = 147.0
[node name="Quit" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer"]
margin_top = 120.0
margin_right = 221.0
margin_bottom = 137.0
margin_top = 151.0
margin_right = 229.0
margin_bottom = 168.0
rect_min_size = Vector2( 0, 17 )
[node name="RichTextLabel" type="RichTextLabel" parent="CenterContainer/PanelContainer/VBoxContainer/Quit"]
@ -197,9 +291,9 @@ __meta__ = {
}
[node name="Return" type="Button" parent="CenterContainer/PanelContainer/VBoxContainer"]
margin_top = 141.0
margin_right = 221.0
margin_bottom = 158.0
margin_top = 172.0
margin_right = 229.0
margin_bottom = 189.0
rect_min_size = Vector2( 0, 17 )
__meta__ = {
"_edit_use_anchors_": false
@ -223,8 +317,11 @@ scroll_active = false
__meta__ = {
"_edit_use_anchors_": false
}
[connection signal="pressed" from="CenterContainer/PanelContainer/VBoxContainer/ContainerServer/ServerStartStop" to="." method="_on_ServerStartStop_pressed"]
[connection signal="pressed" from="CenterContainer/PanelContainer/VBoxContainer/ContainerClient/ClientDisConnect" to="." method="_on_ClientDisConnect_pressed"]
[connection signal="toggled" from="CenterContainer/PanelContainer/VBoxContainer/HBoxContainer/HideAddress" to="." method="_on_HideAddress_toggled"]
[connection signal="visibility_changed" from="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance" method="_on_Appearance_visibility_changed"]
[connection signal="text_changed" from="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer/ContainerName/Name" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance" method="_on_Name_text_changed"]
[connection signal="value_changed" from="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance/VBoxContainer/ContainerColor/HSlider" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Appearance" method="_on_HSlider_value_changed"]
[connection signal="pressed" from="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/ContainerServer/ServerStartStop" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer" method="_on_ServerStartStop_pressed"]
[connection signal="pressed" from="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/ContainerClient/ClientDisConnect" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer" method="_on_ClientDisConnect_pressed"]
[connection signal="toggled" from="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer/ContainerHideAddress/HideAddress" to="CenterContainer/PanelContainer/VBoxContainer/TabContainer/Multiplayer" method="_on_HideAddress_toggled"]
[connection signal="pressed" from="CenterContainer/PanelContainer/VBoxContainer/Quit" to="." method="_on_Quit_pressed"]
[connection signal="pressed" from="CenterContainer/PanelContainer/VBoxContainer/Return" to="." method="_on_Return_pressed"]

@ -3,7 +3,7 @@
[ext_resource path="res://scene/Player.tscn" type="PackedScene" id=1]
[ext_resource path="res://src/Player.cs" type="Script" id=3]
[node name="Player" instance=ExtResource( 1 )]
[node name="LocalPlayer" instance=ExtResource( 1 )]
script = ExtResource( 3 )
[node name="Camera2D" type="Camera2D" parent="." index="0"]

@ -1,15 +1,34 @@
[gd_scene load_steps=3 format=2]
[gd_scene load_steps=4 format=2]
[ext_resource path="res://ui_theme.tres" type="Theme" id=1]
[ext_resource path="res://gfx/player.png" type="Texture" id=2]
[sub_resource type="CircleShape2D" id=1]
radius = 8.0
[node name="Player" type="KinematicBody2D"]
z_index = 10
collision_layer = 0
[node name="CircleShape" type="CollisionShape2D" parent="."]
shape = SubResource( 1 )
[node name="Sprite" type="Sprite" parent="."]
z_index = -5
texture = ExtResource( 2 )
[node name="Name" type="Label" parent="."]
modulate = Color( 1, 1, 1, 0.501961 )
anchor_left = 0.5
anchor_right = 0.5
margin_left = -80.0
margin_top = -24.0
margin_right = 80.0
margin_bottom = -9.0
rect_min_size = Vector2( 160, 15 )
theme = ExtResource( 1 )
align = 1
valign = 1
__meta__ = {
"_edit_use_anchors_": false
}

@ -1,37 +1,13 @@
using Godot;
// TODO: Split network and escape menu logic.
public class EscapeMenu : Container
public class EscapeMenu : Control
{
[Export] public NodePath StatusPath { get; set; }
[Export] public NodePath ServerStartStopPath { get; set; }
[Export] public NodePath ServerPortPath { get; set; }
[Export] public NodePath ClientDisConnectPath { get; set; }
[Export] public NodePath ClientAddressPath { get; set; }
[Export] public NodePath ReturnPath { get; set; }
public Label Status { get; private set; }
public Button ServerStartStop { get; private set; }
public LineEdit ServerPort { get; private set; }
public Button ClientDisConnect { get; private set; }
public LineEdit ClientAddress { get; private set; }
public Button Return { get; private set; }
public Network Network { get; private set; }
public override void _EnterTree()
{
Status = GetNode<Label>(StatusPath);
ServerStartStop = GetNode<Button>(ServerStartStopPath);
ServerPort = GetNode<LineEdit>(ServerPortPath);
ClientDisConnect = GetNode<Button>(ClientDisConnectPath);
ClientAddress = GetNode<LineEdit>(ClientAddressPath);
Return = GetNode<Button>(ReturnPath);
Network = GetNode<Network>("/root/Game/Network");
Network.Connect("StatusChanged", this, "OnNetworkStatusChanged");
ServerPort.PlaceholderText = Network.DefaultPort.ToString();
ClientAddress.PlaceholderText = $"{Network.DefaultAddress}:{Network.DefaultPort}";
}
public override void _Input(InputEvent @event)
@ -39,11 +15,9 @@ public class EscapeMenu : Container
if (@event.IsActionPressed("ui_menu")) Toggle();
}
public void Toggle()
{
if (Visible) Close();
else Open();
}
{ if (Visible) Close(); else Open(); }
public void Open()
{
@ -64,66 +38,8 @@ public class EscapeMenu : Container
#pragma warning disable IDE0051
private void OnNetworkStatusChanged(Network.Status status)
{
switch (status) {
case Network.Status.NoConnection:
Status.Text = "No Connection";
Status.Modulate = Colors.Red;
break;
case Network.Status.ServerRunning:
Status.Text = "Server Running";
Status.Modulate = Colors.Green;
break;
case Network.Status.Connecting:
Status.Text = "Connecting ...";
Status.Modulate = Colors.Yellow;
break;
case Network.Status.ConnectedToServer:
Status.Text = "Connected to Server";
Status.Modulate = Colors.Green;
break;
}
ServerPort.Editable = status == Network.Status.NoConnection;
ServerStartStop.Text = (status == Network.Status.ServerRunning) ? "Stop Server" : "Start Server";
ClientAddress.Editable = status == Network.Status.NoConnection;
ClientDisConnect.Text = (status < Network.Status.Connecting) ? "Connect" : "Disconnect";
ClientDisConnect.Disabled = status == Network.Status.ServerRunning;
if (Visible) GetTree().Paused = status == Network.Status.NoConnection;
}
#pragma warning disable IDE1006
private void _on_ServerStartStop_pressed()
{
if (GetTree().NetworkPeer == null) {
var port = Network.DefaultPort;
if (ServerPort.Text.Length > 0)
port = ushort.Parse(ServerPort.Text);
Network.StartServer(port);
} else Network.StopServer();
}
private void _on_ClientDisConnect_pressed()
{
if (GetTree().NetworkPeer == null) {
var address = Network.DefaultAddress;
var port = Network.DefaultPort;
if (ClientAddress.Text.Length > 0) {
// TODO: Verify input some more, support IPv6?
var split = address.Split(':');
address = (split.Length > 1) ? split[0] : address;
port = (split.Length > 1) ? ushort.Parse(split[1]) : port;
}
Network.ConnectToServer(address, port);
} else Network.DisconnectFromServer();
}
private void _on_HideAddress_toggled(bool pressed)
=> ClientAddress.Secret = pressed;
private void _on_Quit_pressed()
=> GetTree().Quit();
private void _on_Return_pressed()

@ -0,0 +1,103 @@
using System.Text.RegularExpressions;
using Godot;
public class EscapeMenuAppearance : CenterContainer
{
[Export] public NodePath PlayerNamePath { get; set; }
[Export] public NodePath ColorPreviewPath { get; set; }
[Export] public NodePath ColorSliderPath { get; set; }
public LineEdit PlayerName { get; private set; }
public TextureRect ColorPreview { get; private set; }
public Slider ColorSlider { get; private set; }
public Network Network { get; private set; }
public Player LocalPlayer { get; private set; }
public override void _EnterTree()
{
PlayerName = GetNode<LineEdit>(PlayerNamePath);
ColorPreview = GetNode<TextureRect>(ColorPreviewPath);
ColorSlider = GetNode<Slider>(ColorSliderPath);
CallDeferred(nameof(Initialize));
}
private void Initialize()
{
Network = GetNode<Network>("/root/Game/Network");
LocalPlayer = GetNode<Player>("/root/Game/LocalPlayer");
ColorSlider.Value = GD.RandRange(0.0, 1.0);
var color = Color.FromHsv((float)ColorSlider.Value, 1.0F, 1.0F);
LocalPlayer.GetNode<Sprite>("Sprite").Modulate = color;
ColorPreview.Modulate = color;
Network.Connect(nameof(Network.StatusChanged), this, nameof(OnNetworkStatusChanged));
GetTree().Connect("network_peer_connected", this, nameof(OnPeerConnected));
}
private void OnNetworkStatusChanged(Network.Status status)
{
if (status == Network.Status.ConnectedToServer)
SendAppearance();
}
private void OnPeerConnected(int id)
{
// TODO: See if we can do something with syncing these directly?
var name = LocalPlayer.GetNode<Label>("Name").Text;
var hue = LocalPlayer.GetNode<Sprite>("Sprite").Modulate.h;
RpcId(id, nameof(AppearanceChanged), name, hue);
}
private void SendAppearance()
{
// TODO: See if we can do something with syncing these directly?
var name = LocalPlayer.GetNode<Label>("Name").Text;
var hue = LocalPlayer.GetNode<Sprite>("Sprite").Modulate.h;
Rpc(nameof(AppearanceChanged), name, hue);
}
[Remote]
private void AppearanceChanged(string name, float hue)
{
// TODO: Clear out invalid characters from name.
hue = Mathf.Clamp(hue, 0.0F, 1.0F);
var id = GetTree().GetRpcSenderId();
var player = Network.GetOrCreatePlayerWithId(id);
player.GetNode<Label>("Name").Text = name;
player.GetNode<Sprite>("Sprite").Modulate = Color.FromHsv(hue, 1.0F, 1.0F);
}
#pragma warning disable IDE0051
#pragma warning disable IDE1006
private static readonly Regex INVALID_CHARS = new Regex(@"\s");
private void _on_Name_text_changed(string text)
{
var validText = INVALID_CHARS.Replace(text, "");
if (validText != text) {
var previousCaretPos = PlayerName.CaretPosition;
PlayerName.Text = validText;
PlayerName.CaretPosition = previousCaretPos - (text.Length - validText.Length);
}
}
private void _on_HSlider_value_changed(float value)
{
var color = Color.FromHsv(value, 1.0F, 1.0F);
ColorPreview.Modulate = color;
}
private void _on_Appearance_visibility_changed()
{
if (IsVisibleInTree()) return;
LocalPlayer.GetNode<Label>("Name").Text = PlayerName.Text;
LocalPlayer.GetNode<Sprite>("Sprite").Modulate = ColorPreview.Modulate;
if (GetTree().NetworkPeer != null) SendAppearance();
}
}

@ -0,0 +1,94 @@
using Godot;
public class EscapeMenuMultiplayer : Container
{
[Export] public NodePath StatusPath { get; set; }
[Export] public NodePath ServerStartStopPath { get; set; }
[Export] public NodePath ServerPortPath { get; set; }
[Export] public NodePath ClientDisConnectPath { get; set; }
[Export] public NodePath ClientAddressPath { get; set; }
public Label Status { get; private set; }
public Button ServerStartStop { get; private set; }
public LineEdit ServerPort { get; private set; }
public Button ClientDisConnect { get; private set; }
public LineEdit ClientAddress { get; private set; }
public Network Network { get; private set; }
public override void _EnterTree()
{
Status = GetNode<Label>(StatusPath);
ServerStartStop = GetNode<Button>(ServerStartStopPath);
ServerPort = GetNode<LineEdit>(ServerPortPath);
ClientDisConnect = GetNode<Button>(ClientDisConnectPath);
ClientAddress = GetNode<LineEdit>(ClientAddressPath);
Network = GetNode<Network>("/root/Game/Network");
Network.Connect(nameof(Network.StatusChanged), this, nameof(OnNetworkStatusChanged));
ServerPort.PlaceholderText = Network.DefaultPort.ToString();
ClientAddress.PlaceholderText = $"{Network.DefaultAddress}:{Network.DefaultPort}";
}
private void OnNetworkStatusChanged(Network.Status status)
{
switch (status) {
case Network.Status.NoConnection:
Status.Text = "No Connection";
Status.Modulate = Colors.Red;
break;
case Network.Status.ServerRunning:
Status.Text = "Server Running";
Status.Modulate = Colors.Green;
break;
case Network.Status.Connecting:
Status.Text = "Connecting ...";
Status.Modulate = Colors.Yellow;
break;
case Network.Status.ConnectedToServer:
Status.Text = "Connected to Server";
Status.Modulate = Colors.Green;
break;
}
ServerPort.Editable = status == Network.Status.NoConnection;
ServerStartStop.Text = (status == Network.Status.ServerRunning) ? "Stop Server" : "Start Server";
ClientAddress.Editable = status == Network.Status.NoConnection;
ClientDisConnect.Text = (status < Network.Status.Connecting) ? "Connect" : "Disconnect";
ClientDisConnect.Disabled = status == Network.Status.ServerRunning;
if (Visible) GetTree().Paused = status == Network.Status.NoConnection;
}
#pragma warning disable IDE0051
#pragma warning disable IDE1006
private void _on_ServerStartStop_pressed()
{
if (GetTree().NetworkPeer == null) {
var port = Network.DefaultPort;
if (ServerPort.Text.Length > 0)
port = ushort.Parse(ServerPort.Text);
Network.StartServer(port);
} else Network.StopServer();
}
private void _on_ClientDisConnect_pressed()
{
if (GetTree().NetworkPeer == null) {
var address = Network.DefaultAddress;
var port = Network.DefaultPort;
if (ClientAddress.Text.Length > 0) {
// TODO: Verify input some more, support IPv6?
var split = address.Split(':');
address = (split.Length > 1) ? split[0] : address;
port = (split.Length > 1) ? ushort.Parse(split[1]) : port;
}
Network.ConnectToServer(address, port);
} else Network.DisconnectFromServer();
}
private void _on_HideAddress_toggled(bool pressed)
=> ClientAddress.Secret = pressed;
}

@ -9,6 +9,7 @@ public class Game : Node
public override void _Ready()
{
GD.Randomize();
SpawnPlayer();
SpawnBlocks();
}

@ -21,7 +21,7 @@ public class Network : Node
public Node PlayerContainer { get; private set; }
public Player OwnPlayer { get; private set; }
public Player LocalPlayer { get; private set; }
public Status CurrentStatus { get; private set; } = Status.NoConnection;
[Signal] public delegate void StatusChanged(Status status);
@ -29,18 +29,18 @@ public class Network : Node
{
PlayerContainer = GetNode(PlayerContainerPath);
GetTree().Connect("connected_to_server", this, "OnClientConnected");
GetTree().Connect("connection_failed", this, "DisconnectFromServer");
GetTree().Connect("server_disconnected", this, "DisconnectFromServer");
GetTree().Connect("connected_to_server", this, nameof(OnClientConnected));
GetTree().Connect("connection_failed", this, nameof(DisconnectFromServer));
GetTree().Connect("server_disconnected", this, nameof(DisconnectFromServer));
GetTree().Connect("network_peer_connected", this, "OnPeerConnected");
GetTree().Connect("network_peer_disconnected", this, "OnPeerDisconnected");
GetTree().Connect("network_peer_connected", this, nameof(OnPeerConnected));
GetTree().Connect("network_peer_disconnected", this, nameof(OnPeerDisconnected));
}
public override void _Process(float delta)
{
if (OwnPlayer == null) return;
RpcUnreliable("OnPlayerMoved", OwnPlayer.Position);
if (LocalPlayer == null) return;
RpcUnreliable(nameof(OnPlayerMoved), LocalPlayer.Position);
}
@ -53,7 +53,7 @@ public class Network : Node
var error = peer.CreateServer(port);
if (error != Error.Ok) return error;
GetTree().NetworkPeer = peer;
OwnPlayer = FindOwnPlayer();
LocalPlayer = FindLocalPlayer();
CurrentStatus = Status.ServerRunning;
EmitSignal(nameof(StatusChanged), CurrentStatus);
@ -69,7 +69,7 @@ public class Network : Node
((NetworkedMultiplayerENet)GetTree().NetworkPeer).CloseConnection();
GetTree().NetworkPeer = null;
OwnPlayer = null;
LocalPlayer = null;
foreach (var player in GetOtherPlayers())
player.RemoveFromParent();
@ -101,7 +101,7 @@ public class Network : Node
((NetworkedMultiplayerENet)GetTree().NetworkPeer).CloseConnection();
GetTree().NetworkPeer = null;
OwnPlayer = null;
LocalPlayer = null;
foreach (var player in GetOtherPlayers())
player.RemoveFromParent();
@ -109,12 +109,12 @@ public class Network : Node
EmitSignal(nameof(StatusChanged), CurrentStatus);
}
private Player FindOwnPlayer()
=> GetTree().Root.GetChild(0).GetChildren().OfType<Player>().First();
public Player FindLocalPlayer()
=> GetNode<Player>("/root/Game/LocalPlayer");
private Node2D GetPlayerWithId(int id)
public Node2D GetPlayerWithId(int id)
=> PlayerContainer.GetNodeOrNull<Node2D>(id.ToString());
private Node2D GetOrCreatePlayerWithId(int id)
public Node2D GetOrCreatePlayerWithId(int id)
{
var player = GetPlayerWithId(id);
if (player == null) {
@ -127,16 +127,14 @@ public class Network : Node
}
// TODO: This assumes that any node whose name starts with a digit is a player.
private IEnumerable<Node2D> GetOtherPlayers()
public IEnumerable<Node2D> GetOtherPlayers()
=> PlayerContainer.GetChildren().OfType<Node2D>()
.Where(node => char.IsDigit(node.Name[0]));
#pragma warning disable IDE0051
private void OnClientConnected()
{
OwnPlayer = FindOwnPlayer();
LocalPlayer = FindLocalPlayer();
CurrentStatus = Status.ConnectedToServer;
EmitSignal(nameof(StatusChanged), CurrentStatus);

Loading…
Cancel
Save