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]
|
||||
public string message;
|
||||
|
||||
float elapsed = 0;
|
||||
bool running = false;
|
||||
bool finished = false;
|
||||
|
||||
int runID = 0;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
/// OnSequenceDone += ( id, success ) => { RJLog.Log( "OnSequenceDone", Name ); } ;
|
||||
}
|
||||
[Export]
|
||||
public RJTimeLine timeLine;
|
||||
|
||||
|
||||
public override void _OnTrigger()
|
||||
{
|
||||
//RJLog.Log( "Starting", Name );
|
||||
runID = DispatchStart();
|
||||
|
||||
elapsed = 0;
|
||||
running = true;
|
||||
finished = false;
|
||||
var sequenceID = DispatchStart();
|
||||
|
||||
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 System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
@ -44,6 +45,37 @@ namespace Rokojori
|
|||
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
|
||||
{
|
||||
if ( parent == null || action == null )
|
||||
|
|
|
@ -18,20 +18,26 @@ namespace Rokojori
|
|||
return;
|
||||
}
|
||||
|
||||
if ( obj is float || obj is double )
|
||||
{
|
||||
output.Append( RegexUtility.WriteDouble( (double)obj ) );
|
||||
return;
|
||||
}
|
||||
|
||||
output.Append( obj.ToString() );
|
||||
}
|
||||
|
||||
static void LogMessage( string message )
|
||||
{
|
||||
var trace = GetTrace();
|
||||
GD.PrintRich("[b]" + message + "[/b]");
|
||||
GD.PrintRich("\n[b]" + message + "[/b]");
|
||||
GD.PrintRich( trace );
|
||||
}
|
||||
|
||||
static void LogErrorMessage( string message )
|
||||
{
|
||||
var trace = GetTrace();
|
||||
GD.PrintErr( message );
|
||||
GD.PrintErr( "\n"+ message );
|
||||
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 const float fps120Delta = 1/120f;
|
||||
|
||||
public static float Clamp01( float value )
|
||||
{
|
||||
|
@ -186,17 +187,17 @@ namespace Rokojori
|
|||
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 );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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 );
|
||||
newValue = Mathf.Wrap( newValue, 0, 360 );
|
||||
|
@ -218,7 +219,7 @@ namespace Rokojori
|
|||
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 );
|
||||
}
|
||||
|
|
|
@ -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 seed = (int) ( ms * 10000 );
|
||||
var lcg = new LCG();
|
||||
RJLog.Log( "Seed", seed, Time.GetUnixTimeFromSystem() );
|
||||
// RJLog.Log( "Seed", seed, Time.GetUnixTimeFromSystem() );
|
||||
lcg.SetSeed( seed );
|
||||
lcg.Next();
|
||||
return lcg;
|
||||
|
|
|
@ -10,6 +10,18 @@ namespace Rokojori
|
|||
[Export]
|
||||
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;
|
||||
bool _wasActive = false;
|
||||
bool _isActive = false;
|
||||
|
@ -34,13 +46,30 @@ namespace Rokojori
|
|||
_value = value;
|
||||
|
||||
_wasActive = _isActive;
|
||||
_isActive = _value > 0;
|
||||
_isActive = _value > axisActivationTreshold;
|
||||
}
|
||||
|
||||
public override void _Process( double delta )
|
||||
{
|
||||
var inputValue = Input.GetActionRawStrength( inputActionName );
|
||||
UpdateValue( inputValue );
|
||||
if ( pollAsButton )
|
||||
{
|
||||
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 ];
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
|
@ -117,6 +125,13 @@ namespace Rokojori
|
|||
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 )
|
||||
{
|
||||
for ( int i = 0; i < inputList.Count; i++ )
|
||||
|
@ -232,6 +247,21 @@ namespace Rokojori
|
|||
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 )
|
||||
{
|
||||
if ( list == null )
|
||||
|
@ -246,5 +276,7 @@ namespace Rokojori
|
|||
|
||||
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