diff --git a/Runtime/Actions/ActionList.cs b/Runtime/Actions/ActionList.cs index 2679cf7..fee900a 100644 --- a/Runtime/Actions/ActionList.cs +++ b/Runtime/Actions/ActionList.cs @@ -33,37 +33,7 @@ namespace Rokojori public override void _OnTrigger() { - if ( actions != null ) - { - for ( int i = 0; i < actions.Length; i++ ) - { - Actions.Trigger( actions[ i ] ); - } - } - - if ( ! triggerDirectChildren ) - { - return; - } - - Nodes.ForEachDirectChild( this, a => Actions.Trigger( a ) ); - - /* - var childCount = GetChildCount(); - - for ( int i = 0; i < childCount; i++ ) - { - var action = GetChild( i ) as RJAction; - - if ( action == null ) - { - continue; - } - - Actions.Trigger( action ); - } - - */ + Actions.TriggerAll( actions, this, triggerDirectChildren ); } } } \ No newline at end of file diff --git a/Runtime/Actions/Actions.cs b/Runtime/Actions/Actions.cs index 1c77045..d58060d 100644 --- a/Runtime/Actions/Actions.cs +++ b/Runtime/Actions/Actions.cs @@ -15,5 +15,23 @@ namespace Rokojori action.Trigger(); } + + public static void TriggerAll( RJAction[] actions, Node target, bool triggerDirectChildren ) + { + if ( actions != null ) + { + for ( int i = 0; i < actions.Length; i++ ) + { + Actions.Trigger( actions[ i ] ); + } + } + + if ( ! triggerDirectChildren ) + { + return; + } + + Nodes.ForEachDirectChild( target, a => Actions.Trigger( a ) ); + } } } \ No newline at end of file diff --git a/Runtime/Actions/GDDelay.gd b/Runtime/Actions/GDDelay.gd deleted file mode 100644 index 8d64dcf..0000000 --- a/Runtime/Actions/GDDelay.gd +++ /dev/null @@ -1,34 +0,0 @@ -class_name GDDelay -extends RJSequenceAction - -@export var duration = 1 -@export var message = "huhu" - -var running = false -var elapsed = 0; -var id = 0; -var cachedIDs = [] - -func _onTrigger(): - if running: - cachedIDs - - - running = true - elapsed = 0 - id = dispatchStart() - -func _process( delta ): - if ! running: - return - elapsed += delta - - if elapsed > duration: - running = false - elapsed = 0 - print( name + " >> " + message ) - dispatchEnd( id ) - - - - diff --git a/Runtime/Actions/Node/SetNodeState.cs b/Runtime/Actions/Node/SetNodeState.cs new file mode 100644 index 0000000..b186d7a --- /dev/null +++ b/Runtime/Actions/Node/SetNodeState.cs @@ -0,0 +1,24 @@ + +using Godot; + + +namespace Rokojori +{ + [GlobalClass ] + public partial class SetNodeState : RJAction + { + [Export] + public Node[] enable; + + [Export] + public Node[] disable; + + + public override void _OnTrigger() + { + Arrays.ForEach( enable, n => NodeState.Enable( n ) ); + Arrays.ForEach( disable, n => NodeState.Disable( n ) ); + } + } + +} \ No newline at end of file diff --git a/Runtime/Actions/Node3D/CopyMousePosition.cs b/Runtime/Actions/Node3D/CopyMousePosition.cs new file mode 100644 index 0000000..54552fe --- /dev/null +++ b/Runtime/Actions/Node3D/CopyMousePosition.cs @@ -0,0 +1,31 @@ + +using Godot; + + +namespace Rokojori +{ + [GlobalClass ] + public partial class CopyMousePosition : RJAction + { + [Export] + public Camera3D camera; + + [Export] + public float depth; + + [Export] + public Node3D target; + + + public override void _OnTrigger() + { + if ( camera == null || target == null ) + { + return; + } + + var mousePosition = GetViewport().GetMousePosition(); + target.GlobalPosition = camera.ProjectPosition( mousePosition, depth ); + } + } +} \ No newline at end of file diff --git a/Runtime/Actions/Node3D/CopyPosition.cs b/Runtime/Actions/Node3D/CopyPosition.cs new file mode 100644 index 0000000..a91c27c --- /dev/null +++ b/Runtime/Actions/Node3D/CopyPosition.cs @@ -0,0 +1,33 @@ + +using Godot; + + +namespace Rokojori +{ + [GlobalClass, Tool ] + public partial class CopyPosition : RJAction + { + [Export] + public Node3D source; + + [Export] + public Node3D target; + + + public override void _Process( double delta ) + { + _OnTrigger(); + } + + + public override void _OnTrigger() + { + if ( source == null || target == null ) + { + return; + } + + target.GlobalPosition = source.GlobalPosition; + } + } +} \ No newline at end of file diff --git a/Runtime/Actions/Node3D/DistributeChildren.cs b/Runtime/Actions/Node3D/DistributeChildren.cs new file mode 100644 index 0000000..aa97cf4 --- /dev/null +++ b/Runtime/Actions/Node3D/DistributeChildren.cs @@ -0,0 +1,49 @@ + +using Godot; + + +namespace Rokojori +{ + [GlobalClass, Tool ] + public partial class DistributeChildren : RJAction + { + [Export] + public Node3D target; + + [Export] + public Node3D start; + + [Export] + public Node3D end; + + + public override void _Process( double delta ) + { + _OnTrigger(); + } + + + public override void _OnTrigger() + { + if ( start == null || end == null || target == null ) + { + return; + } + + var children = Nodes.GetDirectChildren( target ); + + var startPosition = start.GlobalPosition; + var endPosition = end.GlobalPosition; + + for ( int i = 0; i < children.Count; i++ ) + { + var lerpState = i / ( children.Count - 1f ); + var childPosition = startPosition.Lerp( endPosition, lerpState ); + + children[ i ].GlobalPosition = childPosition; + } + + + } + } +} \ No newline at end of file diff --git a/Runtime/Actions/Node3D/LerpPosition.cs b/Runtime/Actions/Node3D/LerpPosition.cs new file mode 100644 index 0000000..6daa92e --- /dev/null +++ b/Runtime/Actions/Node3D/LerpPosition.cs @@ -0,0 +1,31 @@ +using Godot; + + +namespace Rokojori +{ + [GlobalClass ] + public partial class LerpPosition : RJAction + { + [Export] + public Node3D sourceA; + + [Export] + public Node3D sourceB; + + [Export] + public float lerp; + + [Export] + public Node3D target; + + public override void _OnTrigger() + { + if ( sourceA == null || sourceB == null || target == null ) + { + return; + } + + target.GlobalPosition = sourceA.GlobalPosition.Lerp( sourceB.GlobalPosition, lerp ); + } + } +} \ No newline at end of file diff --git a/Runtime/Actions/Node3D/LookAt.cs b/Runtime/Actions/Node3D/LookAt.cs new file mode 100644 index 0000000..040cdb2 --- /dev/null +++ b/Runtime/Actions/Node3D/LookAt.cs @@ -0,0 +1,30 @@ +using Godot; + + +namespace Rokojori +{ + [GlobalClass, Tool ] + public partial class LookAt : RJAction + { + [Export] + public Node3D lookTarget; + + [Export] + public Node3D lookFrom; + + public override void _Process( double delta ) + { + _OnTrigger(); + } + + public override void _OnTrigger() + { + if ( lookFrom == null || lookTarget == null ) + { + return; + } + + lookFrom.LookAt( lookTarget.GlobalPosition ); + } + } +} \ No newline at end of file diff --git a/Runtime/Actions/OnPhysicsProcess.cs b/Runtime/Actions/OnPhysicsProcess.cs new file mode 100644 index 0000000..5c94aa1 --- /dev/null +++ b/Runtime/Actions/OnPhysicsProcess.cs @@ -0,0 +1,19 @@ + +using Godot; + + +namespace Rokojori +{ + [GlobalClass, Icon("res://Scripts/Rokojori/Rokojori-Action-Library/Icons/RJOnEvent.svg") ] + public partial class OnPhysicsProcess : Node + { + [Export] + public RJAction action; + + public override void _PhysicsProcess( double delta ) + { + // RJLog.Log( "OnReady" ); + Actions.Trigger( action ); + } + } +} \ No newline at end of file diff --git a/Runtime/Actions/OnProcess.cs b/Runtime/Actions/OnProcess.cs new file mode 100644 index 0000000..da9df8d --- /dev/null +++ b/Runtime/Actions/OnProcess.cs @@ -0,0 +1,31 @@ + +using Godot; + + +namespace Rokojori +{ + [GlobalClass, Tool, Icon("res://Scripts/Rokojori/Rokojori-Action-Library/Icons/RJOnEvent.svg") ] + public partial class OnProcess : Node + { + /** Actions to execute*/ + [Export] + public RJAction[] actions; + + /** Whether to execute RJAction child nodes*/ + [Export] + public bool triggerDirectChildren = true; + + [Export] + public bool executeInEditor = false; + + public override void _Process( double delta ) + { + if ( Engine.IsEditorHint() && ! executeInEditor ) + { + return; + } + + Actions.TriggerAll( actions, this, triggerDirectChildren ); + } + } +} \ No newline at end of file diff --git a/Runtime/Actions/GDPrint.cs b/Runtime/Actions/RJLogMessage.cs similarity index 69% rename from Runtime/Actions/GDPrint.cs rename to Runtime/Actions/RJLogMessage.cs index 95d4815..a93c717 100644 --- a/Runtime/Actions/GDPrint.cs +++ b/Runtime/Actions/RJLogMessage.cs @@ -4,14 +4,14 @@ using Godot; namespace Rokojori { - [GlobalClass] - public partial class GDPrint : RJAction + [GlobalClass ] + public partial class RJLogMessage : RJAction { [Export] public string message; public override void _OnTrigger() - { + { RJLog.Log( message ); } } diff --git a/Runtime/Godot/Generated/Classes/RJAnimatableBody3D.cs b/Runtime/Godot/Generated/Classes/RJAnimatableBody3D.cs new file mode 100644 index 0000000..7db506b --- /dev/null +++ b/Runtime/Godot/Generated/Classes/RJAnimatableBody3D.cs @@ -0,0 +1,79 @@ +using Godot; + +namespace Rokojori +{ + + [GlobalClass] + public partial class RJAnimatableBody3D:AnimatableBody3D + { + + + [Export] + public RJAction OnInputEvent; + + [Export] + public RJAction OnMouseEntered; + + [Export] + public RJAction OnMouseExited; + + [Export] + public RJAction OnVisibilityChanged; + + [Export] + public RJAction OnReady; + + [Export] + public RJAction OnRenamed; + + [Export] + public RJAction OnTreeEntered; + + [Export] + public RJAction OnTreeExiting; + + [Export] + public RJAction OnTreeExited; + + [Export] + public RJAction OnChildEnteredTree; + + [Export] + public RJAction OnChildExitingTree; + + [Export] + public RJAction OnChildOrderChanged; + + [Export] + public RJAction OnReplacingBy; + + [Export] + public RJAction OnEditorDescriptionChanged; + + [Export] + public RJAction OnScriptChanged; + + [Export] + public RJAction OnPropertyListChanged; + + public override void _Ready() + { + InputEvent += ( p0, p1, p2, p3, p4 ) => { Actions.Trigger( OnInputEvent ); }; + MouseEntered += ( ) => { Actions.Trigger( OnMouseEntered ); }; + MouseExited += ( ) => { Actions.Trigger( OnMouseExited ); }; + VisibilityChanged += ( ) => { Actions.Trigger( OnVisibilityChanged ); }; + Ready += ( ) => { Actions.Trigger( OnReady ); }; + Renamed += ( ) => { Actions.Trigger( OnRenamed ); }; + TreeEntered += ( ) => { Actions.Trigger( OnTreeEntered ); }; + TreeExiting += ( ) => { Actions.Trigger( OnTreeExiting ); }; + TreeExited += ( ) => { Actions.Trigger( OnTreeExited ); }; + ChildEnteredTree += ( p0 ) => { Actions.Trigger( OnChildEnteredTree ); }; + ChildExitingTree += ( p0 ) => { Actions.Trigger( OnChildExitingTree ); }; + ChildOrderChanged += ( ) => { Actions.Trigger( OnChildOrderChanged ); }; + ReplacingBy += ( p0 ) => { Actions.Trigger( OnReplacingBy ); }; + EditorDescriptionChanged += ( p0 ) => { Actions.Trigger( OnEditorDescriptionChanged ); }; + ScriptChanged += ( ) => { Actions.Trigger( OnScriptChanged ); }; + PropertyListChanged += ( ) => { Actions.Trigger( OnPropertyListChanged ); }; + } + } +} diff --git a/Runtime/Godot/Generated/Classes/RJCharacterBody3D.cs b/Runtime/Godot/Generated/Classes/RJCharacterBody3D.cs new file mode 100644 index 0000000..f395679 --- /dev/null +++ b/Runtime/Godot/Generated/Classes/RJCharacterBody3D.cs @@ -0,0 +1,79 @@ +using Godot; + +namespace Rokojori +{ + + [GlobalClass] + public partial class RJCharacterBody3D:CharacterBody3D + { + + + [Export] + public RJAction OnInputEvent; + + [Export] + public RJAction OnMouseEntered; + + [Export] + public RJAction OnMouseExited; + + [Export] + public RJAction OnVisibilityChanged; + + [Export] + public RJAction OnReady; + + [Export] + public RJAction OnRenamed; + + [Export] + public RJAction OnTreeEntered; + + [Export] + public RJAction OnTreeExiting; + + [Export] + public RJAction OnTreeExited; + + [Export] + public RJAction OnChildEnteredTree; + + [Export] + public RJAction OnChildExitingTree; + + [Export] + public RJAction OnChildOrderChanged; + + [Export] + public RJAction OnReplacingBy; + + [Export] + public RJAction OnEditorDescriptionChanged; + + [Export] + public RJAction OnScriptChanged; + + [Export] + public RJAction OnPropertyListChanged; + + public override void _Ready() + { + InputEvent += ( p0, p1, p2, p3, p4 ) => { Actions.Trigger( OnInputEvent ); }; + MouseEntered += ( ) => { Actions.Trigger( OnMouseEntered ); }; + MouseExited += ( ) => { Actions.Trigger( OnMouseExited ); }; + VisibilityChanged += ( ) => { Actions.Trigger( OnVisibilityChanged ); }; + Ready += ( ) => { Actions.Trigger( OnReady ); }; + Renamed += ( ) => { Actions.Trigger( OnRenamed ); }; + TreeEntered += ( ) => { Actions.Trigger( OnTreeEntered ); }; + TreeExiting += ( ) => { Actions.Trigger( OnTreeExiting ); }; + TreeExited += ( ) => { Actions.Trigger( OnTreeExited ); }; + ChildEnteredTree += ( p0 ) => { Actions.Trigger( OnChildEnteredTree ); }; + ChildExitingTree += ( p0 ) => { Actions.Trigger( OnChildExitingTree ); }; + ChildOrderChanged += ( ) => { Actions.Trigger( OnChildOrderChanged ); }; + ReplacingBy += ( p0 ) => { Actions.Trigger( OnReplacingBy ); }; + EditorDescriptionChanged += ( p0 ) => { Actions.Trigger( OnEditorDescriptionChanged ); }; + ScriptChanged += ( ) => { Actions.Trigger( OnScriptChanged ); }; + PropertyListChanged += ( ) => { Actions.Trigger( OnPropertyListChanged ); }; + } + } +} diff --git a/Runtime/Godot/Generated/GodotClassGenerator.cs b/Runtime/Godot/Generated/GodotClassGenerator.cs index b026ba9..d8d883b 100644 --- a/Runtime/Godot/Generated/GodotClassGenerator.cs +++ b/Runtime/Godot/Generated/GodotClassGenerator.cs @@ -17,16 +17,27 @@ namespace Rokojori [Export] public string testClass; + public override void _Ready() + { + ExportFiles(); + } + public override void _Process( double delta ) { if ( exportFlag ) { exportFlag = false; - var result = CreateClass( testClass ); - FilesSync.SaveUTF8( outputPath + testClass + ".cs", result ); + ExportFiles(); } } + void ExportFiles() + { + RJLog.Log( "Exporting:", testClass ); + var result = CreateClass( testClass ); + FilesSync.SaveUTF8( outputPath + "RJ" + testClass + ".cs", result ); + } + public string CreateClass( string name ) { var output = new StringBuilder(); @@ -41,7 +52,8 @@ namespace Rokojori output.Append( " public partial class RJ" + name + ":" + name + "\n"); output.Append( " {\n" ); - var classType = ReflectionHelper.GetTypeByName( name ); + + var classType = ReflectionHelper.GetTypeByNameFromAssembly( "Godot." + name, typeof( Node ).Assembly ); if ( classType == null ) { @@ -58,6 +70,7 @@ namespace Rokojori var ev = events[ i ]; var eventName = ev.Name; + output.Append( " \n" ); output.Append( " [Export]\n" ); output.Append( " public RJAction On" + eventName + ";\n" ); } @@ -71,16 +84,23 @@ namespace Rokojori { var ev = events[ i ]; var eventName = ev.Name; - var parameters = ev.GetRaiseMethod().GetParameters(); - var p = "("; + + var parameters = classType.GetEvent( eventName ).EventHandlerType.GetMethod( "Invoke" ).GetParameters(); + + var p = "( "; for ( int pn = 0; pn < parameters.Length; pn ++ ) { + if ( pn != 0 ) + { + p += ", "; + } + p += "p" + pn; } - p += ")"; + p += " )"; - output.Append( " " + eventName + " += " + p + " { Actions.Trigger( On" + eventName +" ); }; \n" ); + output.Append( " " + eventName + " += " + p + " => { Actions.Trigger( On" + eventName +" ); }; \n" ); } output.Append( " }\n" ); @@ -89,6 +109,8 @@ namespace Rokojori output.Append( "}\n" ); + RJLog.Log( output.ToString() ); + return output.ToString(); } diff --git a/Runtime/Godot/NodePathLocator.cs b/Runtime/Godot/NodePathLocator.cs new file mode 100644 index 0000000..0958259 --- /dev/null +++ b/Runtime/Godot/NodePathLocator.cs @@ -0,0 +1,19 @@ +using Godot; + +namespace Rokojori +{ + public enum NodePathLocatorType + { + DirectChildrenAndSiblings, + DirectChildren, + Siblings, + AnyChildren, + SiblingsAndAnyChildren + } + + public class NodePathLocator + { + public NodePathLocatorType type = NodePathLocatorType.DirectChildrenAndSiblings; + public int parentOffset = 0; + } +} \ No newline at end of file diff --git a/Runtime/Godot/NodeState.cs b/Runtime/Godot/NodeState.cs new file mode 100644 index 0000000..0beef5e --- /dev/null +++ b/Runtime/Godot/NodeState.cs @@ -0,0 +1,47 @@ +using Godot; + +using System.Collections.Generic; +using System; + +namespace Rokojori +{ + public class NodeState + { + public static void Configure( Node n, bool processEnabled, bool inputEnabled, bool physicsEnabled, bool signalsEnabled, + Node.ProcessModeEnum processMode ) + { + n.SetProcess( processEnabled ); + n.SetProcessInput( inputEnabled ); + n.SetPhysicsProcess( physicsEnabled ); + n.SetBlockSignals( ! signalsEnabled ); + + n.ProcessMode = processMode; + } + + public static void Set( Node n, bool enabled ) + { + Configure( n, enabled, enabled, enabled, enabled, enabled ? Node.ProcessModeEnum.Inherit : Node.ProcessModeEnum.Disabled ); + } + + public static void Set( Node[] nodes, bool enabled ) + { + Arrays.ForEach( nodes, n => Set( n, enabled ) ); + } + + public static void Enable( Node n ) + { + Set( n, true ); + } + + public static void Enable( Node[] n ) + { + Set( n, true ); + } + + public static void Disable( Node n ) + { + Set( n, true ); + } + + } +} \ No newline at end of file diff --git a/Runtime/Godot/Nodes.cs b/Runtime/Godot/Nodes.cs index f045fe6..a8a2e7c 100644 --- a/Runtime/Godot/Nodes.cs +++ b/Runtime/Godot/Nodes.cs @@ -7,6 +7,68 @@ namespace Rokojori { public class Nodes { + public static T Find( Node root, NodePathLocatorType type = NodePathLocatorType.DirectChildren, int parentOffset = 0 ) where T:Node + { + var it = root; + + while ( parentOffset > 0 && it != null ) + { + it = it.GetParent(); + parentOffset --; + } + + if ( it == null ) + { + return default(T); + } + + switch ( type ) + { + case NodePathLocatorType.DirectChildren: + { + return GetDirectChild( it ); + } + + case NodePathLocatorType.Siblings: + { + return GetSibling( it ); + } + + case NodePathLocatorType.DirectChildrenAndSiblings: + { + var child = GetDirectChild( it ); + + if ( child != null ) + { + return child; + } + + return GetSibling( it ); + } + + case NodePathLocatorType.AnyChildren: + { + return GetAnyChild( it ); + } + + case NodePathLocatorType.SiblingsAndAnyChildren: + { + var sibling = GetSibling( it ); + + if ( sibling != null ) + { + return sibling; + } + + return GetAnyChild( it );; + } + + + } + + return default(T); + } + public static void ForEach( Node root, Action callback ) where T:class { var walker = nodesWalker; @@ -82,7 +144,7 @@ namespace Rokojori var node = parent.GetChild( i ); var script = node.GetScript(); - RJLog.Log( "Node is", typeof(T), node.Name, node.GetType(), script.GetType(), ">>", ( node is T ) ); + // RJLog.Log( "Node is", typeof(T), node.Name, node.GetType(), script.GetType(), ">>", ( node is T ) ); if ( ! ( node is T ) ) @@ -130,7 +192,7 @@ namespace Rokojori var castedNode = n as T; - RJLog.Log( "Testing", n.UniqueNameInOwner, castedNode != null, n.GetType() ); + // RJLog.Log( "Testing", n.UniqueNameInOwner, castedNode != null, n.GetType() ); return castedNode != null; diff --git a/Runtime/Godot/Unique.cs b/Runtime/Godot/Unique.cs index 39095d2..0e04f61 100644 --- a/Runtime/Godot/Unique.cs +++ b/Runtime/Godot/Unique.cs @@ -18,7 +18,7 @@ namespace Rokojori var rootWindow = n == null ? Root.Window() : n.Owner; - RJLog.Log( "ROOT", rootWindow ); + // RJLog.Log( "ROOT", rootWindow ); if ( rootWindow == null ) { @@ -27,7 +27,7 @@ namespace Rokojori _singleton = Nodes.GetAnyChild( rootWindow ); - RJLog.Log( "_singleton", _singleton ); + // RJLog.Log( "_singleton", _singleton ); return _singleton; } diff --git a/Runtime/Interactions/MultiRayCaster.cs b/Runtime/Interactions/MultiRayCaster.cs new file mode 100644 index 0000000..f5fd7b7 --- /dev/null +++ b/Runtime/Interactions/MultiRayCaster.cs @@ -0,0 +1,184 @@ +using Godot; +using System.Collections; +using System.Collections.Generic; +using Godot.Collections; + +namespace Rokojori +{ + + [GlobalClass] + public partial class MultiRayCaster:RJCaster + { + [Export] + public float rayLength = 10; + + [Export] + public int maxHits = 100; + + [Export] + public bool sortByPointerPriority; + + List collisions = new List(); + int numCollisions = 0; + + [Export] + public Vector3 to; + + public override int NumColliders() + { + return numCollisions; + } + + + public override Node GetCollider( int index ) + { + return collisions[ index ].collider; + } + + public override Vector3 GetCollisionNormal( int index ) + { + return collisions[ index ].normal; + } + + public override Vector3 GetCollisionPosition( int index ) + { + return collisions[ index ].position; + } + + public override Shape3D GetCollisionShape( int index ) + { + return collisions[ index ].shape; + } + + PhysicsRayQueryParameters3D rayParameters = new PhysicsRayQueryParameters3D(); + + public override void _Process( double delta ) + { + Actions.Trigger( BeforeProcess ); + + ResolveCollisions(); + SortCollisions(); + + + Actions.Trigger( AfterProcess ); + + } + + ValueSorter singleSorter; + MultiValueSorter multiSorter; + + + + CollisionData GetCollisionData( int i ) + { + while ( collisions.Count <= i ) + { + collisions.Add( new CollisionData() ); + } + + return collisions[ i ]; + } + + void ResolveCollisions() + { + var physics = GetWorld3D().DirectSpaceState; + + var excludes = new Array(); + + var from = GlobalPosition; + var to = from + Math3D.GetGlobalForward( this ) * rayLength; + + this.to = to; + + rayParameters.From = from; + rayParameters.To = to; + + numCollisions = 0; + + for ( int i = 0; i < maxHits; i++ ) + { + rayParameters.Exclude = excludes; + + var collisionData = GetCollisionData( numCollisions ); + collisionData.Get( rayParameters, physics ); + + if ( ! collisionData.hasCollision ) + { + return; + } + + excludes.Add( collisionData.rid ); + + if ( IsSelected( collisionData ) ) + { + numCollisions ++; + } + + } + } + + bool IsSelected( CollisionData cd ) + { + var includeSelector = IncludeSelector; + var excludeSelector = ExcludeSelector; + + if ( includeSelector != null && ! includeSelector.Selects( cd.collider ) ) + { + return false; + } + + if ( excludeSelector != null && excludeSelector.Selects( cd.collider ) ) + { + return false; + } + + return true; + } + + void SortCollisions() + { + if ( ! sortByPointerPriority ) + { + if ( singleSorter == null ) + { + singleSorter = ValueSorter.Create( cd => GetDistance( cd ) ); + } + + singleSorter.Sort( 0, numCollisions, collisions ); + } + else + { + if ( multiSorter == null ) + { + multiSorter = MultiValueSorter.Create( + cd => GetPointablePriority( cd ), + cd => GetDistance( cd ) + ); + } + + multiSorter.Sort( 0, numCollisions, collisions ); + } + } + + float GetPointablePriority( CollisionData cd ) + { + float priority = 0; + + var pointable = Nodes.Find( cd.collider ); + + if ( pointable != null ) + { + priority = pointable.PointingPriority; + } + + return priority; + } + + float GetDistance( CollisionData cd ) + { + return ( cd.position - GlobalPosition ).Length(); + } + + + } +} \ No newline at end of file diff --git a/Runtime/Interactions/Pointable.cs b/Runtime/Interactions/Pointable.cs new file mode 100644 index 0000000..061f60f --- /dev/null +++ b/Runtime/Interactions/Pointable.cs @@ -0,0 +1,61 @@ +using Godot; +using System.Collections; +using System.Collections.Generic; +using Godot.Collections; + +namespace Rokojori +{ + + [GlobalClass] + public partial class Pointable:RJPointable + { + List _pointers = new List(); + + public override int NumPointing() + { + return _pointers.Count; + } + + public bool IsPointedBy( RJPointer pointer ) + { + return _pointers.Contains( pointer ); + } + + public override void UpdatePointerState( RJPointer pointer, bool pointed ) + { + var isCurrentlyPointed = IsPointedBy( pointer ); + + if ( isCurrentlyPointed == pointed ) + { + return; + } + + + if ( pointed ) + { + _pointers.Add( pointer ); + Actions.Trigger( OnPointerAdded ); + + if ( _pointers.Count == 1 ) + { + Actions.Trigger( OnPointed ); + } + + } + else + { + _pointers.Remove( pointer ); + + Actions.Trigger( OnPointerRemoved ); + + if ( _pointers.Count == 0 ) + { + Actions.Trigger( OnUnpointed ); + } + + } + + + } + } +} \ No newline at end of file diff --git a/Runtime/Interactions/Pointer.cs b/Runtime/Interactions/Pointer.cs new file mode 100644 index 0000000..62bb2e8 --- /dev/null +++ b/Runtime/Interactions/Pointer.cs @@ -0,0 +1,48 @@ +using Godot; +using System.Collections; +using System.Collections.Generic; +using Godot.Collections; + +namespace Rokojori +{ + + [GlobalClass] + public partial class Pointer:RJPointer + { + [Export] + public RJPointable pointable; + + public override void _Process( double delta ) + { + if ( Caster == null ) + { + return; + } + + var currentCollider = Caster.NumColliders() == 0 ? null : Caster.GetCollider( 0 ); + + + var currentPointable = currentCollider == null ? null : Nodes.Find( currentCollider ); + + // RJLog.Log( currentCollider, currentPointable ); + + if ( currentPointable == pointable ) + { + return; + } + + + if ( pointable != null ) + { + pointable.UpdatePointerState( this, false ); + } + + pointable = currentPointable; + + if ( pointable != null ) + { + pointable.UpdatePointerState( this, true ); + } + } + } +} \ No newline at end of file diff --git a/Runtime/Math/Math3D.cs b/Runtime/Math/Math3D.cs index 7cd3094..d22f488 100644 --- a/Runtime/Math/Math3D.cs +++ b/Runtime/Math/Math3D.cs @@ -23,7 +23,7 @@ namespace Rokojori public static Vector3 GetGlobalForward( Node3D node ) { - return node.GlobalBasis.Z; + return -node.GlobalBasis.Z; } public static Vector3 GetGlobalUp( Node3D node ) diff --git a/Runtime/Physics/CollisionData.cs b/Runtime/Physics/CollisionData.cs new file mode 100644 index 0000000..9978d5c --- /dev/null +++ b/Runtime/Physics/CollisionData.cs @@ -0,0 +1,44 @@ +using Godot; +using System.Collections; +using System.Collections.Generic; + + +namespace Rokojori +{ + public class CollisionData + { + public bool hasCollision = false; + public Node collider; + public Vector3 normal; + public Vector3 position; + public Shape3D shape; + public Rid rid; + + + public void Get( PhysicsRayQueryParameters3D ray, PhysicsDirectSpaceState3D physicsState ) + { + var result = physicsState.IntersectRay( ray ); + + + + if ( ! result.ContainsKey( "collider" ) ) + { + hasCollision = false; + return; + } + + hasCollision = true; + + + + collider = result[ "collider" ].As(); + normal = result[ "normal" ].AsVector3(); + position = result[ "position" ].AsVector3(); + shape = result[ "shape" ].As(); + rid = result[ "rid" ].AsRid(); + + // RJLog.Log( "Has Collision:", HierarchyName.Of( collider ), ">> at position:", position, "with normal:", normal ); + + } + } +} \ No newline at end of file diff --git a/Runtime/Sorting/MultiValueSorter.cs b/Runtime/Sorting/MultiValueSorter.cs new file mode 100644 index 0000000..e600594 --- /dev/null +++ b/Runtime/Sorting/MultiValueSorter.cs @@ -0,0 +1,67 @@ +using System.Collections; +using System.Collections.Generic; +using System; +using System.Reflection; +using System.Text.RegularExpressions; + +namespace Rokojori +{ + + public class MultiValueSorter + { + List> valueSorters = new List>(); + + public void AddValueSorter( Func getFloatValue, bool reverse = false ) + { + var valueSorter = ValueSorter.Create( getFloatValue, reverse ); + valueSorters.Add( valueSorter ); + } + + public void Sort( List data ) + { + valueSorters.ForEach( v => v.ClearCache() ); + data.Sort( ( a, b ) => Compare( a, b ) ); + } + + public void Sort( int index, int count, List data ) + { + valueSorters.ForEach( v => v.ClearCache() ); + data.Sort( index, count, Comparer.Create( ( a, b ) => Compare( a, b ) ) ); + } + + public int Compare( T a, T b ) + { + for ( int i = 0; i < valueSorters.Count; i++ ) + { + var valueProvider = valueSorters[ 0 ]; + + var result = valueProvider.Compare( a, b ); + + if ( result != 0 ) + { + return result; + } + } + + return 0; + } + + public static MultiValueSorter Create( params Func[] valueSorterFunctions ) + { + var multiSorter = new MultiValueSorter(); + + for ( int i = 0; i < valueSorterFunctions.Length; i++ ) + { + multiSorter.AddValueSorter( valueSorterFunctions[ i ] ); + } + + return multiSorter; + } + + + public static void SortBy( List data, params Func[] valueSorterFunctions ) + { + Create( valueSorterFunctions ).Sort( data ); + } + } +} \ No newline at end of file diff --git a/Runtime/Sorting/ValueSorter.cs b/Runtime/Sorting/ValueSorter.cs new file mode 100644 index 0000000..bcb8b34 --- /dev/null +++ b/Runtime/Sorting/ValueSorter.cs @@ -0,0 +1,73 @@ +using System.Collections; +using System.Collections.Generic; +using System; +using System.Reflection; +using System.Text.RegularExpressions; + +namespace Rokojori +{ + public class ValueSorter + { + Func getFloatValue; + bool reverse_highestFirst = false; + + Dictionary cachedValues = new Dictionary(); + + public static ValueSorter Create( Func getFloatValue, bool reverse_highestFirst = false ) + { + var vs = new ValueSorter(); + vs.getFloatValue = getFloatValue; + vs.reverse_highestFirst = reverse_highestFirst; + return vs; + } + + public void ClearCache() + { + cachedValues.Clear(); + } + + public float GetValue( T t ) + { + if ( ! cachedValues.ContainsKey( t ) ) + { + cachedValues[ t ] = getFloatValue( t );; + } + + return cachedValues[ t ]; + } + + public int Compare( T a, T b ) + { + var valueA = GetValue( a ); + var valueB = GetValue( b ); + + if ( valueA != valueB ) + { + var difference = valueA - valueB; + + if ( reverse_highestFirst ) + { + difference = - difference; + } + + return MathF.Sign( difference ); + } + + return 0; + } + + public void Sort( List data ) + { + ClearCache(); + data.Sort( ( a, b ) => Compare( a, b ) ); + } + + public void Sort( int index, int count, List data ) + { + ClearCache(); + data.Sort( index, count, Comparer.Create( ( a, b ) => Compare( a, b ) ) ); + } + } + + +} \ No newline at end of file diff --git a/Runtime/Tools/Arrays.cs b/Runtime/Tools/Arrays.cs new file mode 100644 index 0000000..4c25e74 --- /dev/null +++ b/Runtime/Tools/Arrays.cs @@ -0,0 +1,18 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System; + +namespace Rokojori +{ + public class Arrays + { + public static void ForEach( T[] values, Action callback ) + { + foreach ( var it in values ) + { + callback( it ); + } + } + } +} \ No newline at end of file diff --git a/Runtime/VirtualCameras/MouseEditorCamera.cs b/Runtime/VirtualCameras/MouseEditorCamera.cs index caa763b..5a71312 100644 --- a/Runtime/VirtualCameras/MouseEditorCamera.cs +++ b/Runtime/VirtualCameras/MouseEditorCamera.cs @@ -168,7 +168,7 @@ namespace Rokojori GlobalRotation = new Vector3( Mathf.DegToRad( pitch ), Mathf.DegToRad( yaw ), 0 ); var forward = Math3D.GetGlobalForward( this ) * smoothDistance; - GlobalPosition = target - forward; + GlobalPosition = target + forward; } } } \ No newline at end of file diff --git a/Runtime/VirtualCameras/StrategyTopDownCamera.cs b/Runtime/VirtualCameras/StrategyTopDownCamera.cs index 2802c73..f5b3f9a 100644 --- a/Runtime/VirtualCameras/StrategyTopDownCamera.cs +++ b/Runtime/VirtualCameras/StrategyTopDownCamera.cs @@ -220,7 +220,7 @@ namespace Rokojori GlobalRotation = new Vector3( Mathf.DegToRad( pitch ), Mathf.DegToRad( yaw ), 0 ); var forward = Math3D.GetGlobalForward( this ) * smoothDistance; - GlobalPosition = target - forward; + GlobalPosition = target + forward; } } } \ No newline at end of file