TimeLines, VirtualCameras
This commit is contained in:
parent
a383c5da49
commit
0e4f09e19c
|
@ -0,0 +1,98 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
width="16"
|
||||||
|
version="1.1"
|
||||||
|
id="svg4"
|
||||||
|
sodipodi:docname="VirtualCamera3DSlot.svg"
|
||||||
|
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
|
||||||
|
xml:space="preserve"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs8"><linearGradient
|
||||||
|
inkscape:collect="never"
|
||||||
|
id="linearGradient3074"><stop
|
||||||
|
style="stop-color:#e26708;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop3070" /><stop
|
||||||
|
style="stop-color:#bb3c00;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3072" /></linearGradient><radialGradient
|
||||||
|
xlink:href="#linearGradient45008"
|
||||||
|
id="radialGradient3076"
|
||||||
|
cx="30.688875"
|
||||||
|
cy="30.069115"
|
||||||
|
fx="30.688875"
|
||||||
|
fy="30.069115"
|
||||||
|
r="14.05412"
|
||||||
|
gradientUnits="userSpaceOnUse" /><linearGradient
|
||||||
|
xlink:href="#linearGradient45008"
|
||||||
|
id="linearGradient45010"
|
||||||
|
x1="-31.87768"
|
||||||
|
y1="22.065159"
|
||||||
|
x2="-31.87768"
|
||||||
|
y2="48.78738"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(101.16951,-6.5921995)" /><linearGradient
|
||||||
|
id="linearGradient45008"><stop
|
||||||
|
style="stop-color:#e14500;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop45004" /><stop
|
||||||
|
style="stop-color:#e17900;stop-opacity:1;"
|
||||||
|
offset="0.59811592"
|
||||||
|
id="stop45012" /><stop
|
||||||
|
style="stop-color:#e19c00;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop45006" /></linearGradient><linearGradient
|
||||||
|
xlink:href="#linearGradient45008"
|
||||||
|
id="linearGradient46715"
|
||||||
|
x1="31.917692"
|
||||||
|
y1="47.524929"
|
||||||
|
x2="31.917692"
|
||||||
|
y2="22.632998"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="translate(1.7923447e-6)" /></defs><sodipodi:namedview
|
||||||
|
id="namedview6"
|
||||||
|
pagecolor="#505050"
|
||||||
|
bordercolor="#eeeeee"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#505050"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="22.627418"
|
||||||
|
inkscape:cx="17.390407"
|
||||||
|
inkscape:cy="0"
|
||||||
|
inkscape:window-width="3840"
|
||||||
|
inkscape:window-height="2066"
|
||||||
|
inkscape:window-x="-11"
|
||||||
|
inkscape:window-y="-11"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="g2210" /><g
|
||||||
|
id="g2210"
|
||||||
|
transform="matrix(0.54328517,0,0,0.54328517,-9.4489315,-11.300948)"><path
|
||||||
|
d="m 38.807674,25.692051 a 4.270706,4.270706 0 0 0 -4.270706,3.953249 4.270706,4.270706 0 1 0 -4.270706,7.184752 v 3.097685 a 1.4235688,1.4235688 0 0 0 1.42357,1.423568 h 8.541413 a 1.4235688,1.4235688 0 0 0 1.423568,-1.423568 v -1.42357 l 4.270708,2.847138 v -8.541412 l -4.270708,2.847137 v -2.519719 a 4.270706,4.270706 0 0 0 -2.847139,-7.44526 z"
|
||||||
|
fill="#fc7f7f"
|
||||||
|
id="path66330"
|
||||||
|
style="fill:#f7b200;fill-opacity:1;stroke:none;stroke-width:1.42356;stroke-opacity:1" /><path
|
||||||
|
sodipodi:type="star"
|
||||||
|
style="fill:#f7b200;fill-opacity:1;stroke:none;stroke-width:0.975547;stroke-linecap:round;stroke-dasharray:1.95109, 1.95109"
|
||||||
|
id="path80365"
|
||||||
|
inkscape:flatsided="true"
|
||||||
|
sodipodi:sides="3"
|
||||||
|
sodipodi:cx="-6.2499995"
|
||||||
|
sodipodi:cy="6.7656245"
|
||||||
|
sodipodi:r1="2.1930733"
|
||||||
|
sodipodi:r2="1.0965366"
|
||||||
|
sodipodi:arg1="0"
|
||||||
|
sodipodi:arg2="1.0471976"
|
||||||
|
inkscape:rounded="0"
|
||||||
|
inkscape:randomized="0"
|
||||||
|
d="m -4.0569263,6.7656245 -3.2896099,1.8992572 0,-3.7985143 z"
|
||||||
|
transform="matrix(2.4507872,0,0,2.4507872,35.79769,18.74394)"
|
||||||
|
inkscape:transform-center-x="-0.73000592" /></g></svg>
|
After Width: | Height: | Size: 3.8 KiB |
|
@ -0,0 +1,37 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://bw4lwbtmuf06s"
|
||||||
|
path="res://.godot/imported/VirtualCamera3DSlot.svg-c72b6fb2631e86a90ef74119fcd12075.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://Scripts/Rokojori/Rokojori-Action-Library/Icons/VirtualCamera3DSlot.svg"
|
||||||
|
dest_files=["res://.godot/imported/VirtualCamera3DSlot.svg-c72b6fb2631e86a90ef74119fcd12075.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
[GlobalClass ]
|
||||||
|
public partial class ActionReference : RJAction
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public RJAction referencedAction;
|
||||||
|
|
||||||
|
public override void _OnTrigger()
|
||||||
|
{
|
||||||
|
Actions.Trigger( referencedAction );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -13,45 +13,27 @@ namespace Rokojori
|
||||||
[Export]
|
[Export]
|
||||||
public string message;
|
public string message;
|
||||||
|
|
||||||
float elapsed = 0;
|
[Export]
|
||||||
bool running = false;
|
public RJTimeLine timeLine;
|
||||||
bool finished = false;
|
|
||||||
|
|
||||||
int runID = 0;
|
|
||||||
|
|
||||||
public override void _Ready()
|
|
||||||
{
|
|
||||||
/// OnSequenceDone += ( id, success ) => { RJLog.Log( "OnSequenceDone", Name ); } ;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void _OnTrigger()
|
public override void _OnTrigger()
|
||||||
{
|
{
|
||||||
//RJLog.Log( "Starting", Name );
|
var sequenceID = DispatchStart();
|
||||||
runID = DispatchStart();
|
|
||||||
|
|
||||||
elapsed = 0;
|
|
||||||
running = true;
|
|
||||||
finished = false;
|
|
||||||
|
|
||||||
|
var eventID = TimeLineScheduler.ScheduleEventIn( timeLine, duration,
|
||||||
|
( eventID ) =>
|
||||||
|
{
|
||||||
|
RJLog.Log( ">> delay ended", Time.GetTicksMsec(), sequenceID, eventID );
|
||||||
|
DispatchEnd( sequenceID );
|
||||||
|
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
RJLog.Log( ">> delay started", Time.GetTicksMsec(), sequenceID, eventID );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Process( double delta )
|
|
||||||
{
|
|
||||||
if ( ! running )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
elapsed += (float) delta;
|
|
||||||
|
|
||||||
if ( elapsed > duration )
|
|
||||||
{
|
|
||||||
running = false;
|
|
||||||
finished = true;
|
|
||||||
|
|
||||||
RJLog.Log( Name, " >> '" + message + "'" );
|
|
||||||
DispatchEnd( runID );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Rokojori
|
namespace Rokojori
|
||||||
{
|
{
|
||||||
|
@ -44,6 +45,37 @@ namespace Rokojori
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<T> GetDirectChildren<T>( Node parent ) where T:Node
|
||||||
|
{
|
||||||
|
if ( parent == null )
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var list = new List<T>();
|
||||||
|
|
||||||
|
var numChildren = parent.GetChildCount();
|
||||||
|
|
||||||
|
for ( int i = 0; i < numChildren; i++ )
|
||||||
|
{
|
||||||
|
var node = parent.GetChild( i );
|
||||||
|
var script = node.GetScript();
|
||||||
|
|
||||||
|
RJLog.Log( "Node is", typeof(T), node.Name, node.GetType(), script.GetType(), ">>", ( node is T ) );
|
||||||
|
|
||||||
|
|
||||||
|
if ( ! ( node is T ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list.Add( node as T );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
public static void ForEachDirectChild<T>( Node parent, System.Action<T> action ) where T:Node
|
public static void ForEachDirectChild<T>( Node parent, System.Action<T> action ) where T:Node
|
||||||
{
|
{
|
||||||
if ( parent == null || action == null )
|
if ( parent == null || action == null )
|
||||||
|
|
|
@ -18,20 +18,26 @@ namespace Rokojori
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( obj is float || obj is double )
|
||||||
|
{
|
||||||
|
output.Append( RegexUtility.WriteDouble( (double)obj ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
output.Append( obj.ToString() );
|
output.Append( obj.ToString() );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LogMessage( string message )
|
static void LogMessage( string message )
|
||||||
{
|
{
|
||||||
var trace = GetTrace();
|
var trace = GetTrace();
|
||||||
GD.PrintRich("[b]" + message + "[/b]");
|
GD.PrintRich("\n[b]" + message + "[/b]");
|
||||||
GD.PrintRich( trace );
|
GD.PrintRich( trace );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LogErrorMessage( string message )
|
static void LogErrorMessage( string message )
|
||||||
{
|
{
|
||||||
var trace = GetTrace();
|
var trace = GetTrace();
|
||||||
GD.PrintErr( message );
|
GD.PrintErr( "\n"+ message );
|
||||||
GD.PrintRich( trace );
|
GD.PrintRich( trace );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Godot;
|
||||||
|
using System.Text;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
public class Math3D
|
||||||
|
{
|
||||||
|
public static Quaternion GetGlobalRotation( Node3D node )
|
||||||
|
{
|
||||||
|
return node.GlobalBasis.GetRotationQuaternion();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetGlobalRotation( Node3D node, Quaternion quaternion )
|
||||||
|
{
|
||||||
|
var forward = quaternion * Vector3.Forward;
|
||||||
|
var up = quaternion * Vector3.Up;
|
||||||
|
|
||||||
|
node.LookAt( node.GlobalPosition + forward, up );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 GetGlobalForward( Node3D node )
|
||||||
|
{
|
||||||
|
return node.GlobalBasis.Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 GetGlobalUp( Node3D node )
|
||||||
|
{
|
||||||
|
return node.GlobalBasis.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector3 GetGlobalRight( Node3D node )
|
||||||
|
{
|
||||||
|
return node.GlobalBasis.X;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ namespace Rokojori
|
||||||
{
|
{
|
||||||
public class MathX
|
public class MathX
|
||||||
{
|
{
|
||||||
|
public const float fps120Delta = 1/120f;
|
||||||
|
|
||||||
public static float Clamp01( float value )
|
public static float Clamp01( float value )
|
||||||
{
|
{
|
||||||
|
@ -186,17 +187,17 @@ namespace Rokojori
|
||||||
return Mathf.Pow( power, 1f / exponent );
|
return Mathf.Pow( power, 1f / exponent );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float SmoothingCoefficient( float ms, float reachingTarget = 0.1f, float frameDurationMS = 16.66666666f )
|
public static float SmoothingCoefficient( float ms, float reachingTarget = 0.1f, float frameDurationMS = MathX.fps120Delta )
|
||||||
{
|
{
|
||||||
return 1f - Base( ms / frameDurationMS, reachingTarget );
|
return 1f - Base( ms / frameDurationMS, reachingTarget );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float SmoothValue( float oldValue, float newValue, float ms, float reachingTarget = 0.1f, float frameDurationMS = 16.66666666f )
|
public static float SmoothValue( float oldValue, float newValue, float ms, float reachingTarget = 0.1f, float frameDurationMS = MathX.fps120Delta )
|
||||||
{
|
{
|
||||||
return oldValue + SmoothingCoefficient( ms, reachingTarget, frameDurationMS ) * ( newValue - oldValue );
|
return oldValue + SmoothingCoefficient( ms, reachingTarget, frameDurationMS ) * ( newValue - oldValue );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float SmoothDegrees( float oldValue, float newValue, float ms, float reachingTarget = 0.1f, float frameDurationMS = 16.66666666f )
|
public static float SmoothDegrees( float oldValue, float newValue, float ms, float reachingTarget = 0.1f, float frameDurationMS = MathX.fps120Delta )
|
||||||
{
|
{
|
||||||
oldValue = Mathf.Wrap( oldValue, 0, 360 );
|
oldValue = Mathf.Wrap( oldValue, 0, 360 );
|
||||||
newValue = Mathf.Wrap( newValue, 0, 360 );
|
newValue = Mathf.Wrap( newValue, 0, 360 );
|
||||||
|
@ -218,7 +219,7 @@ namespace Rokojori
|
||||||
return oldValue + SmoothingCoefficient( ms, reachingTarget, frameDurationMS ) * ( newValue - oldValue );
|
return oldValue + SmoothingCoefficient( ms, reachingTarget, frameDurationMS ) * ( newValue - oldValue );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Vector3 SmoothVector3( Vector3 oldValue, Vector3 newValue, float ms, float reachingTarget = 0.1f, float frameDurationMS = 16.66666666f )
|
public static Vector3 SmoothVector3( Vector3 oldValue, Vector3 newValue, float ms, float reachingTarget = 0.1f, float frameDurationMS = 8.33333333333f )
|
||||||
{
|
{
|
||||||
return oldValue + SmoothingCoefficient( ms, reachingTarget, frameDurationMS ) * ( newValue - oldValue );
|
return oldValue + SmoothingCoefficient( ms, reachingTarget, frameDurationMS ) * ( newValue - oldValue );
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
[System.Serializable]
|
||||||
|
public class Range
|
||||||
|
{
|
||||||
|
public float min;
|
||||||
|
public float max;
|
||||||
|
|
||||||
|
public Range( float min, float max )
|
||||||
|
{
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnsureCorrectness()
|
||||||
|
{
|
||||||
|
if ( max < min )
|
||||||
|
{
|
||||||
|
var b = max; max = min; min = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains( float value )
|
||||||
|
{
|
||||||
|
return min <= value && value <= max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Overlaps( Range other )
|
||||||
|
{
|
||||||
|
if ( other.max < min ) { return false; }
|
||||||
|
if ( other.min > max ) { return false; }
|
||||||
|
|
||||||
|
if ( other.Contains( min ) || other.Contains( max ) )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( Contains( min ) || Contains( max ) )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float center { get { return 0.5f * ( max + min ); } }
|
||||||
|
public float range { get { return max - min; } }
|
||||||
|
public float length { get { return max - min; } }
|
||||||
|
|
||||||
|
public float DistanceTo( Range other )
|
||||||
|
{
|
||||||
|
var center = this.center;
|
||||||
|
var otherCenter = other.center;
|
||||||
|
|
||||||
|
var range = this.range;
|
||||||
|
var otherRange = other.range;
|
||||||
|
|
||||||
|
var distance = Mathf.Abs( center - otherCenter );
|
||||||
|
|
||||||
|
return Mathf.Max( 0, distance - 0.5f * ( range + otherRange ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Range Copy()
|
||||||
|
{
|
||||||
|
return new Range( min, max );
|
||||||
|
}
|
||||||
|
|
||||||
|
public float SampleAt( float normalized )
|
||||||
|
{
|
||||||
|
return min + ( max - min ) * normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Range Of_01
|
||||||
|
{
|
||||||
|
get { return new Range( 0, 1 ); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Range Of_Zero
|
||||||
|
{
|
||||||
|
get { return new Range( 0, 0 ); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Range Of_One
|
||||||
|
{
|
||||||
|
get { return new Range( 1, 1 ); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static bool Contains( float min, float max, float value )
|
||||||
|
{
|
||||||
|
return min <= value && value <= max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ContainsExclusive( float min, float max, float value )
|
||||||
|
{
|
||||||
|
return min < value && value < max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ContainsExclusiveMax( float min, float max, float value )
|
||||||
|
{
|
||||||
|
return min <= value && value < max;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
[System.Serializable]
|
||||||
|
public class RangeDouble
|
||||||
|
{
|
||||||
|
public double min;
|
||||||
|
public double max;
|
||||||
|
|
||||||
|
public RangeDouble( double min, double max )
|
||||||
|
{
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnsureCorrectness()
|
||||||
|
{
|
||||||
|
if ( max < min )
|
||||||
|
{
|
||||||
|
var b = max; max = min; min = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains( double value )
|
||||||
|
{
|
||||||
|
return min <= value && value <= max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Overlaps( RangeDouble other )
|
||||||
|
{
|
||||||
|
if ( other.max < min ) { return false; }
|
||||||
|
if ( other.min > max ) { return false; }
|
||||||
|
|
||||||
|
if ( other.Contains( min ) || other.Contains( max ) )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( Contains( min ) || Contains( max ) )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double center { get { return 0.5f * ( max + min ); } }
|
||||||
|
public double range { get { return max - min; } }
|
||||||
|
public double length { get { return max - min; } }
|
||||||
|
|
||||||
|
public double DistanceTo( RangeDouble other )
|
||||||
|
{
|
||||||
|
var center = this.center;
|
||||||
|
var otherCenter = other.center;
|
||||||
|
|
||||||
|
var RangeDouble = this.range;
|
||||||
|
var otherRangeDouble = other.range;
|
||||||
|
|
||||||
|
var distance = Mathf.Abs( center - otherCenter );
|
||||||
|
|
||||||
|
return Mathf.Max( 0, distance - 0.5f * ( RangeDouble + otherRangeDouble ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public RangeDouble Copy()
|
||||||
|
{
|
||||||
|
return new RangeDouble( min, max );
|
||||||
|
}
|
||||||
|
|
||||||
|
public double SampleAt( double normalized )
|
||||||
|
{
|
||||||
|
return min + ( max - min ) * normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RangeDouble Of_01
|
||||||
|
{
|
||||||
|
get { return new RangeDouble( 0, 1 ); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RangeDouble Of_Zero
|
||||||
|
{
|
||||||
|
get { return new RangeDouble( 0, 0 ); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RangeDouble Of_One
|
||||||
|
{
|
||||||
|
get { return new RangeDouble( 1, 1 ); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static bool Contains( double min, double max, double value )
|
||||||
|
{
|
||||||
|
return min <= value && value <= max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ContainsExclusive( double min, double max, double value )
|
||||||
|
{
|
||||||
|
return min < value && value < max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ContainsExclusiveMax( double min, double max, double value )
|
||||||
|
{
|
||||||
|
return min <= value && value < max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ContainsExclusiveMin( double min, double max, double value )
|
||||||
|
{
|
||||||
|
return min < value && value <= max;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
public class Smoother
|
||||||
|
{
|
||||||
|
float overflowDelta = 0;
|
||||||
|
|
||||||
|
public float SmoothForDuration( float value, float nextValue, float duration, float delta, float processDelta = MathX.fps120Delta )
|
||||||
|
{
|
||||||
|
var coefficient = MathX.SmoothingCoefficient( duration * 1000f );
|
||||||
|
return SmoothWithCoefficient( value, nextValue, coefficient, delta );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public float SmoothWithCoefficient( float value, float nextValue, float coefficient, float delta, float processDelta = MathX.fps120Delta )
|
||||||
|
{
|
||||||
|
overflowDelta += delta;
|
||||||
|
|
||||||
|
while ( overflowDelta > processDelta )
|
||||||
|
{
|
||||||
|
value += coefficient * ( nextValue - value );
|
||||||
|
overflowDelta -= processDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Quaternion SmoothForDuration( Quaternion value, Quaternion nextValue, float duration, float delta, float processDelta = MathX.fps120Delta )
|
||||||
|
{
|
||||||
|
var coefficient = MathX.SmoothingCoefficient( duration * 1000f );
|
||||||
|
return SmoothWithCoefficient( value, nextValue, coefficient, delta );
|
||||||
|
}
|
||||||
|
|
||||||
|
public Quaternion SmoothWithCoefficient( Quaternion value, Quaternion nextValue, float coefficient, float delta, float processDelta = MathX.fps120Delta )
|
||||||
|
{
|
||||||
|
overflowDelta += delta;
|
||||||
|
|
||||||
|
while ( overflowDelta > processDelta )
|
||||||
|
{
|
||||||
|
value = value.Slerp( nextValue, coefficient );
|
||||||
|
overflowDelta -= processDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,7 +29,7 @@ namespace Rokojori
|
||||||
var ms = Time.GetUnixTimeFromSystem() % 1;
|
var ms = Time.GetUnixTimeFromSystem() % 1;
|
||||||
var seed = (int) ( ms * 10000 );
|
var seed = (int) ( ms * 10000 );
|
||||||
var lcg = new LCG();
|
var lcg = new LCG();
|
||||||
RJLog.Log( "Seed", seed, Time.GetUnixTimeFromSystem() );
|
// RJLog.Log( "Seed", seed, Time.GetUnixTimeFromSystem() );
|
||||||
lcg.SetSeed( seed );
|
lcg.SetSeed( seed );
|
||||||
lcg.Next();
|
lcg.Next();
|
||||||
return lcg;
|
return lcg;
|
||||||
|
|
|
@ -10,6 +10,18 @@ namespace Rokojori
|
||||||
[Export]
|
[Export]
|
||||||
public string inputActionName = "";
|
public string inputActionName = "";
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public bool pollAsButton = false;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public bool pollAsReleasedOnly = false;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float buttonSmoothingFilterCoefficient = 1;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float axisActivationTreshold = 0.75f;
|
||||||
|
|
||||||
float _value = 0;
|
float _value = 0;
|
||||||
bool _wasActive = false;
|
bool _wasActive = false;
|
||||||
bool _isActive = false;
|
bool _isActive = false;
|
||||||
|
@ -34,13 +46,30 @@ namespace Rokojori
|
||||||
_value = value;
|
_value = value;
|
||||||
|
|
||||||
_wasActive = _isActive;
|
_wasActive = _isActive;
|
||||||
_isActive = _value > 0;
|
_isActive = _value > axisActivationTreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _Process( double delta )
|
public override void _Process( double delta )
|
||||||
{
|
{
|
||||||
var inputValue = Input.GetActionRawStrength( inputActionName );
|
if ( pollAsButton )
|
||||||
UpdateValue( inputValue );
|
{
|
||||||
|
if ( pollAsReleasedOnly )
|
||||||
|
{
|
||||||
|
bool state = Input.IsActionJustReleased( inputActionName );
|
||||||
|
UpdateValue( state ? 1 : 0 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool state = Input.IsActionPressed( inputActionName );
|
||||||
|
UpdateValue( state ? 1 : 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float value = Input.GetActionRawStrength( inputActionName );
|
||||||
|
UpdateValue( value );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
public class TimeLineEvent
|
||||||
|
{
|
||||||
|
public long id;
|
||||||
|
public bool persistent;
|
||||||
|
public double position;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
[GlobalClass]
|
||||||
|
public partial class TimeLineManager:RJTimeLineManager
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public RJTimeLine[] timeLines;
|
||||||
|
|
||||||
|
List<TimeLineRunner> _runners = new List<TimeLineRunner>();
|
||||||
|
|
||||||
|
int _idCounter = 0;
|
||||||
|
bool _initialized = false;
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Initialize()
|
||||||
|
{
|
||||||
|
if ( _initialized )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_initialized = true;
|
||||||
|
_runners = Lists.Map( timeLines, tl => new TimeLineRunner( tl ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeLineRunner GetRunner( int index )
|
||||||
|
{
|
||||||
|
if ( index < 0 || index >= _runners.Count )
|
||||||
|
{
|
||||||
|
return null ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _runners[ index ];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int CreateID()
|
||||||
|
{
|
||||||
|
_idCounter ++;
|
||||||
|
return _idCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _Process( double delta )
|
||||||
|
{
|
||||||
|
_runners.ForEach( r => r.UpdateTimeLine( delta, this ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ScheduleEvent( int timeLineIndex, double position, int callbackID, bool isPersistent )
|
||||||
|
{
|
||||||
|
var runner = _runners[ timeLineIndex ];
|
||||||
|
runner.ScheduleEvent( position, callbackID, isPersistent );
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ScheduleSpan( int timeLineIndex, double start, double end, int callbackID, bool isPersistent )
|
||||||
|
{
|
||||||
|
var runner = _runners[ timeLineIndex ];
|
||||||
|
runner.ScheduleSpan( start, end, callbackID, isPersistent );
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double GetLastPosition( int timeLineIndex )
|
||||||
|
{
|
||||||
|
var runner = GetRunner( timeLineIndex ); if ( runner == null ){ return 0; }
|
||||||
|
|
||||||
|
return runner.lastPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double GetPosition( int timeLineIndex )
|
||||||
|
{
|
||||||
|
var runner = GetRunner( timeLineIndex ); if ( runner == null ){ return 0; }
|
||||||
|
return runner.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetPosition( int timeLineIndex, double position )
|
||||||
|
{
|
||||||
|
var runner = GetRunner( timeLineIndex ); if ( runner == null ){ return; }
|
||||||
|
runner.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override double GetSpeed( int timeLineIndex )
|
||||||
|
{
|
||||||
|
var runner = GetRunner( timeLineIndex ); if ( runner == null ){ return 0; }
|
||||||
|
return runner.speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetSpeed( int timeLineIndex, double speed )
|
||||||
|
{
|
||||||
|
var runner = GetRunner( timeLineIndex ); if ( runner == null ){ return; }
|
||||||
|
runner.speed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override bool GetPlayState( int timeLineIndex )
|
||||||
|
{
|
||||||
|
var runner = GetRunner( timeLineIndex ); if ( runner == null ){ return false; }
|
||||||
|
return runner.playing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetPlayState( int timeLineIndex, bool isPlaying )
|
||||||
|
{
|
||||||
|
var runner = GetRunner( timeLineIndex ); if ( runner == null ){ return; }
|
||||||
|
runner.playing = isPlaying;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,162 @@
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
public class TimeLineRunner
|
||||||
|
{
|
||||||
|
public RJTimeLine timeLine;
|
||||||
|
|
||||||
|
public double lastPosition = 0;
|
||||||
|
public double position = 0;
|
||||||
|
public bool playing = false;
|
||||||
|
public double deltaScale = 1;
|
||||||
|
public double speed = 1;
|
||||||
|
|
||||||
|
List<TimeLineEvent> events = new List<TimeLineEvent>();
|
||||||
|
List<TimeLineSpan> spans = new List<TimeLineSpan>();
|
||||||
|
|
||||||
|
public TimeLineRunner( RJTimeLine timeLine )
|
||||||
|
{
|
||||||
|
this.timeLine = timeLine;
|
||||||
|
|
||||||
|
playing = timeLine.AutoStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateTimeLine( double delta, TimeLineManager manager )
|
||||||
|
{
|
||||||
|
if ( ! playing )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastPosition = position;
|
||||||
|
position += delta * deltaScale * speed;
|
||||||
|
|
||||||
|
var isForward = speed >= 0;
|
||||||
|
|
||||||
|
if ( isForward )
|
||||||
|
{
|
||||||
|
ProcessForward( manager );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessForward( TimeLineManager manager )
|
||||||
|
{
|
||||||
|
List<int> eventRemovals = null;
|
||||||
|
List<int> spanRemovals = null;
|
||||||
|
|
||||||
|
|
||||||
|
for ( int i = 0; i < events.Count; i++ )
|
||||||
|
{
|
||||||
|
var eventPosition = events[ i ].position;
|
||||||
|
|
||||||
|
if ( ! RangeDouble.ContainsExclusiveMax( lastPosition, position, eventPosition ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
RJLog.Log( "Emitting:",
|
||||||
|
"last:", lastPosition,
|
||||||
|
"now:", position,
|
||||||
|
"event:", eventPosition
|
||||||
|
);
|
||||||
|
|
||||||
|
manager.EmitSignal( TimeLineManager.SignalName.OnEvent, events[ i ].id );
|
||||||
|
|
||||||
|
if ( events[ i ].persistent )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( eventRemovals == null ){ eventRemovals = new List<int>(); }
|
||||||
|
|
||||||
|
eventRemovals.Add( i );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( eventRemovals != null )
|
||||||
|
{
|
||||||
|
Lists.RemoveIncreasingIndices( events, eventRemovals );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( spans.Count == 0 )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var timelineSpan = new RangeDouble( lastPosition, position );
|
||||||
|
var span = new RangeDouble( 0, 1 );
|
||||||
|
|
||||||
|
for ( int i = 0; i < spans.Count; i++ )
|
||||||
|
{
|
||||||
|
span.min = spans[ i ].start;
|
||||||
|
span.max = spans[ i ].end;
|
||||||
|
|
||||||
|
if ( ! timelineSpan.Overlaps( span ) )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var isStart = timelineSpan.Contains( spans[ i ].start );
|
||||||
|
var isEnd = timelineSpan.Contains( spans[ i ].end );
|
||||||
|
|
||||||
|
|
||||||
|
var spanType = TimeLineSpan.InSpan;
|
||||||
|
|
||||||
|
if ( isStart && isEnd )
|
||||||
|
{
|
||||||
|
spanType = TimeLineSpan.CompletelyInside;
|
||||||
|
}
|
||||||
|
else if ( isStart )
|
||||||
|
{
|
||||||
|
spanType = TimeLineSpan.Start;
|
||||||
|
}
|
||||||
|
else if ( isEnd )
|
||||||
|
{
|
||||||
|
spanType = TimeLineSpan.End;
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.EmitSignal( TimeLineManager.SignalName.OnSpan, spans[ i ].id, spanType );
|
||||||
|
|
||||||
|
if ( spans[ i ].persistent )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( spanRemovals == null ){ spanRemovals = new List<int>(); }
|
||||||
|
|
||||||
|
spanRemovals.Add( i );
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ScheduleEvent( double position, int callbackID, bool isPersistent )
|
||||||
|
{
|
||||||
|
var tle = new TimeLineEvent();
|
||||||
|
tle.position = position;
|
||||||
|
tle.id = callbackID;
|
||||||
|
tle.persistent = isPersistent;
|
||||||
|
|
||||||
|
events.Add( tle );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ScheduleSpan( double start, double end, int callbackID, bool isPersistent )
|
||||||
|
{
|
||||||
|
var tse = new TimeLineSpan();
|
||||||
|
tse.start = start;
|
||||||
|
tse.end = end;
|
||||||
|
tse.id = callbackID;
|
||||||
|
tse.persistent = isPersistent;
|
||||||
|
tse.wasInside = false;
|
||||||
|
|
||||||
|
spans.Add( tse );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
[GlobalClass]
|
||||||
|
public partial class TimeLineScheduler:Node
|
||||||
|
{
|
||||||
|
public static int ScheduleEventIn( RJTimeLine timeLine, double offset, Action<int> action, bool persistent = false )
|
||||||
|
{
|
||||||
|
var scheduler = Unique<TimeLineScheduler>.Get();
|
||||||
|
return scheduler._ScheduleEventIn( timeLine, offset, action, persistent );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ScheduleEventAt( RJTimeLine timeLine, double position, Action<int> action, bool persistent = false )
|
||||||
|
{
|
||||||
|
var scheduler = Unique<TimeLineScheduler>.Get();
|
||||||
|
return scheduler._ScheduleEventAt( timeLine, position, action, persistent );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _ScheduleEventAt( RJTimeLine timeLine, double position, Action<int> action, bool persistent = false )
|
||||||
|
{
|
||||||
|
AttachListeners();
|
||||||
|
var tm = Unique<TimeLineManager>.Get();
|
||||||
|
var tIndex = tm.GetTimeLineIndex( timeLine );
|
||||||
|
var id = tm.CreateID();
|
||||||
|
_eventActions[ id ] = action;
|
||||||
|
tm.ScheduleEvent( tIndex, position, id, persistent );
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _ScheduleEventIn( RJTimeLine timeLine, double offset, Action<int> action, bool persistent = false )
|
||||||
|
{
|
||||||
|
var tm = Unique<TimeLineManager>.Get();
|
||||||
|
var tIndex = tm.GetTimeLineIndex( timeLine );
|
||||||
|
var position = tm.GetPosition( tIndex ) + offset;
|
||||||
|
return _ScheduleEventAt( timeLine, position, action, persistent );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static int ScheduleSpanAt( RJTimeLine timeLine, double start, double end, Action<int,int> action, bool persistent = false )
|
||||||
|
{
|
||||||
|
var scheduler = Unique<TimeLineScheduler>.Get();
|
||||||
|
return scheduler._ScheduleSpan( timeLine, start, end, action, persistent );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ScheduleSpanIn( RJTimeLine timeLine, double offset, double duration, Action<int,int> action, bool persistent = false )
|
||||||
|
{
|
||||||
|
var scheduler = Unique<TimeLineScheduler>.Get();
|
||||||
|
var tm = Unique<TimeLineManager>.Get();
|
||||||
|
var tIndex = tm.GetTimeLineIndex( timeLine );
|
||||||
|
var position = tm.GetPosition( tIndex );
|
||||||
|
var start = position + offset;
|
||||||
|
var end = start + duration;
|
||||||
|
return scheduler._ScheduleSpan( timeLine, start, end, action, persistent );
|
||||||
|
}
|
||||||
|
|
||||||
|
int _ScheduleSpan( RJTimeLine timeLine, double start, double end, Action<int,int> action, bool persistent = false )
|
||||||
|
{
|
||||||
|
AttachListeners();
|
||||||
|
var tm = Unique<TimeLineManager>.Get();
|
||||||
|
var tIndex = tm.GetTimeLineIndex( timeLine );
|
||||||
|
var id = tm.CreateID();
|
||||||
|
_spanActions[ id ] = action;
|
||||||
|
tm.ScheduleSpan( tIndex, start, end, id, persistent );
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _listenersAttached = false;
|
||||||
|
|
||||||
|
|
||||||
|
HashSet<int> _persistentEventsAndSpans = new HashSet<int>();
|
||||||
|
Dictionary<int,Action<int>> _eventActions = new Dictionary<int, Action<int>>();
|
||||||
|
Dictionary<int,Action<int,int>> _spanActions = new Dictionary<int, Action<int,int>>();
|
||||||
|
|
||||||
|
void AttachListeners()
|
||||||
|
{
|
||||||
|
if ( _listenersAttached )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_listenersAttached = true;
|
||||||
|
|
||||||
|
var tm = Unique<TimeLineManager>.Get();
|
||||||
|
|
||||||
|
tm.OnEvent += ( id ) => OnEvent( id );
|
||||||
|
tm.OnSpan += ( id, type ) => onSpan( id, type );
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnEvent( long s_id )
|
||||||
|
{
|
||||||
|
var id = (int) s_id;
|
||||||
|
|
||||||
|
if ( ! _eventActions.ContainsKey( id ) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_eventActions[ id ]( id );
|
||||||
|
|
||||||
|
if ( _persistentEventsAndSpans.Contains( id ) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_eventActions.Remove( id );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void onSpan( long s_id, long s_type )
|
||||||
|
{
|
||||||
|
var id = (int) s_id;
|
||||||
|
var type = (int) s_type;
|
||||||
|
|
||||||
|
if ( ! _spanActions.ContainsKey( id ) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_spanActions[ id ]( id, type );
|
||||||
|
|
||||||
|
if ( _persistentEventsAndSpans.Contains( id ) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_spanActions.Remove( id );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
public class TimeLineSpan
|
||||||
|
{
|
||||||
|
public static int Start = 0;
|
||||||
|
public static int InSpan = 1;
|
||||||
|
public static int End = 2;
|
||||||
|
public static int CompletelyInside = 3;
|
||||||
|
|
||||||
|
public long id;
|
||||||
|
public bool persistent;
|
||||||
|
public double start;
|
||||||
|
public double end;
|
||||||
|
public bool wasInside;
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,6 +33,14 @@ namespace Rokojori
|
||||||
return list.Count == 0 ? default(T) : list[ list.Count - 1 ];
|
return list.Count == 0 ? default(T) : list[ list.Count - 1 ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void RemoveIncreasingIndices<T>( List<T> list, List<int> removals )
|
||||||
|
{
|
||||||
|
for ( var i = removals.Count - 1; i >= 0; i-- )
|
||||||
|
{
|
||||||
|
list.RemoveAt( i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static int CountItems<T>( List<T> list, Predicate<T> test )
|
public static int CountItems<T>( List<T> list, Predicate<T> test )
|
||||||
{
|
{
|
||||||
|
@ -117,6 +125,13 @@ namespace Rokojori
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<T> From<[Godot.MustBeVariant] T>( Godot.Collections.Array<T> list )
|
||||||
|
{
|
||||||
|
var copy = new List<T>();
|
||||||
|
copy.AddRange( list );
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
public static void Filter<T>( List<T> inputList, List<T> list, Func<T,int,bool> filter )
|
public static void Filter<T>( List<T> inputList, List<T> list, Func<T,int,bool> filter )
|
||||||
{
|
{
|
||||||
for ( int i = 0; i < inputList.Count; i++ )
|
for ( int i = 0; i < inputList.Count; i++ )
|
||||||
|
@ -232,6 +247,21 @@ namespace Rokojori
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<U> Map<[Godot.MustBeVariant]T,U>( Godot.Collections.Array<T> inputList, Func<T,U> mapper, List<U> list = null )
|
||||||
|
{
|
||||||
|
if ( list == null )
|
||||||
|
{
|
||||||
|
list = new List<U>();
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < inputList.Count; i++ )
|
||||||
|
{
|
||||||
|
list.Add( mapper( inputList[ i ] ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
public static List<U> Map<T,U>( T[] inputList, Func<T,U> mapper, List<U> list = null )
|
public static List<U> Map<T,U>( T[] inputList, Func<T,U> mapper, List<U> list = null )
|
||||||
{
|
{
|
||||||
if ( list == null )
|
if ( list == null )
|
||||||
|
@ -246,5 +276,7 @@ namespace Rokojori
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
[Tool]
|
||||||
|
[GlobalClass]
|
||||||
|
public partial class FollowCamera3D:VirtualCamera3D
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public Node3D target;
|
||||||
|
[Export]
|
||||||
|
public float speed = 5;
|
||||||
|
[Export]
|
||||||
|
public float distance = 5;
|
||||||
|
[Export]
|
||||||
|
public float rotationSmoothingCoefficient = 0.1f;
|
||||||
|
|
||||||
|
Smoother smoother = new Smoother();
|
||||||
|
|
||||||
|
public override void _Process( double delta )
|
||||||
|
{
|
||||||
|
if ( target == null )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var d = (float) delta;
|
||||||
|
|
||||||
|
Move( d );
|
||||||
|
Rotate( d );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Move( float delta )
|
||||||
|
{
|
||||||
|
var direction = target.GlobalPosition - GlobalPosition;
|
||||||
|
|
||||||
|
if ( direction.Length() > distance )
|
||||||
|
{
|
||||||
|
var step = direction.Normalized() * speed * delta;
|
||||||
|
GlobalPosition += step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rotate( float delta )
|
||||||
|
{
|
||||||
|
var currentRotation = Math3D.GetGlobalRotation( this );
|
||||||
|
LookAt( target.GlobalPosition, Vector3.Up, true );
|
||||||
|
var nextRotation = Math3D.GetGlobalRotation( this );
|
||||||
|
|
||||||
|
var smoothedRotation = smoother.SmoothWithCoefficient( currentRotation, nextRotation, rotationSmoothingCoefficient, delta );
|
||||||
|
|
||||||
|
Math3D.SetGlobalRotation( this, smoothedRotation );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,173 @@
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
[Tool]
|
||||||
|
[GlobalClass]
|
||||||
|
public partial class MouseEditorCamera:VirtualCamera3D
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public Vector3 target;
|
||||||
|
[Export]
|
||||||
|
public float yaw = 0;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float pitch = 0;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float distance = 10;
|
||||||
|
float smoothDistance = 10;
|
||||||
|
|
||||||
|
[ExportCategory("Orbit")]
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float yawSpeed = 1;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float pitchSpeed = 1;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float minPitch = -89;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float maxPitch = 89;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public RJSensor orbitButton;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public RJSensor[] orbitModifierButtons;
|
||||||
|
|
||||||
|
[ExportCategory("Pan")]
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float panSpeedX = 1f;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float panSpeedY = 1f;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public RJSensor panButton;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public RJSensor[] panModifierButtons;
|
||||||
|
|
||||||
|
[ExportCategory("Zoom")]
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float zoomStepInPercentage = 10;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float minDistance = 0.001f;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float maxDistance = 200f;
|
||||||
|
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public RJSensor zoomInButton;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public RJSensor[] zoomInModifierButtons;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public RJSensor zoomOutButton;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public RJSensor[] zoomOutModifierButtons;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float zoomSmoothingCoefficient = 0.1f;
|
||||||
|
Smoother smoother = new Smoother();
|
||||||
|
|
||||||
|
public override void _Process( double delta )
|
||||||
|
{
|
||||||
|
Orbit();
|
||||||
|
Pan();
|
||||||
|
Zoom();
|
||||||
|
|
||||||
|
Apply( (float) delta );
|
||||||
|
|
||||||
|
if ( ! hasMotionDelta )
|
||||||
|
{
|
||||||
|
motionDelta.X = 0;
|
||||||
|
motionDelta.Y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasMotionDelta = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasMotionDelta = false;
|
||||||
|
Vector2 motionDelta = Vector2.Zero;
|
||||||
|
|
||||||
|
public override void _Input( InputEvent inputEvent )
|
||||||
|
{
|
||||||
|
if ( inputEvent is InputEventMouseMotion )
|
||||||
|
{
|
||||||
|
var eventMouseMotion = inputEvent as InputEventMouseMotion;
|
||||||
|
motionDelta = eventMouseMotion.ScreenRelative;
|
||||||
|
hasMotionDelta = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Orbit()
|
||||||
|
{
|
||||||
|
if ( ! orbitButton.IsActive() )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
yaw += motionDelta.X * yawSpeed;
|
||||||
|
pitch += motionDelta.Y * pitchSpeed;
|
||||||
|
|
||||||
|
pitch = Mathf.Clamp( pitch, minPitch, maxPitch );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Pan()
|
||||||
|
{
|
||||||
|
if ( ! panButton.IsActive() )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var xAmount = motionDelta.X * smoothDistance * GlobalBasis.X * panSpeedX;
|
||||||
|
var yAmount = motionDelta.Y * smoothDistance * GlobalBasis.Y * panSpeedY;
|
||||||
|
|
||||||
|
target += xAmount + yAmount;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Zoom()
|
||||||
|
{
|
||||||
|
if ( zoomInButton.IsActive() )
|
||||||
|
{
|
||||||
|
distance *= Mathf.Pow( 1 + zoomStepInPercentage / 100f, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( zoomOutButton.IsActive() )
|
||||||
|
{
|
||||||
|
distance *= Mathf.Pow( 1 + zoomStepInPercentage / 100f, -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
distance = Mathf.Clamp( distance, minDistance, maxDistance );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Apply( float delta )
|
||||||
|
{
|
||||||
|
smoothDistance = smoother.SmoothWithCoefficient( smoothDistance, distance, zoomSmoothingCoefficient, delta );
|
||||||
|
GlobalRotation = new Vector3( Mathf.DegToRad( pitch ), Mathf.DegToRad( yaw ), 0 );
|
||||||
|
|
||||||
|
var forward = Math3D.GetGlobalForward( this ) * smoothDistance;
|
||||||
|
GlobalPosition = target - forward;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
[Tool]
|
||||||
|
[GlobalClass]
|
||||||
|
public partial class VirtualCamera3D:RJVirtualCamera3D
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public float fov = 60;
|
||||||
|
|
||||||
|
public override Vector3 GetCameraPosition()
|
||||||
|
{
|
||||||
|
return GlobalPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Quaternion GetCameraRotation()
|
||||||
|
{
|
||||||
|
return GlobalBasis.GetRotationQuaternion();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float GetCameraFOV()
|
||||||
|
{
|
||||||
|
return fov;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
[Tool]
|
||||||
|
[GlobalClass]
|
||||||
|
public partial class VirtualCamera3DManager:RJVirtualCamera3DManager
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public Camera3D camera;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public bool refreshSlots = false;
|
||||||
|
|
||||||
|
public override void _Process( double delta )
|
||||||
|
{
|
||||||
|
LerpCameras( delta );
|
||||||
|
}
|
||||||
|
|
||||||
|
public float smoothStepDelta => 1f / CameraPrioritySmoothingStepFPS;
|
||||||
|
public float safeSmoothing => Mathf.Max( 0, CameraPrioritySmoothingCoefficient );
|
||||||
|
|
||||||
|
List<VirtualCamera3DSlot> _cameraSlots = new List<VirtualCamera3DSlot>();
|
||||||
|
|
||||||
|
public void SetActiveSlot( VirtualCamera3DSlot slot )
|
||||||
|
{
|
||||||
|
_cameraSlots.ForEach( c => c.priority = c == slot ? 1 : 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void LerpCameras( double delta )
|
||||||
|
{
|
||||||
|
if ( refreshSlots || _cameraSlots == null || _cameraSlots.Count == 0 )
|
||||||
|
{
|
||||||
|
refreshSlots = false;
|
||||||
|
_cameraSlots = Nodes.GetDirectChildren<VirtualCamera3DSlot>( this );
|
||||||
|
|
||||||
|
//RJLog.Log( "GRABBED SLOTs" , _cameraSlots.Count );
|
||||||
|
}
|
||||||
|
|
||||||
|
var sumPriority = 0f;
|
||||||
|
|
||||||
|
_cameraSlots.ForEach(
|
||||||
|
c =>
|
||||||
|
{
|
||||||
|
c.Update( delta, this );
|
||||||
|
sumPriority += MathF.Max( 0, c.smoothedPriority );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( sumPriority == 0 )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var position = new Vector3();
|
||||||
|
var up = new Vector3();
|
||||||
|
var forward = new Vector3();
|
||||||
|
|
||||||
|
_cameraSlots.ForEach(
|
||||||
|
c =>
|
||||||
|
{
|
||||||
|
var priority = MathF.Max( 0, c.smoothedPriority );
|
||||||
|
var rotation = c.camera.GetCameraRotation();
|
||||||
|
var vUp = rotation * Vector3.Up;
|
||||||
|
var vForward = rotation * Vector3.Forward;
|
||||||
|
|
||||||
|
position += priority * c.camera.GetCameraPosition();
|
||||||
|
up += priority * vUp;
|
||||||
|
forward += priority * vForward;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
position /= sumPriority;
|
||||||
|
|
||||||
|
if ( forward.LengthSquared() == 0 )
|
||||||
|
{
|
||||||
|
forward = camera.Basis.Z;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
forward = forward.Normalized();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( up.LengthSquared() == 0 )
|
||||||
|
{
|
||||||
|
up = camera.Basis.Y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
up = up.Normalized();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
camera.GlobalPosition = position;
|
||||||
|
camera.LookAt( position - forward, up );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override RJVirtualCamera3D GetCamera( int index )
|
||||||
|
{
|
||||||
|
return _cameraSlots[ index ].camera;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetCameraIndex( RJVirtualCamera3D camera3D )
|
||||||
|
{
|
||||||
|
return _cameraSlots.FindIndex( c => c.camera == camera3D );
|
||||||
|
}
|
||||||
|
|
||||||
|
public override float GetCameraPriority( int index )
|
||||||
|
{
|
||||||
|
return _cameraSlots[ index ].priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetCameraPriority( int index, float priority )
|
||||||
|
{
|
||||||
|
_cameraSlots[ index ].priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Rokojori
|
||||||
|
{
|
||||||
|
[Tool]
|
||||||
|
[Icon("res://Scripts/Rokojori/Rokojori-Action-Library/Icons/VirtualCamera3DSlot.svg") ]
|
||||||
|
[GlobalClass]
|
||||||
|
public partial class VirtualCamera3DSlot:RJAction
|
||||||
|
{
|
||||||
|
[Export]
|
||||||
|
public RJVirtualCamera3D camera;
|
||||||
|
|
||||||
|
[Export]
|
||||||
|
public float priority;
|
||||||
|
|
||||||
|
float _smoothedPriority;
|
||||||
|
public float smoothedPriority => _smoothedPriority;
|
||||||
|
|
||||||
|
Smoother smoother = new Smoother();
|
||||||
|
|
||||||
|
public void Update( double delta, VirtualCamera3DManager manager )
|
||||||
|
{
|
||||||
|
|
||||||
|
_smoothedPriority = smoother.SmoothWithCoefficient( _smoothedPriority, priority,
|
||||||
|
manager.safeSmoothing,
|
||||||
|
(float) delta, manager.smoothStepDelta );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _OnTrigger()
|
||||||
|
{
|
||||||
|
var vm = GetParent<VirtualCamera3DManager>();
|
||||||
|
|
||||||
|
if ( vm == null )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.SetActiveSlot( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue