Remove LocalPlayer ... again

- Add PlayerMovement, child node
  of Player which handles movement
- PlayerMovement and Camera are
  added through code when spawned
- Add Player.IsLocal property
- Move Velocity property to Player
- Remove ResetPosition, instead just
  use RsetId on Position and Velocity
main
copygirl 4 years ago
parent 7c4ae2ce45
commit 3352518f08
  1. 11
      scene/LocalPlayer.tscn
  2. 3
      src/EscapeMenuWorld.cs
  3. 7
      src/Items/CreativeBuilding.cs
  4. 18
      src/Items/Weapon.cs
  5. 8
      src/Objects/Player.cs
  6. 37
      src/Objects/PlayerMovement.cs
  7. 14
      src/Scenes/Client.cs
  8. 10
      src/World.cs

@ -1,11 +0,0 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://scene/Player.tscn" type="PackedScene" id=1]
[ext_resource path="res://src/Objects/LocalPlayer.cs" type="Script" id=2]
[node name="LocalPlayer" instance=ExtResource( 1 )]
script = ExtResource( 2 )
[node name="Camera" type="Camera2D" parent="." index="0"]
pause_mode = 2
current = true

@ -106,7 +106,8 @@ public class EscapeMenuWorld : CenterContainer
foreach (var player in server.GetWorld().Players) { foreach (var player in server.GetWorld().Players) {
// Reset players' positions. // Reset players' positions.
// Can't use RPC helper method here since player is not a LocalPlayer here. // Can't use RPC helper method here since player is not a LocalPlayer here.
player.RpcId(player.NetworkID, nameof(LocalPlayer.ResetPosition), Vector2.Zero); player.RsetId(player.NetworkID, "position", Vector2.Zero);
player.RsetId(player.NetworkID, nameof(Player.Velocity), Vector2.Zero);
// Reset the visbility tracker so the client will receive new chunks. // Reset the visbility tracker so the client will receive new chunks.
player.VisibilityTracker.Reset(); player.VisibilityTracker.Reset();
} }

