rj-action-library/Runtime/VirtualCameras/StrategyTopDownCamera.cs

281 lines
6.5 KiB
C#

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;
}
}
}