From eb29e137a6a115e92f1e1062c6bdfb14dd3de83c Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Mon, 5 Aug 2024 23:54:22 +0800 Subject: [PATCH] :sparkles: Block placing --- Scenes/Player.tscn | 7 +- Scenes/Root.tscn | 26 +++--- Scenes/Tiles/Brick.tscn | 24 ++++++ .../{MultiplayerUI.tscn => StartScreen.tscn} | 28 ++++--- Scripts/{Multiplayer.cs => Launcher.cs} | 8 +- Scripts/Logic/PlayerInput.cs | 27 +++++-- Scripts/Logic/World.cs | 1 - Scripts/Player.cs | 43 ++++++++-- Scripts/TilesManager.cs | 35 ++++++++ .../UI/{MultiplayerUi.cs => StartScreen.cs} | 14 +++- Sprites/Brick.png | Bin 0 -> 23006 bytes Sprites/Brick.png.import | 34 ++++++++ export_presets.cfg | 76 ++++++++++++++++++ project.godot | 1 + 14 files changed, 282 insertions(+), 42 deletions(-) create mode 100644 Scenes/Tiles/Brick.tscn rename Scenes/UI/{MultiplayerUI.tscn => StartScreen.tscn} (50%) rename Scripts/{Multiplayer.cs => Launcher.cs} (92%) create mode 100644 Scripts/TilesManager.cs rename Scripts/UI/{MultiplayerUi.cs => StartScreen.cs} (80%) create mode 100644 Sprites/Brick.png create mode 100644 Sprites/Brick.png.import create mode 100644 export_presets.cfg diff --git a/Scenes/Player.tscn b/Scenes/Player.tscn index 7350165..65b31c4 100644 --- a/Scenes/Player.tscn +++ b/Scenes/Player.tscn @@ -5,7 +5,7 @@ [ext_resource type="Script" path="res://Scripts/Logic/PlayerInput.cs" id="3_tvoua"] [sub_resource type="CircleShape2D" id="CircleShape2D_68yf8"] -radius = 26.0768 +radius = 20.48 [sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_bekoo"] properties/0/path = NodePath(".:position") @@ -23,15 +23,14 @@ properties/1/path = NodePath("InputSynchronizer:MovementDirection") properties/1/spawn = true properties/1/replication_mode = 1 -[node name="Player" type="CharacterBody2D" node_paths=PackedStringArray("PlayerCamera", "PlayerInput", "PlayerDashCountdown")] +[node name="Player" type="CharacterBody2D" node_paths=PackedStringArray("PlayerCamera", "PlayerInput")] script = ExtResource("1_0btyt") PlayerCamera = NodePath("Camera2D") PlayerInput = NodePath("InputSynchronizer") -PlayerDashCountdown = NodePath("DashCountdown") [node name="Sprite2D" type="Sprite2D" parent="."] position = Vector2(2.08165e-12, 2.08165e-12) -scale = Vector2(0.05, 0.05) +scale = Vector2(0.04, 0.04) texture = ExtResource("1_cqpqa") [node name="CollisionShape2D" type="CollisionShape2D" parent="."] diff --git a/Scenes/Root.tscn b/Scenes/Root.tscn index 078d053..f776242 100644 --- a/Scenes/Root.tscn +++ b/Scenes/Root.tscn @@ -1,23 +1,31 @@ -[gd_scene load_steps=5 format=3 uid="uid://bjhmjrldq4lkt"] +[gd_scene load_steps=6 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"] +[ext_resource type="PackedScene" uid="uid://bvll23f5ibd4v" path="res://Scenes/UI/StartScreen.tscn" id="2_7o53i"] +[ext_resource type="Script" path="res://Scripts/Launcher.cs" id="2_u5cms"] [ext_resource type="Script" path="res://Scripts/Logic/World.cs" id="3_xwguj"] +[ext_resource type="Script" path="res://Scripts/TilesManager.cs" id="5_5wdx5"] [node name="Node" type="Node"] -[node name="MultiplayerNode" type="Node" parent="." node_paths=PackedStringArray("World")] -script = ExtResource("1_fym13") -World = NodePath("../World") +[node name="StartScreen" parent="." node_paths=PackedStringArray("Launcher") instance=ExtResource("2_7o53i")] +Launcher = NodePath("../LauncherNode") -[node name="MultiplayerUi" parent="." node_paths=PackedStringArray("MultiplayerController") instance=ExtResource("2_7o53i")] -MultiplayerController = NodePath("../MultiplayerNode") +[node name="LauncherNode" type="Node" parent="." node_paths=PackedStringArray("World")] +script = ExtResource("2_u5cms") +World = NodePath("../World") [node name="World" type="Node2D" parent="."] script = ExtResource("3_xwguj") PlayerScene = ExtResource("1_vby0g") -[node name="MultiplayerSpawner" type="MultiplayerSpawner" parent="."] +[node name="TilesSpawner" type="MultiplayerSpawner" parent="World"] +_spawnable_scenes = PackedStringArray("res://Scenes/Tiles/Brick.tscn") +spawn_path = NodePath("../Tiles") + +[node name="Tiles" type="Node2D" parent="World"] +script = ExtResource("5_5wdx5") + +[node name="PlayerSpawner" type="MultiplayerSpawner" parent="."] _spawnable_scenes = PackedStringArray("res://Scenes/Player.tscn") spawn_path = NodePath("../World") diff --git a/Scenes/Tiles/Brick.tscn b/Scenes/Tiles/Brick.tscn new file mode 100644 index 0000000..e3ec998 --- /dev/null +++ b/Scenes/Tiles/Brick.tscn @@ -0,0 +1,24 @@ +[gd_scene load_steps=4 format=3 uid="uid://nj0k4l4mgq6"] + +[ext_resource type="Texture2D" uid="uid://c2qpm7mcrvq57" path="res://Sprites/Brick.png" id="1_fms8g"] + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_saayk"] +size = Vector2(51.2, 51.2) + +[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_fbc2m"] +properties/0/path = NodePath(".:position") +properties/0/spawn = true +properties/0/replication_mode = 1 + +[node name="Brick" type="StaticBody2D"] + +[node name="Sprite2D" type="Sprite2D" parent="."] +position = Vector2(2.08165e-12, 2.08165e-12) +scale = Vector2(0.05, 0.05) +texture = ExtResource("1_fms8g") + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +shape = SubResource("RectangleShape2D_saayk") + +[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."] +replication_config = SubResource("SceneReplicationConfig_fbc2m") diff --git a/Scenes/UI/MultiplayerUI.tscn b/Scenes/UI/StartScreen.tscn similarity index 50% rename from Scenes/UI/MultiplayerUI.tscn rename to Scenes/UI/StartScreen.tscn index 39a5d45..768ee58 100644 --- a/Scenes/UI/MultiplayerUI.tscn +++ b/Scenes/UI/StartScreen.tscn @@ -1,8 +1,8 @@ [gd_scene load_steps=2 format=3 uid="uid://bvll23f5ibd4v"] -[ext_resource type="Script" path="res://Scripts/UI/MultiplayerUi.cs" id="1_fm6j5"] +[ext_resource type="Script" path="res://Scripts/UI/StartScreen.cs" id="1_f8by8"] -[node name="MultiplayerUi" type="Control" node_paths=PackedStringArray("ServerPortInput", "ServerAddrInput", "StartAsServerButton", "StartAsClientButton")] +[node name="StartScreen" type="Control" node_paths=PackedStringArray("ServerPortInput", "ServerAddrInput", "StartAsSingleButton", "StartAsServerButton", "StartAsClientButton")] process_mode = 3 layout_mode = 3 anchors_preset = 15 @@ -10,11 +10,12 @@ anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -script = ExtResource("1_fm6j5") +script = ExtResource("1_f8by8") ServerPortInput = NodePath("CenterContainer/VBoxContainer/PortEdit") ServerAddrInput = NodePath("CenterContainer/VBoxContainer/AddrEdit") -StartAsServerButton = NodePath("CenterContainer/VBoxContainer/HBoxContainer/HostButton") -StartAsClientButton = NodePath("CenterContainer/VBoxContainer/HBoxContainer/ConnectButton") +StartAsSingleButton = NodePath("CenterContainer/VBoxContainer/PlayAloneButton") +StartAsServerButton = NodePath("CenterContainer/VBoxContainer/MultiplayerActions/HostButton") +StartAsClientButton = NodePath("CenterContainer/VBoxContainer/MultiplayerActions/ConnectButton") [node name="CenterContainer" type="CenterContainer" parent="."] layout_mode = 0 @@ -24,7 +25,16 @@ offset_bottom = 648.0 [node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"] layout_mode = 2 -[node name="Label" type="Label" parent="CenterContainer/VBoxContainer"] +[node name="SinglePlayerTitle" type="Label" parent="CenterContainer/VBoxContainer"] +layout_mode = 2 +text = "Singleplayer" +horizontal_alignment = 1 + +[node name="PlayAloneButton" type="Button" parent="CenterContainer/VBoxContainer"] +layout_mode = 2 +text = "Play Alone" + +[node name="MultiplayerTitle" type="Label" parent="CenterContainer/VBoxContainer"] layout_mode = 2 text = "Mutiplayer" horizontal_alignment = 1 @@ -37,13 +47,13 @@ placeholder_text = "Server port" layout_mode = 2 placeholder_text = "Server address" -[node name="HBoxContainer" type="HBoxContainer" parent="CenterContainer/VBoxContainer"] +[node name="MultiplayerActions" type="HBoxContainer" parent="CenterContainer/VBoxContainer"] layout_mode = 2 -[node name="HostButton" type="Button" parent="CenterContainer/VBoxContainer/HBoxContainer"] +[node name="HostButton" type="Button" parent="CenterContainer/VBoxContainer/MultiplayerActions"] layout_mode = 2 text = "Host a Game" -[node name="ConnectButton" type="Button" parent="CenterContainer/VBoxContainer/HBoxContainer"] +[node name="ConnectButton" type="Button" parent="CenterContainer/VBoxContainer/MultiplayerActions"] layout_mode = 2 text = "Connect a Game" diff --git a/Scripts/Multiplayer.cs b/Scripts/Launcher.cs similarity index 92% rename from Scripts/Multiplayer.cs rename to Scripts/Launcher.cs index b3a9bd8..29c2fa0 100644 --- a/Scripts/Multiplayer.cs +++ b/Scripts/Launcher.cs @@ -3,7 +3,7 @@ using Godot; namespace CodingLand.Scripts; -public partial class Multiplayer : Node +public partial class Launcher : Node { [Export] public World World; @@ -30,6 +30,12 @@ public partial class Multiplayer : Node } } + public void StartAsSingle() + { + GameUnfreeze(); + World.StartGame(); + } + public bool StartAsServer(int port) { var peer = new ENetMultiplayerPeer(); diff --git a/Scripts/Logic/PlayerInput.cs b/Scripts/Logic/PlayerInput.cs index 60a30a3..b82f7c3 100644 --- a/Scripts/Logic/PlayerInput.cs +++ b/Scripts/Logic/PlayerInput.cs @@ -6,22 +6,26 @@ public partial class PlayerInput : MultiplayerSynchronizer { [Export] public bool IsDashing; + [Export] public Vector2 BuildingAt; + [Export] public Vector2 MovementDirection; + private bool IsCurrentPlayer => GetMultiplayerAuthority() == Multiplayer.GetUniqueId(); + public override void _Ready() { - if (GetMultiplayerAuthority() != Multiplayer.GetUniqueId()) - { - SetProcess(false); - SetPhysicsProcess(false); - } + if (IsCurrentPlayer) return; + SetProcess(false); + SetPhysicsProcess(false); } [Rpc(CallLocal = true)] private void Dash() - { - IsDashing = true; - } + => IsDashing = true; + + [Rpc(CallLocal = true)] + private void Build(Vector2 pos) + => BuildingAt = pos; public override void _Process(double delta) { @@ -30,4 +34,11 @@ public partial class PlayerInput : MultiplayerSynchronizer if (Input.IsActionJustPressed("move_dash")) Rpc(nameof(Dash)); } + + public override void _Input(InputEvent evt) + { + if (!IsCurrentPlayer) return; + if (evt is InputEventMouseButton { Pressed: true }) + Rpc(nameof(Build), GetViewport().GetMousePosition()); + } } \ No newline at end of file diff --git a/Scripts/Logic/World.cs b/Scripts/Logic/World.cs index 7fd4127..0390700 100644 --- a/Scripts/Logic/World.cs +++ b/Scripts/Logic/World.cs @@ -1,4 +1,3 @@ -using System.Numerics; using Godot; using Vector2 = Godot.Vector2; diff --git a/Scripts/Player.cs b/Scripts/Player.cs index 484b903..848584e 100644 --- a/Scripts/Player.cs +++ b/Scripts/Player.cs @@ -6,20 +6,22 @@ namespace CodingLand.Scripts; public partial class Player : CharacterBody2D { private int _currentPlayerId = 1; - + [Export] public float MaxSpeed = 400f; [Export] public float Acceleration = 500f; [Export] public float Deceleration = 500f; [Export] public float RotationSpeed = 5f; + [Export] public int Reach = 5; + [Export] public Camera2D PlayerCamera; [Export] public PlayerInput PlayerInput; - [Export] public Timer PlayerDashCountdown; [Export] public float PlayerDashAcceleration = 2f; - [Export] public int PlayerId + [Export] + public int PlayerId { get => _currentPlayerId; set @@ -34,18 +36,34 @@ public partial class Player : CharacterBody2D PlayerId = id; PlayerInput.SetMultiplayerAuthority(id); } + + private TilesManager _tilesMgr; public override void _Ready() { if (PlayerId == Multiplayer.GetUniqueId()) PlayerCamera.Enabled = true; + _tilesMgr = GetNode("../Tiles"); + } + + public override void _Process(double delta) + { + var vec = GetGlobalMousePosition(); + if (PlayerInput.BuildingAt == Vector2.Zero) return; + var distance = Position.DistanceTo(vec); + if (distance <= Reach * _tilesMgr.TileSize) + { + // Able to build + Rpc(nameof(AddTile), vec); + } + + PlayerInput.BuildingAt = Vector2.Zero; } public override void _PhysicsProcess(double delta) { var input = PlayerInput.MovementDirection; - if (input != Vector2.Zero) { input = input.Normalized(); @@ -59,14 +77,27 @@ public partial class Player : CharacterBody2D Velocity = Velocity.MoveToward(Vector2.Zero, Deceleration * (float)delta); } - if (PlayerInput.IsDashing && PlayerDashCountdown.IsStopped()) + var dashCountdown = GetNode("DashCountdown"); + if (PlayerInput.IsDashing && dashCountdown.IsStopped()) { PlayerInput.IsDashing = false; Velocity *= PlayerDashAcceleration; - PlayerDashCountdown.Start(); + dashCountdown.Start(); } Position += Velocity * (float)delta; MoveAndSlide(); } + + [Rpc(mode: MultiplayerApi.RpcMode.AnyPeer, CallLocal = true)] + public void AddTile(Vector2 pos) + { + if (_tilesMgr.GetTileByPosition(pos) != null) return; + + var tileVec = new Vector2(_tilesMgr.TileSize, _tilesMgr.TileSize); + var blueprint = GD.Load("res://Scenes/Tiles/Brick.tscn"); + var instance = blueprint.Instantiate(); + instance.Position = pos.Snapped(tileVec); + _tilesMgr.AddChild(instance); + } } diff --git a/Scripts/TilesManager.cs b/Scripts/TilesManager.cs new file mode 100644 index 0000000..477ac00 --- /dev/null +++ b/Scripts/TilesManager.cs @@ -0,0 +1,35 @@ +using Godot; + +namespace CodingLand.Scripts; + +public partial class TilesManager : Node2D +{ + [Export] public float TileSize = 51.2f; + + [Rpc(CallLocal = true)] + public void AddTile(Vector2 pos) + { + if (GetTileByPosition(pos) == null) + { + var tileVec = new Vector2(TileSize, TileSize); + // TODO Replace the brick to player selection + var blueprint = GD.Load("res://Scenes/Tiles/Brick.tscn"); + var instance = blueprint.Instantiate(); + instance.Position = pos.Snapped(tileVec); + AddChild(instance); + } + } + + public T GetTileByPosition(Vector2 position) where T : Node2D + { + foreach (var item in GetChildren()) + { + if (item is T tile && tile.Position == position) + { + return tile; + } + } + + return null; + } +} \ No newline at end of file diff --git a/Scripts/UI/MultiplayerUi.cs b/Scripts/UI/StartScreen.cs similarity index 80% rename from Scripts/UI/MultiplayerUi.cs rename to Scripts/UI/StartScreen.cs index 7b2cbad..defa4ab 100644 --- a/Scripts/UI/MultiplayerUi.cs +++ b/Scripts/UI/StartScreen.cs @@ -2,15 +2,16 @@ using Godot; namespace CodingLand.Scripts.UI; -public partial class MultiplayerUi : Control +public partial class StartScreen : Control { [Export] public int DefaultServerPort = 4343; [Export] public string DefaultServerAddr = "127.0.0.1"; - [Export] public Multiplayer MultiplayerController; + [Export] public Launcher Launcher; [Export] public LineEdit ServerPortInput; [Export] public LineEdit ServerAddrInput; + [Export] public Button StartAsSingleButton; [Export] public Button StartAsServerButton; [Export] public Button StartAsClientButton; @@ -41,6 +42,11 @@ public partial class MultiplayerUi : Control ServerPortInput.Text = DefaultServerPort.ToString(); ServerAddrInput.Text = DefaultServerAddr; + StartAsSingleButton.Pressed += () => + { + Launcher.StartAsSingle(); + Hide(); + }; StartAsServerButton.Pressed += () => { if (!DoValidation()) @@ -50,7 +56,7 @@ public partial class MultiplayerUi : Control } var port = ServerPortInput.Text; - var result = MultiplayerController.StartAsServer(int.Parse(port)); + var result = Launcher.StartAsServer(int.Parse(port)); if (result) Hide(); @@ -65,7 +71,7 @@ public partial class MultiplayerUi : Control var addr = ServerAddrInput.Text; var port = ServerPortInput.Text; - var result = MultiplayerController.StartAsClient(addr, int.Parse(port)); + var result = Launcher.StartAsClient(addr, int.Parse(port)); if (result) Hide(); diff --git a/Sprites/Brick.png b/Sprites/Brick.png new file mode 100644 index 0000000000000000000000000000000000000000..c6b4f02f553ce7c9906257ffc9d2d837495fc74c GIT binary patch literal 23006 zcmeHPeQ;A%7QZijt!XP7pw=ofeHLNSw)uhzgeHv;pw$LC6}PF1Hnb_5kv1_2BubT} z4xkQ$)hd1r3>{@zcXxz}%=(FKbq2IT>&R$j79^;4i_g2ji|@wutQQ zyXg#kIb^d`G@8xiHYm$U1~Y}E@gne#FgKEPp-jl1nQ4jg1I+B0j0|Kn1b&k1;N7^z zE(`{mqy^sms~q0^cj2?j?z63JvU(gYuFB=$<|s>)^Pr7wV}(9)puE3>Nsiwki}%Np zj3Ej9eISL9k8#ocr4~h zUA?18X>D+eE57$>y#tt(r*9=CfZ$jc>WE8rUeYENU>H)hQ|o#t`RN%FjSoTWxbY)~@5%Vwk5@ z!%L;%f0hapq?(h<6ICt$Up2K^s+!cir`hf?Xk(*Es-;>hTy`7$MufR)Vk)V1De}CT zbb>S2n(R%sW;ee+4LD?}YQm-oRV|lSO=(I|1^esF;EfGdkJV)L*bMv@C|1ueR+p?4 zx4_(zLVibpdH+XN($8X-4SJZk7tP$%UQ#3{>cin$>2RzyOtiDbSqS7*lO zcHs0iIY&w~Urv8=nlr8b+gTY$Og*2Zw|uzTaEH0fb5B{#$EKqjqPm*tm+}V(eiKQ%@6ZsCF-%9@r+dreGNLd`9CU>|M=mGncdcJS_s9`n8a0Hm!)PS4 zE&B_nB!}g@WV)x(6|!`h%-HkXs%I0k77B9m4PBv_tx%Ax?dP7RhcS|HM(Waxeq+E- zsyZ8LZb>XxD9HTt=n6KAW&N!)-!Bl%mzb1-d_Y%lRUAihijH5GNmR_f$a1{Y#BXzWFJ$p*9g8XOY7G$xMkk^-V1Ng4 zFviGYOpY`IGBwE5#CaC51d?4bV<63dG($YFWPkTGLvZ-P@Mjt&GJ+?YL zHaOnn9?1XKi2*&$HA|TA1Oj3q9zN39h!lWC)1j06F`Xo!3k>`ci7r0*#;TV{;QVdj z;j_b+hP?XkdoT8PwU<5G7&-dFBS$OX!ni1Ks;uk95AE+>9NKW^`uYr@uRG z>c|CIz9Ax?C3UMWAdPqL*Q2zp>mV1`S(mv~B5Y?EuJ~LFy=gmvB)4?3GZL8tp%6IW zCvCaw4RlV<0x7v7OY7tW;tK`iy+%@=y>J)3=Zhe3m|N5%r)S0$b7c3Xoh#_-)9+Ht=$Vyg%Zc3@no6xW0P$OQ>&(0WJ+s~Etp7mg z5RLWSkch48nX;80j79Sbc1H6GZj9cG;E;k*2o4Ai$@2oi0l@*m0WW5F@8$1G7*+_e z5r!3FM21nD5QAb+ES!)C4hRk@{0)Kwf4HWmI#`d(J~c zU6Lz9>yU{?DOfp&z<7Z}S!j zt@CGuPaoNxF;n6!hahqKQr{LDVuIWJ#JQ$smPEK75~r0R$)m2$Wk&MOTZQfPW2k{Q z{Y1TI=w^CzzB7X(Cyu{RAxX$uj3n>aXd8`&CnhV%;JM!2^vvptII{Iji{v5NLC7k5 z*W0RTd{skM`H;sTc}&&Ivi^ndYj34zmIqnodR@L`5evaMJ6FB@JUz3mkX6>~yjHS^ z=?oL>+go`jy#>*{f}PR4f*YgviixA&4jgWM>)pQ*lJg(_ZvjwOAvE=GZE7?x9&`R~ zJm!Q86y73)I}u*egexcBfrY~X!9nD<5gZU4l35M}2Ly){vH`&X!2!Vm*|RH*oE&dD zyvXq%QX>E?O!%y7V S@f!apiYt~ZH|