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.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 _colliders = new List(); 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(); var enteredColliders = new List(); 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; } }