Skip to content
Snippets Groups Projects
WorldCursor.cs 6.22 KiB
Newer Older
  • Learn to ignore specific revisions
  • using System.Globalization;
    
    using System.Collections.Generic;
    using UnityEngine;
    
    Richard Marcus's avatar
    Richard Marcus committed
    using UnityEngine.EventSystems;
    
    MaZiFAU's avatar
    MaZiFAU committed
    using MoreLinq;
    using System.Linq;
    
    
    public class WorldCursor : MonoBehaviour
    {
    
        public RaycastHit Hit;
    
        // TODO experimentell for multiple hits
    
    MaZiFAU's avatar
    MaZiFAU committed
        public RaycastHit[] Hits;
    
        public float IntersectionDistance = 0.1f;
    
        private int layerMask;
    
        public float MaxRange = 10f;
        public bool useCamCurser = false;
    
    
        private void Awake()
        {
            //Ignore player and TalkingZone
    
            this.layerMask = ~LayerMask.GetMask("Player", "TalkingZone");
    
    Richard Marcus's avatar
    Richard Marcus committed
    
    
        void Start()
        {
            Cam = Camera.main;
    
            CultureInfo.CurrentCulture = new CultureInfo("en-US");
    
        public void setLayerMask(int layerMask)
        {
    
            this.layerMask = layerMask;
        }
    
    
        // working currently to include multiple hits 
        // TODO 
    
    
            UpdateMaxRange();
    
            Cam = Camera.main; //WARN: Should not called every Update; TODO: Cache in Start/Awake?
            Vector3 mousePos = UIconfig.InputManagerVersion switch
    
                1 or 2 or 3 => Input.mousePosition,
                _ => Vector3.zero
            };
    
    MaZiFAU's avatar
    MaZiFAU committed
            Ray ray = useCamCurser
                ? new Ray(Cam.transform.position, Cam.transform.forward)
                : Cam.ScreenPointToRay(mousePos);
    
            transform.up = Cam.transform.forward;
            transform.position = ray.GetPoint(GlobalBehaviour.GadgetPhysicalDistance);
    
    Richard Marcus's avatar
    Richard Marcus committed
    
    
            //************************************************
    
            bool deactSnapKey =
                   Input.GetButton(this.deactivateSnapKey)
                && UIconfig.InputManagerVersion >= 1
                && UIconfig.InputManagerVersion <= 3;
    
            //************************************************
    
    MaZiFAU's avatar
    MaZiFAU committed
            Hits = Physics.RaycastAll(ray, MaxRange, layerMask);
            if (Hits.Length == 0)
    
    MaZiFAU's avatar
    MaZiFAU committed
                Hits = Physics.RaycastAll(transform.position, Vector3.down, GlobalBehaviour.GadgetPhysicalDistance, layerMask);
                if (Hits.Length == 0)
                    return; // in case we dont hit anything, just return
    
            Hits = Hits
                .OrderBy(h => h.distance)
                .ToArray();
    
    ki7077's avatar
    ki7077 committed
    
    
    MaZiFAU's avatar
    MaZiFAU committed
            Fact[] facts = Hits
                .Select(h =>
                    h.transform.TryGetComponent(out FactObject factObj)
                    ? FactOrganizer.AllFacts[factObj.URI]
                    : null)
                .ToArray();
    
    MaZiFAU's avatar
    MaZiFAU committed
            int i = 0;
            for (; i < Hits.Length; i++)
    
            { // find first acceptable hit
    
    MaZiFAU's avatar
    MaZiFAU committed
                if (facts[i] is AbstractLineFact lineFact)
    
    MaZiFAU's avatar
    MaZiFAU committed
                    Hits[i].point =
                        Math3d.ProjectPointOnLine(lineFact.Point1.Point, lineFact.Dir, Hits[i].point);
    
    MaZiFAU's avatar
    MaZiFAU committed
                else if (facts[i] is CircleFact circleFact)
    
    MaZiFAU's avatar
    MaZiFAU committed
                    var projPlane =
                        Math3d.ProjectPointOnPlane(circleFact.normal, circleFact.Point1.Point, Hits[i].point);
    
                    var circleDistance = projPlane - circleFact.Point1.Point;
                    if (circleDistance.magnitude >= circleFact.radius)
                    {
                        projPlane = circleFact.Point1.Point + circleDistance.normalized * circleFact.radius;
                        Hits[i].normal = circleDistance.normalized;
                    }
    
                    Hits[i].point = projPlane;
    
                else if (!deactSnapKey &&
                      (Hits[i].collider.transform.CompareTag("SnapZone")
                    || Hits[i].collider.transform.CompareTag("Selectable")))
    
    MaZiFAU's avatar
    MaZiFAU committed
                    Hits[i].point = Hits[i].collider.transform.position;
                    Hits[i].normal = Vector3.up;
    
                else
                    continue;
    
                break; // we had at least 1 succesfull case
            }
    
            if (i == Hits.Length)
                return; // no valid Hit
    
            Hits = Hits.Skip(i)
                   .TakeWhile(h => h.distance - Hits[i].distance < IntersectionDistance)
                   .ToArray();
    
            if (Hits.Length > 1)
            { // we have two or more objects intersecting
    
    MaZiFAU's avatar
    MaZiFAU committed
                if (facts[i + 0] is RayFact rayFact1
                 && facts[i + 1] is RayFact rayFact2)
    
    MaZiFAU's avatar
    MaZiFAU committed
                    if (Math3d.LineLineIntersection(out Vector3 intersectionPoint
                        , rayFact2.Point1.Point, rayFact2.Dir
                        , rayFact1.Point1.Point, rayFact1.Dir))
                    {
    
                        Hits[i + 0].point = intersectionPoint;
                        Hits[i + 1].point = intersectionPoint;
    
    MaZiFAU's avatar
    MaZiFAU committed
                //TODO: check for other types of intersection. Future Work
            }
    
            transform.up = Hits[0].normal;
            transform.position = Hits[0].point + .01f * Hits[0].normal;
    
    MaZiFAU's avatar
    MaZiFAU committed
            if (Input.GetMouseButtonDown(0))
                ClickHandler();
    
        private void UpdateMaxRange()
    
            switch (UIconfig.GameplayMode)
            {
    
                    UIconfig.interactingRangeMode = UIconfig.InteractingRangeMode.fromObserverView;
    
                    UIconfig.interactingRangeMode = UIconfig.InteractingRangeMode.fromCharacterView;
    
        private void ClickHandler()
    
            if (Hits[0].collider.transform.CompareTag("NPC1_text")
    
    MaZiFAU's avatar
    MaZiFAU committed
             && UIconfig.nextDialogPlease < 2)
                UIconfig.nextDialogPlease++;
    
    MaZiFAU's avatar
    MaZiFAU committed
            if (IsPointerOverUIObject() //Needed for Android. NOT JUST: EventSystem.current.IsPointerOverGameObject()
    
             || Hits[0].transform.gameObject.layer == LayerMask.NameToLayer("Water") // not allowed to meassure on water
             || Hits[0].collider.transform.CompareTag("NPC1_text"))                  // not allowed to meassure on textfields
    
    MaZiFAU's avatar
    MaZiFAU committed
                return;
    
    MaZiFAU's avatar
    MaZiFAU committed
            CommunicationEvents.TriggerEvent.Invoke(Hits);
            return;
    
    MaZiFAU's avatar
    MaZiFAU committed
            static bool IsPointerOverUIObject()
            {
                PointerEventData eventDataCurrentPosition = new(EventSystem.current)
    
    MaZiFAU's avatar
    MaZiFAU committed
                    position = new Vector2(Input.mousePosition.x, Input.mousePosition.y)
                };
    
    MaZiFAU's avatar
    MaZiFAU committed
                List<RaycastResult> results = new();
                EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
    
    MaZiFAU's avatar
    MaZiFAU committed
                return results.Count > 0;
            }