151 lines
3.4 KiB
C#
151 lines
3.4 KiB
C#
using Godot;
|
|
using System.Collections.Generic;
|
|
|
|
using Rokojori.Extensions;
|
|
namespace Rokojori
|
|
{
|
|
public enum LockOnCycleMode
|
|
{
|
|
None,
|
|
ClosestCycle,
|
|
Directional
|
|
}
|
|
|
|
// Only tracks the current candidate list and the single selected pointable (sticky - stays on
|
|
// the selection until it is cycled away from or stops being a valid candidate). Owns no concept
|
|
// of "locked" - that is CameraLocker's job, reading/driving this pointer's pointable.
|
|
[Tool]
|
|
[GlobalClass]
|
|
public partial class LockOnPointer : Pointer
|
|
{
|
|
public int test = 0;
|
|
|
|
List<Pointable> _candidates = new List<Pointable>();
|
|
|
|
public int numCandidates => _candidates.Count;
|
|
|
|
public Pointable GetCandidate( int index )
|
|
{
|
|
return _candidates[ index ];
|
|
}
|
|
|
|
public bool IsCandidate( Pointable p )
|
|
{
|
|
return p != null && _candidates.Contains( p );
|
|
}
|
|
|
|
protected override void _OnTrigger()
|
|
{
|
|
if ( caster == null )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( pointable != null && ! IsInstanceValid( pointable ) )
|
|
{
|
|
pointable = null;
|
|
}
|
|
|
|
RefreshCandidates();
|
|
|
|
if ( pointable == null || ! _candidates.Contains( pointable ) )
|
|
{
|
|
SetPointable( ClosestCandidate() );
|
|
}
|
|
}
|
|
|
|
void RefreshCandidates()
|
|
{
|
|
_candidates.Clear();
|
|
|
|
for ( int i = 0; i < caster.NumColliders(); i++ )
|
|
{
|
|
var p = Nodes.Find<Pointable>( caster.GetCollider( i ) );
|
|
|
|
if ( p != null && p.enabled )
|
|
{
|
|
_candidates.Add( p );
|
|
}
|
|
}
|
|
}
|
|
|
|
Pointable ClosestCandidate()
|
|
{
|
|
return _candidates.Count == 0 ? null : _candidates[ 0 ];
|
|
}
|
|
|
|
public void CycleNext()
|
|
{
|
|
if ( _candidates.Count == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
var currentIndex = _candidates.IndexOf( pointable );
|
|
var nextIndex = currentIndex == -1 ? 0 : ( currentIndex + 1 ) % _candidates.Count;
|
|
|
|
SetPointable( _candidates[ nextIndex ] );
|
|
}
|
|
|
|
public void CyclePrevious()
|
|
{
|
|
if ( _candidates.Count == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
var currentIndex = _candidates.IndexOf( pointable );
|
|
var previousIndex = currentIndex == -1 ? 0 : ( currentIndex - 1 + _candidates.Count ) % _candidates.Count;
|
|
|
|
SetPointable( _candidates[ previousIndex ] );
|
|
}
|
|
|
|
public void CycleInScreenSpaceDirection( Vector2 screenSpaceDirection )
|
|
{
|
|
if ( pointable == null )
|
|
{
|
|
SetPointable( ClosestCandidate() );
|
|
return;
|
|
}
|
|
|
|
var right = caster.GlobalTransform.Basis.X;
|
|
var up = caster.GlobalTransform.Basis.Y;
|
|
var currentPosition = pointable.GlobalPosition;
|
|
|
|
Pointable best = null;
|
|
var bestScore = float.NegativeInfinity;
|
|
|
|
for ( int i = 0; i < _candidates.Count; i++ )
|
|
{
|
|
var candidate = _candidates[ i ];
|
|
|
|
if ( candidate == pointable )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var offset = candidate.GlobalPosition - currentPosition;
|
|
var projected = new Vector2( offset.Dot( right ), offset.Dot( up ) );
|
|
|
|
if ( projected.LengthSquared() < 0.0001f )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var score = projected.Normalized().Dot( screenSpaceDirection );
|
|
|
|
if ( score > bestScore )
|
|
{
|
|
bestScore = score;
|
|
best = candidate;
|
|
}
|
|
}
|
|
|
|
if ( best != null )
|
|
{
|
|
SetPointable( best );
|
|
}
|
|
}
|
|
}
|
|
}
|