303 lines
6.7 KiB
C#
303 lines
6.7 KiB
C#
public sealed partial class Dedugan
|
|
{
|
|
public Component Pressed { get; set; }
|
|
public bool EnablePressing { get; set; } = true;
|
|
public Component Hovered { get; set; }
|
|
|
|
[Sync( SyncFlags.Interpolate )]
|
|
public Vector3 TracedHitPos { get; set; }
|
|
[Sync]
|
|
public bool CameraTraceIsHit { get; set; }
|
|
public Vector3 TracedHitNormal { get; set; }
|
|
|
|
private GameObject interactionPanel;
|
|
private static GameObject interactionPanelPrefab;
|
|
|
|
private TimeSince holdTimer;
|
|
private bool isHolding;
|
|
private bool triggered;
|
|
|
|
private const string InteractionPrefabPath = "prefabs/InteractionPanel.prefab";
|
|
|
|
public void UpdateLookAt()
|
|
{
|
|
if ( EnablePressing )
|
|
{
|
|
if ( Pressed.IsValid() )
|
|
{
|
|
UpdatePressed();
|
|
}
|
|
else
|
|
{
|
|
UpdateHovered();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UpdatePressed()
|
|
{
|
|
bool flag = Input.Pressed( "Use" );
|
|
|
|
if ( flag && Pressed.Components.TryGet<IPressable>( out var pressable ) )
|
|
{
|
|
if ( pressable.RequiresHold )
|
|
{
|
|
if ( !isHolding )
|
|
{
|
|
holdTimer = 0;
|
|
isHolding = true;
|
|
triggered = false;
|
|
}
|
|
|
|
if ( triggered ) return;
|
|
|
|
var progress = holdTimer / pressable.HoldTime;
|
|
ShowInteractionUI( TracedHitPos, pressable.DisplayText, true, progress );
|
|
|
|
if ( holdTimer > pressable.HoldTime )
|
|
{
|
|
triggered = true;
|
|
pressable.Pressing( new IPressable.Event
|
|
{
|
|
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ),
|
|
Source = this
|
|
} );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
flag = pressable.Pressing( new IPressable.Event
|
|
{
|
|
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ),
|
|
Source = this
|
|
} );
|
|
}
|
|
}
|
|
|
|
if ( GetDistanceFromGameObject( Pressed.GameObject, Camera.WorldPosition ) > InteractDistance )
|
|
{
|
|
flag = false;
|
|
}
|
|
|
|
if ( !flag )
|
|
{
|
|
StopPressing();
|
|
}
|
|
}
|
|
|
|
private void UpdateHovered()
|
|
{
|
|
SwitchHovered( TryGetLookedAt() );
|
|
|
|
if ( Hovered is IPressable pressable )
|
|
{
|
|
pressable.Look( new IPressable.Event
|
|
{
|
|
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ),
|
|
Source = this
|
|
} );
|
|
|
|
ShowInteractionUI( TracedHitPos, pressable.DisplayText );
|
|
}
|
|
else
|
|
{
|
|
ClearInteractionUI();
|
|
}
|
|
|
|
if ( Input.Pressed( "use" ) )
|
|
{
|
|
StartPressing( Hovered );
|
|
}
|
|
}
|
|
|
|
public void StartPressing( Component obj )
|
|
{
|
|
StopPressing();
|
|
|
|
if ( !obj.IsValid() )
|
|
{
|
|
ISceneEvent<PlayerController.IEvents>.PostToGameObject( GameObject, x => x.FailPressing() );
|
|
return;
|
|
}
|
|
|
|
var component = obj.Components.Get<IPressable>( FindMode.EnabledInSelfAndDescendants );
|
|
|
|
if ( component != null )
|
|
{
|
|
if ( !component.CanPress( new IPressable.Event
|
|
{
|
|
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ),
|
|
Source = this
|
|
} ) )
|
|
{
|
|
ISceneEvent<PlayerController.IEvents>.PostToGameObject( GameObject, x => x.FailPressing() );
|
|
return;
|
|
}
|
|
|
|
component.Press( new IPressable.Event
|
|
{
|
|
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ),
|
|
Source = this
|
|
} );
|
|
}
|
|
|
|
Pressed = obj;
|
|
|
|
if ( Pressed.IsValid() )
|
|
{
|
|
ISceneEvent<PlayerController.IEvents>.PostToGameObject( GameObject, x => x.StartPressing( Pressed ) );
|
|
}
|
|
}
|
|
|
|
private Component TryGetLookedAt()
|
|
{
|
|
for ( float num = 0f; num <= 4f; num += 2f )
|
|
{
|
|
var from = Scene.Camera.WorldPosition + Scene.Camera.WorldRotation.Forward;
|
|
var to = from + Scene.Camera.WorldRotation.Forward * (InteractDistance - num);
|
|
var eyeTrace = Scene.Trace.Ray( from, to ).IgnoreGameObjectHierarchy( GameObject ).Radius( num ).Run();
|
|
|
|
TracedHitPos = eyeTrace.Hit ? eyeTrace.HitPosition : eyeTrace.EndPosition;
|
|
CameraTraceIsHit = eyeTrace.Hit;
|
|
TracedHitNormal = eyeTrace.Normal;
|
|
|
|
if ( !eyeTrace.Hit || !eyeTrace.GameObject.IsValid() )
|
|
continue;
|
|
|
|
Component foundComponent = null;
|
|
|
|
ISceneEvent<PlayerController.IEvents>.PostToGameObject( GameObject, x =>
|
|
{
|
|
foundComponent = x.GetUsableComponent( eyeTrace.GameObject ) ?? foundComponent;
|
|
} );
|
|
|
|
if ( foundComponent.IsValid() )
|
|
return foundComponent;
|
|
|
|
foreach ( var component in eyeTrace.GameObject.Components.GetAll<IPressable>() )
|
|
{
|
|
if ( component.CanPress( new IPressable.Event
|
|
{
|
|
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ),
|
|
Source = this
|
|
} ) )
|
|
{
|
|
return component as Component;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public void StopPressing()
|
|
{
|
|
if ( Pressed.IsValid() )
|
|
{
|
|
ISceneEvent<PlayerController.IEvents>.PostToGameObject( GameObject, x => x.StopPressing( Pressed ) );
|
|
|
|
if ( Pressed is IPressable pressable )
|
|
{
|
|
pressable.Release( new IPressable.Event
|
|
{
|
|
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ),
|
|
Source = this
|
|
} );
|
|
}
|
|
|
|
Pressed = null;
|
|
}
|
|
|
|
isHolding = false;
|
|
triggered = false;
|
|
ClearInteractionUI();
|
|
}
|
|
|
|
private void SwitchHovered( Component obj )
|
|
{
|
|
var e = new IPressable.Event
|
|
{
|
|
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ),
|
|
Source = this
|
|
};
|
|
|
|
if ( Hovered == obj )
|
|
{
|
|
if ( Hovered is IPressable pressable )
|
|
{
|
|
pressable.Look( e );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( Hovered is IPressable pressable2 )
|
|
{
|
|
pressable2.Blur( e );
|
|
Hovered = null;
|
|
}
|
|
|
|
Hovered = obj;
|
|
|
|
if ( Hovered is IPressable pressable3 )
|
|
{
|
|
pressable3.Hover( e );
|
|
pressable3.Look( e );
|
|
}
|
|
}
|
|
|
|
private float GetDistanceFromGameObject( GameObject obj, Vector3 point )
|
|
{
|
|
var a = obj.WorldPosition;
|
|
var b = Camera.WorldPosition;
|
|
float minDist = Vector3.DistanceBetween( a, b );
|
|
|
|
foreach ( var collider in Pressed.GetComponentsInChildren<Collider>() )
|
|
{
|
|
var closest = collider.FindClosestPoint( Camera.WorldPosition );
|
|
var dist = Vector3.DistanceBetween( closest, Camera.WorldPosition );
|
|
|
|
if ( dist < minDist )
|
|
{
|
|
minDist = dist;
|
|
}
|
|
}
|
|
|
|
return minDist;
|
|
}
|
|
|
|
private void ShowInteractionUI( Vector3 position, string text, bool showProgress = false, float progress = 0f )
|
|
{
|
|
if ( interactionPanelPrefab == null )
|
|
{
|
|
interactionPanelPrefab = GameObject.GetPrefab( InteractionPrefabPath );
|
|
if ( interactionPanelPrefab == null ) return;
|
|
}
|
|
|
|
if ( !interactionPanel.IsValid() )
|
|
{
|
|
interactionPanel = interactionPanelPrefab.Clone( GameObject.Scene );
|
|
}
|
|
|
|
interactionPanel.Transform.Position = position;
|
|
interactionPanel.Transform.Rotation = Rotation.LookAt( Camera.WorldPosition - position );
|
|
|
|
var panel = interactionPanel.GetComponent<PanelComponent>()?.GetPanel();
|
|
if ( panel is not null )
|
|
{
|
|
panel.SetProperty( "InteractionString", text );
|
|
panel.SetProperty( "IsHoldInteraction", showProgress );
|
|
panel.SetProperty( "ProgressionHold", progress );
|
|
}
|
|
}
|
|
|
|
private void ClearInteractionUI()
|
|
{
|
|
if ( interactionPanel.IsValid() )
|
|
{
|
|
interactionPanel.Destroy();
|
|
interactionPanel = null;
|
|
}
|
|
}
|
|
}
|