Player/Camera Updates

This commit is contained in:
Josef 2025-05-21 22:44:28 +02:00
parent 3b74292b2c
commit af3786e6b4
65 changed files with 2619 additions and 431 deletions

View File

@ -98,7 +98,8 @@ namespace Rokojori
List<HighlightAnimation> _active = new List<HighlightAnimation>(); List<HighlightAnimation> _active = new List<HighlightAnimation>();
public void Highlight( HighlightActionType type, Node3D[] targets ) public void Highlight( HighlightActionType type, Node3D[] targets )
{ {
if ( HighlightActionType.Start == type ) if ( HighlightActionType.Start == type )
{ {
StartHighlight( targets ); StartHighlight( targets );
@ -131,6 +132,7 @@ namespace Rokojori
var outlineMaterial = new OutlineMaterial(); var outlineMaterial = new OutlineMaterial();
outlineMaterial.albedo.Set( colorTransparent ); outlineMaterial.albedo.Set( colorTransparent );
material = outlineMaterial; material = outlineMaterial;
outlineMaterial.size.Set( 2 );
outlineMaterial.opacityModulationDuration.Set( opacityModulationDuration ); outlineMaterial.opacityModulationDuration.Set( opacityModulationDuration );
outlineMaterial.opacityModulationStrength.Set( opacityModulationStrength ); outlineMaterial.opacityModulationStrength.Set( opacityModulationStrength );

View File

@ -31,5 +31,5 @@ opacityModulationStrength = 0.75
opacityModulationDuration = 1.0 opacityModulationDuration = 1.0
opacityModulationTransition = 1.0 opacityModulationTransition = 1.0
outlineMaterialMode = 0 outlineMaterialMode = 0
overlayOpacity = 0.01 overlayOpacity = 0.1
overlayMaterialMode = 0 overlayMaterialMode = 0

View File

@ -23,7 +23,17 @@ namespace Rokojori
return exp.ComputeDuration(); return exp.ComputeDuration();
} }
public static float ComputeCoefficientForFramesAdaptiveTreshold( int numFrames )
{
var fps60 = 1f/60f;
var treshold = MathX.MapClamped( numFrames, 400, 600, fps60/50, fps60/2 );
return ComputeCoefficientForFrames( numFrames, treshold );
}
public static float ComputeCoefficientForFrames( int numFrames, float treshold = 1f/60f * 0.02f ) public static float ComputeCoefficientForFrames( int numFrames, float treshold = 1f/60f * 0.02f )
{ {

View File

@ -8,12 +8,12 @@ namespace Rokojori
[GlobalClass] [GlobalClass]
public partial class FrameSmoothing: Smoothing public partial class FrameSmoothing: Smoothing
{ {
[Export( PropertyHint.Range, "0,600")] [Export( PropertyHint.Range, "0,1800")]
public float frames = 10; public float frames = 10;
protected override float _ComputeInterpolationAmount( float delta ) protected override float _ComputeInterpolationAmount( float delta )
{ {
frames = Mathf.Clamp( frames, 0, 600 ); frames = Mathf.Clamp( frames, 0, 1800 );
if ( frames <= 0 ) if ( frames <= 0 )
{ {
@ -36,7 +36,7 @@ namespace Rokojori
public static float ComputeCoefficientInt( float delta, int frames ) public static float ComputeCoefficientInt( float delta, int frames )
{ {
frames = Mathf.Clamp( frames, 0, 600 ); frames = Mathf.Clamp( frames, 0, 1800 );
if ( frames <= 0 ) if ( frames <= 0 )
{ {

File diff suppressed because it is too large Load Diff

View File

@ -11,20 +11,13 @@ namespace Rokojori
[Export] [Export]
public string path; public string path;
[Export] [ExportToolButton( "Compute")]
public bool compute public Callable ComputeButton => Callable.From( Compute );
{
get { return false; }
set
{
if ( ! value )
{
return;
}
FrameSmoothingTable.ComputeAndSaveTable( path ); async void Compute()
} {
} await FrameSmoothingTable.ComputeAndSaveTable( this, path );
}
} }
} }

View File

@ -9,12 +9,44 @@ namespace Rokojori
public partial class Smoothing: Resource public partial class Smoothing: Resource
{ {
float _currentFloat = 0; float _currentFloat = 0;
public void SetCurrent( float value )
{
_currentFloat = value;
}
Vector2 _currentVector2 = Vector2.Zero; Vector2 _currentVector2 = Vector2.Zero;
Vector3 _currentVector3 = Vector3.Zero; Vector3 _currentVector3 = Vector3.Zero;
Vector4 _currentVector4 = Vector4.Zero; Vector4 _currentVector4 = Vector4.Zero;
public void SetCurrent( Vector2 value )
{
_currentVector2 = value;
}
public void SetCurrent( Vector3 value )
{
_currentVector3 = value;
}
public void SetCurrent( Vector4 value )
{
_currentVector4 = value;
}
Quaternion _currentQuaternion = Quaternion.Identity; Quaternion _currentQuaternion = Quaternion.Identity;
public void SetCurrent( Quaternion quaternion )
{
_currentQuaternion = quaternion;
}
Color _currentColor = Colors.Black; Color _currentColor = Colors.Black;
public void SetCurrent( Color color )
{
_currentColor = color;
}
public float Smooth( float nextValue, float delta ) public float Smooth( float nextValue, float delta )
{ {
@ -29,7 +61,16 @@ namespace Rokojori
return sm.Smooth( value, delta ); return sm.Smooth( value, delta );
} }
public Vector2 Smooth( Vector2 nextValue, float delta ) public static float ApplyWith( Smoothing sm, float oldValue, float nextValue, float delta )
{
if ( sm == null ){ return nextValue; }
sm._currentFloat = oldValue;
return sm.Smooth( nextValue, delta );
}
public Vector2 Smooth( Vector2 nextValue, float delta )
{ {
_currentVector2 = _currentVector2.Lerp( nextValue, _ComputeInterpolationAmount( delta ) ); _currentVector2 = _currentVector2.Lerp( nextValue, _ComputeInterpolationAmount( delta ) );
@ -42,6 +83,30 @@ namespace Rokojori
return sm.Smooth( value, delta ); return sm.Smooth( value, delta );
} }
public static float ApplyDegrees( Smoothing sm, float value, float delta )
{
var newV = MathX.RadiansToVector2( MathX.DegreesToRadians * value );
return MathX.RadiansToDegrees * MathX.Vector2ToRadians( Apply( sm, newV, delta ) );
}
public static float ApplyDegreesWith( Smoothing sm, float oldValue, float nextValue, float delta )
{
var oldV = MathX.RadiansToVector2( MathX.DegreesToRadians * oldValue );
var newV = MathX.RadiansToVector2( MathX.DegreesToRadians * nextValue );
return MathX.RadiansToDegrees * MathX.Vector2ToRadians( ApplyWith( sm, oldV, newV, delta ) );
}
public static Vector2 ApplyWith( Smoothing sm, Vector2 oldValue, Vector2 nextValue, float delta )
{
if ( sm == null ){ return nextValue; }
sm._currentVector2 = oldValue;
return sm.Smooth( nextValue, delta );
}
public Vector3 Smooth( Vector3 nextValue, float delta ) public Vector3 Smooth( Vector3 nextValue, float delta )
{ {
_currentVector3 = _currentVector3.Lerp( nextValue, _ComputeInterpolationAmount( delta ) ); _currentVector3 = _currentVector3.Lerp( nextValue, _ComputeInterpolationAmount( delta ) );
@ -70,7 +135,8 @@ namespace Rokojori
public Quaternion Smooth( Quaternion nextValue, float delta ) public Quaternion Smooth( Quaternion nextValue, float delta )
{ {
_currentQuaternion = _currentQuaternion.Slerp( nextValue, _ComputeInterpolationAmount( delta ) ); _currentQuaternion = _currentQuaternion.GetNormalized();
_currentQuaternion = _currentQuaternion.Slerp( nextValue.GetNormalized(), _ComputeInterpolationAmount( delta ) );
return _currentQuaternion; return _currentQuaternion;
} }
@ -109,16 +175,18 @@ namespace Rokojori
var duration = 0f; var duration = 0f;
var lastValue = value; var lastValue = value;
var maxDuration = 30; var maxDuration = 120;
while ( value > tresholdValue && duration < maxDuration ) Safe.While(
{ ()=> value > tresholdValue && duration < maxDuration,
lastValue = value; ()=>
value = Smooth( 0, delta ); {
lastValue = value;
value = Smooth( 0, delta );
duration += delta; duration += delta;
}
} );
_currentFloat = cached; _currentFloat = cached;

View File

@ -76,8 +76,22 @@ namespace Rokojori
); );
} }
void InitializeCamera()
{
var cameraManager = this.Get<VirtualCamera3DManager>();
var camera = this.Get<Camera3D>();
cameraManager.camera = camera;
var slot = cameraManager.CreateChild<VirtualCamera3DSlot>();
slot.camera = this.Get<MouseEditorCamera>();
}
} }
} }

View File

@ -13,6 +13,11 @@ namespace Rokojori
return Directory.Exists( path ); return Directory.Exists( path );
} }
public static bool FileExists( string path )
{
return File.Exists( path );
}
public static void CreateDirectory( string path ) public static void CreateDirectory( string path )
{ {
Directory.CreateDirectory( path ); Directory.CreateDirectory( path );

View File

@ -9,6 +9,16 @@ namespace Rokojori
{ {
public static class Nodes public static class Nodes
{ {
public static T Get<T>( this Node node ) where T:Node
{
return GetAnyChild<T>( node );
}
public static T GetChild<T>( this Node node ) where T:Node
{
return GetDirectChild<T>( node );
}
public static void CopyData<T>( T from, T to ) where T:Node public static void CopyData<T>( T from, T to ) where T:Node
{ {
var memberInfos = ReflectionHelper.GetDataMemberInfos<T>( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly ); var memberInfos = ReflectionHelper.GetDataMemberInfos<T>( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly );

View File

@ -5,7 +5,7 @@ using Godot.Collections;
namespace Rokojori namespace Rokojori
{ {
[Tool]
[GlobalClass] [GlobalClass]
public partial class Caster:Node3D public partial class Caster:Node3D
{ {

View File

@ -5,6 +5,7 @@ using Godot.Collections;
namespace Rokojori namespace Rokojori
{ {
[Tool]
[GlobalClass] [GlobalClass]
public partial class CharacterController:Node public partial class CharacterController:Node
{ {
@ -28,14 +29,10 @@ namespace Rokojori
[Export] [Export]
public float rotationSmoothingDuration = 0; public Smoothing rotationSmoothing;
Smoother rotationSmoother = new Smoother();
[Export] [Export]
public float positionSmoothingDuration = 0; public Smoothing positionSmoothing;
Smoother positionSmoother = new Smoother();
public float delta = 0; public float delta = 0;
@ -49,22 +46,24 @@ namespace Rokojori
if ( CharacterUpdateMode.Process == characterUpdateMode ) if ( CharacterUpdateMode.Process == characterUpdateMode )
{ {
this.delta = (float)delta; this.delta = (float) delta;
Nodes.ForEachDirectChild<CharacterControllerAction>( actionsContainer, a => Action.Trigger( a ) ); Nodes.ForEachDirectChild<CharacterControllerAction>( actionsContainer, Action.Trigger );
} }
// positionSmoother.CopyPosition( graphics, body, rotationSmoothingDuration, delta ); // positionSmoother.CopyPosition( graphics, body, rotationSmoothingDuration, delta );
// rotationSmoother.CopyRotation( graphics, body, positionSmoothingDuration, delta ); // rotationSmoother.CopyRotation( graphics, body, positionSmoothingDuration, delta );
Pose.CopyTo( body, graphics ); graphics.GlobalPosition = Smoothing.Apply( positionSmoothing, body.GlobalPosition, this.delta );
graphics.SetGlobalQuaternion( Smoothing.Apply( rotationSmoothing, body.GetGlobalQuaternion(), this.delta ) );
// Pose.CopyTo( body, graphics );
} }
public override void _PhysicsProcess( double delta ) public override void _PhysicsProcess( double delta )
{ {
if ( CharacterUpdateMode.Physics_Process == characterUpdateMode ) if ( CharacterUpdateMode.Physics_Process == characterUpdateMode )
{ {
this.delta = (float)delta; this.delta = (float) delta;
Nodes.ForEachDirectChild<CharacterControllerAction>( actionsContainer, a => Action.Trigger( a ) ); Nodes.ForEachDirectChild<CharacterControllerAction>( actionsContainer, Action.Trigger );
} }
} }
} }

View File

@ -5,6 +5,7 @@ using Godot.Collections;
namespace Rokojori namespace Rokojori
{ {
[Tool]
[GlobalClass] [GlobalClass]
public partial class CharacterControllerAction:Action public partial class CharacterControllerAction:Action
{ {

View File

@ -5,30 +5,18 @@ using Godot.Collections;
namespace Rokojori namespace Rokojori
{ {
[Tool]
[GlobalClass] [GlobalClass]
public partial class CharacterMovement:CharacterControllerAction public partial class CharacterMovement:CharacterControllerAction
{ {
[Export] [Export]
public float onFloorMultiply = 0f; public float onFloorMultiply = 1f;
[Export]
public bool overwriteVelocity = true;
[ExportGroup( "Actions" )]
[Export]
public Action onMoving;
[Export]
public Action onIdle;
[Export] [Export]
public Action onForward; public float inAirMultiply = 0.01f;
[Export]
public Action onBackwards;
[Export]
public Action onStrafeLeft;
[Export]
public Action onStrafeRight;
[Export]
public CameraTargetOffset cameraTargetOffset;
[ExportGroup( "Direction Source" )] [ExportGroup( "Direction Source" )]
[Export] [Export]
@ -39,34 +27,28 @@ namespace Rokojori
None, None,
Zero_Y_And_Normalize, Zero_Y_And_Normalize,
Project_On_TransformPlane Project_On_TransformPlane
} }
[Export] [ExportGroup("Movement")]
public DirectionProcessing directionProcessing;
[ExportGroup( "Moving" )]
[Export] [Export]
public float moveSpeed; public float moveSpeed;
[Export] [Export]
public Sensor forward; public CharacterMovementType controllerMovementType;
[Export] [Export]
public Sensor backwards; public CharacterMovementType mouseKeyboardMovementType;
[ExportGroup( "Strafing" )]
[Export]
public float strafeSpeed;
[Export] [Export]
public Sensor strafeLeft; public CharacterMovementType currentMovementType;
[Export] [Export]
public Sensor strafeRight; public Smoothing onFloorMovementSmoothing = new FrameSmoothing();
[Export] [Export]
public bool useBodyDirection = true; public Smoothing inAirMovementSmoothing = new FrameSmoothing();
[ExportGroup( "Rotation" )] [ExportGroup( "Rotation" )]
@ -74,74 +56,73 @@ namespace Rokojori
public bool adjustRotation = true; public bool adjustRotation = true;
[Export] [Export]
public Curve forwardToRotation = MathX.Curve( 0, 1 ); public Curve forwardToRotationSmoothingFrames = MathX.Curve( 0, 1 );
[Export( PropertyHint.Range, "0,1")] [Export(PropertyHint.Range, "0,600")]
public float rotationSmoothingCoefficient = 0.1f; public int airRotationSmoothingFrames = 120;
Smoother rotationSmoother = new Smoother();
FrameSmoothing rotationSmoothing = new FrameSmoothing();
protected CharacterMovementData characterMovementData = new CharacterMovementData();
protected override void _OnTrigger() protected override void _OnTrigger()
{ {
if ( ! body.IsOnFloor() ) var onFloor = body.IsOnFloor();
characterMovementData.Reset( this );
if ( currentMovementType == null )
{ {
return; return;
} }
var movement = Vector3.Zero; currentMovementType.ProcessMovement( characterMovementData );
var fw = Sensors.GetValue( forward ); if ( cameraTargetOffset != null )
var bw = Sensors.GetValue( backwards );
var fbAxis = Sensors.PolarAxis( backwards, forward );
var dir = directionSource != null ? directionSource : body;
var forwardDirection = dir.GlobalForward();
var rightDirection = useBodyDirection ? body.GlobalRight() : dir.GlobalRight();
if ( DirectionProcessing.Zero_Y_And_Normalize == directionProcessing )
{ {
forwardDirection.Y = 0; cameraTargetOffset.SetMovingForward( characterMovementData.isMovingForward ? 1f : 0f );
rightDirection.Y = 0;
} }
else if ( DirectionProcessing.Project_On_TransformPlane == directionProcessing )
{
var bodyPlane = Plane3.CreateFromNode3D( body );
forwardDirection = bodyPlane.ConstrainToPlane( forwardDirection + body.GlobalPosition ) - body.GlobalPosition;
rightDirection = bodyPlane.ConstrainToPlane( rightDirection + body.GlobalPosition ) - body.GlobalPosition;
}
forwardDirection = forwardDirection.Normalized();
rightDirection = rightDirection.Normalized();
movement += forwardDirection * Sensors.PolarAxis( backwards, forward ) * moveSpeed; var movementMultiply = onFloor ? onFloorMultiply : inAirMultiply;
movement += rightDirection * Sensors.PolarAxis( strafeLeft, strafeRight ) * strafeSpeed ;
characterMovementData.movement *= movementMultiply;
if ( body.IsOnFloor() )
{
movement *= onFloorMultiply;
}
if ( adjustRotation ) if ( adjustRotation )
{ {
var currentRotation = body.GetGlobalQuaternion(); var nextRotation = Math3D.LookRotation( characterMovementData.forwardDirection );
var nextRotation = Math3D.LookRotation( forwardDirection ); var speed = MathX.Clamp01( characterMovementData.movement.Length() / moveSpeed );
var sm = 1f - rotationSmoothingCoefficient; if ( speed > 0 )
sm = sm * sm; {
Quaternion rotation;
var speed = MathX.Clamp01( movement.Length() / moveSpeed ) * Mathf.Max( fw, bw ); if ( onFloor )
{
sm *= forwardToRotation.Sample( speed ); rotationSmoothing.frames = Mathf.Round( forwardToRotationSmoothingFrames.Sample( speed ) );
}
else
{
rotationSmoothing.frames = airRotationSmoothingFrames;
}
var rotation = rotationSmoother.SmoothWithCoefficient( currentRotation, nextRotation, sm, controller.delta ); rotation = rotationSmoothing.Smooth( nextRotation, controller.delta );
body.SetGlobalQuaternion( rotation ); body.SetGlobalQuaternion( rotation );
}
} }
Velocity( movement, overwriteVelocity ); var smoothedMovement = Vector3.Zero;
if ( onFloor )
{
smoothedMovement = onFloorMovementSmoothing.Smooth( characterMovementData.movement, controller.delta );
}
else
{
smoothedMovement = inAirMovementSmoothing.Smooth( characterMovementData.movement, controller.delta );
}
Velocity( smoothedMovement, onFloor );
} }
} }

View File

@ -0,0 +1,14 @@
using Godot;
using System.Collections;
using System.Collections.Generic;
using Godot.Collections;
namespace Rokojori
{
public enum CharacterDirectionProcessing
{
None,
Zero_Y_And_Normalize,
Project_On_TransformPlane
}
}

View File

@ -0,0 +1,23 @@
using Godot;
using System.Collections;
using System.Collections.Generic;
using Godot.Collections;
namespace Rokojori
{
public class CharacterMovementData
{
public CharacterMovement characterMovement;
public Vector3 movement;
public Vector3 forwardDirection;
public bool isMovingForward;
public void Reset( CharacterMovement characterMovement )
{
this.characterMovement = characterMovement;
movement = Vector3.Zero;
forwardDirection = Vector3.Forward;
isMovingForward = false;
}
}
}

View File

@ -0,0 +1 @@
uid://bh7oo1wqi4cau

View File

@ -0,0 +1,17 @@
using Godot;
using System.Collections;
using System.Collections.Generic;
using Godot.Collections;
namespace Rokojori
{
[Tool]
[GlobalClass]
public partial class CharacterMovementType:Resource
{
public virtual void ProcessMovement( CharacterMovementData characterMovementData )
{
}
}
}

View File

@ -0,0 +1 @@
uid://dco3ngscxqjf5

View File

@ -0,0 +1,78 @@
using Godot;
using System.Collections;
using System.Collections.Generic;
using Godot.Collections;
namespace Rokojori
{
[Tool]
[GlobalClass]
public partial class StrafeMovementType:CharacterMovementType
{
public enum StrafeDirectionSource
{
Character_Movement_Direction_Source,
Character_Controller_Body
}
[ExportGroup( "Movement" )]
[Export]
public Sensor forward;
[Export]
public Sensor backwards;
[Export]
public CharacterDirectionProcessing directionProcessing;
[ExportGroup( "Strafing" )]
[Export]
public float strafeSpeedMultiply = 1.0f;
[Export]
public Sensor strafeLeft;
[Export]
public Sensor strafeRight;
[Export]
public StrafeDirectionSource strafeDirectionSource = StrafeDirectionSource.Character_Controller_Body;
public override void ProcessMovement( CharacterMovementData characterMovementData )
{
var characterMovement = characterMovementData.characterMovement;
var directionSource = characterMovement.directionSource;
var body = characterMovement.body;
var dir = directionSource != null ? directionSource : body;
var forwardDirection = dir.GlobalForward();
var rightDirection = StrafeDirectionSource.Character_Controller_Body == strafeDirectionSource ?
body.GlobalRight() : dir.GlobalRight();
if ( CharacterDirectionProcessing.Zero_Y_And_Normalize == directionProcessing )
{
forwardDirection.Y = 0;
rightDirection.Y = 0;
}
else if ( CharacterDirectionProcessing.Project_On_TransformPlane == directionProcessing )
{
var bodyPlane = Plane3.CreateFromNode3D( body );
forwardDirection = bodyPlane.ConstrainToPlane( forwardDirection + body.GlobalPosition ) - body.GlobalPosition;
rightDirection = bodyPlane.ConstrainToPlane( rightDirection + body.GlobalPosition ) - body.GlobalPosition;
}
forwardDirection = forwardDirection.Normalized();
rightDirection = rightDirection.Normalized();
var movement = forwardDirection * Sensors.PolarAxis( backwards, forward ) * characterMovement.moveSpeed;
movement += rightDirection * Sensors.PolarAxis( strafeLeft, strafeRight ) * characterMovement.moveSpeed * strafeSpeedMultiply ;
characterMovementData.movement = movement;
characterMovementData.isMovingForward = forward.isActive;
characterMovementData.forwardDirection = forwardDirection;
}
}
}

View File

@ -0,0 +1 @@
uid://b37sjsfvphc8b

View File

@ -0,0 +1,105 @@
using Godot;
using System.Collections;
using System.Collections.Generic;
using Godot.Collections;
namespace Rokojori
{
[Tool]
[GlobalClass]
public partial class TurnMovementType:CharacterMovementType
{
[Export]
public CharacterDirectionProcessing directionProcessing;
[ExportGroup( "Movement" )]
[Export]
public Sensor up;
[Export]
public Sensor down;
[Export]
public Sensor left;
[Export]
public Sensor right;
[ExportGroup( "Strafing" )]
[Export]
public bool useBodyDirection = true;
[Export]
public Sensor strafeBack;
[Export]
public Sensor strafeLeft;
[Export]
public Sensor strafeRight;
[Export]
public float strafeBackSpeedMultiply = 1.0f;
[Export]
public float strafeSidewardsSpeedMultiply = 1.0f;
public override void ProcessMovement( CharacterMovementData characterMovementData )
{
var characterMovement = characterMovementData.characterMovement;
var directionSource = characterMovement.directionSource;
var body = characterMovement.body;
var dir = directionSource != null ? directionSource : body;
var forwardDirection = dir.GlobalForward();
var rightDirection = dir.GlobalRight();
var forwardStrafe = useBodyDirection ? body.GlobalForward() : dir.GlobalForward();
var rightStrafe = useBodyDirection ? body.GlobalRight() : dir.GlobalRight();
if ( CharacterDirectionProcessing.Zero_Y_And_Normalize == directionProcessing )
{
forwardDirection.Y = 0;
rightDirection.Y = 0;
}
else if ( CharacterDirectionProcessing.Project_On_TransformPlane == directionProcessing )
{
var bodyPlane = Plane3.CreateFromNode3D( body );
forwardDirection = bodyPlane.ConstrainToPlane( forwardDirection + body.GlobalPosition ) - body.GlobalPosition;
rightDirection = bodyPlane.ConstrainToPlane( rightDirection + body.GlobalPosition ) - body.GlobalPosition;
}
forwardDirection = forwardDirection.Normalized();
rightDirection = rightDirection.Normalized();
var direction = Sensors.FourDirectional( left, right, up, down );
var movement = forwardDirection * - direction.Y * characterMovement.moveSpeed;
movement += rightDirection * direction.X * characterMovement.moveSpeed;
var turningForwardDirection = movement.Normalized();
if ( Sensors.IsActive( strafeBack ) )
{
movement += -Sensors.GetValue( strafeBack ) * forwardStrafe * characterMovement.moveSpeed * strafeBackSpeedMultiply;
turningForwardDirection = forwardDirection;
}
if ( Sensors.IsActive( strafeLeft ) || Sensors.IsActive( strafeRight ) )
{
var strafeStrength = Sensors.PolarAxis( strafeLeft, strafeRight );
movement += strafeStrength * rightStrafe * characterMovement.moveSpeed * strafeSidewardsSpeedMultiply;
turningForwardDirection = forwardDirection;
}
movement = movement.ConstrainLength( characterMovement.moveSpeed );
characterMovementData.movement = movement;
characterMovementData.isMovingForward = ! Math3D.FacingSameDirection( turningForwardDirection, forwardDirection );
characterMovementData.forwardDirection = turningForwardDirection;
}
}
}

View File

@ -0,0 +1 @@
uid://kodskdb1mcd4

View File

@ -5,6 +5,7 @@ using Godot.Collections;
namespace Rokojori namespace Rokojori
{ {
[Tool]
[GlobalClass] [GlobalClass]
public partial class Gravity:CharacterControllerAction public partial class Gravity:CharacterControllerAction
{ {

View File

@ -5,6 +5,7 @@ using Godot.Collections;
namespace Rokojori namespace Rokojori
{ {
[Tool]
[GlobalClass] [GlobalClass]
public partial class GroundReset:CharacterControllerAction public partial class GroundReset:CharacterControllerAction
{ {

View File

@ -5,29 +5,43 @@ using Godot.Collections;
namespace Rokojori namespace Rokojori
{ {
[Tool]
[GlobalClass] [GlobalClass]
public partial class Jump:CharacterControllerAction public partial class Jump:CharacterControllerAction
{ {
[Export] [Export]
public Sensor button; public Sensor button;
[Export] [ExportGroup( "Jump Impulse")]
public float jumpStrength;
[Export] [Export]
public float maxJumpDuration; public float jumpImpulseStrength;
[Export] [Export( PropertyHint.Range, "0,100" )]
public Curve jumpCurveStrength = MathX.Curve( 1, 0 ); public float velocityToJumpDirection = 0.5f;
[Export] [Export]
public float jumpedDuration; public float velocityTresholdForJumpDirection = 1f;
[ExportGroup( "Air Control")]
[Export] [Export]
public bool canJump = false; public Curve airControlCurveStrength = MathX.Curve( 1, 0 );
[Export] [Export]
public bool jumping = false; public float airMaxControlStrength;
[Export]
public float maxAirControlDuration;
float jumpedDuration;
bool canJump = false;
bool jumping = false;
bool needsToRelease = false;
@ -35,7 +49,11 @@ namespace Rokojori
{ {
if ( body.IsOnFloor() ) if ( body.IsOnFloor() )
{ {
jumping = false; if ( jumping )
{
jumping = false;
needsToRelease = true;
}
} }
if ( ! ( jumping || body.IsOnFloor() ) ) if ( ! ( jumping || body.IsOnFloor() ) )
@ -46,6 +64,12 @@ namespace Rokojori
if ( ! button.isActive ) if ( ! button.isActive )
{ {
jumping = false; jumping = false;
needsToRelease = false;
return;
}
if ( needsToRelease )
{
return; return;
} }
@ -53,17 +77,33 @@ namespace Rokojori
{ {
jumping = true; jumping = true;
jumpedDuration = 0; jumpedDuration = 0;
var jumpDirection = Vector3.Up * jumpImpulseStrength;
if ( body.Velocity.Length() > velocityTresholdForJumpDirection )
{
var xz = body.Velocity;
xz.Y = 0;
// xz = xz.Normalized();
jumpDirection += xz * velocityToJumpDirection;
}
SetVelocity( jumpDirection );
return;
} }
jumpedDuration += controller.delta; jumpedDuration += controller.delta;
canJump = jumpedDuration < maxJumpDuration; canJump = jumpedDuration < maxAirControlDuration;
if ( jumpedDuration < maxJumpDuration ) if ( canJump )
{ {
var jumpStrengthMultiply = jumpCurveStrength.Sample( jumpedDuration / maxJumpDuration ); var jumpStrengthMultiply = airControlCurveStrength.Sample( jumpedDuration / maxAirControlDuration );
AddVelocity( Vector3.Up * jumpStrength ); AddVelocity( Vector3.Up * airMaxControlStrength * jumpStrengthMultiply );
} }

View File

@ -5,6 +5,7 @@ using Godot.Collections;
namespace Rokojori namespace Rokojori
{ {
[Tool]
[GlobalClass] [GlobalClass]
public partial class MoveAndSlide:CharacterControllerAction public partial class MoveAndSlide:CharacterControllerAction
{ {

View File

@ -21,10 +21,17 @@ namespace Rokojori
[Export] [Export]
public Node3D grabOffset; public Node3D grabOffset;
[Export]
public Smoothing positionSmoothing;
[Export]
public Smoothing rotationSmoothing;
[ExportGroup("Read Only")] [ExportGroup("Read Only")]
[Export] [Export]
public Grabbable grabbable; public Grabbable grabbable;
public override void _Ready() public override void _Ready()
{ {
@ -59,7 +66,7 @@ namespace Rokojori
return; return;
} }
var grabbable = Nodes.Find<Grabbable>( pointable.GetParent() ); grabbable = Nodes.Find<Grabbable>( pointable.GetParent() );
if ( grabbable == null ) if ( grabbable == null )
{ {
@ -75,7 +82,9 @@ namespace Rokojori
{ {
return; return;
} }
positionSmoothing.SetCurrent( grabbable.grabTarget.GlobalPosition );
rotationSmoothing.SetCurrent( grabbable.grabTarget.GetGlobalQuaternion() );
UpdateGrabbable(); UpdateGrabbable();
} }
); );
@ -87,9 +96,11 @@ namespace Rokojori
_callback = null; _callback = null;
} }
void UpdateGrabbable() void UpdateGrabbable()
{ {
// this.LogInfo( "Grabbing", HierarchyName.Of( grabbable ) );
grabbable.grabTarget.GlobalPosition = Smoothing.Apply( positionSmoothing, grabOffset.GlobalPosition, timeLine.delta );
grabbable.grabTarget.SetGlobalQuaternion( Smoothing.Apply( rotationSmoothing, grabOffset.GetGlobalQuaternion(), timeLine.delta ) );
} }
} }

View File

@ -5,7 +5,7 @@ using Godot.Collections;
namespace Rokojori namespace Rokojori
{ {
[Tool]
[GlobalClass] [GlobalClass]
public partial class MultiRayCaster:Caster public partial class MultiRayCaster:Caster
{ {
@ -24,6 +24,9 @@ namespace Rokojori
[Export] [Export]
public Vector3 to; public Vector3 to;
[Export]
public Node collider;
public override int NumColliders() public override int NumColliders()
{ {
return numCollisions; return numCollisions;
@ -59,7 +62,15 @@ namespace Rokojori
ResolveCollisions(); ResolveCollisions();
SortCollisions(); SortCollisions();
var nextCollider = NumColliders() == 0 ? null : GetCollider( 0 );
if ( nextCollider != collider )
{
collider = nextCollider;
// this.LogInfo( "New Collider:", HierarchyName.Of( collider ) );
}
Action.Trigger( afterProcess ); Action.Trigger( afterProcess );
} }

View File

@ -4,8 +4,8 @@ using System.Collections.Generic;
using Godot.Collections; using Godot.Collections;
namespace Rokojori namespace Rokojori
{ {
[Tool]
[GlobalClass,Icon("res://addons/rokojori_action_library/Icons/Pointer.svg")] [GlobalClass,Icon("res://addons/rokojori_action_library/Icons/Pointer.svg")]
public partial class Pointer:Node3D public partial class Pointer:Node3D
{ {

View File

@ -18,6 +18,11 @@ namespace Rokojori
return LookingAtEachOtherAngle( lookDirectionA, lookDirectionB ) > 0; return LookingAtEachOtherAngle( lookDirectionA, lookDirectionB ) > 0;
} }
public static bool FacingSameDirection( Vector3 lookDirectionA, Vector3 lookDirectionB )
{
return ! LookingAtEachOther( lookDirectionA, lookDirectionB );
}
public static bool LookingTowards( Vector3 from, Vector3 fromDirection, Vector3 to ) public static bool LookingTowards( Vector3 from, Vector3 fromDirection, Vector3 to )
{ {
return LookingAtEachOther( fromDirection, to - from ); return LookingAtEachOther( fromDirection, to - from );
@ -103,11 +108,26 @@ namespace Rokojori
return v.X == 0 && v.Y == 0 && v.Z == 0; return v.X == 0 && v.Y == 0 && v.Z == 0;
} }
public static Vector3 ConstrainLength( this Vector3 v, float maxLength )
{
var length = v.Length();
if ( length <= maxLength )
{
return v;
}
return v.Normalized() * maxLength;
}
public static Vector3 ComputeNormalFast( Vector3 a, Vector3 b, Vector3 c ) public static Vector3 ComputeNormalFast( Vector3 a, Vector3 b, Vector3 c )
{ {
return Math3D.Cross( c - b , a - b ).Normalized(); return Math3D.Cross( c - b , a - b ).Normalized();
} }
public static Vector3 ComputeNormal( Vector3 a, Vector3 b, Vector3 c ) public static Vector3 ComputeNormal( Vector3 a, Vector3 b, Vector3 c )
{ {
var cross = Math3D.Cross( c - b , a - b ); var cross = Math3D.Cross( c - b , a - b );
@ -440,7 +460,12 @@ namespace Rokojori
public static float GlobalYaw( Vector3 direction ) public static float GlobalYaw( Vector3 direction )
{ {
return Mathf.Atan2( direction.Z, direction.X ); return ( Mathf.Pi * 2.0f - Mathf.Atan2( direction.Z, direction.X ) ) - Mathf.Pi / 2.0f;
}
public static float GlobalYawDegrees( Vector3 direction )
{
return Mathf.RadToDeg( GlobalYaw( direction ) );
} }
public static float GlobalPitch( Vector3 direction ) public static float GlobalPitch( Vector3 direction )
@ -451,6 +476,11 @@ namespace Rokojori
return Mathf.Atan2( y, xz ); return Mathf.Atan2( y, xz );
} }
public static float GlobalPitchDegrees( Vector3 direction )
{
return Mathf.RadToDeg( GlobalPitch( direction ) );
}
public static void SetGlobalQuaternion( this Node3D node, Quaternion quaternion ) public static void SetGlobalQuaternion( this Node3D node, Quaternion quaternion )
{ {
var localScale = node.Scale; var localScale = node.Scale;
@ -620,6 +650,38 @@ namespace Rokojori
node.GlobalPosition = gp; node.GlobalPosition = gp;
} }
public static void SetLocalX( this Node3D node, float x )
{
var gp = node.Position;
gp.X = x;
node.Position = gp;
}
public static void SetLocalY( this Node3D node, float y )
{
var gp = node.Position;
gp.Y = y;
node.Position = gp;
}
public static void SetLocalZ( this Node3D node, float z )
{
var gp = node.Position;
gp.Z = z;
node.Position = gp;
}
public static Vector3 GetOrientationBasedGlobalOffset( this Node3D node, Vector3 offset )
{
return offset.X * node.GlobalRight() + offset.Y * node.GlobalUp() + offset.Z * node.GlobalForward();
}
public static Vector3 Average( List<Vector3> vectors ) public static Vector3 Average( List<Vector3> vectors )
{ {
var average = Vector3.Zero; var average = Vector3.Zero;

View File

@ -96,6 +96,21 @@ namespace Rokojori
return Mathf.Abs( AngleDelta( degreesA, degreesB ) ); return Mathf.Abs( AngleDelta( degreesA, degreesB ) );
} }
public static float NormalizeAngle( float degrees )
{
while ( degrees > 180 )
{
degrees -= 360;
}
while ( degrees < -180 )
{
degrees += 360;
}
return degrees;
}
public static float Smoothstep ( float edge0, float edge1, float x ) public static float Smoothstep ( float edge0, float edge1, float x )
{ {
x = MathX.Clamp01( ( x - edge0 ) / ( edge1 - edge0 ) ); x = MathX.Clamp01( ( x - edge0 ) / ( edge1 - edge0 ) );
@ -118,6 +133,17 @@ namespace Rokojori
return Mathf.Floor( value / snappingDistance ) * snappingDistance; return Mathf.Floor( value / snappingDistance ) * snappingDistance;
} }
public static Vector2 RadiansToVector2( float angle )
{
return new Vector2( Mathf.Cos( angle ), Mathf.Sin( angle ) );
}
public static float Vector2ToRadians( Vector2 circle )
{
return Mathf.Atan2( circle.Y, circle.X );
}
public const float DegreesToRadians = Mathf.Pi / 180f; public const float DegreesToRadians = Mathf.Pi / 180f;
public const float RadiansToDegrees = 180f / Mathf.Pi; public const float RadiansToDegrees = 180f / Mathf.Pi;

View File

@ -27,23 +27,9 @@ namespace Rokojori
[Export] [Export]
public MeshInstance3D output; public MeshInstance3D output;
[Export]
public bool update = false; [ExportToolButton( "Update")]
public Callable UpdateButton => Callable.From( () => Create() );
[Export]
public bool updateAlways = false;
public override void _Process( double delta )
{
if ( ! ( update || updateAlways ) )
{
return;
}
update = false;
Create();
}
public float X() public float X()
@ -148,6 +134,11 @@ namespace Rokojori
mg.AddQuad( 20, 21, 22, 23, true ); mg.AddQuad( 20, 21, 22, 23, true );
if ( output == null )
{
output = this.CreateChild<MeshInstance3D>();
}
output.Mesh = mg.GenerateMesh(); output.Mesh = mg.GenerateMesh();
} }

View File

@ -1,10 +1,10 @@
[gd_resource type="Resource" script_class="GamePadAxisSensor" load_steps=2 format=3 uid="uid://dbha8dmhxgm05"] [gd_resource type="Resource" script_class="GamePadAxisSensor" load_steps=2 format=3 uid="uid://dbha8dmhxgm05"]
[ext_resource type="Script" path="res://addons/rokojori_action_library/Runtime/Sensors/GamePadAxisSensor.cs" id="1_yy4wi"] [ext_resource type="Script" uid="uid://cb81s7ud1de7h" path="res://addons/rokojori_action_library/Runtime/Sensors/GamePadAxisSensor.cs" id="1_yy4wi"]
[resource] [resource]
script = ExtResource("1_yy4wi") script = ExtResource("1_yy4wi")
axis = 0 axis = 1
type = 1 type = 1
continous = true continous = true
_value = 0.0 _value = 0.0

View File

@ -0,0 +1,9 @@
[gd_resource type="Resource" script_class="GamePadAxisSensor" load_steps=2 format=3 uid="uid://ck7woerh7mhp"]
[ext_resource type="Script" uid="uid://cb81s7ud1de7h" path="res://addons/rokojori_action_library/Runtime/Sensors/GamePadAxisSensor.cs" id="1_nrdau"]
[resource]
script = ExtResource("1_nrdau")
axis = 3
type = 1
continous = true

View File

@ -1,13 +0,0 @@
[gd_resource type="Resource" script_class="GamePadAxisSensor" load_steps=2 format=3 uid="uid://ck7woerh7mhp"]
[ext_resource type="Script" path="res://addons/rokojori_action_library/Runtime/Sensors/GamePadAxisSensor.cs" id="1_nrdau"]
[resource]
script = ExtResource("1_nrdau")
axis = 3
type = 1
continous = true
_value = 0.0
_wasActive = false
_active = false
_activeTreshold = 0.5

View File

@ -1,12 +1,8 @@
[gd_resource type="Resource" script_class="GamePadButtonSensor" load_steps=2 format=3 uid="uid://jvwwq6guhl77"] [gd_resource type="Resource" script_class="GamePadButtonSensor" load_steps=2 format=3 uid="uid://jvwwq6guhl77"]
[ext_resource type="Script" path="res://addons/rokojori_action_library/Runtime/Sensors/GamePadButtonSensor.cs" id="1_4da72"] [ext_resource type="Script" uid="uid://0ji11kv86cpk" path="res://addons/rokojori_action_library/Runtime/Sensors/GamePadButtonSensor.cs" id="1_4da72"]
[resource] [resource]
script = ExtResource("1_4da72") script = ExtResource("1_4da72")
button = 1 button = 2
continous = false continous = false
_value = 0.0
_wasActive = false
_active = false
_activeTreshold = 0.5

View File

@ -1,12 +1,8 @@
[gd_resource type="Resource" script_class="GamePadButtonSensor" load_steps=2 format=3 uid="uid://dpwq5eyla8rob"] [gd_resource type="Resource" script_class="GamePadButtonSensor" load_steps=2 format=3 uid="uid://dpwq5eyla8rob"]
[ext_resource type="Script" path="res://addons/rokojori_action_library/Runtime/Sensors/GamePadButtonSensor.cs" id="1_yv1r0"] [ext_resource type="Script" uid="uid://0ji11kv86cpk" path="res://addons/rokojori_action_library/Runtime/Sensors/GamePadButtonSensor.cs" id="1_yv1r0"]
[resource] [resource]
script = ExtResource("1_yv1r0") script = ExtResource("1_yv1r0")
button = 2 button = 3
continous = false continous = false
_value = 0.0
_wasActive = false
_active = false
_activeTreshold = 0.5

View File

@ -1,14 +1,14 @@
[gd_resource type="Resource" script_class="SensorGroup" load_steps=28 format=3 uid="uid://bv40lrpi3831d"] [gd_resource type="Resource" script_class="SensorGroup" load_steps=28 format=3 uid="uid://bv40lrpi3831d"]
[ext_resource type="Script" path="res://addons/rokojori_action_library/Runtime/Sensors/SensorGroup.cs" id="1_k6ypa"] [ext_resource type="Script" uid="uid://da4bhmvkury2" path="res://addons/rokojori_action_library/Runtime/Sensors/SensorGroup.cs" id="1_k6ypa"]
[ext_resource type="Resource" uid="uid://5gnh5dmv1p21" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Left-Joystick X-Negative.tres" id="2_1ywmr"] [ext_resource type="Resource" uid="uid://5gnh5dmv1p21" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Left-Joystick Left -X.tres" id="2_1ywmr"]
[ext_resource type="Resource" uid="uid://dsrf03g6mgu5t" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Left-Joystick X-Positive.tres" id="3_1yuu5"] [ext_resource type="Resource" uid="uid://dsrf03g6mgu5t" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Left-Joystick Right +X.tres" id="3_1yuu5"]
[ext_resource type="Resource" uid="uid://dbha8dmhxgm05" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Left-Joystick Y-Negative.tres" id="4_ehig4"] [ext_resource type="Resource" uid="uid://dbha8dmhxgm05" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Left-Joystick Up -Y.tres" id="4_ehig4"]
[ext_resource type="Resource" uid="uid://cyyy0ycusgil3" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Left-Joystick Y-Positive.tres" id="5_adyq7"] [ext_resource type="Resource" uid="uid://cyyy0ycusgil3" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Left-Joystick Down +Y.tres" id="5_adyq7"]
[ext_resource type="Resource" uid="uid://b16mtcrpm1f6i" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Right-Joystick X-Negative.tres" id="6_g7fxo"] [ext_resource type="Resource" uid="uid://b16mtcrpm1f6i" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Right-Joystick Left -X.tres" id="6_g7fxo"]
[ext_resource type="Resource" uid="uid://d05w143o644d3" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Right-Joystick X-Positive.tres" id="7_b0v3q"] [ext_resource type="Resource" uid="uid://d05w143o644d3" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Right-Joystick Right +X.tres" id="7_b0v3q"]
[ext_resource type="Resource" uid="uid://ck7woerh7mhp" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Right-Joystick Y-Negative.tres" id="8_ljqng"] [ext_resource type="Resource" uid="uid://ck7woerh7mhp" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Right-Joystick Up -Y.tres" id="8_ljqng"]
[ext_resource type="Resource" uid="uid://6emg8n3qxhlv" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Right-Joystick Y-Positive.tres" id="9_qkgw5"] [ext_resource type="Resource" uid="uid://6emg8n3qxhlv" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Right-Joystick Down +Y.tres" id="9_qkgw5"]
[ext_resource type="Resource" uid="uid://cs12bjge707ri" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Trigger Left, LT, PS L2, Nin ZL.tres" id="10_t2i3f"] [ext_resource type="Resource" uid="uid://cs12bjge707ri" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Trigger Left, LT, PS L2, Nin ZL.tres" id="10_t2i3f"]
[ext_resource type="Resource" uid="uid://cy3ja8squnin6" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Trigger Right, RT, PS R2, Nin ZR.tres" id="11_u6ig2"] [ext_resource type="Resource" uid="uid://cy3ja8squnin6" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Axis/Trigger Right, RT, PS R2, Nin ZR.tres" id="11_u6ig2"]
[ext_resource type="Resource" uid="uid://dffkdky8iowro" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Buttons/Button A, PS Cross, Nin B.tres" id="12_0r6yt"] [ext_resource type="Resource" uid="uid://dffkdky8iowro" path="res://addons/rokojori_action_library/Runtime/Sensors/Default-Sensors/Gamepad/Buttons/Button A, PS Cross, Nin B.tres" id="12_0r6yt"]

View File

@ -0,0 +1,75 @@
using Godot;
using System.Collections.Generic;
namespace Rokojori
{
[Tool]
[GlobalClass,Icon("res://addons/rokojori_action_library/Icons/SensorGroup.svg")]
public partial class HoldSensor : Sensor
{
[Export]
public Sensor holdButton;
[Export]
public bool negateHoldButton;
[Export]
public Sensor triggerButton;
protected override void UpdateValue()
{
if ( holdButton == null || triggerButton == null )
{
SetFloatValue( 0 );
return;
}
var holdButtonValue = holdButton.isActive;
if ( negateHoldButton )
{
holdButtonValue = ! holdButtonValue;
}
if ( ! holdButtonValue )
{
SetFloatValue( 0 );
return;
}
SetFloatValue( triggerButton.value );
}
public override string ToString()
{
return RJLog.GetInfo( this, holdButton, triggerButton );
}
[Export]
public InputIcon[] inputIcons = [];
[Export]
public bool useInputIconsFromSensors = true;
public override List<InputIcon> GetInputIcons()
{
var list = Lists.From( inputIcons );
if ( useInputIconsFromSensors )
{
if ( holdButton != null )
{
list.AddRange( holdButton.GetInputIcons() );
}
if ( triggerButton != null )
{
list.AddRange( triggerButton.GetInputIcons() );
}
}
return list;
}
}
}

View File

@ -0,0 +1 @@
uid://b3c1sl7uhvqu8

View File

@ -17,18 +17,13 @@ namespace Rokojori
[Export] [Export]
public bool continous = false; public bool continous = false;
[ExportGroup("Read Only")] protected float _value = 0;
[Export]
public float _value = 0;
[Export] protected bool _wasActive = false;
public bool _wasActive = false;
[Export] protected bool _active = false;
public bool _active = false;
[Export] protected float _activeTreshold = 0.5f;
public float _activeTreshold = 0.5f;
public void ProcessSensor( SensorRunner runner, float delta ) public void ProcessSensor( SensorRunner runner, float delta )
{ {

View File

@ -35,16 +35,22 @@ namespace Rokojori
[ExportGroup("Read Only")] [ExportGroup("Read Only")]
[Export] [Export]
public SensorDevice[] deviceList = new SensorDevice[]{}; public SensorDevice[] deviceList =[];
[Export] [Export]
public float[] deviceLastInputTimeStamp = new float[]{}; public float[] deviceLastInputTimeStamp = [];
[ExportGroup("Testing")] [ExportGroup("Testing")]
[Export] [Export]
public SensorDevice testingLastActiveDevice; public SensorDevice testingLastActiveDevice;
[Export]
public bool showRegistratedSensors = true;
[Export]
public Sensor[] registratedSensors = [];
@ -61,6 +67,12 @@ namespace Rokojori
DateTime _startTime; DateTime _startTime;
public bool isMouseKeyboardLastActive => lastActiveDevice == mouseKeyboardDevice ||
lastActiveDevice == mouseDevice ||
lastActiveDevice == keyboardDevice;
public bool isControllerLastActive => lastActiveDevice == gamePadDevice;
public SensorDevice lastActiveDevice public SensorDevice lastActiveDevice
{ {
get get
@ -175,8 +187,11 @@ namespace Rokojori
runners.ForEach( r => r.Update( (float) delta ) ); runners.ForEach( r => r.Update( (float) delta ) );
} }
public void Register( Sensor s, SensorInputHandler sih ) public void Register( Sensor s, SensorInputHandler sih )
{ {
this.LogInfo( "Registrating", s );
var sensorRunner = sensorToRunner[ s ]; var sensorRunner = sensorToRunner[ s ];
if ( sensorRunner.listeners.Contains( sih ) ) if ( sensorRunner.listeners.Contains( sih ) )
@ -185,6 +200,8 @@ namespace Rokojori
} }
sensorRunner.listeners.Add( sih ); sensorRunner.listeners.Add( sih );
} }
public void Unregister( Sensor s, SensorInputHandler sih ) public void Unregister( Sensor s, SensorInputHandler sih )
@ -196,6 +213,11 @@ namespace Rokojori
public static void Register( SensorInputHandler handler, params Sensor[] sensors ) public static void Register( SensorInputHandler handler, params Sensor[] sensors )
{ {
var sm = Unique<SensorManager>.Get(); var sm = Unique<SensorManager>.Get();
if ( sm == null )
{
Nodes.ForEachInScene<Node>( n => n.LogInfo() );
}
foreach ( var s in sensors ) foreach ( var s in sensors )
{ {
@ -241,6 +263,11 @@ namespace Rokojori
sensorsSet.Add( s ); sensorsSet.Add( s );
runners.Add( new SensorRunner( s ) ); runners.Add( new SensorRunner( s ) );
if ( showRegistratedSensors )
{
registratedSensors = Arrays.Add( registratedSensors, s );
}
} }
HashSet<object> _scannedObjects = new HashSet<object>(); HashSet<object> _scannedObjects = new HashSet<object>();
@ -257,6 +284,19 @@ namespace Rokojori
var sensors = ReflectionHelper.GetDataMemberValues<Sensor>( obj ); var sensors = ReflectionHelper.GetDataMemberValues<Sensor>( obj );
if ( sensors.Count > 0 )
{
if ( obj is Node n )
{
n.LogInfo( sensors );
}
else if ( obj is Resource r )
{
r.LogInfo( sensors );
}
}
sensors.ForEach( sensors.ForEach(
s => s =>
{ {
@ -309,12 +349,12 @@ namespace Rokojori
foreach ( var n in autoScanForSensors ) foreach ( var n in autoScanForSensors )
{ {
Nodes.ForEach<Node>( n, cn=> AddSensorsFrom( cn ) ); Nodes.ForEach<Node>( n, AddSensorsFrom );
} }
if ( autoScanParent ) if ( autoScanParent )
{ {
Nodes.ForEach<Node>( GetParent(), cn=> AddSensorsFrom( cn ) ); Nodes.ForEach<Node>( GetParent(), AddSensorsFrom );
} }
runners.ForEach( runners.ForEach(

View File

@ -0,0 +1,32 @@
using Godot;
using System.Collections.Generic;
using System;
namespace Rokojori
{
[Tool]
[GlobalClass,Icon("res://addons/rokojori_action_library/Icons/SensorManager.svg")]
public partial class SensorViewer: Node
{
[Export]
public Sensor sensor;
[Export]
public float value;
[Export]
public bool active;
public override void _Process(double delta)
{
if ( sensor == null )
{
return;
}
value = sensor.value;
active = sensor.isActive;
}
}
}

View File

@ -0,0 +1 @@
uid://bodk4mqlebnwi

View File

@ -34,5 +34,23 @@ namespace Rokojori
{ {
return GetValue( negative, -scale, deadZone ) + GetValue( positive, scale, deadZone ); return GetValue( negative, -scale, deadZone ) + GetValue( positive, scale, deadZone );
} }
public static Vector2 FourDirectional( Sensor left, Sensor right, Sensor up, Sensor down, bool normalize = true, float deadZone = 0.3f )
{
var x = PolarAxis( left, right, 1, deadZone );
var y = PolarAxis( up, down, 1, deadZone );
var v = new Vector2( x, y );
if ( normalize && v.Length() > 1 )
{
v = v.Normalized();
}
return v;
}
} }
} }

View File

@ -14,7 +14,9 @@ namespace Rokojori
public Action action; public Action action;
public override void _Ready() public override void _Ready()
{ {
this.LogInfo( "Root" );
SensorManager.Register( this, sensor ); SensorManager.Register( this, sensor );
} }

View File

@ -72,4 +72,19 @@ float angleDelta( float degreesA, float degreesB )
float angleDelta = degreesB - degreesA; float angleDelta = degreesB - degreesA;
angleDelta = mod( angleDelta + 180.0, 360.0 ) - 180.0; angleDelta = mod( angleDelta + 180.0, 360.0 ) - 180.0;
return angleDelta; return angleDelta;
}
float snapRounded( float value, float snappingDistance )
{
return round( value / snappingDistance ) * snappingDistance;
}
float snapCeiled( float value, float snappingDistance )
{
return ceil( value / snappingDistance ) * snappingDistance;
}
float snapFloored( float value, float snappingDistance )
{
return floor( value / snappingDistance ) * snappingDistance;
} }

View File

@ -1,5 +1,7 @@
// #include "res://addons/rokojori_action_library/Runtime/Shading/Library/Noise.gdshaderinc" // #include "res://addons/rokojori_action_library/Runtime/Shading/Library/Noise.gdshaderinc"
#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Math.gdshaderinc"
float random( vec2 uv ) float random( vec2 uv )
{ {
return fract( sin( dot( uv.xy, vec2( 12.9898, 78.233 ) ) ) * 43758.5453123 ); return fract( sin( dot( uv.xy, vec2( 12.9898, 78.233 ) ) ) * 43758.5453123 );
@ -7,9 +9,16 @@ float random( vec2 uv )
vec2 random_v2( vec2 uv ) vec2 random_v2( vec2 uv )
{ {
return vec2( fract( sin( dot( uv.xy, vec2( 12.9898,78.233 ) ) ) * 43758.5453123 ) ); uv = vec2
(
dot(uv, vec2( 127.1,311.7 ) ),
dot(uv, vec2( 269.5,183.3 ) )
);
return -1.0 + 2.0 * fract( sin( uv ) * 43758.5453123 );
} }
vec3 random_v3( vec3 uvw ) vec3 random_v3( vec3 uvw )
{ {
@ -20,7 +29,20 @@ vec3 random_v3( vec3 uvw )
return -1.0 + 2.0 * fract(sin(uvw) * 43758.5453123); return -1.0 + 2.0 * fract(sin(uvw) * 43758.5453123);
} }
float perlin( vec2 uv ) // float perlin( vec2 uv )
// {
// vec2 uv_index = floor(uv);
// vec2 uv_fract = fract(uv);
// vec2 blur = smoothstep(0.0, 1.0, uv_fract);
// return mix( mix( dot( random_v2(uv_index + vec2(0.0,0.0) ), uv_fract - vec2(0.0,0.0) ),
// dot( random_v2(uv_index + vec2(1.0,0.0) ), uv_fract - vec2(1.0,0.0) ), blur.x),
// mix( dot( random_v2(uv_index + vec2(0.0,1.0) ), uv_fract - vec2(0.0,1.0) ),
// dot( random_v2(uv_index + vec2(1.0,1.0) ), uv_fract - vec2(1.0,1.0) ), blur.x), blur.y) + 0.5;
// }
float perlin(vec2 uv)
{ {
vec2 uv_index = floor(uv); vec2 uv_index = floor(uv);
vec2 uv_fract = fract(uv); vec2 uv_fract = fract(uv);
@ -33,6 +55,61 @@ float perlin( vec2 uv )
dot( random_v2(uv_index + vec2(1.0,1.0) ), uv_fract - vec2(1.0,1.0) ), blur.x), blur.y) + 0.5; dot( random_v2(uv_index + vec2(1.0,1.0) ), uv_fract - vec2(1.0,1.0) ), blur.x), blur.y) + 0.5;
} }
float perlinOctaves( vec2 uv, int octaves, float scale, float gain )
{
float s = 1.0;
float g = 1.0;
float v = perlin( uv * s ) * g;
float n = 1.0;
for ( int i = 0; i < octaves; i++ )
{
s *= scale;
g *= gain;
v += perlin( uv * s ) * g;
n += g;
}
return v / n;
}
vec2 seamLessCoordinate( vec2 uv, vec2 seamRange, vec2 seamFade, vec2 type )
{
return mod( uv - seamFade * type, seamRange );
}
float perlinOctavesSeamless( vec2 uv, int octaves, float scale, float gain, vec2 seamRange, vec2 seamFade )
{
// uv = mod( uv , seamRange );
seamFade *= seamRange;
vec2 fading = mod( uv, seamRange ) ;
fading.x = normalizeToRange01( fading.x, seamRange.x - seamFade.x, seamRange.x );
fading.y = normalizeToRange01( fading.y, seamRange.y - seamFade.y, seamRange.y );
// 0, seamRange - seamFade, seamRange
//
vec2 p00 = seamLessCoordinate( uv, seamRange, seamFade, vec2( 0.0, 0.0 ) );
vec2 p10 = seamLessCoordinate( uv, seamRange, seamFade, vec2( 1.0, 0.0 ) );
vec2 p01 = seamLessCoordinate( uv, seamRange, seamFade, vec2( 0.0, 1.0 ) );
vec2 p11 = seamLessCoordinate( uv, seamRange, seamFade, vec2( 1.0, 1.0 ) );
float n00 = perlinOctaves( p00, octaves, scale, gain );
float n10 = perlinOctaves( p10, octaves, scale, gain );
float n01 = perlinOctaves( p01, octaves, scale, gain );
float n11 = perlinOctaves( p11, octaves, scale, gain );
float n0 = mix( n00, n10, fading.x );
float n1 = mix( n01, n11, fading.x );
return mix( n0, n1, fading.y );
}
float perlin3D( vec3 uvw ) float perlin3D( vec3 uvw )
{ {
vec3 gridIndex = floor( uvw ); vec3 gridIndex = floor( uvw );

View File

@ -43,11 +43,12 @@ namespace Rokojori
{ {
low = tweened; low = tweened;
} }
else else
{ {
high = tweened; high = tweened;
} }
if ( validateLimits != null && ! validateLimits( low, high ) ) if ( validateLimits != null && ! validateLimits( low, high ) )
{ {
throw new Exception( "Limit validation failed" ); throw new Exception( "Limit validation failed" );

View File

@ -39,6 +39,20 @@ namespace Rokojori
return last; return last;
} }
public static async Task<double> WaitIfExceeded( double last, Node node, double waitTime = Async.waitTime )
{
var now = Time.GetTicksMsec() / 1000.0;
if ( ( now - last ) > waitTime )
{
await node.RequestNextFrame();
return Time.GetTicksMsec() / 1000.0;;
}
return last;
}
public static double DoIfExceeded( double last, System.Action action, double waitTime = Async.waitTime ) public static double DoIfExceeded( double last, System.Action action, double waitTime = Async.waitTime )
{ {
var now = Time.GetTicksMsec() / 1000.0; var now = Time.GetTicksMsec() / 1000.0;

View File

@ -8,7 +8,7 @@ namespace Rokojori
{ {
public class Safe public class Safe
{ {
static readonly int maxWhileIterations = 2000 * 1000; static readonly int maxWhileIterations = 1000 * 1000;
public static void While( Func<bool> condition, System.Action action, System.Action onTooManyIterations = null ) public static void While( Func<bool> condition, System.Action action, System.Action onTooManyIterations = null )
{ {

View File

@ -0,0 +1,53 @@
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System;
using Godot;
namespace Rokojori
{
[Tool]
[GlobalClass]
public partial class CameraTargetOffset:Node3D
{
[Export]
public float cameraTargetMinOffsetZ = 0;
[Export]
public float cameraTargetMaxOffsetZ = 10;
[Export]
public Smoothing cameraTargetOffsetZSmoothing = new FrameSmoothing();
[Export]
public float cameraTargetMinOffsetY = 1.7f;
[Export]
public float cameraTargetMaxOffsetY = 2f;
[Export]
public Smoothing cameraTargetOffsetYSmoothing = new FrameSmoothing();
protected float nextZ = 0;
protected float nextY = 0;
public virtual void SetMovingForward( float movingForward )
{
nextZ = Mathf.Lerp( cameraTargetMinOffsetZ, cameraTargetMaxOffsetZ, movingForward );
nextY = Mathf.Lerp( cameraTargetMinOffsetY, cameraTargetMaxOffsetY, movingForward );
}
public override void _Process( double delta )
{
var smoothedOffsetZ = cameraTargetOffsetZSmoothing.Smooth( nextZ, (float)delta );
this.SetLocalZ( smoothedOffsetZ );
var smoothedOffsetY = cameraTargetOffsetYSmoothing.Smooth( nextY, (float)delta );
this.SetLocalY( smoothedOffsetY );
}
}
}

View File

@ -0,0 +1 @@
uid://bk5eoi53m08jh

View File

@ -14,6 +14,9 @@ namespace Rokojori
{ {
[Export] [Export]
public Node3D target; public Node3D target;
[Export]
public Smoothing targetFollowSmoothing = new FrameSmoothing();
[ExportGroup("Yaw")] [ExportGroup("Yaw")]
@ -26,14 +29,39 @@ namespace Rokojori
[Export] [Export]
public Sensor yawNegativeAxis; public Sensor yawNegativeAxis;
[Export]
public bool roundYaw = false;
[Export]
public int roundedYawResolution = 64;
[Export] [Export]
public float yaw = 0; public float yaw = 0;
[Export] [Export]
public float yawSmoothingDuration = 0.1f; 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;
Smoother yawSmoother = new Smoother();
[ExportGroup("Pitch")] [ExportGroup("Pitch")]
@ -58,27 +86,44 @@ namespace Rokojori
[Export] [Export]
public float maxPitch = 80; public float maxPitch = 80;
public float normalizedPitch => MathX.NormalizeClamped( pitch, minPitch, maxPitch );
[Export] [Export]
public float pitchSmoothingDuration = 0.1f; public Smoothing pitchSmoothing = new FrameSmoothing();
Smoother pitchSmoother = new Smoother(); [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] [Export]
public Curve distanceForPitch = MathX.Curve( 1, 1 ); public Curve distanceForPitch = MathX.Curve( 1, 1 );
[Export] [Export]
public float distanceScale = 1; public float distanceScale = 1;
[ExportGroup("Offset")] [ExportGroup("Camera Offset")]
[Export] [Export]
public Vector3 offset; public Vector3 offset;
Smoother distanceSmoother = new Smoother();
float smoothedYaw = 0; float smoothedYaw = 0;
float smoothedPitch = 0; float smoothedPitch = 0;
float smoothedDistance = 0; float smoothedDistance = 0;
float _centerPitchActivation = 0;
float _yawBehindActivation = 0;
public override void _Process( double delta ) public override void _Process( double delta )
{ {
@ -87,38 +132,97 @@ namespace Rokojori
return; 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 yawAxis = Sensors.PolarAxis( yawNegativeAxis, yawPositiveAxis );
var pitchAxis = Sensors.PolarAxis( pitchNegativeAxis, pitchPositiveAxis ); var pitchAxis = Sensors.PolarAxis( pitchNegativeAxis, pitchPositiveAxis );
yaw += yawAxis * yawSpeed * (float)delta; 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 ); // yaw = MathX.Repeat( yaw, 360f );
if ( pitchIsRelative ) if ( pitchIsRelative )
{ {
pitch += pitchAxis * pitchSpeed * (float)delta; pitch += pitchAxis * pitchSpeed * (float)delta;
pitch = Mathf.Clamp( pitch, minPitch, maxPitch ); 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 else
{ {
pitch = Mathf.Remap( pitchAxis, -1, 1, minPitch, maxPitch ); pitch = Mathf.Remap( pitchAxis, -1, 1, minPitch, maxPitch );
} }
if ( Mathf.Abs( yaw - smoothedYaw ) > 180 ) // if ( Mathf.Abs( yaw - smoothedYaw ) > 180 )
{ // {
if ( yaw > smoothedYaw ) // if ( yaw > smoothedYaw )
{ // {
smoothedYaw += 360; // smoothedYaw += 360;
} // }
else if ( yaw < smoothedYaw ) // else if ( yaw < smoothedYaw )
{ // {
smoothedYaw -= 360; // 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 );
// }
smoothedYaw = yaw;
smoothedPitch = pitchSmoother.SmoothForDuration( smoothedPitch, pitch, pitchSmoothingDuration, (float) delta );
// RJLog.Log( "Pitch", smoothedPitch ); // RJLog.Log( "Pitch", smoothedPitch );
@ -126,11 +230,11 @@ namespace Rokojori
// smoothedPitch = pitch; // smoothedPitch = pitch;
var distance = distanceForPitch.Sample( MathX.NormalizeClamped( pitch, minPitch, maxPitch ) ) * distanceScale; var distance = distanceForPitch.Sample( MathX.NormalizeClamped( pitch, minPitch, maxPitch ) ) * distanceScale;
GlobalPosition = target.GlobalPosition + Math3D.YawPitchRotation( smoothedYaw, smoothedPitch ) * Vector3.Forward * distance + offset; GlobalPosition = targetPosition + Math3D.YawPitchRotation( smoothedYaw, smoothedPitch ) * Vector3.Forward * distance;
LookAt( target.GlobalPosition + offset, Vector3.Up, true ); LookAt( targetPosition, Vector3.Up, true );
GlobalPosition += this.GetOrientationBasedGlobalOffset( offset );
} }

View File

@ -0,0 +1,39 @@
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System;
using Godot;
namespace Rokojori
{
[Tool]
[GlobalClass]
public partial class ThirdPersonCameraTargetOffset:CameraTargetOffset
{
[Export]
public ThirdPersonCamera thirdPersonCamera;
[Export]
public Curve pitchMultiply;
public override void SetMovingForward( float movingForward )
{
if ( pitchMultiply != null && thirdPersonCamera != null )
{
var normalizedPitch = thirdPersonCamera.normalizedPitch;
var sampledPitchMultiply = pitchMultiply.Sample( normalizedPitch );
movingForward *= sampledPitchMultiply;
}
nextZ = Mathf.Lerp( cameraTargetMinOffsetZ, cameraTargetMaxOffsetZ, movingForward );
nextY = Mathf.Lerp( cameraTargetMinOffsetY, cameraTargetMaxOffsetY, movingForward );
}
}
}

View File

@ -0,0 +1 @@
uid://s7mi8hpmma3e

View File

@ -21,6 +21,7 @@ namespace Rokojori
[Export] [Export]
public bool active = false; public bool active = false;
public static VirtualCamera3DManager Get() public static VirtualCamera3DManager Get()
{ {
return Unique<VirtualCamera3DManager>.Get(); return Unique<VirtualCamera3DManager>.Get();