using System.Diagnostics; using System.Collections; using System.Collections.Generic; using System; using Godot; namespace Rokojori { [Tool] [GlobalClass] public partial class ThirdPersonCamera:VirtualCamera3D { [Export] public Node3D target; [Export] public Smoothing targetFollowSmoothing = new FrameSmoothing(); [ExportGroup("Yaw")] [Export] public float yawSpeed; [Export] public Sensor yawPositiveAxis; [Export] public Sensor yawNegativeAxis; [Export] public bool roundYaw = false; [Export] public int roundedYawResolution = 64; [Export] public float yaw = 0; [Export] public Smoothing yawSmoothing = new FrameSmoothing(); [Export] public bool yawGoesBehindPlayer = true; [Export] public Smoothing yawToBehingSmoothing = new FrameSmoothing(); [Export] public float yawBehindDelayDuration = 5; [Export] public float yawGoesBehindActivation = 0.1f; [Export] public float behindYaw = 0; [Export] public float currentYaw = 0; [Export] public float bcDelta = 0; [ExportGroup("Pitch")] [Export] public float pitchSpeed; [Export] public Sensor pitchPositiveAxis; [Export] public Sensor pitchNegativeAxis; [Export] public bool pitchIsRelative = false; [Export] public float pitch = 0; [Export] public float minPitch = -10; [Export] public float maxPitch = 80; public float normalizedPitch => MathX.NormalizeClamped( pitch, minPitch, maxPitch ); [Export] public Smoothing pitchSmoothing = new FrameSmoothing(); [Export] public bool pitchGoesBackToCenter = true; [Export] public Smoothing toCenterPitchSmoothing = new FrameSmoothing(); [Export] public float centerPitchDelayDuration = 5; [Export] public float centerPitch = 30; [Export] public float centerPitchActivation = 0.1f; [ExportGroup("Distance")] [Export] public Curve distanceForPitch = MathX.Curve( 1, 1 ); [Export] public float distanceScale = 1; [ExportGroup("Camera Offset")] [Export] public Vector3 offset; float smoothedYaw = 0; float smoothedPitch = 0; float smoothedDistance = 0; float _centerPitchActivation = 0; float _yawBehindActivation = 0; public override void _Process( double delta ) { if ( target == null ) { return; } behindYaw = Math3D.GlobalYawDegrees( target.GlobalForward() * -1 ); behindYaw = MathX.NormalizeAngle( behindYaw ); currentYaw = MathX.NormalizeAngle( yaw ); bcDelta = MathX.NormalizeAngle( MathX.AngleDelta( behindYaw, currentYaw ) ); var targetPosition = Smoothing.Apply( targetFollowSmoothing, target.GlobalPosition, (float) delta ); var yawAxis = Sensors.PolarAxis( yawNegativeAxis, yawPositiveAxis ); var pitchAxis = Sensors.PolarAxis( pitchNegativeAxis, pitchPositiveAxis ); yaw += yawAxis * yawSpeed * (float)delta; if ( yawGoesBehindPlayer ) { if ( Mathf.Abs( yawAxis ) < yawGoesBehindActivation ) { _yawBehindActivation += (float)delta; if ( yawGoesBehindPlayer && _yawBehindActivation > yawBehindDelayDuration ) { yaw = Smoothing.ApplyDegreesWith( yawToBehingSmoothing, yaw, behindYaw, (float) delta ); } } else { _yawBehindActivation = 0; } } // yaw = MathX.Repeat( yaw, 360f ); if ( pitchIsRelative ) { pitch += pitchAxis * pitchSpeed * (float)delta; pitch = Mathf.Clamp( pitch, minPitch, maxPitch ); if ( Mathf.Abs( pitchAxis ) < centerPitchActivation ) { _centerPitchActivation += (float)delta; if ( _centerPitchActivation > centerPitchDelayDuration ) { pitch = Smoothing.ApplyWith( toCenterPitchSmoothing, pitch, centerPitch, (float) delta ); } } else { _centerPitchActivation = 0; } } else { pitch = Mathf.Remap( pitchAxis, -1, 1, minPitch, maxPitch ); } // if ( Mathf.Abs( yaw - smoothedYaw ) > 180 ) // { // if ( yaw > smoothedYaw ) // { // smoothedYaw += 360; // } // else if ( yaw < smoothedYaw ) // { // smoothedYaw -= 360; // } // } var appliedYaw = yaw; // if ( roundYaw ) // { // appliedYaw = MathX.SnapRounded( yaw, 360f/roundedYawResolution ); // } smoothedYaw = Smoothing.ApplyDegrees( yawSmoothing, appliedYaw, (float) delta ); smoothedPitch = Smoothing.Apply( pitchSmoothing, pitch, (float) delta ); // if ( pitchGoesBackToCenter ) // { // pitch = toCenterPitchSmoothing.Smooth( centerPitch, (float) delta ); // } // RJLog.Log( "Pitch", smoothedPitch ); // smoothedYaw = yaw; // smoothedPitch = pitch; var distance = distanceForPitch.Sample( MathX.NormalizeClamped( pitch, minPitch, maxPitch ) ) * distanceScale; GlobalPosition = targetPosition + Math3D.YawPitchRotation( smoothedYaw, smoothedPitch ) * Vector3.Forward * distance; LookAt( targetPosition, Vector3.Up, true ); GlobalPosition += this.GetOrientationBasedGlobalOffset( offset ); } } }