@ -35,7 +35,7 @@ public class CreativeBuilding : Node2D
public override void _UnhandledInput(InputEvent ev) public override void _UnhandledInput(InputEvent ev)
{ {
if (!Visible || !(Player is LocalPlayer) || !Player.IsAlive) return; if (!Visible || !Player.IsLocal || !Player.IsAlive) return;
if (ev.IsActionPressed("interact_primary")) { if (ev.IsActionPressed("interact_primary")) {
GetTree().SetInputAsHandled(); GetTree().SetInputAsHandled();
@ -49,7 +49,7 @@ public class CreativeBuilding : Node2D
public override void _Process(float delta) public override void _Process(float delta)
{ {
if (!(Player is LocalPlayer)) return; if (!Player.IsLocal) return;
if (!Visible || !Player.IsAlive) _currentMode = null; if (!Visible || !Player.IsAlive) _currentMode = null;
if (_currentMode == BuildMode.Placing) { if (_currentMode == BuildMode.Placing) {
@ -86,8 +86,7 @@ public class CreativeBuilding : Node2D
public override void _Draw() public override void _Draw()
{ {
if (!(Player is LocalPlayer) || !Cursor.Visible || if (!Player.IsLocal || !Cursor.Visible || EscapeMenu.Instance.Visible) return;
EscapeMenu.Instance.Visible) return;
var green = Color.FromHsv(1.0F / 3, 1.0F, 1.0F, 0.4F); var green = Color.FromHsv(1.0F / 3, 1.0F, 1.0F, 0.4F);
var red = Color.FromHsv(0.0F, 1.0F, 1.0F, 0.4F); var red = Color.FromHsv(0.0F, 1.0F, 1.0F, 0.4F);

@ -60,7 +60,7 @@ public class Weapon : Sprite
public override void _UnhandledInput(InputEvent ev) public override void _UnhandledInput(InputEvent ev)
{ {
if (!(Player is LocalPlayer)) return; if (!Player.IsLocal) return;
if (ev.IsActionPressed("interact_primary")) if (ev.IsActionPressed("interact_primary"))
{ HoldingTrigger = TimeSpan.Zero; OnTriggerPressed(); } { HoldingTrigger = TimeSpan.Zero; OnTriggerPressed(); }
if (ev.IsActionPressed("interact_reload")) Reload(); if (ev.IsActionPressed("interact_reload")) Reload();
@ -82,7 +82,7 @@ public class Weapon : Sprite
_reloadDelay = 0.0F; _reloadDelay = 0.0F;
Rounds = Capacity; Rounds = Capacity;
HoldingTrigger = null; HoldingTrigger = null;
if (Player is LocalPlayer) Update(); if (Player.IsLocal) Update();
} else if (Visible) { } else if (Visible) {
if (HoldingTrigger is TimeSpan holding) if (HoldingTrigger is TimeSpan holding)
HoldingTrigger = holding + TimeSpan.FromSeconds(delta); HoldingTrigger = holding + TimeSpan.FromSeconds(delta);
@ -101,7 +101,7 @@ public class Weapon : Sprite
_fireDelay = 0; _fireDelay = 0;
} }
if (Player is LocalPlayer) { if (Player.IsLocal) {
// Automatically reload when out of rounds. // Automatically reload when out of rounds.
if (Rounds <= 0) Reload(); if (Rounds <= 0) Reload();
@ -165,7 +165,7 @@ public class Weapon : Sprite
if (float.IsNaN(value = Mathf.PosMod(value, Mathf.Tau))) return; if (float.IsNaN(value = Mathf.PosMod(value, Mathf.Tau))) return;
RPC.Unreliable(SendAimAngle, value); RPC.Unreliable(SendAimAngle, value);
} else if (!(Player is LocalPlayer)) } else if (!Player.IsLocal)
AimDirection = value; AimDirection = value;
} }
@ -175,7 +175,7 @@ public class Weapon : Sprite
var seed = unchecked((int)GD.Randi()); var seed = unchecked((int)GD.Randi());
if (!FireInternal(AimDirection, Scale.y > 0, seed)) return; if (!FireInternal(AimDirection, Scale.y > 0, seed)) return;
RPC.Reliable(1, SendFire, AimDirection, Scale.y > 0, seed); RPC.Reliable(1, SendFire, AimDirection, Scale.y > 0, seed);
((LocalPlayer)Player).Velocity -= Mathf.Polar2Cartesian(Knockback, Rotation); Player.Velocity -= Mathf.Polar2Cartesian(Knockback, Rotation);
} }
protected virtual bool FireInternal(float aimDirection, bool toRight, int seed) protected virtual bool FireInternal(float aimDirection, bool toRight, int seed)
@ -209,7 +209,7 @@ public class Weapon : Sprite
_currentSpreadInc += Mathf.Deg2Rad(SpreadIncrease); _currentSpreadInc += Mathf.Deg2Rad(SpreadIncrease);
_currentRecoil += Mathf.Deg2Rad(random.NextFloat(RecoilMin, RecoilMax)); _currentRecoil += Mathf.Deg2Rad(random.NextFloat(RecoilMin, RecoilMax));
if (isServer || (Player is LocalPlayer)) { if (isServer || Player.IsLocal) {
// Do not keep track of fire rate or ammo for other players. // Do not keep track of fire rate or ammo for other players.
_fireDelay += 60.0F / RateOfFire; _fireDelay += 60.0F / RateOfFire;
Rounds -= 1; Rounds -= 1;
@ -227,7 +227,7 @@ public class Weapon : Sprite
// TODO: Only send to players who can see the full path of the bullet. // TODO: Only send to players who can see the full path of the bullet.
if (FireInternal(aimDirection, toRight, seed)) if (FireInternal(aimDirection, toRight, seed))
RPC.Reliable(SendFire, aimDirection, toRight, seed); RPC.Reliable(SendFire, aimDirection, toRight, seed);
} else if (!(Player is LocalPlayer)) } else if (!Player.IsLocal)
FireInternal(aimDirection, toRight, seed); FireInternal(aimDirection, toRight, seed);
} }
@ -250,14 +250,14 @@ public class Weapon : Sprite
if (this.GetGame() is Server) { if (this.GetGame() is Server) {
if (Player.NetworkID != GetTree().GetRpcSenderId()) return; if (Player.NetworkID != GetTree().GetRpcSenderId()) return;
if (ReloadInternal()) RPC.Reliable(SendReload); if (ReloadInternal()) RPC.Reliable(SendReload);
} else if (!(Player is LocalPlayer)) } else if (!Player.IsLocal)
ReloadInternal(); ReloadInternal();
} }
public override void _Draw() public override void _Draw()
{ {
if (!(Player is LocalPlayer) || !Player.IsAlive || _lowered) return; if (!Player.IsLocal || !Player.IsAlive || _lowered) return;
// Draws an "aiming cone" to show where bullets might travel. // Draws an "aiming cone" to show where bullets might travel.
var tip = TipOffset + new Vector2(4, 0); var tip = TipOffset + new Vector2(4, 0);

@ -16,9 +16,12 @@ public class Player : KinematicBody2D, IInitializable
public IItems Items { get; private set; } public IItems Items { get; private set; }
public int NetworkID { get => int.Parse(Name); set => Name = value.ToString(); } public int NetworkID { get => int.Parse(Name); set => Name = value.ToString(); }
public bool IsLocal => NetworkID == GetTree().GetNetworkUniqueId();
public string DisplayName { get => DisplayNameLabel.Text; set => DisplayNameLabel.Text = value; } public string DisplayName { get => DisplayNameLabel.Text; set => DisplayNameLabel.Text = value; }
public Color Color { get => Sprite.SelfModulate; set => Sprite.SelfModulate = value; } public Color Color { get => Sprite.SelfModulate; set => Sprite.SelfModulate = value; }
public Vector2 Velocity { get; set; }
public float Health { get; set; } = 1.0F; public float Health { get; set; } = 1.0F;
public bool IsAlive => Health > 0.0F; public bool IsAlive => Health > 0.0F;
private float _previousHealth; private float _previousHealth;
@ -37,6 +40,7 @@ public class Player : KinematicBody2D, IInitializable
RsetConfig("modulate", MultiplayerAPI.RPCMode.Puppetsync); RsetConfig("modulate", MultiplayerAPI.RPCMode.Puppetsync);
RsetConfig(nameof(DisplayName), MultiplayerAPI.RPCMode.Puppetsync); RsetConfig(nameof(DisplayName), MultiplayerAPI.RPCMode.Puppetsync);
RsetConfig(nameof(Color), MultiplayerAPI.RPCMode.Puppetsync); RsetConfig(nameof(Color), MultiplayerAPI.RPCMode.Puppetsync);
RsetConfig(nameof(Velocity), MultiplayerAPI.RPCMode.Puppet);
RsetConfig(nameof(Health), MultiplayerAPI.RPCMode.Puppet); RsetConfig(nameof(Health), MultiplayerAPI.RPCMode.Puppet);
} }
@ -59,8 +63,8 @@ public class Player : KinematicBody2D, IInitializable
if (!IsAlive && ((_respawnDelay += delta) > RESPAWN_TIMER.TotalSeconds)) { if (!IsAlive && ((_respawnDelay += delta) > RESPAWN_TIMER.TotalSeconds)) {
// TODO: Move respawning related code to its own method. // TODO: Move respawning related code to its own method.
// Can't use RPC helper method here since player is not a LocalPlayer here. RsetId(NetworkID, "position", Vector2.Zero);
RpcId(NetworkID, nameof(LocalPlayer.ResetPosition), Vector2.Zero); RsetId(NetworkID, nameof(Velocity), Vector2.Zero);
Rset("modulate", Colors.White); Rset("modulate", Colors.White);
Health = 1.0F; Health = 1.0F;
_respawnDelay = 0.0F; _respawnDelay = 0.0F;

@ -1,7 +1,7 @@
using System; using System;
using Godot; using Godot;
public class LocalPlayer : Player public class PlayerMovement : Node
{ {
// TODO: Implement "low jumps" activated by releasing the jump button early. // TODO: Implement "low jumps" activated by releasing the jump button early.
public TimeSpan JumpEarlyTime { get; } = TimeSpan.FromSeconds(0.2F); public TimeSpan JumpEarlyTime { get; } = TimeSpan.FromSeconds(0.2F);
@ -15,47 +15,40 @@ public class LocalPlayer : Player
public float GroundFriction { get; set; } = 0.2F; public float GroundFriction { get; set; } = 0.2F;
public float AirFriction { get; set; } = 0.05F; public float AirFriction { get; set; } = 0.05F;
private Player _player;
public Vector2 Velocity = Vector2.Zero;
private DateTime? _jumpPressed = null; private DateTime? _jumpPressed = null;
private DateTime? _lastOnFloor = null; private DateTime? _lastOnFloor = null;
public override void _Ready()
=> _player = GetParent<Player>();
public override void _Process(float delta) public override void _Process(float delta)
{ => RPC.Unreliable(1, _player.Move, _player.Position);
base._Process(delta);
RPC.Unreliable(1, Move, Position);
}
public override void _PhysicsProcess(float delta) public override void _PhysicsProcess(float delta)
{ {
var moveDir = 0.0F; var moveDir = 0.0F;
var jumpPressed = false; var jumpPressed = false;
if (!EscapeMenu.Instance.Visible && IsAlive) { if (!EscapeMenu.Instance.Visible && _player.IsAlive) {
moveDir = Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left"); moveDir = Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left");
jumpPressed = Input.IsActionJustPressed("move_jump"); jumpPressed = Input.IsActionJustPressed("move_jump");
} }
var friction = IsOnFloor() ? GroundFriction : AirFriction; var velocity = _player.Velocity;
Velocity.x = (moveDir != 0) ? Mathf.Lerp(Velocity.x, moveDir * MovementSpeed, Acceleration) var friction = _player.IsOnFloor() ? GroundFriction : AirFriction;
: Mathf.Lerp(Velocity.x, 0, friction); velocity.x = (moveDir != 0) ? Mathf.Lerp(_player.Velocity.x, moveDir * MovementSpeed, Acceleration)
Velocity.y += Gravity * delta; : Mathf.Lerp(_player.Velocity.x, 0, friction);
Velocity = MoveAndSlide(Velocity, Vector2.Up); velocity.y += Gravity * delta;
_player.Velocity = _player.MoveAndSlide(velocity, Vector2.Up);
if (jumpPressed) _jumpPressed = DateTime.Now; if (jumpPressed) _jumpPressed = DateTime.Now;
if (IsOnFloor()) _lastOnFloor = DateTime.Now; if (_player.IsOnFloor()) _lastOnFloor = DateTime.Now;
if (((DateTime.Now - _jumpPressed) <= JumpEarlyTime) && if (((DateTime.Now - _jumpPressed) <= JumpEarlyTime) &&
((DateTime.Now - _lastOnFloor) <= JumpCoyoteTime)) { ((DateTime.Now - _lastOnFloor) <= JumpCoyoteTime)) {
Velocity.y = -JumpVelocity; _player.Velocity -= new Vector2(0, JumpVelocity);
_jumpPressed = null; _jumpPressed = null;
_lastOnFloor = null; _lastOnFloor = null;
} }
} }
[Puppet]
public void ResetPosition(Vector2 position)
{
Position = position;
Velocity = Vector2.Zero;
}
} }

@ -12,15 +12,15 @@ public class Client : Game
public NetworkedMultiplayerENet Peer => (NetworkedMultiplayerENet)Multiplayer.NetworkPeer; public NetworkedMultiplayerENet Peer => (NetworkedMultiplayerENet)Multiplayer.NetworkPeer;
public ConnectionStatus Status => Peer?.GetConnectionStatus() ?? ConnectionStatus.Disconnected; public ConnectionStatus Status => Peer?.GetConnectionStatus() ?? ConnectionStatus.Disconnected;
public LocalPlayer LocalPlayer => (LocalPlayer)this.GetWorld().GetPlayer(GetTree().GetNetworkUniqueId()); public Player LocalPlayer => this.GetWorld().GetPlayer(GetTree().GetNetworkUniqueId());
private LocalPlayer _storedLocalPlayer; private Player _storedLocalPlayer;
public event Action Connected; public event Action Connected;
public event Action Disconnected; public event Action Disconnected;
public event Action<LocalPlayer> LocalPlayerSpawned; public event Action<Player> LocalPlayerSpawned;
public event Action<ConnectionStatus> StatusChanged; public event Action<ConnectionStatus> StatusChanged;
internal void FireLocalPlayerSpawned(LocalPlayer player) internal void FireLocalPlayerSpawned(Player player)
=> LocalPlayerSpawned?.Invoke(player); => LocalPlayerSpawned?.Invoke(player);
@ -57,9 +57,9 @@ public class Client : Game
if (IntegratedServer.Server.IsRunning) { if (IntegratedServer.Server.IsRunning) {
foreach (var player in this.GetWorld().Players) { foreach (var player in this.GetWorld().Players) {
// Store the local player for later restoration, but remove it from the scene. // Store the local player for later restoration, but remove it from the scene.
if (player is LocalPlayer localPlayer) { if (player.IsLocal) {
_storedLocalPlayer = localPlayer; _storedLocalPlayer = player;
localPlayer.GetParent().RemoveChild(localPlayer); player.GetParent().RemoveChild(player);
// Do NOT call QueueFree - like RemoveFromParent does. // Do NOT call QueueFree - like RemoveFromParent does.
} else player.RemoveFromParent(); } else player.RemoveFromParent();
} }

@ -61,14 +61,16 @@ public class World : Node
[PuppetSync] [PuppetSync]
public void SpawnPlayer(int networkID, Vector2 position) public void SpawnPlayer(int networkID, Vector2 position)
{ {
var isLocal = networkID == GetTree().GetNetworkUniqueId(); var player = SceneCache<Player>.Instance();
var player = (isLocal ? LOCAL_PLAYER : PLAYER).Init<Player>();
player.NetworkID = networkID; player.NetworkID = networkID;
player.Position = position; player.Position = position;
PlayerContainer.AddChild(player); PlayerContainer.AddChild(player);
if (player is LocalPlayer localPlayer) if (player.IsLocal) {
this.GetClient().FireLocalPlayerSpawned(localPlayer); player.AddChild(new PlayerMovement { Name = "PlayerMovement" });
player.AddChild(new Camera2D { Name = "Camera", Current = true });
this.GetClient().FireLocalPlayerSpawned(player);
}
if (this.GetGame() is Server) { if (this.GetGame() is Server) {
player.VisibilityTracker.ChunkTracked += (chunkPos) => { player.VisibilityTracker.ChunkTracked += (chunkPos) => {

Loading…
Cancel
Save