diff --git a/.idea/.idea.CodingLand/.idea/vcs.xml b/.idea/.idea.CodingLand/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/.idea.CodingLand/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Scenes/Player.tscn b/Scenes/Player.tscn index 55a06ed..649872a 100644 --- a/Scenes/Player.tscn +++ b/Scenes/Player.tscn @@ -6,8 +6,9 @@ [sub_resource type="CircleShape2D" id="CircleShape2D_68yf8"] radius = 26.0768 -[node name="Player" type="CharacterBody2D"] +[node name="Player" type="CharacterBody2D" node_paths=PackedStringArray("PlayerDashCountdown")] script = ExtResource("1_0btyt") +PlayerDashCountdown = NodePath("DashCountdown") [node name="Sprite2D" type="Sprite2D" parent="."] position = Vector2(2.08165e-12, 2.08165e-12) @@ -16,3 +17,6 @@ texture = ExtResource("1_cqpqa") [node name="CollisionShape2D" type="CollisionShape2D" parent="."] shape = SubResource("CircleShape2D_68yf8") + +[node name="DashCountdown" type="Timer" parent="."] +one_shot = true diff --git a/Scenes/Root.tscn b/Scenes/Root.tscn index 9fbb810..3b911f1 100644 --- a/Scenes/Root.tscn +++ b/Scenes/Root.tscn @@ -1,14 +1,26 @@ -[gd_scene load_steps=2 format=3 uid="uid://bjhmjrldq4lkt"] +[gd_scene load_steps=4 format=3 uid="uid://bjhmjrldq4lkt"] +[ext_resource type="Script" path="res://Scripts/Multiplayer.cs" id="1_fym13"] [ext_resource type="PackedScene" uid="uid://b3gx0bl43lku3" path="res://Scenes/Player.tscn" id="1_vby0g"] +[ext_resource type="PackedScene" uid="uid://bvll23f5ibd4v" path="res://Scenes/UI/MultiplayerUI.tscn" id="2_7o53i"] [node name="Node" type="Node"] -[node name="Camera2D" type="Camera2D" parent="."] +[node name="MultiplayerNode" type="Node" parent="." node_paths=PackedStringArray("Playground")] +script = ExtResource("1_fym13") +Playground = NodePath("../Playground") + +[node name="MultiplayerUi" parent="." node_paths=PackedStringArray("MultiplayerController") instance=ExtResource("2_7o53i")] +MultiplayerController = NodePath("../MultiplayerNode") + +[node name="Playground" type="Node2D" parent="."] + +[node name="Camera2D" type="Camera2D" parent="Playground"] +enabled = false process_callback = 0 position_smoothing_enabled = true rotation_smoothing_enabled = true -[node name="Player" parent="." node_paths=PackedStringArray("PlayerCamera") instance=ExtResource("1_vby0g")] +[node name="Player" parent="Playground" node_paths=PackedStringArray("PlayerCamera") instance=ExtResource("1_vby0g")] position = Vector2(0, 2) PlayerCamera = NodePath("../Camera2D") diff --git a/Scenes/UI/MultiplayerUI.tscn b/Scenes/UI/MultiplayerUI.tscn new file mode 100644 index 0000000..39a5d45 --- /dev/null +++ b/Scenes/UI/MultiplayerUI.tscn @@ -0,0 +1,49 @@ +[gd_scene load_steps=2 format=3 uid="uid://bvll23f5ibd4v"] + +[ext_resource type="Script" path="res://Scripts/UI/MultiplayerUi.cs" id="1_fm6j5"] + +[node name="MultiplayerUi" type="Control" node_paths=PackedStringArray("ServerPortInput", "ServerAddrInput", "StartAsServerButton", "StartAsClientButton")] +process_mode = 3 +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_fm6j5") +ServerPortInput = NodePath("CenterContainer/VBoxContainer/PortEdit") +ServerAddrInput = NodePath("CenterContainer/VBoxContainer/AddrEdit") +StartAsServerButton = NodePath("CenterContainer/VBoxContainer/HBoxContainer/HostButton") +StartAsClientButton = NodePath("CenterContainer/VBoxContainer/HBoxContainer/ConnectButton") + +[node name="CenterContainer" type="CenterContainer" parent="."] +layout_mode = 0 +offset_right = 1152.0 +offset_bottom = 648.0 + +[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="CenterContainer/VBoxContainer"] +layout_mode = 2 +text = "Mutiplayer" +horizontal_alignment = 1 + +[node name="PortEdit" type="LineEdit" parent="CenterContainer/VBoxContainer"] +layout_mode = 2 +placeholder_text = "Server port" + +[node name="AddrEdit" type="LineEdit" parent="CenterContainer/VBoxContainer"] +layout_mode = 2 +placeholder_text = "Server address" + +[node name="HBoxContainer" type="HBoxContainer" parent="CenterContainer/VBoxContainer"] +layout_mode = 2 + +[node name="HostButton" type="Button" parent="CenterContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Host a Game" + +[node name="ConnectButton" type="Button" parent="CenterContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +text = "Connect a Game" diff --git a/Scripts/Multiplayer.cs b/Scripts/Multiplayer.cs new file mode 100644 index 0000000..ee6a593 --- /dev/null +++ b/Scripts/Multiplayer.cs @@ -0,0 +1,71 @@ +using System; +using Godot; + +namespace CodingLand.Scripts; + +public partial class Multiplayer : Node +{ + [Export] public Node2D Playground; + + private void GameFreeze() + { + Playground.Hide(); + GetTree().Paused = true; + } + + private void GameUnfreeze() + { + Playground.Show(); + Playground.GetNode("Camera2D").Enabled = true; + GetTree().Paused = false; + } + + public override void _Ready() + { + GameFreeze(); + + if (DisplayServer.GetName() == "headless") + { + GD.Print("Starting server in headless mode..."); + StartAsServer(4343); + } + } + + public bool StartAsServer(int port) + { + var peer = new ENetMultiplayerPeer(); + peer.CreateServer(port); + if (peer.GetConnectionStatus() == MultiplayerPeer.ConnectionStatus.Disconnected) + { + GD.PrintErr("Failed to start multiplayer server..."); + OS.Alert("Failed to start multiplayer server..."); + return false; + } + + Multiplayer.MultiplayerPeer = peer; + GameUnfreeze(); + + return true; + } + + public bool StartAsClient(string addr, int port) + { + if (string.IsNullOrEmpty(addr)) return false; + + var peer = new ENetMultiplayerPeer(); + peer.CreateClient(addr, port); + if (peer.GetConnectionStatus() == MultiplayerPeer.ConnectionStatus.Disconnected) + { + var info = $"Unable to connect multiplayer server {addr}:{port}"; + GD.PrintErr(info); + OS.Alert(info); + return false; + } + + Multiplayer.MultiplayerPeer = peer; + GameUnfreeze(); + + return true; + } + +} diff --git a/Scripts/Player.cs b/Scripts/Player.cs index 4d7b803..805db43 100644 --- a/Scripts/Player.cs +++ b/Scripts/Player.cs @@ -1,3 +1,4 @@ +using System; using Godot; namespace CodingLand.Scripts; @@ -12,6 +13,9 @@ public partial class Player : CharacterBody2D [Export] public float CameraSmoothness = 0.05f; [Export] public Camera2D PlayerCamera; + + [Export] public Timer PlayerDashCountdown; + [Export] public float PlayerDashAcceleration = 2f; public override void _PhysicsProcess(double delta) { @@ -39,6 +43,12 @@ public partial class Player : CharacterBody2D { Velocity = Velocity.MoveToward(Vector2.Zero, Deceleration * (float)delta); } + + if (Input.IsActionJustPressed("move_dash") && PlayerDashCountdown.IsStopped()) + { + Velocity *= PlayerDashAcceleration; + PlayerDashCountdown.Start(); + } Position += Velocity * (float)delta; MoveAndSlide(); diff --git a/Scripts/UI/MultiplayerUi.cs b/Scripts/UI/MultiplayerUi.cs new file mode 100644 index 0000000..f4d7003 --- /dev/null +++ b/Scripts/UI/MultiplayerUi.cs @@ -0,0 +1,74 @@ +using Godot; + +namespace CodingLand.Scripts.UI; + +public partial class MultiplayerUi : Control +{ + [Export] public int DefaultServerPort = 4343; + [Export] public string DefaultServerAddr = "127.0.0.1"; + + [Export] public Multiplayer MultiplayerController; + + [Export] public LineEdit ServerPortInput; + [Export] public LineEdit ServerAddrInput; + [Export] public Button StartAsServerButton; + [Export] public Button StartAsClientButton; + + private void ApplySize() + { + var screenSize = GetViewportRect().Size; + + Position = new Vector2(0, 0); + Size = screenSize; + GetNode("CenterContainer").Size = screenSize; + } + + private bool DoValidation() + { + var addr = ServerAddrInput.Text; + var port = ServerPortInput.Text; + + if (string.IsNullOrEmpty(addr)) return false; + if (string.IsNullOrEmpty(port) || !int.TryParse(port, out _)) return false; + + return true; + } + + public override void _Ready() + { + ApplySize(); + + ServerPortInput.Text = DefaultServerPort.ToString(); + ServerAddrInput.Text = DefaultServerAddr; + + StartAsServerButton.Pressed += () => + { + if (!DoValidation()) + { + OS.Alert("Invalid multiplayer configuration."); + return; + } + + var port = ServerPortInput.Text; + var result = MultiplayerController.StartAsServer(int.Parse(port)); + + if (result) + Hide(); + }; + StartAsServerButton.Pressed += () => + { + if (!DoValidation()) + { + OS.Alert("Invalid multiplayer configuration."); + return; + } + + var addr = ServerAddrInput.Text; + var port = ServerPortInput.Text; + var result = MultiplayerController.StartAsClient(addr, int.Parse(port)); + + if (result) + Hide(); + }; + } +} diff --git a/project.godot b/project.godot index 4fb437d..9980d8d 100644 --- a/project.godot +++ b/project.godot @@ -41,6 +41,11 @@ move_right={ "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"echo":false,"script":null) ] } +move_dash={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":0,"echo":false,"script":null) +] +} [rendering]