Pointer, Particles, Numbers
This commit is contained in:
parent
4bbed6ba6c
commit
f472d031a8
|
|
@ -13,19 +13,38 @@ namespace Rokojori
|
||||||
[Export]
|
[Export]
|
||||||
public string message;
|
public string message;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Node node;
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
public bool printPath;
|
public bool printPath;
|
||||||
|
|
||||||
protected override void _OnTrigger()
|
protected override void _OnTrigger()
|
||||||
{
|
{
|
||||||
if ( printPath )
|
if ( printPath )
|
||||||
|
{
|
||||||
|
if ( node != null )
|
||||||
|
{
|
||||||
|
this.LogInfo( message, node );
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
this.LogInfo( message );
|
this.LogInfo( message );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( node != null )
|
||||||
|
{
|
||||||
|
RJLog.Log( message, node );
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RJLog.Log( message );
|
RJLog.Log( message );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -13,6 +13,8 @@ namespace Rokojori
|
||||||
[Export]
|
[Export]
|
||||||
public Node3D lookTarget;
|
public Node3D lookTarget;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public bool useModelFront = false;
|
||||||
|
|
||||||
protected override void _OnTrigger()
|
protected override void _OnTrigger()
|
||||||
{
|
{
|
||||||
|
|
@ -21,7 +23,7 @@ namespace Rokojori
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lookFrom.LookAt( lookTarget.GlobalPosition );
|
lookFrom.LookAt( lookTarget.GlobalPosition, Vector3.Up, useModelFront );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
|
||||||
|
using Rokojori.Extensions;
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
[GlobalClass, Tool ]
|
||||||
|
public partial class SetNode3D : Action
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public Node source;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public string sourceMember;
|
||||||
|
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Node target;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public string targetMember;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected override void _OnTrigger()
|
||||||
|
{
|
||||||
|
if ( target == null || source == null )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var value = ReflectionHelper.GetValue<Node3D>( source, sourceMember );
|
||||||
|
|
||||||
|
ReflectionHelper.SetValue<Node3D>( target, targetMember, value );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://dnx8jc8lsfwoi
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
|
||||||
|
using Godot;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
using Rokojori.Extensions;
|
||||||
|
namespace Rokojori;
|
||||||
|
|
||||||
|
[Tool]
|
||||||
|
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Action.svg")]
|
||||||
|
public partial class NumberMath:Action
|
||||||
|
{
|
||||||
|
public enum Operator
|
||||||
|
{
|
||||||
|
Set,
|
||||||
|
Add,
|
||||||
|
Substract,
|
||||||
|
Multiply,
|
||||||
|
Divide,
|
||||||
|
Modulo,
|
||||||
|
Freeze,
|
||||||
|
Unfreeze,
|
||||||
|
Reset
|
||||||
|
}
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public NumberValue target;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Operator operation = Operator.Set;
|
||||||
|
|
||||||
|
public enum Order
|
||||||
|
{
|
||||||
|
Target_Op_Source,
|
||||||
|
Source_Op_Target
|
||||||
|
}
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Order order = Order.Target_Op_Source;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public double sourceValue;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public NumberValue sourceReference;
|
||||||
|
|
||||||
|
protected override void _OnTrigger()
|
||||||
|
{
|
||||||
|
var valueRight = ( sourceReference == null ? 0 : sourceReference.value ) + sourceValue;
|
||||||
|
var valueLeft = target.value;
|
||||||
|
|
||||||
|
if ( order == Order.Source_Op_Target )
|
||||||
|
{
|
||||||
|
var buffer = valueLeft;
|
||||||
|
valueLeft = valueRight;
|
||||||
|
valueRight = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( operation )
|
||||||
|
{
|
||||||
|
case Operator.Set: { target.value = valueRight; } break;
|
||||||
|
case Operator.Add: { target.value = valueLeft + valueRight; } break;
|
||||||
|
case Operator.Substract: { target.value = valueLeft - valueRight; } break;
|
||||||
|
case Operator.Multiply: { target.value = valueLeft * valueRight; } break;
|
||||||
|
case Operator.Divide: { target.value = valueLeft / valueRight; } break;
|
||||||
|
case Operator.Modulo: { target.value = valueLeft % valueRight; } break;
|
||||||
|
case Operator.Freeze: { target.FreezeValue(); } break;
|
||||||
|
case Operator.Unfreeze: { target.UnfreezeValue(); } break;
|
||||||
|
case Operator.Reset: { target.ResetValue(); } break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://b7uiy1j04s3fu
|
||||||
|
|
@ -0,0 +1,134 @@
|
||||||
|
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
|
||||||
|
using Rokojori.Extensions;
|
||||||
|
namespace Rokojori;
|
||||||
|
|
||||||
|
[Tool][GlobalClass]
|
||||||
|
public partial class NumberValue : Node
|
||||||
|
{
|
||||||
|
protected double _value = 0;
|
||||||
|
protected bool _frozen;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public double value
|
||||||
|
{
|
||||||
|
get => _value;
|
||||||
|
set { _OnValueChange( value ); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return GetType().Name + " { value = " + _value._DDD() + ", frozen = " + _frozen + " }";
|
||||||
|
}
|
||||||
|
|
||||||
|
void _OnValueChange( double v )
|
||||||
|
{
|
||||||
|
if ( _frozen )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var setterValue = Mathf.Clamp( v, minValue, maxValue );
|
||||||
|
|
||||||
|
if ( _value == setterValue )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var before = _value;
|
||||||
|
_value = setterValue;
|
||||||
|
|
||||||
|
var belowLowTreshold = before < lowTreshold;
|
||||||
|
var aboveHighTreshold = before > highTreshold;
|
||||||
|
|
||||||
|
onChange?.Trigger();
|
||||||
|
|
||||||
|
if ( ! belowLowTreshold && _value < lowTreshold )
|
||||||
|
{
|
||||||
|
onBelowLowTreshold?.Trigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! aboveHighTreshold && _value > highTreshold )
|
||||||
|
{
|
||||||
|
onAboveHighTreshold?.Trigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _value == minValue )
|
||||||
|
{
|
||||||
|
onMin?.Trigger();
|
||||||
|
|
||||||
|
if ( autoFreezeOnMin )
|
||||||
|
{
|
||||||
|
_frozen = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( _value == maxValue )
|
||||||
|
{
|
||||||
|
onMax?.Trigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FreezeValue()
|
||||||
|
{
|
||||||
|
this._frozen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnfreezeValue()
|
||||||
|
{
|
||||||
|
this._frozen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetValue()
|
||||||
|
{
|
||||||
|
this._frozen = false;
|
||||||
|
this._value = resetValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public double resetValue = 100;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public double minValue = 0;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public double maxValue = 125;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public double lowTreshold = 25;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public double highTreshold = 75;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public bool autoFreezeOnMin = true;
|
||||||
|
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Action onChange;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Action onIncrement;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Action onDecrement;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Action onMin;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Action onMax;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Action onBelowLowTreshold;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Action onAboveHighTreshold;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bg8bavpgdo0r6
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
using Rokojori.Extensions;
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
[Tool]
|
||||||
|
[GlobalClass]
|
||||||
|
public partial class LockOnCamera : VirtualCamera
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public Node3D playerTarget;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public LockOnPointer source;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Node3D lockTarget;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public LockOnCameraSettings settings;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public CharacterController.CharacterUpdateMode updateMode = CharacterController.CharacterUpdateMode.Physics_Process;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public bool processInEditor = false;
|
||||||
|
|
||||||
|
public bool canProcess => processInEditor || ! Engine.IsEditorHint();
|
||||||
|
|
||||||
|
public void SetLockTarget( Node3D target )
|
||||||
|
{
|
||||||
|
lockTarget = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node3D CurrentLockTarget()
|
||||||
|
{
|
||||||
|
if ( source != null && source.pointable != null )
|
||||||
|
{
|
||||||
|
return source.pointable;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lockTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _Process( double delta )
|
||||||
|
{
|
||||||
|
if ( canProcess && CharacterController.CharacterUpdateMode.Process == updateMode )
|
||||||
|
{
|
||||||
|
_ProcessCamera( delta );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _PhysicsProcess( double delta )
|
||||||
|
{
|
||||||
|
if ( canProcess && CharacterController.CharacterUpdateMode.Physics_Process == updateMode )
|
||||||
|
{
|
||||||
|
_ProcessCamera( delta );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _ProcessCamera( double gameDelta )
|
||||||
|
{
|
||||||
|
if ( playerTarget == null || settings == null )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var delta = (float) gameDelta;
|
||||||
|
var target = CurrentLockTarget();
|
||||||
|
|
||||||
|
var playerPosition = Smoothing.Apply( settings.playerFollowSmoothing, playerTarget.GlobalPosition, delta );
|
||||||
|
|
||||||
|
Vector3 axisDirection;
|
||||||
|
Vector3 lookAtPoint;
|
||||||
|
|
||||||
|
if ( target != null )
|
||||||
|
{
|
||||||
|
var targetPosition = Smoothing.Apply( settings.targetFollowSmoothing, target.GlobalPosition, delta );
|
||||||
|
var offset = targetPosition - playerPosition;
|
||||||
|
var flat = new Vector3( offset.X, 0, offset.Z );
|
||||||
|
|
||||||
|
axisDirection = flat.LengthSquared() > 0.0001f ? flat.Normalized() : -playerTarget.GlobalTransform.Basis.Z;
|
||||||
|
lookAtPoint = playerPosition.Lerp( targetPosition, settings.lookAtTargetWeight );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
axisDirection = -playerTarget.GlobalTransform.Basis.Z;
|
||||||
|
lookAtPoint = playerPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
var side = axisDirection.Cross( Vector3.Up );
|
||||||
|
|
||||||
|
var desiredPosition = playerPosition - axisDirection * settings.distance + Vector3.Up * settings.height + side * settings.sideOffset;
|
||||||
|
|
||||||
|
cameraPosition = Smoothing.Apply( settings.positionSmoothing, desiredPosition, delta );
|
||||||
|
|
||||||
|
lookAtPoint.Y += settings.lookAtHeight;
|
||||||
|
|
||||||
|
cameraForward = ( lookAtPoint - cameraPosition ).Normalized();
|
||||||
|
|
||||||
|
var basis = Basis.LookingAt( cameraForward, Vector3.Up, true );
|
||||||
|
cameraRotation = new Quaternion( basis );
|
||||||
|
|
||||||
|
FOV = settings.fov;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 cameraPosition;
|
||||||
|
|
||||||
|
public override Vector3 GetCameraPosition()
|
||||||
|
{
|
||||||
|
return cameraPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 cameraForward;
|
||||||
|
|
||||||
|
public Quaternion cameraRotation;
|
||||||
|
|
||||||
|
public override Quaternion GetCameraRotation()
|
||||||
|
{
|
||||||
|
return cameraRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float FOV = 60f;
|
||||||
|
|
||||||
|
public override float GetCameraFOV()
|
||||||
|
{
|
||||||
|
return FOV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://b5o54ra4cgj2k
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
using Rokojori.Extensions;
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
[Tool]
|
||||||
|
[GlobalClass]
|
||||||
|
public partial class LockOnCameraSettings : Resource
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public float distance = 6f;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float height = 2f;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float sideOffset = 0f;
|
||||||
|
|
||||||
|
[ExportGroup( "Look At" )]
|
||||||
|
[Export(PropertyHint.Range, "0,1")]
|
||||||
|
public float lookAtTargetWeight = 0.5f;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float lookAtHeight = 0f;
|
||||||
|
|
||||||
|
[ExportGroup( "FOV" )]
|
||||||
|
[Export]
|
||||||
|
public float fov = 60f;
|
||||||
|
|
||||||
|
[ExportGroup( "Smoothing" )]
|
||||||
|
[Export]
|
||||||
|
public Smoothing playerFollowSmoothing = new FrameSmoothing();
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Smoothing targetFollowSmoothing = new FrameSmoothing();
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Smoothing positionSmoothing = new FrameSmoothing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://cqa8ktsmoa041
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
using Rokojori.Extensions;
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
public enum ThirdPersonCameraLockMode
|
||||||
|
{
|
||||||
|
Lock,
|
||||||
|
Release
|
||||||
|
}
|
||||||
|
|
||||||
|
[Tool]
|
||||||
|
[GlobalClass]
|
||||||
|
public partial class SetThirdPersonCameraLockTarget : Action
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public ThirdPersonCamera camera;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Pointer source;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public ThirdPersonCameraLockMode mode = ThirdPersonCameraLockMode.Lock;
|
||||||
|
|
||||||
|
protected override void _OnTrigger()
|
||||||
|
{
|
||||||
|
if ( camera == null )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( mode == ThirdPersonCameraLockMode.Release )
|
||||||
|
{
|
||||||
|
camera.lockTarget = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
camera.lockTarget = source != null && source.pointable != null ? source.pointable.pointerPosition : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://pesdcfjnpi30
|
||||||
|
|
@ -16,6 +16,9 @@ namespace Rokojori
|
||||||
[Export]
|
[Export]
|
||||||
public Node3D target;
|
public Node3D target;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Node3D lockTarget;
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
public float yaw;
|
public float yaw;
|
||||||
|
|
||||||
|
|
@ -35,6 +38,8 @@ namespace Rokojori
|
||||||
|
|
||||||
public bool canProcess => processInEditor || ! Engine.IsEditorHint();
|
public bool canProcess => processInEditor || ! Engine.IsEditorHint();
|
||||||
|
|
||||||
|
Vector3 _lastLockTargetPosition;
|
||||||
|
|
||||||
public override void _Process( double delta )
|
public override void _Process( double delta )
|
||||||
{
|
{
|
||||||
if ( canProcess && CharacterController.CharacterUpdateMode.Process == updateMode )
|
if ( canProcess && CharacterController.CharacterUpdateMode.Process == updateMode )
|
||||||
|
|
@ -71,6 +76,30 @@ namespace Rokojori
|
||||||
|
|
||||||
var targetPosition = Smoothing.Apply( settings.targetFollowSmoothing, target.GlobalPosition, delta );
|
var targetPosition = Smoothing.Apply( settings.targetFollowSmoothing, target.GlobalPosition, delta );
|
||||||
|
|
||||||
|
var hasLockTarget = lockTarget != null;
|
||||||
|
var lockTargetPosition = _lastLockTargetPosition;
|
||||||
|
|
||||||
|
if ( hasLockTarget )
|
||||||
|
{
|
||||||
|
lockTargetPosition = Smoothing.Apply( settings.lockTargetFollowSmoothing, lockTarget.GlobalPosition, delta );
|
||||||
|
_lastLockTargetPosition = lockTargetPosition;
|
||||||
|
|
||||||
|
if ( settings.lockReleaseDistance > 0f && ( lockTargetPosition - targetPosition ).Length() > settings.lockReleaseDistance )
|
||||||
|
{
|
||||||
|
lockTarget = null;
|
||||||
|
hasLockTarget = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lockBlend fades 0->1 on engage and 1->0 on release instead of snapping, so the focus
|
||||||
|
// point, yaw override, pitch clamp and bounding-distance below all ease in/out together -
|
||||||
|
// lockTargetPosition keeps the last known value through the fade-out tail even after
|
||||||
|
// lockTarget itself has gone null.
|
||||||
|
var lockBlend = Smoothing.Apply( settings.lockBlendSmoothing, hasLockTarget ? 1f : 0f, delta );
|
||||||
|
var isLocked = lockBlend > 0.001f;
|
||||||
|
|
||||||
|
var focusPosition = targetPosition.Lerp( ( targetPosition + lockTargetPosition ) / 2f, lockBlend );
|
||||||
|
|
||||||
var yawAxis = 0f;
|
var yawAxis = 0f;
|
||||||
var pitchAxis = 0f;
|
var pitchAxis = 0f;
|
||||||
|
|
||||||
|
|
@ -81,7 +110,20 @@ namespace Rokojori
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.LogInfo( "YAW:", yawAxis, "PITCH:", pitchAxis );
|
// this.LogInfo( "YAW:", yawAxis, "PITCH:", pitchAxis );
|
||||||
|
if ( isLocked )
|
||||||
|
{
|
||||||
|
var lockDirection = lockTargetPosition - targetPosition;
|
||||||
|
lockDirection.Y = 0;
|
||||||
|
|
||||||
|
if ( lockDirection.LengthSquared() > 0.0001f )
|
||||||
|
{
|
||||||
|
yaw = Math3D.GlobalYawDegrees( lockDirection );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
yaw += yawAxis * settings.yawSpeed * data.yawSpeed * delta;
|
yaw += yawAxis * settings.yawSpeed * data.yawSpeed * delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if ( data.pitchIsRelative )
|
if ( data.pitchIsRelative )
|
||||||
|
|
@ -94,6 +136,11 @@ namespace Rokojori
|
||||||
pitch = Mathf.Remap( pitchAxis, -1, 1, settings.minPitch, settings.maxPitch );
|
pitch = Mathf.Remap( pitchAxis, -1, 1, settings.minPitch, settings.maxPitch );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( isLocked )
|
||||||
|
{
|
||||||
|
pitch = Mathf.Clamp( pitch, settings.lockMinPitch, settings.lockMaxPitch );
|
||||||
|
}
|
||||||
|
|
||||||
var appliedYaw = yaw;
|
var appliedYaw = yaw;
|
||||||
|
|
||||||
var smoothedYaw = Smoothing.ApplyDegrees( settings.yawSmoothing, appliedYaw, delta );
|
var smoothedYaw = Smoothing.ApplyDegrees( settings.yawSmoothing, appliedYaw, delta );
|
||||||
|
|
@ -103,16 +150,35 @@ namespace Rokojori
|
||||||
|
|
||||||
|
|
||||||
var pitchState = MathX.NormalizeClamped( pitch, settings.minPitch, settings.maxPitch );
|
var pitchState = MathX.NormalizeClamped( pitch, settings.minPitch, settings.maxPitch );
|
||||||
var distance = settings.distanceForPitch.Sample( pitchState ) * settings.distanceScale;
|
|
||||||
|
|
||||||
var smoothedDistance = Smoothing.Apply( settings.distanceSmoothing, distance, delta );
|
|
||||||
FOV = settings.fovOffset + ( settings.fovForPitch?.Sample( pitchState ) ?? 0f );
|
FOV = settings.fovOffset + ( settings.fovForPitch?.Sample( pitchState ) ?? 0f );
|
||||||
|
|
||||||
|
var desiredDistance = settings.distanceForPitch.Sample( pitchState ) * settings.distanceScale;
|
||||||
|
|
||||||
|
if ( isLocked )
|
||||||
|
{
|
||||||
|
// The camera always looks exactly at focusPosition (cameraForward is -fowardDirection by
|
||||||
|
// construction below), so fitting a bounding sphere around target+lockTarget in the view
|
||||||
|
// cone is pitch-independent - unlike pulling back along a single axis, it cannot
|
||||||
|
// degenerate when the view direction is near-vertical. radius/sin(halfFov) is the
|
||||||
|
// standard distance that makes a sphere of that radius exactly fill the frame.
|
||||||
|
var boundingRadius = ( lockTargetPosition - targetPosition ).Length() * 0.5f + settings.lockBoundsPadding;
|
||||||
|
var halfFovRadians = Mathf.DegToRad( FOV * 0.5f );
|
||||||
|
|
||||||
|
if ( boundingRadius > 0f && halfFovRadians > 0.001f )
|
||||||
|
{
|
||||||
|
var minDistanceForBounds = boundingRadius / Mathf.Sin( halfFovRadians );
|
||||||
|
desiredDistance = Mathf.Lerp( desiredDistance, Mathf.Max( desiredDistance, minDistanceForBounds ), lockBlend );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var smoothedDistance = Smoothing.Apply( settings.distanceSmoothing, desiredDistance, delta );
|
||||||
|
|
||||||
var fowardDirection = Math3D.YawPitchRotation( smoothedYaw, smoothedPitch ) * Vector3.Forward;
|
var fowardDirection = Math3D.YawPitchRotation( smoothedYaw, smoothedPitch ) * Vector3.Forward;
|
||||||
|
|
||||||
cameraPosition = targetPosition + fowardDirection * smoothedDistance;
|
cameraPosition = focusPosition + fowardDirection * smoothedDistance;
|
||||||
|
|
||||||
cameraForward = ( targetPosition - cameraPosition ).Normalized();
|
cameraForward = ( focusPosition - cameraPosition ).Normalized();
|
||||||
// LookAt( targetPosition, Vector3.Up, true );
|
// LookAt( targetPosition, Vector3.Up, true );
|
||||||
|
|
||||||
var pitchOffset = settings.offset;
|
var pitchOffset = settings.offset;
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,27 @@ namespace Rokojori
|
||||||
public float fovOffset = 60;
|
public float fovOffset = 60;
|
||||||
|
|
||||||
|
|
||||||
|
[ExportGroup("Lock")]
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Smoothing lockTargetFollowSmoothing = new FrameSmoothing();
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Smoothing lockBlendSmoothing = new FrameSmoothing();
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float lockReleaseDistance = 0f;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float lockMinPitch = -10;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float lockMaxPitch = 45;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float lockBoundsPadding = 0f;
|
||||||
|
|
||||||
|
|
||||||
public float GetNormalizedPitch( float pitch )
|
public float GetNormalizedPitch( float pitch )
|
||||||
{
|
{
|
||||||
return MathX.Normalize( pitch, minPitch, maxPitch );
|
return MathX.Normalize( pitch, minPitch, maxPitch );
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,13 @@ namespace Rokojori
|
||||||
[Export]
|
[Export]
|
||||||
public CharacterMovementType[] deviceMovementTypes = [];
|
public CharacterMovementType[] deviceMovementTypes = [];
|
||||||
|
|
||||||
|
[ExportGroup( "Manual Movement Type Switch" )]
|
||||||
|
[Export]
|
||||||
|
public Sensor movementTypeSwitch;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public CharacterMovementType switchedMovementType;
|
||||||
|
|
||||||
[Export]
|
[Export]
|
||||||
public Smoothing onFloorMovementSmoothing = new FrameSmoothing();
|
public Smoothing onFloorMovementSmoothing = new FrameSmoothing();
|
||||||
|
|
||||||
|
|
@ -119,6 +126,11 @@ namespace Rokojori
|
||||||
|
|
||||||
currentMovementType = deviceMovementTypes.FindNonNull( d => d.deviceSelector.Selects( activeDevice ) );
|
currentMovementType = deviceMovementTypes.FindNonNull( d => d.deviceSelector.Selects( activeDevice ) );
|
||||||
|
|
||||||
|
if ( movementTypeSwitch != null && movementTypeSwitch.isActive && switchedMovementType != null )
|
||||||
|
{
|
||||||
|
currentMovementType = switchedMovementType;
|
||||||
|
}
|
||||||
|
|
||||||
if ( currentMovementType == null )
|
if ( currentMovementType == null )
|
||||||
{
|
{
|
||||||
// this.LogInfo( "No device found:", activeDevice == null ? "null" : activeDevice.GetType().Name );
|
// this.LogInfo( "No device found:", activeDevice == null ? "null" : activeDevice.GetType().Name );
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
using Rokojori.Extensions;
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
[Tool]
|
||||||
|
[GlobalClass]
|
||||||
|
public partial class DirectionalCycleInput : Resource
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public Sensor sensor;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Vector2 direction = Vector2.Right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://dc6l8lylcqdtv
|
||||||
|
|
@ -0,0 +1,289 @@
|
||||||
|
using Godot;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Rokojori.Extensions;
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
public enum LockOnCycleMode
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
ClosestCycle,
|
||||||
|
Directional
|
||||||
|
}
|
||||||
|
|
||||||
|
[Tool]
|
||||||
|
[GlobalClass]
|
||||||
|
public partial class LockOnPointer : Pointer
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public Sensor engageSensor;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public bool releaseWhenTargetInvalid = true;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Action onLockEngaged;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Action onLockReleased;
|
||||||
|
|
||||||
|
[ExportGroup( "Cycling" )]
|
||||||
|
[Export]
|
||||||
|
public LockOnCycleMode cycleMode = LockOnCycleMode.None;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Sensor cycleSensor;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public DirectionalCycleInput[] directionalCycleInputs = [];
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Node3D closestVisualizer;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Action onClosestFound;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Action onClosestLost;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Action onClosestChanged;
|
||||||
|
|
||||||
|
[ExportGroup("Read Only")]
|
||||||
|
[Export]
|
||||||
|
public Pointable closestCandidate;
|
||||||
|
|
||||||
|
|
||||||
|
bool _engaged = false;
|
||||||
|
|
||||||
|
public bool isEngaged => _engaged;
|
||||||
|
|
||||||
|
protected override void _OnTrigger()
|
||||||
|
{
|
||||||
|
if ( caster == null )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateClosestCandidate();
|
||||||
|
|
||||||
|
var wasLocked = pointable != null;
|
||||||
|
|
||||||
|
if ( visualizer != null && pointable != null )
|
||||||
|
{
|
||||||
|
visualizer.CopyGlobalPoseFrom( pointable.pointerPosition );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( engageSensor != null )
|
||||||
|
{
|
||||||
|
_engaged = engageSensor.isActive;
|
||||||
|
|
||||||
|
if ( ! _engaged )
|
||||||
|
{
|
||||||
|
if ( pointable != null )
|
||||||
|
{
|
||||||
|
SetPointable( null );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( pointable == null )
|
||||||
|
{
|
||||||
|
SetPointable( closestCandidate );
|
||||||
|
}
|
||||||
|
else if ( releaseWhenTargetInvalid && ! IsStillValidTarget( pointable ) )
|
||||||
|
{
|
||||||
|
SetPointable( null );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HandleCycling();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fires off the pointable transition (not the raw engage-sensor edge) so it also covers the
|
||||||
|
// releaseWhenTargetInvalid auto-release path above, and so pointable already holds its new
|
||||||
|
// value (or null) by the time a listener - e.g. SetThirdPersonCameraLockTarget - reads it.
|
||||||
|
var isNowLocked = pointable != null;
|
||||||
|
|
||||||
|
if ( isNowLocked != wasLocked )
|
||||||
|
{
|
||||||
|
Action.TriggerSafe( isNowLocked ? onLockEngaged : onLockReleased );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateClosestCandidate()
|
||||||
|
{
|
||||||
|
var next = FindClosestCandidate();
|
||||||
|
|
||||||
|
if ( next == closestCandidate )
|
||||||
|
{
|
||||||
|
if ( closestVisualizer != null && closestCandidate != null )
|
||||||
|
{
|
||||||
|
closestVisualizer.CopyGlobalPoseFrom( closestCandidate.pointerPosition );
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
closestCandidate = next;
|
||||||
|
|
||||||
|
onClosestChanged?.Trigger();
|
||||||
|
|
||||||
|
if ( closestCandidate == null )
|
||||||
|
{
|
||||||
|
onClosestLost?.Trigger();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
onClosestFound?.Trigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( closestVisualizer != null && closestCandidate != null )
|
||||||
|
{
|
||||||
|
closestVisualizer.CopyGlobalPoseFrom( closestCandidate.pointerPosition );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleCycling()
|
||||||
|
{
|
||||||
|
if ( cycleMode == LockOnCycleMode.ClosestCycle )
|
||||||
|
{
|
||||||
|
if ( cycleSensor != null && cycleSensor.isDown )
|
||||||
|
{
|
||||||
|
SetPointable( FindNextClosestCandidate() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( cycleMode != LockOnCycleMode.Directional || directionalCycleInputs == null )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < directionalCycleInputs.Length; i++ )
|
||||||
|
{
|
||||||
|
var input = directionalCycleInputs[ i ];
|
||||||
|
|
||||||
|
if ( input == null || input.sensor == null || ! input.sensor.isDown )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var next = FindDirectionalCandidate( input.direction );
|
||||||
|
|
||||||
|
if ( next != null )
|
||||||
|
{
|
||||||
|
SetPointable( next );
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Pointable FindClosestCandidate()
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < caster.NumColliders(); i++ )
|
||||||
|
{
|
||||||
|
var p = Nodes.Find<Pointable>( caster.GetCollider( i ) );
|
||||||
|
|
||||||
|
if ( p != null && p.enabled )
|
||||||
|
{
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pointable FindNextClosestCandidate()
|
||||||
|
{
|
||||||
|
var currentIndex = -1;
|
||||||
|
var candidates = new List<Pointable>();
|
||||||
|
|
||||||
|
for ( int i = 0; i < caster.NumColliders(); i++ )
|
||||||
|
{
|
||||||
|
var p = Nodes.Find<Pointable>( caster.GetCollider( i ) );
|
||||||
|
|
||||||
|
if ( p == null || ! p.enabled )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( p == pointable )
|
||||||
|
{
|
||||||
|
currentIndex = candidates.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
candidates.Add( p );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( candidates.Count == 0 )
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( currentIndex == -1 )
|
||||||
|
{
|
||||||
|
return candidates[ 0 ];
|
||||||
|
}
|
||||||
|
|
||||||
|
return candidates[ ( currentIndex + 1 ) % candidates.Count ];
|
||||||
|
}
|
||||||
|
|
||||||
|
Pointable FindDirectionalCandidate( Vector2 direction )
|
||||||
|
{
|
||||||
|
if ( pointable == null )
|
||||||
|
{
|
||||||
|
return FindClosestCandidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
var right = caster.GlobalTransform.Basis.X;
|
||||||
|
var up = caster.GlobalTransform.Basis.Y;
|
||||||
|
var currentPosition = pointable.GlobalPosition;
|
||||||
|
|
||||||
|
Pointable best = null;
|
||||||
|
var bestScore = float.NegativeInfinity;
|
||||||
|
|
||||||
|
for ( int i = 0; i < caster.NumColliders(); i++ )
|
||||||
|
{
|
||||||
|
var candidate = Nodes.Find<Pointable>( caster.GetCollider( i ) );
|
||||||
|
|
||||||
|
if ( candidate == null || candidate == pointable || ! candidate.enabled )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var offset = candidate.GlobalPosition - currentPosition;
|
||||||
|
var projected = new Vector2( offset.Dot( right ), offset.Dot( up ) );
|
||||||
|
|
||||||
|
if ( projected.LengthSquared() < 0.0001f )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var score = projected.Normalized().Dot( direction );
|
||||||
|
|
||||||
|
if ( score > bestScore )
|
||||||
|
{
|
||||||
|
bestScore = score;
|
||||||
|
best = candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsStillValidTarget( Pointable p )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < caster.NumColliders(); i++ )
|
||||||
|
{
|
||||||
|
if ( Nodes.Find<Pointable>( caster.GetCollider( i ) ) == p )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://c0oeivnw2q0a5
|
||||||
|
|
@ -33,6 +33,11 @@ namespace Rokojori
|
||||||
[Export]
|
[Export]
|
||||||
public Action onPointerRemoved;
|
public Action onPointerRemoved;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Node3D pointerPositionOverride;
|
||||||
|
|
||||||
|
public Node3D pointerPosition => pointerPositionOverride ?? this;
|
||||||
|
|
||||||
[ExportGroup("Highlighting")]
|
[ExportGroup("Highlighting")]
|
||||||
[Export]
|
[Export]
|
||||||
public HighlightEffect highlightEffect;
|
public HighlightEffect highlightEffect;
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,25 @@ namespace Rokojori
|
||||||
[Export]
|
[Export]
|
||||||
public HighlightEffect defaultHighlighter;
|
public HighlightEffect defaultHighlighter;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Node3D visualizer;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Action onPointed;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Action onUnpointed;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public Action onPointerChanged;
|
||||||
|
|
||||||
[ExportGroup("Read Only")]
|
[ExportGroup("Read Only")]
|
||||||
[Export]
|
[Export]
|
||||||
public Pointable pointable;
|
public Pointable pointable;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public readonly EventSlot<Pointable> onPointerChange = new EventSlot<Pointable>();
|
public readonly EventSlot<Pointable> onPointerChange = new EventSlot<Pointable>();
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -37,24 +51,35 @@ namespace Rokojori
|
||||||
|
|
||||||
var currentCollider = caster.NumColliders() == 0 ? null : caster.GetCollider( 0 );
|
var currentCollider = caster.NumColliders() == 0 ? null : caster.GetCollider( 0 );
|
||||||
|
|
||||||
|
|
||||||
var currentPointable = currentCollider == null ? null : Nodes.Find<Pointable>( currentCollider );
|
var currentPointable = currentCollider == null ? null : Nodes.Find<Pointable>( currentCollider );
|
||||||
|
|
||||||
// RJLog.Log( currentCollider, currentPointable );
|
SetPointable( currentPointable );
|
||||||
|
|
||||||
|
|
||||||
if ( currentPointable == pointable )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected void SetPointable( Pointable next )
|
||||||
|
{
|
||||||
|
if ( next == pointable )
|
||||||
|
{
|
||||||
|
if ( visualizer != null && pointable != null )
|
||||||
|
{
|
||||||
|
var pointable3D = pointable.pointerPosition;
|
||||||
|
visualizer.CopyGlobalPoseFrom( pointable3D );
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ( pointable != null )
|
if ( pointable != null )
|
||||||
{
|
{
|
||||||
pointable.UpdatePointerState( this, false );
|
pointable.UpdatePointerState( this, false );
|
||||||
Highlight( HighlightActionType.End, pointable );
|
Highlight( HighlightActionType.End, pointable );
|
||||||
}
|
}
|
||||||
|
|
||||||
pointable = currentPointable;
|
pointable = next;
|
||||||
|
|
||||||
if ( pointable != null )
|
if ( pointable != null )
|
||||||
{
|
{
|
||||||
|
|
@ -62,7 +87,25 @@ namespace Rokojori
|
||||||
Highlight( HighlightActionType.Start, pointable );
|
Highlight( HighlightActionType.Start, pointable );
|
||||||
}
|
}
|
||||||
|
|
||||||
onPointerChange.DispatchEvent( currentPointable );
|
|
||||||
|
|
||||||
|
onPointerChange.DispatchEvent( pointable );
|
||||||
|
onPointerChanged?.Trigger();
|
||||||
|
|
||||||
|
if ( pointable == null )
|
||||||
|
{
|
||||||
|
onUnpointed?.Trigger();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
onPointed?.Trigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( visualizer != null && pointable != null )
|
||||||
|
{
|
||||||
|
var pointable3D = pointable.pointerPosition;
|
||||||
|
visualizer.CopyGlobalPoseFrom( pointable3D );
|
||||||
|
}
|
||||||
|
|
||||||
if ( printPointables )
|
if ( printPointables )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
|
||||||
|
using Godot;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Rokojori.Extensions;
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
public enum ActivationMode
|
||||||
|
{
|
||||||
|
Hold,
|
||||||
|
Toggle
|
||||||
|
}
|
||||||
|
|
||||||
|
[Tool]
|
||||||
|
[GlobalClass]
|
||||||
|
public partial class ActivationModeSensor : Sensor
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public Sensor button;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public ActivationMode mode = ActivationMode.Hold;
|
||||||
|
|
||||||
|
bool _toggledOn = false;
|
||||||
|
|
||||||
|
public override bool IsSensor( InputEvent ie )
|
||||||
|
{
|
||||||
|
return button != null && button.IsSensor( ie );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Release()
|
||||||
|
{
|
||||||
|
_toggledOn = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateValue()
|
||||||
|
{
|
||||||
|
if ( button == null )
|
||||||
|
{
|
||||||
|
SetBoolValue( false );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( mode == ActivationMode.Hold )
|
||||||
|
{
|
||||||
|
SetFloatValue( button.value );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( button.isDown )
|
||||||
|
{
|
||||||
|
_toggledOn = ! _toggledOn;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetBoolValue( _toggledOn );
|
||||||
|
}
|
||||||
|
|
||||||
|
public override List<InputIcon> GetInputIcons()
|
||||||
|
{
|
||||||
|
return button == null ? new List<InputIcon>() : button.GetInputIcons();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://b4eorkinrt8kv
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
using Godot;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Rokojori.Extensions;
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
|
||||||
|
[Tool]
|
||||||
|
[GlobalClass]
|
||||||
|
public partial class ReleaseActivationModeSensor : Action
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public ActivationModeSensor activationModeSensor;
|
||||||
|
|
||||||
|
protected override void _OnTrigger()
|
||||||
|
{
|
||||||
|
activationModeSensor?.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bmhvyxsurpcql
|
||||||
|
|
@ -214,7 +214,7 @@ public partial class TimelineManager:NetworkNode
|
||||||
{
|
{
|
||||||
var inManager = timelines.Contains( timeline );
|
var inManager = timelines.Contains( timeline );
|
||||||
|
|
||||||
RJLog.Log( "No runner found for:", timeline, "Is in manager:", inManager );
|
// RJLog.Log( "No runner found for:", timeline, "Is in manager:", inManager );
|
||||||
}
|
}
|
||||||
|
|
||||||
return runner;
|
return runner;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ colors = PackedColorArray(0.96, 0.9211765, 0.24000007, 1, 1, 0.19607843, 0, 1, 0
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_w2g18"]
|
[sub_resource type="Resource" id="Resource_w2g18"]
|
||||||
script = ExtResource("1_b51fw")
|
script = ExtResource("1_b51fw")
|
||||||
baseColor = Color(1, 0.19607843, 0, 1)
|
baseColor = Color(1, 0.5342896, 0, 1)
|
||||||
centerAttraction = 0.0
|
centerAttraction = 0.0
|
||||||
temperaturePolarBlendRadius = 30.0
|
temperaturePolarBlendRadius = 30.0
|
||||||
startTemperatureShift = 45.0
|
startTemperatureShift = 45.0
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,11 @@ void fragment()
|
||||||
{
|
{
|
||||||
|
|
||||||
float d = distance( UV, vec2(0.5) );
|
float d = distance( UV, vec2(0.5) );
|
||||||
float a = 1.0 - clamp( d / 0.5, 0.0, 1.0);
|
float a = 1.0 - clamp( d / ( 0.5 * COLOR.a ), 0.0, 1.0);
|
||||||
|
|
||||||
|
|
||||||
ALBEDO = COLOR.rgb;
|
ALBEDO = COLOR.rgb;
|
||||||
|
|
||||||
ALPHA *= a * COLOR.a;
|
ALPHA *= a;
|
||||||
ALPHA_SCISSOR_THRESHOLD = 0.01;
|
ALPHA_SCISSOR_THRESHOLD = 0.01;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,9 @@ public partial class EmberVFXData:ParticleVFXData
|
||||||
|
|
||||||
UpdateCoreSettings( preset, particles );
|
UpdateCoreSettings( preset, particles );
|
||||||
|
|
||||||
processMaterial.Color = preset.color * preset.colorIntensity;
|
var color = preset.color.ScaleColor( preset.colorIntensity );
|
||||||
|
|
||||||
|
processMaterial.Color = color;
|
||||||
|
|
||||||
|
|
||||||
var rampTexture = processMaterial.ColorRamp as GradientTexture1D;
|
var rampTexture = processMaterial.ColorRamp as GradientTexture1D;
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,11 @@ public partial class ParticleVFX:Node3D
|
||||||
_data = data;
|
_data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Play()
|
||||||
|
{
|
||||||
|
preset.Play( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
|
||||||
|
using Godot;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using Rokojori.Extensions;
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
[Tool][GlobalClass, Icon("res://addons/rokojori_action_library/Icons/PlayParticles.svg")]
|
||||||
|
public partial class ParticleVFXControl:Action
|
||||||
|
{
|
||||||
|
public enum ControlType
|
||||||
|
{
|
||||||
|
Play
|
||||||
|
}
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public ParticleVFX particleVFX;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public ControlType controlType = ControlType.Play;
|
||||||
|
|
||||||
|
protected override void _OnTrigger()
|
||||||
|
{
|
||||||
|
if ( ControlType.Play == controlType )
|
||||||
|
{
|
||||||
|
particleVFX?.Play();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://cw6q1qxm35l7l
|
||||||
Loading…
Reference in New Issue