Files
FORT-BO/Assets/CONTENT/Game/Scripts/Player/PlayerInteractionController.cs
T
AsanoRema ffa1064063 Squashed commit of the following:
commit 428243f4a6
Author: AsanoRema <asanorema2036@gmail.com>
Date:   Sat Aug 29 13:43:13 2026 +0300

    Squashed commit of the following:

    commit 68e78fa464
    Author: AsanoRema <asanorema2036@gmail.com>
    Date:   Sat Aug 29 13:41:49 2026 +0300

        Updated .gitignore

commit 9f87122a34
Author: AsanoRema <asanorema2036@gmail.com>
Date:   Sat Aug 29 13:34:57 2026 +0300

    Added Dohya

commit f6a7547e84
Author: AsanoRema <asanorema2036@gmail.com>
Date:   Fri Aug 21 17:59:13 2026 +0300

    Fixed

commit b98901c366
Author: AsanoRema <asanorema2036@gmail.com>
Date:   Tue Aug 18 17:37:22 2026 +0300

    Added new particle Package

commit bb2f4a3b16
Author: AsanoRema <asanorema2036@gmail.com>
Date:   Tue Aug 18 17:17:48 2026 +0300

    Map mehanic ready to multiplayer

commit c01ff800f6
Author: AsanoRema <asanorema2036@gmail.com>
Date:   Tue Aug 18 16:16:19 2026 +0300

    Squashed commit of the following:

    commit 173bbb165c
    Author: henjkey <henjkey@gmail.com>
    Date:   Fri Aug 14 18:51:23 2026 +0500

        Mappp

    commit d559ab338a
    Author: henjkey <henjkey@gmail.com>
    Date:   Thu Aug 13 18:42:41 2026 +0500

        Map

        Controller
        Coordinates
        Target System
        Crosshair System
        Radar System
2026-08-29 13:45:55 +03:00

163 lines
5.2 KiB
C#

using Unity.Netcode;
using UnityEngine;
using UnityEngine.InputSystem;
public sealed class PlayerInteractionController : NetworkBehaviour, IPlayerSystem
{
[SerializeField, Min(0.1f)] private float interactionDistance = 3f;
[SerializeField] private LayerMask interactionMask = ~0;
private Camera playerCamera;
private IInteractable focusedInteractable;
private IPlayerInteractionSession activeSession;
private readonly RaycastHit[] interactionHits = new RaycastHit[32];
private bool activeSessionReleaseRequested;
private bool isInitialized;
public void Initialize(PlayerFacade facade)
{
playerCamera = GetComponentInChildren<Camera>(true);
isInitialized = playerCamera != null;
}
private void Update()
{
if (!isInitialized || !IsOwner)
return;
if (PlayerInteractionSessionRegistry.TryGetControlledSession(
OwnerClientId,
out activeSession))
{
focusedInteractable = null;
bool isHoldingControl = Mouse.current != null &&
Mouse.current.leftButton.isPressed;
if (!isHoldingControl && !activeSessionReleaseRequested)
{
activeSessionReleaseRequested = true;
activeSession.RequestRelease();
}
return;
}
activeSession = null;
activeSessionReleaseRequested = false;
focusedInteractable = FindFocusedInteractable();
if (focusedInteractable == null || !focusedInteractable.IsInteractionAvailable)
return;
bool startsHoldSession = focusedInteractable is IPlayerInteractionSession &&
Mouse.current != null && Mouse.current.leftButton.wasPressedThisFrame;
bool performsRegularInteraction = focusedInteractable is not IPlayerInteractionSession &&
Keyboard.current != null && Keyboard.current.eKey.wasPressedThisFrame;
if (startsHoldSession || performsRegularInteraction)
{
focusedInteractable.RequestInteraction();
}
}
private IInteractable FindFocusedInteractable()
{
Ray ray = new(playerCamera.transform.position, playerCamera.transform.forward);
int hitCount = Physics.RaycastNonAlloc(
ray,
interactionHits,
interactionDistance,
interactionMask,
QueryTriggerInteraction.Collide);
if (hitCount <= 0)
return null;
IInteractable closestAvailable = null;
float closestAvailableDistance = float.PositiveInfinity;
IInteractable closestUnavailable = null;
float closestUnavailableDistance = float.PositiveInfinity;
float closestBlockingDistance = float.PositiveInfinity;
for (int hitIndex = 0; hitIndex < hitCount; hitIndex++)
{
RaycastHit hit = interactionHits[hitIndex];
if (hit.collider != null && hit.collider.transform.IsChildOf(transform))
continue;
IInteractable interactable = FindInteractable(hit.collider);
if (interactable == null)
{
closestBlockingDistance = Mathf.Min(closestBlockingDistance, hit.distance);
continue;
}
if (interactable.IsInteractionAvailable)
{
if (hit.distance < closestAvailableDistance)
{
closestAvailable = interactable;
closestAvailableDistance = hit.distance;
}
}
else if (hit.distance < closestUnavailableDistance)
{
closestUnavailable = interactable;
closestUnavailableDistance = hit.distance;
}
}
if (closestAvailable != null && closestAvailableDistance <= closestBlockingDistance)
return closestAvailable;
return closestUnavailable != null && closestUnavailableDistance <= closestBlockingDistance
? closestUnavailable
: null;
}
private static IInteractable FindInteractable(Collider collider)
{
foreach (MonoBehaviour component in collider.GetComponentsInParent<MonoBehaviour>())
{
if (component is IInteractable interactable)
return interactable;
}
return null;
}
private void OnGUI()
{
if (!IsOwner)
return;
if (activeSession != null)
{
DrawPrompt(activeSession.ReleasePrompt);
return;
}
if (focusedInteractable == null)
return;
string inputPrompt = focusedInteractable is IPlayerInteractionSession
? "[Hold LMB] "
: "[E] ";
string prompt = focusedInteractable.IsInteractionAvailable
? inputPrompt + focusedInteractable.InteractionPrompt
: "In use";
DrawPrompt(prompt);
}
private static void DrawPrompt(string prompt)
{
GUIStyle style = new(GUI.skin.label)
{
alignment = TextAnchor.MiddleCenter,
fontSize = 16,
normal = { textColor = Color.white }
};
Rect area = new(0f, Screen.height * 0.62f, Screen.width, 28f);
GUI.Label(area, prompt, style);
}
}