diff --git a/gfx/background.png b/gfx/background.png new file mode 100644 index 0000000..bea64d4 Binary files /dev/null and b/gfx/background.png differ diff --git a/gfx/background.png.import b/gfx/background.png.import new file mode 100644 index 0000000..d42ae6b --- /dev/null +++ b/gfx/background.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/background.png-34463f2717b0502091d019b33ae7e4f3.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://gfx/background.png" +dest_files=[ "res://.import/background.png-34463f2717b0502091d019b33ae7e4f3.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=1 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=false +svg/scale=1.0 diff --git a/scene/GameScene.tscn b/scene/GameScene.tscn index b456539..3ff8483 100644 --- a/scene/GameScene.tscn +++ b/scene/GameScene.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=10 format=2] +[gd_scene load_steps=12 format=2] [ext_resource path="res://scene/EscapeMenu.tscn" type="PackedScene" id=1] [ext_resource path="res://src/Cursor.cs" type="Script" id=2] @@ -9,6 +9,8 @@ [ext_resource path="res://src/Viewport.cs" type="Script" id=7] [ext_resource path="res://src/Network.cs" type="Script" id=8] [ext_resource path="res://scene/Player.tscn" type="PackedScene" id=9] +[ext_resource path="res://gfx/background.png" type="Texture" id=10] +[ext_resource path="res://src/Background.cs" type="Script" id=11] [node name="Game" type="Node"] script = ExtResource( 3 ) @@ -22,6 +24,19 @@ script = ExtResource( 8 ) PlayerContainerPath = NodePath("../Players") OtherPlayerScene = ExtResource( 9 ) +[node name="Background" type="TextureRect" parent="."] +modulate = Color( 0.278431, 0.286275, 0.301961, 1 ) +margin_left = 1.0 +margin_top = -1.0 +margin_right = 1281.0 +margin_bottom = 719.0 +texture = ExtResource( 10 ) +stretch_mode = 2 +script = ExtResource( 11 ) +__meta__ = { +"_edit_use_anchors_": false +} + [node name="Players" type="Node" parent="."] [node name="LocalPlayer" parent="Players" instance=ExtResource( 5 )] diff --git a/scene/LocalPlayer.tscn b/scene/LocalPlayer.tscn index 381385c..93240e3 100644 --- a/scene/LocalPlayer.tscn +++ b/scene/LocalPlayer.tscn @@ -6,5 +6,5 @@ [node name="LocalPlayer" instance=ExtResource( 1 )] script = ExtResource( 3 ) -[node name="Camera2D" type="Camera2D" parent="." index="0"] +[node name="Camera" type="Camera2D" parent="." index="0"] current = true diff --git a/src/Background.cs b/src/Background.cs new file mode 100644 index 0000000..8adf67b --- /dev/null +++ b/src/Background.cs @@ -0,0 +1,14 @@ +using Godot; + +public class Background : TextureRect +{ + public override void _Process(float delta) + { + var offset = new Vector2(8, 8); + var tileSize = Texture.GetSize(); + var viewportSize = GetViewport().Size; + var camera = LocalPlayer.Instance.GetNode("Camera"); + RectPosition = ((camera.GlobalPosition - viewportSize / 2) / tileSize).Floor() * tileSize - offset; + RectSize = ((viewportSize + offset) / tileSize + Vector2.One).Ceil() * tileSize; + } +} diff --git a/src/EscapeMenuAppearance.cs b/src/EscapeMenuAppearance.cs index f1a6eda..53403cb 100644 --- a/src/EscapeMenuAppearance.cs +++ b/src/EscapeMenuAppearance.cs @@ -17,7 +17,7 @@ public class EscapeMenuAppearance : CenterContainer ColorPreview = GetNode(ColorPreviewPath); ColorSlider = GetNode(ColorSliderPath); - ColorSlider.Value = GD.RandRange(0.0, 1.0); + ColorSlider.Value = GD.Randf(); var color = Color.FromHsv((float)ColorSlider.Value, 1.0F, 1.0F); LocalPlayer.Instance.Color = ColorPreview.Modulate = color; } diff --git a/src/Extensions.cs b/src/Extensions.cs index ef39fd2..4ff0b68 100644 --- a/src/Extensions.cs +++ b/src/Extensions.cs @@ -14,43 +14,40 @@ public static class Extensions } - public static void Rset(this Node @this, int except, string property, string method, object value) + public static void RsetProperty(this Node @this, Node propertyOwner, string property, string method, object value) { - if (@this.IsInsideTree() && @this.GetTree().NetworkPeer != null) { - if (@this.GetTree().IsNetworkServer()) - @this.RsetExcept(except, property, value); - else if (Network.Status == NetworkStatus.ConnectedToServer) - @this.RpcId(1, method, value); - } + if (!@this.IsInsideTree()) return; + if (Network.IsServer) propertyOwner.RsetExcept(@this as Player, property, value); + else if (Network.IsMultiplayerReady) @this.RpcId(1, method, value); } - public static void RsetUnreliable(this Node @this, int except, string property, string method, object value) + public static void RsetPropertyUnreliable(this Node @this, Node propertyOwner, string property, string method, object value) { - if (@this.IsInsideTree() && @this.GetTree().NetworkPeer != null) { - if (@this.GetTree().IsNetworkServer()) - @this.RsetUnreliableExcept(except, property, value); - else if (Network.Status == NetworkStatus.ConnectedToServer) - @this.RpcUnreliableId(1, method, value); - } + if (!@this.IsInsideTree()) return; + if (Network.IsServer) propertyOwner.RsetUnreliableExcept(@this as Player, property, value); + else if (Network.IsMultiplayerReady) @this.RpcUnreliableId(1, method, value); } - public static void RpcExcept(this Node @this, int except, string method, params object[] args) + public static void RpcExcept(this Node @this, Player except, string method, params object[] args) { - foreach (var peer in @this.GetTree().GetNetworkConnectedPeers()) - if (peer != except) @this.RpcId(peer, method, args); + foreach (var player in Network.Players) + if (player != except) + @this.RpcId(player.NetworkId, method, args); } - public static void RsetUnreliableExcept(this Node @this, int except, string property, object value) + public static void RsetExcept(this Node @this, Player except, string property, object value) { - foreach (var peer in @this.GetTree().GetNetworkConnectedPeers()) - if (peer != except) @this.RsetUnreliableId(peer, property, value); + foreach (var player in Network.Players) + if (player != except) + @this.RsetId(player.NetworkId, property, value); } - public static void RsetExcept(this Node @this, int except, string property, object value) + public static void RsetUnreliableExcept(this Node @this, Player except, string property, object value) { - foreach (var peer in @this.GetTree().GetNetworkConnectedPeers()) - if (peer != except) @this.RsetId(peer, property, value); + foreach (var player in Network.Players) + if (player != except) + @this.RsetUnreliableId(player.NetworkId, property, value); } } diff --git a/src/Game.cs b/src/Game.cs index e792096..fdfd24c 100644 --- a/src/Game.cs +++ b/src/Game.cs @@ -4,7 +4,6 @@ public class Game : Node { public static Game Instance { get; private set; } - [Export] public Vector2 RoomSize { get; set; } = new Vector2(32, 18) * 16; [Export] public PackedScene BlockScene { get; set; } public Game() => Instance = this; @@ -18,23 +17,11 @@ public class Game : Node private void SpawnBlocks() { - void SpawnBlockAt(int x, int y) - { + for (var x = -6; x <= 6; x++) { var block = BlockScene.Init(); - block.Position = new Vector2(x, y); + block.Position = new Vector2(x * 16, 48); + block.Modulate = Color.FromHsv(GD.Randf(), 0.1F, 1.0F); AddChild(block); } - - // Top and bottom. - for (var x = (int)RoomSize.x / -2; x <= (int)RoomSize.x / 2; x += 16) { - SpawnBlockAt(x, (int)RoomSize.y / -2); - SpawnBlockAt(x, (int)RoomSize.y / 2); - } - - // Left and right. - for (var y = (int)RoomSize.y / -2 + 16; y <= (int)RoomSize.y / 2 - 16; y += 16) { - SpawnBlockAt((int)RoomSize.x / -2, y); - SpawnBlockAt((int)RoomSize.x / 2, y); - } } } diff --git a/src/LocalPlayer.cs b/src/LocalPlayer.cs index 08c9e8b..b619bef 100644 --- a/src/LocalPlayer.cs +++ b/src/LocalPlayer.cs @@ -17,7 +17,7 @@ public class LocalPlayer : Player [Export(PropertyHint.Range, "0,1")] public float Acceleration { get; set; } = 0.25F; - private Vector2 _velocity = Vector2.Zero; + public Vector2 Velocity = Vector2.Zero; private DateTime? _jumpPressed = null; private DateTime? _lastOnFloor = null; @@ -27,10 +27,10 @@ public class LocalPlayer : Player public override void _PhysicsProcess(float delta) { var moveDir = Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left"); - _velocity.x = (moveDir != 0) ? Mathf.Lerp(_velocity.x, moveDir * Speed, Acceleration) - : Mathf.Lerp(_velocity.x, 0, Friction); - _velocity.y += Gravity * delta; - _velocity = MoveAndSlide(_velocity, Vector2.Up); + Velocity.x = (moveDir != 0) ? Mathf.Lerp(Velocity.x, moveDir * Speed, Acceleration) + : Mathf.Lerp(Velocity.x, 0, Friction); + Velocity.y += Gravity * delta; + Velocity = MoveAndSlide(Velocity, Vector2.Up); if (Input.IsActionJustPressed("move_jump")) _jumpPressed = DateTime.Now; @@ -39,9 +39,18 @@ public class LocalPlayer : Player if (((DateTime.Now - _jumpPressed) <= JumpEarlyTime) && ((DateTime.Now - _lastOnFloor) <= JumpCoyoteTime)) { - _velocity.y = -JumpSpeed; + Velocity.y = -JumpSpeed; _jumpPressed = null; _lastOnFloor = null; } } + + internal void ResetPositionInternal(Vector2 position) + { + Position = position; + Velocity = Vector2.Zero; + } + [Puppet] + internal void ResetPosition(Vector2 position) + => ResetPositionInternal(position); } diff --git a/src/Network.cs b/src/Network.cs index d831528..c909e66 100644 --- a/src/Network.cs +++ b/src/Network.cs @@ -18,8 +18,11 @@ public class Network : Node public static Network Instance { get; private set; } public static NetworkStatus Status { get; private set; } = NetworkStatus.NoConnection; - public static bool IsServer => Instance.GetTree().IsNetworkServer(); + public static bool IsMultiplayerReady => (Status == NetworkStatus.ServerRunning) || (Status == NetworkStatus.ConnectedToServer); + public static bool IsAuthoratative => Status <= NetworkStatus.ServerRunning; + public static bool IsServer => Status == NetworkStatus.ServerRunning; public static int LocalNetworkId => Instance.GetTree().GetNetworkUniqueId(); + public static IEnumerable Players => Instance._playersById.Values; private readonly Dictionary _playersById = new Dictionary(); @@ -162,6 +165,7 @@ public class Network : Node EmitSignal(nameof(StatusChanged), Status); LocalPlayer.Instance.Position = position; + LocalPlayer.Instance.Velocity = Vector2.Zero; return LocalPlayer.Instance; } diff --git a/src/Player.cs b/src/Player.cs index c8bd74b..6a7adbc 100644 --- a/src/Player.cs +++ b/src/Player.cs @@ -24,7 +24,7 @@ public class Player : KinematicBody2D, IInitializer get => Sprite.Modulate; set { Sprite.Modulate = value; - Sprite.Rset(NetworkId, "modulate", nameof(OnColorChanged), value); + this.RsetProperty(Sprite, "modulate", nameof(OnColorChanged), value); } } @@ -32,7 +32,7 @@ public class Player : KinematicBody2D, IInitializer get => DisplayNameLabel.Text; set { DisplayNameLabel.Text = value; - DisplayNameLabel.Rset(NetworkId, "text", nameof(OnDisplayNameChanged), value); + this.RsetProperty(DisplayNameLabel, "text", nameof(OnDisplayNameChanged), value); } } @@ -54,11 +54,19 @@ public class Player : KinematicBody2D, IInitializer } public override void _Process(float delta) - => this.RsetUnreliable(NetworkId, "position", nameof(OnPositionChanged), Position); + { + this.RsetPropertyUnreliable(this, "position", nameof(OnPositionChanged), Position); + + if (Network.IsAuthoratative && (Position.y > 9000)) { + if (this is LocalPlayer localPlayer) localPlayer.ResetPositionInternal(Vector2.Zero); + else RpcId(NetworkId, nameof(LocalPlayer.ResetPosition), Vector2.Zero); + } + } + [Master] private void OnPositionChanged(Vector2 value) - { if (GetTree().GetRpcSenderId() == NetworkId) Position = value; } + { if (GetTree().GetRpcSenderId() == NetworkId) Position = value.Floor(); } [Master] private void OnColorChanged(Color value)