using System; using UnityEngine; using UnityEngine.EventSystems; using Framework.Selection; using Framework.Services; namespace Framework.Actors.Shooter { /// Highlights objects in the camera's center public class LookHighlighter : ScriptComponent { /// Tracker into which the selected objects are entered public SelectionTracker SelectionTracker; /// Maximum distance at which objects can be highlighted public float MaxDistance = 10.0f; /// Layers that will prevent highlighting from happening public LayerMask BlockingLayerMask = 0; /// Layers that can contain highlightable objects /// /// This should be any solid in-game object. Usually you'd exclude glass, water, /// user interface elements and such. /// public LayerMask HighlightableLayerMask = Physics.DefaultRaycastLayers; /// Called once per visual frame protected void Update() { // If the user is looking at a UI element, do not highlight things behind it! EventSystem currentEventSystem = EventSystem.current; if (currentEventSystem != null) { var lookInputModule = currentEventSystem.currentInputModule as LookInputModule; if (lookInputModule != null) { if (lookInputModule.ActivePointee != null) { setHighlightedObject(null); return; } } } // Good, user seems to be looking at the scene, so lets see if he's looking // at something that is selectable or highlightable Selectable target = RaycastSelectable(); if(target != null) { if(target.CanBeHighlighted) { setHighlightedObject(target); } else { setHighlightedObject(null); } } else { setHighlightedObject(null); } } /// Called when the component is removed from a game object protected void OnDestroy() { if(this.currentlyHighlighted != null) { setHighlightedObject(null); } } /// Called when the highlighter component gets disabled protected virtual void OnDisable() { if(this.currentlyHighlighted != null) { setHighlightedObject(null); } } /// Does a raycast to determine the currently highlighted game object /// The highlightable game object in the center of the view protected Selectable RaycastSelectable() { Selectable selectable; // Determine if the highlighter is pointing at a game object with a collider RaycastHit hitInfo; bool hitSomething = Physics.Raycast( transform.position, transform.forward, out hitInfo, this.MaxDistance, this.BlockingLayerMask | this.HighlightableLayerMask ); if (hitSomething) { // Check if the game object is on a layer that we should highlight { int gameObjectLayerMask = (1 << hitInfo.transform.gameObject.layer); hitSomething &= ((gameObjectLayerMask & this.HighlightableLayerMask) != 0); } if (hitSomething) { selectable = hitInfo.collider.GetComponentInParent(); } else { selectable = null; } #if UNITY_EDITOR Debug.DrawLine( transform.position, hitInfo.point, (selectable != null) ? Color.green : Color.red ); #endif //UNITY_EDITOR } else { selectable = null; } return selectable; } /// Updates the highlighted game object /// IHighlightable component of the highlighted object private void setHighlightedObject(Selectable highlighted) { //Debug.Log("Now highlighting " + ((highlighted == null) ? "" : ((Component)highlighted).name)); if(!ReferenceEquals(highlighted, this.currentlyHighlighted)) { if(this.currentlyHighlighted != null) { this.SelectionTracker.HighlightedObjects.Remove(this.currentlyHighlighted); } this.currentlyHighlighted = highlighted; if(highlighted != null) { this.SelectionTracker.HighlightedObjects.Add(highlighted); } } } /// IHighlightable component of the currently highlighted game object private Selectable currentlyHighlighted; } } // namespace Framework.Actors.Shooter