- Appearance (name and color) can be changed - Appearance is synced to other players - Split tabs into multiple scripts - Use nameof() where applicablemain
parent
d302a56855
commit
7b76d44b43
8 changed files with 386 additions and 158 deletions
@ -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 |
||||
} |
||||
|
@ -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; |
||||
} |
Loading…
Reference in new issue