using System.Diagnostics; using System.Collections; using System.Collections.Generic; using System; using Godot; namespace Rokojori { [Tool] [GlobalClass] public partial class StrategyTopDownCamera:VirtualCamera3D { public enum ConstrainMode { Unconstrained, Axis_Aligned_Box, Circle_XZ_Range_Y } [Export] public Vector3 target; [Export] public float yaw = 0; [Export] public float pitch = 0; [Export] public float distance = 10; float smoothDistance = 10; [ExportCategory("Move")] [Export] public ConstrainMode constrainMode = ConstrainMode.Unconstrained; [Export] public Node3D constrainMin; [Export] public Node3D constrainMax; [Export] public RJSensor moveUpButton; [Export] public RJSensor moveDownButton; [Export] public RJSensor moveRightButton; [Export] public RJSensor moveLeftButton; [Export] public float buttonMoveSpeed = 1f; [Export] public RJSensor mouseMoveButton; [Export] public float mouseMoveSpeed = 0.001f; [Export] public bool flipHorizontal = false; [Export] public bool flipVertical = false; [Export] public bool moveAtBorders = true; [Export] public float moveAtBorderSpeed = 0.001f; [Export] public float borderSizePercentage = 5; [ExportCategory("Orbit")] [Export] public RJSensor orbitRightButton; [Export] public RJSensor orbitLeftButton; [Export] public RJSensor orbitMouseButton; [Export] public float mouseOrbitSpeedScale = -0.5f; [Export] public float orbitSpeed = 0.001f; [ExportCategory("Zoom")] [Export] public float zoomStepInPercentage = 10; [Export] public float minDistance = 0.001f; [Export] public float maxDistance = 200f; [Export] public RJSensor zoomInButton; [Export] public RJSensor[] zoomInModifierButtons; [Export] public RJSensor zoomOutButton; [Export] public RJSensor[] zoomOutModifierButtons; [Export] public float zoomSmoothingCoefficient = 0.1f; Smoother smoother = new Smoother(); public override void _Process( double delta ) { Move(); Orbit( (float) delta ); Zoom(); Apply( (float) delta ); if ( ! hasMotionDelta ) { motionDelta.X = 0; motionDelta.Y = 0; } hasMotionDelta = false; } bool hasMotionDelta = false; Vector2 motionDelta = Vector2.Zero; float borderMoveHorizontal = 0; float borderMoveVertical = 0; float GetBorderSize() { var size = GetViewport().GetVisibleRect().Size; var borderX = ( size.X * borderSizePercentage ) / 100f; var borderY = ( size.Y * borderSizePercentage ) / 100f; return Mathf.Min( borderX, borderY ); } public override void _Input( InputEvent inputEvent ) { if ( inputEvent is InputEventMouseMotion ) { var eventMouseMotion = inputEvent as InputEventMouseMotion; motionDelta = eventMouseMotion.ScreenRelative; if ( moveAtBorders ) { var position = eventMouseMotion.Position; var screenSize = GetViewport().GetVisibleRect().Size; var borderSize = GetBorderSize(); borderMoveHorizontal = - MathX.PolarAxis( position.X < borderSize, position.X > screenSize.X - borderSize ); borderMoveVertical = - MathX.PolarAxis( position.Y < borderSize, position.Y > screenSize.Y - borderSize ); } hasMotionDelta = true; } } void Move() { var deltaX = 0f; var deltaY = 0f; if ( Sensors.IsActive( mouseMoveButton ) ) { deltaX = motionDelta.X * mouseMoveSpeed; deltaY = motionDelta.Y * mouseMoveSpeed; } else { deltaX = Sensors.PolarAxis( moveLeftButton, moveRightButton ) + borderMoveHorizontal * moveAtBorderSpeed; deltaY = Sensors.PolarAxis( moveUpButton, moveDownButton ) + borderMoveVertical * moveAtBorderSpeed; } var forward = Math3D.GetYPlaneForward( this ); var right = Math3D.GetYPlaneRight( this ); var flipH = flipHorizontal ? -1 : 1; var flipV = flipVertical ? -1 : 1; var xAmount = deltaX * smoothDistance * right * flipH; var zAmount = deltaY * smoothDistance * forward * flipV; target += ( xAmount + zAmount ); ConstrainTarget(); } void ConstrainTarget() { if ( ConstrainMode.Unconstrained == constrainMode ) { return; } if ( ConstrainMode.Axis_Aligned_Box == constrainMode ) { target = Box3.Constrain( target, constrainMin.GlobalPosition, constrainMax.GlobalPosition ); return; } if ( ConstrainMode.Circle_XZ_Range_Y == constrainMode ) { var direction = ( constrainMax.GlobalPosition - constrainMin.GlobalPosition ); var directionXZ = direction; directionXZ.Y = 0; var distanceXZ = directionXZ.Length(); var targetDirection = target - constrainMin.GlobalPosition; var targetDirectionXZ = targetDirection; targetDirectionXZ.Y = 0; target.Y = Mathf.Clamp( target.Y, constrainMin.GlobalPosition.Y, constrainMax.GlobalPosition.Y ); if ( targetDirectionXZ.Length() > distanceXZ ) { targetDirectionXZ = targetDirectionXZ.Normalized() * distanceXZ; var constrainedPosition = constrainMin.GlobalPosition + targetDirectionXZ; target = new Vector3( constrainedPosition.X, target.Y, constrainedPosition.Z ); } } } void Orbit( float delta ) { var direction = Sensors.PolarAxis( orbitLeftButton, orbitRightButton ); if ( Sensors.IsActive( orbitMouseButton ) ) { yaw += motionDelta.X * mouseOrbitSpeedScale; } yaw += direction * orbitSpeed * delta; } void Zoom() { var zoomButtonAxis = Sensors.PolarAxis( zoomOutButton, zoomInButton ); distance *= Mathf.Pow( 1 + zoomStepInPercentage / 100f, zoomButtonAxis ); distance = Mathf.Clamp( distance, minDistance, maxDistance ); } void Apply( float delta ) { smoothDistance = smoother.SmoothWithCoefficient( smoothDistance, distance, zoomSmoothingCoefficient, delta ); GlobalRotation = new Vector3( Mathf.DegToRad( pitch ), Mathf.DegToRad( yaw ), 0 ); var forward = Math3D.GetGlobalForward( this ) * smoothDistance; GlobalPosition = target + forward; } } }