DomeFox/DomeFox/Game Objects/Eye/Eye.cs

212 lines
4.1 KiB
C#

using Godot;
using Rokojori;
using System.Collections.Generic;
using System.Threading.Tasks;
[Tool, GlobalClass]
public partial class Eye : Node
{
[Export]
public Node3D transform;
[Export]
public Node3D beamScale;
[Export]
public Action onHasCollider;
[Export]
public Action onNoCollider;
[Export]
public PlayerSight playerSight;
[Export]
public Smoothing toPlayerRotationSmoothing;
[Export]
public float maxLength = 10;
[Export]
public float rootScale = 20;
[Export]
public MultiRayCaster multiRayCaster;
[Export]
public Health health;
[Export]
public Smoothing lengthSmoothing;
float _nextLength = 10;
[Export]
public Collider collider;
[ExportGroup( "Debugging")]
[Export]
public bool forceDebugLength = false;
[Export]
public float debugLength = 5;
[Export]
public float wobbleRaycast = 1;
public override void _Process( double delta )
{
var currentNumColliders = _colliders.Count;
var pos = multiRayCaster.Position;
var random = GodotRandom.Get().InsideCircle( wobbleRaycast );
multiRayCaster.Position = new Vector3( random.X, random.Y, pos.Z );
ResolveCollisions();
if ( currentNumColliders != _colliders.Count )
{
var hasColliders = _colliders.Count > 0;
Action.Trigger( hasColliders ? onNoCollider : onHasCollider );
}
if ( forceDebugLength )
{
_nextLength = debugLength;
}
var length = Smoothing.Apply( lengthSmoothing, _nextLength, (float) delta );
beamScale.SetScaleZ( length / maxLength );
UpdateRotation( (float) delta );
}
void UpdateRotation( float delta )
{
if ( playerSight == null )
{
return;
}
if ( playerSight.visible )
{
var player = Unique<Player>.Get();
var playerDirection = transform.DirectionTowards( player.transform.GlobalPosition );
var toPlayerRotation = Math3D.LookRotation( playerDirection );
var smoothedRotation = Smoothing.Apply( toPlayerRotationSmoothing, toPlayerRotation, delta );
transform.SetGlobalQuaternion( smoothedRotation );
// this.LogInfo( playerDirection, toPlayerRotation, smoothedRotation );
}
else
{
if ( toPlayerRotationSmoothing != null )
{
toPlayerRotationSmoothing.SetCurrent( transform.GlobalQuaternion() );
}
}
}
List<Node> _colliders = new List<Node>();
void ResolveCollisions()
{
var invalid = _colliders.Has( c => ! IsInstanceValid( c ) );
if ( invalid )
{
_colliders = _colliders.Filter( c=> IsInstanceValid( c ) );
}
var numColliders = multiRayCaster.NumColliders();
if ( health.isDead )
{
numColliders = 0;
}
var same = _colliders.Count == numColliders;
var minDistance = maxLength;
for ( int i = 0; i < numColliders; i++ )
{
if ( same && _colliders[ i ] != multiRayCaster.GetCollider( i ) )
{
same = false;
}
var distance = transform.DistanceTo( multiRayCaster.GetCollisionPosition( i ) ) / rootScale;
minDistance = Mathf.Min( distance, minDistance );
}
_nextLength = minDistance;
if ( same )
{
return;
}
var newColliders = new List<Node>();
var enteredColliders = new List<Node>();
for ( int i = 0; i < numColliders; i++ )
{
var collider = multiRayCaster.GetCollider( i );
if ( collider == null )
{
// this.LogInfo( "Collider is null!", i, multiRayCaster.NumColliders() );
continue;
}
newColliders.Add( collider );
if ( ! _colliders.Contains( collider ) )
{
enteredColliders.Add( collider );
}
}
var exitedColliders = _colliders.Filter( c => ! newColliders.Contains( c ) );
exitedColliders.ForEach(
( c )=>
{
// this.LogInfo( "Collider exited:", HierarchyName.Of( c ) );
collider.TriggerOnExited( c as Node3D );
}
);
enteredColliders.ForEach(
( c )=>
{
// this.LogInfo( "Collider entered:", HierarchyName.Of( c ) );
collider.TriggerOnEnter( c as Node3D );
}
);
_colliders = newColliders;
}
}