242 lines
6.2 KiB
C#
242 lines
6.2 KiB
C#
using Godot;
|
|
|
|
public partial class Player : CharacterBody3D
|
|
{
|
|
[Export] public double Speed = 5;
|
|
[Export] public double SprintMultiplier = 2;
|
|
[Export] public double JumpForce = 5;
|
|
[Export] public double MouseSensitivity = 0.2;
|
|
[Export] public double NetworkSyncInterval = 0.2;
|
|
[Export] public double NetworkPhysicsSyncInterval = 0.05;
|
|
|
|
public Control GameMenu { get; set; }
|
|
public Character PlayerData { get; set; }
|
|
|
|
public Vector3 GravityVelocity { get; set; } = Vector3.Zero;
|
|
public Vector3 MovementVelocity { get; set; } = Vector3.Zero;
|
|
|
|
private GravityReceiver gravityReceiver;
|
|
private double cameraPitch = 0;
|
|
private Camera3D camera;
|
|
private double networkSyncCounter = 0;
|
|
private double networkPhysicsSyncCounter = 0;
|
|
|
|
public override void _Ready()
|
|
{
|
|
camera = GetNode<Camera3D>("Camera");
|
|
camera.Current = IsMultiplayerAuthority();
|
|
|
|
gravityReceiver = GetNode<GravityReceiver>("GravityReceiver");
|
|
|
|
PlayerData.UpdateNodePosition();
|
|
}
|
|
|
|
public override void _Process(double delta)
|
|
{
|
|
if (IsMultiplayerAuthority())
|
|
{
|
|
RPCNode rpc = RPCNode.Instance;
|
|
|
|
networkPhysicsSyncCounter += delta;
|
|
if (networkPhysicsSyncCounter >= NetworkPhysicsSyncInterval)
|
|
{
|
|
networkPhysicsSyncCounter = 0;
|
|
rpc.Rpc(nameof(rpc.RpcSyncPlayerPhysics), GetMultiplayerAuthority(), MovementVelocity, GravityVelocity, GlobalRotation);
|
|
}
|
|
|
|
networkSyncCounter += delta;
|
|
if (networkSyncCounter >= NetworkSyncInterval)
|
|
{
|
|
networkSyncCounter = 0;
|
|
rpc.Rpc(nameof(rpc.RpcSyncPlayer), GetMultiplayerAuthority(), GlobalPosition, PlayerData.CurrentSector.Coordinates);
|
|
}
|
|
|
|
PlayerData.SetCoordinatesFromLocal(GlobalPosition);
|
|
}
|
|
|
|
PlayerData.Simulate(delta);
|
|
}
|
|
|
|
public override void _PhysicsProcess(double delta)
|
|
{
|
|
Vector3 newGravityVelocity = GravityVelocity;
|
|
Vector3 newMovementVelocity = MovementVelocity;
|
|
|
|
if (!GameMenu.Visible && IsMultiplayerAuthority())
|
|
{
|
|
if (IsInGravity())
|
|
{
|
|
ProcessGravity(delta, ref newGravityVelocity);
|
|
ProcessControlsGravity(ref newGravityVelocity, ref newMovementVelocity);
|
|
}
|
|
else
|
|
{
|
|
newGravityVelocity = Vector3.Zero;
|
|
|
|
ProcessCamera(delta);
|
|
ProcessControls(ref newMovementVelocity);
|
|
}
|
|
}
|
|
|
|
GravityVelocity = newGravityVelocity;
|
|
MovementVelocity = newMovementVelocity;
|
|
Velocity = newGravityVelocity + newMovementVelocity;
|
|
|
|
MoveAndSlide();
|
|
}
|
|
|
|
public override void _Input(InputEvent @event)
|
|
{
|
|
if (GameMenu.Visible)
|
|
{
|
|
return;
|
|
}
|
|
if (!IsMultiplayerAuthority())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (@event is InputEventMouseMotion motion)
|
|
{
|
|
double yawDelta = -motion.Relative.X * MouseSensitivity;
|
|
double yawDeltaRad = Mathf.DegToRad(yawDelta);
|
|
double pitchDelta = -motion.Relative.Y * MouseSensitivity;
|
|
double pitchDeltaRad = Mathf.DegToRad(pitchDelta);
|
|
|
|
RotateObjectLocal(Vector3.Up, yawDeltaRad);
|
|
|
|
if (IsInGravity())
|
|
{
|
|
cameraPitch = Mathf.Clamp(cameraPitch + pitchDelta, -90, 90);
|
|
}
|
|
else
|
|
{
|
|
RotateObjectLocal(Vector3.Right, pitchDeltaRad);
|
|
}
|
|
|
|
camera.RotationDegrees = new Vector3(cameraPitch, 0, 0);
|
|
}
|
|
}
|
|
|
|
public bool IsInGravity()
|
|
{
|
|
return gravityReceiver.InGravityZone && gravityReceiver.GetGravityStrength() > 0;
|
|
}
|
|
|
|
public bool IsOnGravityFloor()
|
|
{
|
|
for (int i = 0; i < GetSlideCollisionCount(); i++)
|
|
{
|
|
KinematicCollision3D collision = GetSlideCollision(i);
|
|
Vector3 collisionNormal = collision.GetNormal();
|
|
|
|
double alignment = collisionNormal.Dot(gravityReceiver.GetGravityDirection());
|
|
|
|
if (alignment > 0.7)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void ProcessGravity(double delta, ref Vector3 newGravityVelocity)
|
|
{
|
|
if (!IsOnGravityFloor())
|
|
{
|
|
newGravityVelocity -= gravityReceiver.GetGravityDirection() * gravityReceiver.GetGravityStrength() * (float)delta;
|
|
}
|
|
else
|
|
{
|
|
newGravityVelocity = -gravityReceiver.GetGravityDirection();
|
|
}
|
|
|
|
Vector3 currentUp = GlobalTransform.Basis.Y;
|
|
Vector3 targetUp = gravityReceiver.GetGravityDirection();
|
|
|
|
Vector3 axis = currentUp.Cross(targetUp);
|
|
if (axis.Length() < 0.00001)
|
|
{
|
|
return;
|
|
}
|
|
double angle = currentUp.AngleTo(targetUp);
|
|
|
|
GlobalRotate(axis.Normalized(), angle * delta * 10);
|
|
}
|
|
|
|
private void ProcessCamera(double delta)
|
|
{
|
|
if (cameraPitch > 0.01)
|
|
{
|
|
cameraPitch -= 90 * delta;
|
|
}
|
|
else if (cameraPitch < -0.001)
|
|
{
|
|
cameraPitch += 90 * delta;
|
|
}
|
|
if (Mathf.Abs(cameraPitch) < 1)
|
|
{
|
|
cameraPitch = 0;
|
|
}
|
|
camera.RotationDegrees = new Vector3(cameraPitch, 0, 0);
|
|
}
|
|
|
|
private void ProcessControlsGravity(ref Vector3 newGravityVelocity, ref Vector3 newMovementVelocity)
|
|
{
|
|
float inputX = Input.GetAxis("move_left", "move_right");
|
|
float inputZ = Input.GetAxis("move_forward", "move_back");
|
|
|
|
bool sprint = Input.IsActionPressed("sprint");
|
|
|
|
Vector3 direction = GlobalTransform.Basis.X * inputX + GlobalTransform.Basis.Z * inputZ;
|
|
|
|
if (direction != Vector3.Zero)
|
|
{
|
|
newMovementVelocity.X = direction.X * Speed * (sprint ? SprintMultiplier : 1);
|
|
newMovementVelocity.Y = direction.Y * Speed * (sprint ? SprintMultiplier : 1);
|
|
newMovementVelocity.Z = direction.Z * Speed * (sprint ? SprintMultiplier : 1);
|
|
}
|
|
else
|
|
{
|
|
newMovementVelocity.X = 0;
|
|
newMovementVelocity.Y = 0;
|
|
newMovementVelocity.Z = 0;
|
|
}
|
|
|
|
if (Input.IsActionJustPressed("jump") && IsOnGravityFloor())
|
|
{
|
|
newGravityVelocity = gravityReceiver.GetGravityDirection() * JumpForce;
|
|
}
|
|
}
|
|
|
|
private void ProcessControls(ref Vector3 newMovementVelocity)
|
|
{
|
|
float inputX = Input.GetAxis("move_left", "move_right");
|
|
float inputY = -Input.GetAxis("move_up", "move_down");
|
|
float inputZ = Input.GetAxis("move_forward", "move_back");
|
|
|
|
bool sprint = Input.IsActionPressed("sprint");
|
|
|
|
Vector3 direction = Transform.Basis.X * inputX + Transform.Basis.Y * inputY + Transform.Basis.Z * inputZ;
|
|
|
|
if (direction != Vector3.Zero)
|
|
{
|
|
newMovementVelocity.X = direction.X * Speed * (sprint ? SprintMultiplier : 1);
|
|
newMovementVelocity.Y = direction.Y * Speed * (sprint ? SprintMultiplier : 1);
|
|
newMovementVelocity.Z = direction.Z * Speed * (sprint ? SprintMultiplier : 1);
|
|
}
|
|
else
|
|
{
|
|
newMovementVelocity.X = 0;
|
|
newMovementVelocity.Y = 0;
|
|
newMovementVelocity.Z = 0;
|
|
}
|
|
|
|
double inputRotateZ = Input.GetAxis("rotate_left", "rotate_right");
|
|
|
|
double rotateAmountZ = Mathf.DegToRad(inputRotateZ);
|
|
|
|
RotateObjectLocal(Vector3.Forward, rotateAmountZ);
|
|
}
|
|
}
|