using System; using Godot; using RustyOptions; namespace Movementtests.systems; public partial class HeadSystem : Node3D { private Camera3D _camera; private Marker3D _cameraAnchor; private AnimationPlayer _animationPlayer; [Export(PropertyHint.Range, "0,10,0.1,or_greater")] public float LookSensitivity { get; set; } = 1f; [Export(PropertyHint.Range, "0.1,50,0.1,or_greater")] public double CameraInclineAcceleration { get; set; } = 10f; [Export(PropertyHint.Range, "0,10,0.1,or_greater")] public float WallRunCameraIncline { get; set; } = 5f; [Export(PropertyHint.Range, "0,10,0.1,or_greater")] public float GroundedCameraIncline { get; set; } = 5f; [Export(PropertyHint.Range, "0,2,0.1,or_greater")] public float SlidingCameraHeightOffset { get; set; } = 1.0f; [Export(PropertyHint.Range, "0,1,0.01,or_greater")] public float SlidingJitterFrequency { get; set; } = 0.01f; [Export(PropertyHint.Range, "0,1,0.01,or_greater")] public float SlidingJitterAmplitude { get; set; } = 0.1f; private FastNoiseLite _slidingNoise = new FastNoiseLite(); public void Init() { Input.SetMouseMode(Input.MouseModeEnum.Captured); _camera = GetNode("CameraSmooth/Camera3D"); _cameraAnchor = GetNode("CameraAnchor"); _animationPlayer = GetNode("AnimationPlayer"); _slidingNoise.NoiseType = FastNoiseLite.NoiseTypeEnum.Perlin; _slidingNoise.SetFrequency(SlidingJitterFrequency); } public void OnMantle() { _animationPlayer.Play("mantle"); } public void LookAround(double delta, Vector2 lookDir, Vector3 playerInput, Vector3 playerVelocity, Vector3? wallContactPoint = null, float sensitivitMultiplier = 1f, bool isSliding = false) { // Horizontal movement of head float angleForHorizontalRotation = lookDir.X * LookSensitivity * sensitivitMultiplier; RotateY(angleForHorizontalRotation); // Vertical movement of head Vector3 currentCameraRotation = _cameraAnchor.Rotation; currentCameraRotation.X += Convert.ToSingle(lookDir.Y * LookSensitivity * sensitivitMultiplier); currentCameraRotation.X = Mathf.Clamp(currentCameraRotation.X, Mathf.DegToRad(-90f), Mathf.DegToRad(90f)); // Camera incline on Wall and more var isWallRunning = wallContactPoint.HasValue && wallContactPoint.Value.Length() > Mathf.Epsilon; float cameraIncline; if (isWallRunning) { var directionToWall = (wallContactPoint.Value - GlobalPosition).Normalized(); var cameraInclineFactor = ComputeCameraInclineFactor(directionToWall); cameraIncline = Mathf.DegToRad(WallRunCameraIncline * cameraInclineFactor); } else { var cameraInclineFactor = ComputeCameraInclineFactor(playerInput); cameraIncline = Mathf.DegToRad(GroundedCameraIncline * cameraInclineFactor * -1.0f); } currentCameraRotation.Z = (float) Mathf.Lerp(currentCameraRotation.Z, cameraIncline, delta * CameraInclineAcceleration); _cameraAnchor.Rotation = currentCameraRotation; if (isSliding) { _cameraAnchor.Position = Vector3.Down*SlidingCameraHeightOffset; float noise1D = _slidingNoise.GetNoise1D(Time.GetTicksMsec()); float noiseAmplitude = SlidingJitterAmplitude*Mathf.Clamp(playerVelocity.Length(), 0f, 1f); _cameraAnchor.Position += Vector3.Up*noise1D*noiseAmplitude; } else { _cameraAnchor.Position = Vector3.Zero; } _camera.GlobalTransform = _cameraAnchor.GetGlobalTransformInterpolated(); } public float ComputeCameraInclineFactor(Vector3 direction) { var forward = GetForwardHorizontalVector().Normalized(); var crossProduct = forward.Cross(direction); return crossProduct.Length()*Mathf.Sign(crossProduct.Y); } public Vector3 GetForwardHorizontalVector() { return GetGlobalTransform().Basis.Z; } public void SetHeight(float height) { Position = new Vector3(Position.X, height, Position.Z); } }