using Godot; public partial class Player : CharacterBody3D { [Export] Control GameMenu; [Export] public float Speed = 5f; [Export] public float JumpForce = 5f; [Export] public float MouseSensitivity = 0.2f; private Vector3 gravityVelocity = Vector3.Zero; private Vector3 movementVelocity = Vector3.Zero; private float cameraPitch = 0f; private Camera3D camera; private GravityReceiver gravityReceiver; public override void _Ready() { camera = GetNode("Camera"); gravityReceiver = GetNode("GravityReceiver"); } public override void _PhysicsProcess(double delta) { Vector3 newGravityVelocity = gravityVelocity; Vector3 newMovementVelocity = movementVelocity; if (IsInGravity()) { ProcessGravity(delta, ref newGravityVelocity); if (!GameMenu.Visible) { ProcessControlsGravity(ref newGravityVelocity, ref newMovementVelocity); } } else { newGravityVelocity = Vector3.Zero; ProcessCamera(delta); if (!GameMenu.Visible) { ProcessControls(ref newMovementVelocity); } } gravityVelocity = newGravityVelocity; movementVelocity = newMovementVelocity; Velocity = newGravityVelocity + newMovementVelocity; MoveAndSlide(); } public override void _Input(InputEvent @event) { if (GameMenu.Visible) { return; } if (@event is InputEventMouseMotion motion) { float yawDelta = -motion.Relative.X * MouseSensitivity; float yawDeltaRad = Mathf.DegToRad(yawDelta); float pitchDelta = -motion.Relative.Y * MouseSensitivity; float pitchDeltaRad = Mathf.DegToRad(pitchDelta); RotateObjectLocal(Vector3.Up, yawDeltaRad); if (IsInGravity()) { cameraPitch = Mathf.Clamp(cameraPitch + pitchDelta, -90f, 90f); } else { RotateObjectLocal(Vector3.Right, pitchDeltaRad); } camera.RotationDegrees = new Vector3(cameraPitch, 0, 0); } } public bool IsInGravity() { return gravityReceiver.InGravityZone && gravityReceiver.GravityStrength > 0f; } public bool IsOnGravityFloor() { for (int i = 0; i < GetSlideCollisionCount(); i++) { KinematicCollision3D collision = GetSlideCollision(i); Vector3 collisionNormal = collision.GetNormal(); float alignment = collisionNormal.Dot(gravityReceiver.GravityDirection); if (alignment > 0.7f) { return true; } } return false; } private void ProcessGravity(double delta, ref Vector3 newGravityVelocity) { if (!IsOnGravityFloor()) { newGravityVelocity -= gravityReceiver.GravityDirection * gravityReceiver.GravityStrength * (float)delta; } else { newGravityVelocity = -gravityReceiver.GravityDirection; } Vector3 currentUp = GlobalTransform.Basis.Y; Vector3 targetUp = gravityReceiver.GravityDirection; Vector3 axis = currentUp.Cross(targetUp); if (axis.Length() < 0.00001f) { return; } float angle = currentUp.AngleTo(targetUp); Rotate(axis.Normalized(), angle * (float)delta * 10f); } private void ProcessCamera(double delta) { if (cameraPitch > 0.01f) { cameraPitch -= 90f * (float)delta; } else if (cameraPitch < -0.001f) { cameraPitch += 90f * (float)delta; } if (Mathf.Abs(cameraPitch) < 1f) { cameraPitch = 0f; } 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"); Vector3 direction = Transform.Basis.X * inputX + Transform.Basis.Z * inputZ; if (direction != Vector3.Zero) { newMovementVelocity.X = direction.X * Speed; newMovementVelocity.Y = direction.Y * Speed; newMovementVelocity.Z = direction.Z * Speed; } else { newMovementVelocity.X = 0f; newMovementVelocity.Y = 0f; newMovementVelocity.Z = 0f; } if (Input.IsActionJustPressed("jump") && IsOnGravityFloor()) { newGravityVelocity = gravityReceiver.GravityDirection * 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"); Vector3 direction = Transform.Basis.X * inputX + Transform.Basis.Y * inputY + Transform.Basis.Z * inputZ; if (direction != Vector3.Zero) { newMovementVelocity.X = direction.X * Speed; newMovementVelocity.Y = direction.Y * Speed; newMovementVelocity.Z = direction.Z * Speed; } else { newMovementVelocity.X = 0f; newMovementVelocity.Y = 0f; newMovementVelocity.Z = 0f; } float inputRotateZ = Input.GetAxis("rotate_left", "rotate_right"); float rotateAmountZ = Mathf.DegToRad(inputRotateZ); RotateObjectLocal(Vector3.Forward, rotateAmountZ); } }