VRTK_PlayAreaCursor

提供跟蹤指針光標位置的播放區(qū)域邊界的可視化表示;

 // Play Area Cursor|Pointers|10050
namespace VRTK
{
using UnityEngine;

/// <summary>
/// Event Payload
/// </summary>
/// <param name="collidedWith">The collider that is/was being collided with.</param>
public struct PlayAreaCursorEventArgs
{
    public Collider collider;//
}

/// <summary>
/// Event Payload
/// </summary>
/// <param name="sender">this object</param>
/// <param name="e"><see cref="PlayAreaCursorEventArgs"/></param>
public delegate void PlayAreaCursorEventHandler(object sender, PlayAreaCursorEventArgs e);

/// <summary>
/// Provides a visual representation of the play area boundaries that tracks to the cursor position of a pointer.
/// </summary>
/// <remarks>
/// **Optional Components:**
///  * `VRTK_PointerDirectionIndicator` - A Pointer Direction Indicator to set the cursor rotation to.
/// 
/// **Script Usage:**
///  * Place the `VRTK_PlayAreaCursor` script on the same GameObject as the Pointer Renderer script it is linked to.
///  * Link the required Play Area Cursor script to the `Playarea Cursor` parameter on the required Pointer Renderer script.
///
/// **Script Dependencies:**
///  * A Base Pointer Renderer script attached to a valid Pointer script is required so the PlayArea Cursor script can be linked to follow the valid Base Pointer Renderer cursor GameObject.
/// </remarks>
/// <example>
/// `VRTK/Examples/012_Controller_PointerWithAreaCollision` shows how a Bezier Pointer with the Play Area Cursor and Collision Detection enabled can be used to traverse a game area but not allow teleporting into areas where the walls or other objects would fall into the play area space enabling the user to enter walls.
/// </example>
[AddComponentMenu("VRTK/Scripts/Pointers/VRTK_PlayAreaCursor")]
public class VRTK_PlayAreaCursor : MonoBehaviour
{
    [Header("Appearance Settings")]

    [Tooltip("If this is checked then the pointer valid/invalid colours will also be used to change the colour of the play area cursor when colliding/not colliding.")]
    public bool usePointerColor = true;//使用指針顏色:如果選中此項嘹叫,則指針有效/無效顏色也將用于在碰撞/不碰撞時更改游戲區(qū)域光標的顏色
    [Tooltip("Determines the size of the play area cursor and collider. If the values are left as zero then the Play Area Cursor will be sized to the calibrated Play Area space.")]
    public Vector2 playAreaCursorDimensions = Vector2.zero;//播放區(qū)域光標尺寸:確定播放區(qū)域光標和對撞機的大小筒占。如果值保留為零,則播放區(qū)域光標將調(diào)整為校準的播放區(qū)域空間谦絮。
    [Tooltip("If this is checked then if the play area cursor is colliding with any other object then the pointer colour will change to the `Pointer Miss Color` and the `DestinationMarkerSet` event will not be triggered, which will prevent teleporting into areas where the play area will collide.")]
    public bool handlePlayAreaCursorCollisions = false;//處理游戲區(qū)域光標碰撞:如果選中此項,則如果游戲區(qū)域光標與任何其他對象發(fā)生碰撞拷淘,則指針顏色將變?yōu)椴叻停琍ointer Miss Color并且DestinationMarkerSet不會觸發(fā)事件逛裤,這將阻止傳送到游戲區(qū)域?qū)l(fā)生碰撞的區(qū)域。
    [Tooltip("If this is checked then if the user's headset is outside of the play area cursor bounds then it is considered a collision even if the play area isn't colliding with anything.")]
    public bool headsetOutOfBoundsIsCollision = false;//耳機超出界限是碰撞:如果選中此項猴抹,則如果用戶的耳機位于游戲區(qū)域光標范圍之外带族,則即使游戲區(qū)域未與任何物體發(fā)生碰撞,也會將其視為碰撞蟀给。
    [Tooltip("If this is checked then the play area cursor will be displayed when the location is invalid.")]
    public bool displayOnInvalidLocation = true;//顯示無效位置:如果選中此選項蝙砌,則當位置無效時將顯示播放區(qū)域光標
    [Tooltip("A specified VRTK_PolicyList to use to determine whether the play area cursor collisions will be acted upon.")]
    public VRTK_PolicyList targetListPolicy;

    [Header("Custom Settings")]
    [Tooltip("A custom Pointer Direction Indicator to use to determine the rotation of the Play Area Cursor.")]
    public VRTK_PointerDirectionIndicator directionIndicator;//方向指示器:用于確定游戲區(qū)域光標旋轉(zhuǎn)的自定義指針方向指示器。
    [Tooltip("A custom GameObject to use for the play area cursor representation for when the location is valid.")]
    public GameObject validLocationObject;//有效位置對象:用于位置有效時的游戲區(qū)域光標表示的自定義GameObject跋理。
    [Tooltip("A custom GameObject to use for the play area cursor representation for when the location is invalid.")]
    public GameObject invalidLocationObject;//無效的位置對象:用于播放區(qū)域光標表示的自定義GameObject择克,用于位置無效。

    /// <summary>
    /// Emitted when the play area collides with another object.
    /// </summary>
    public event PlayAreaCursorEventHandler PlayAreaCursorStartCollision;// 當游戲區(qū)域與另一個對象發(fā)生碰撞時發(fā)出前普。
    /// <summary>
    /// Emitted when the play area stops colliding with another object.
    /// </summary>
    public event PlayAreaCursorEventHandler PlayAreaCursorEndCollision;//當游戲區(qū)域停止與另一個物體碰撞時發(fā)出肚邢。

    protected bool headsetPositionCompensation;
    protected bool playAreaCursorCollided = false;
    protected bool headsetOutOfBounds = false;
    protected Transform playArea;
    protected GameObject playAreaCursor;
    protected GameObject[] playAreaCursorBoundaries;
    protected BoxCollider playAreaCursorCollider;
    protected Transform headset;
    protected Renderer[] boundaryRenderers = new Renderer[0];
    protected GameObject playAreaCursorValidChild;
    protected GameObject playAreaCursorInvalidChild;

    protected int btmRightInner = 0;
    protected int btmLeftInner = 1;
    protected int topLeftInner = 2;
    protected int topRightInner = 3;
    protected int btmRightOuter = 4;
    protected int btmLeftOuter = 5;
    protected int topLeftOuter = 6;
    protected int topRightOuter = 7;

    public virtual void OnPlayAreaCursorStartCollision(PlayAreaCursorEventArgs e)
    {
        if (PlayAreaCursorStartCollision != null)
        {
            PlayAreaCursorStartCollision(this, e);
        }
    }

    public virtual void OnPlayAreaCursorEndCollision(PlayAreaCursorEventArgs e)
    {
        if (PlayAreaCursorEndCollision != null)
        {
            PlayAreaCursorEndCollision(this, e);
        }
    }

    /// <summary>
    /// The HasCollided method returns the state of whether the play area cursor has currently collided with another valid object.
    /// </summary>
    /// <returns>Returns `true` if the play area is colliding with a valid object and `false` if not.</returns>
    public virtual bool HasCollided()
    {
        return (playAreaCursorCollided || headsetOutOfBounds);//返回播放區(qū)域光標當前是否與另一個有效對象沖突的狀態(tài)
    }

    /// <summary>
    /// The SetHeadsetPositionCompensation method determines whether the offset position of the headset from the centre of the play area should be taken into consideration when setting the destination marker. If `true` then it will take the offset position into consideration.
    /// </summary>
    /// <param name="state">The state of whether to take the position of the headset within the play area into account when setting the destination marker.</param>
    public virtual void SetHeadsetPositionCompensation(bool state)
    {
        headsetPositionCompensation = state;//確定在設(shè)置目標標記時是否應(yīng)考慮耳機距游戲區(qū)域中心的偏移位置。如果true那時它將考慮偏移位置拭卿。
    }

    /// <summary>
    /// 確定是否應(yīng)該使用播放區(qū)域光標考慮播放區(qū)域沖突
    /// The SetPlayAreaCursorCollision method determines whether play area collisions should be taken into consideration with the play area cursor.
    /// </summary>
    /// <param name="state">The state of whether to check for play area collisions.</param>
    /// <param name="collider">The state of whether to check for play area collisions.</param>
    public virtual void SetPlayAreaCursorCollision(bool state, Collider collider = null)
    {
        playAreaCursorCollided = false;
        if (handlePlayAreaCursorCollisions)
        {
            playAreaCursorCollided = (!enabled ? false : state);
            EmitEvent(collider);
        }
    }

    /// <summary>
    /// 設(shè)置播放區(qū)域光標上的當前材質(zhì)顏色
    /// The SetMaterialColor method sets the current material colour on the play area cursor.
    /// </summary>
    /// <param name="color">The colour to update the play area cursor material to.</param>
    /// <param name="validity">Determines if the colour being set is based from a valid location or invalid location.</param>
    public virtual void SetMaterialColor(Color color, bool validity)
    {
        if (validLocationObject == null)
        {
            ToggleVisibility(!(!validity && !displayOnInvalidLocation));

            if (usePointerColor)
            {
                for (int i = 0; i < playAreaCursorBoundaries.Length; i++)
                {
                    SetCursorColor(playAreaCursorBoundaries[i], color);
                }
            }
        }
        else
        {
            ToggleValidPlayAreaState(!playAreaCursorCollided);
            if (usePointerColor)
            {
                SetCursorColor(playAreaCursor, color);
            }
        }
    }

    /// <summary>
    /// 用于將世界空間中游戲區(qū)域光標的位置更新為給定位置
    /// The SetPlayAreaCursorTransform method is used to update the position of the play area cursor in world space to the given location.
    /// </summary>
    /// <param name="location">The location where to draw the play area cursor.</param>
    public virtual void SetPlayAreaCursorTransform(Vector3 location)
    {
        Vector3 offset = Vector3.zero;
        if (headsetPositionCompensation)
        {
            Vector3 playAreaPos = new Vector3(playArea.transform.position.x, 0f, playArea.transform.position.z);
            Vector3 headsetPos = new Vector3(headset.position.x, 0f, headset.position.z);
            offset = playAreaPos - headsetPos;
        }

        if (playAreaCursor != null)
        {
            if (playAreaCursor.activeInHierarchy && handlePlayAreaCursorCollisions && headsetOutOfBoundsIsCollision)
            {
                Vector3 checkPoint = new Vector3(location.x, playAreaCursor.transform.position.y + (playAreaCursor.transform.localScale.y * 2), location.z);
                if (!playAreaCursorCollider.bounds.Contains(checkPoint))
                {
                    headsetOutOfBounds = true;
                }
                else
                {
                    headsetOutOfBounds = false;
                }
            }
            playAreaCursor.transform.rotation = (directionIndicator != null && directionIndicator.gameObject.activeInHierarchy ? directionIndicator.transform.rotation : playArea.rotation);
            playAreaCursor.transform.position = location + offset;
        }
    }

    /// <summary>
    /// 啟用或禁用播放區(qū)域光標的可見性
    /// The ToggleState method enables or disables the visibility of the play area cursor.
    /// </summary>
    /// <param name="state">The state of whether to show or hide the play area cursor.</param>
    public virtual void ToggleState(bool state)
    {
        state = (!enabled ? false : state);
        if (playAreaCursor != null)
        {
            playAreaCursor.SetActive(state);
        }
    }

    /// <summary>
    /// 返回游戲區(qū)域游標GameObject是否處于活動狀態(tài)
    /// The IsActive method returns whether the play area cursor GameObject is active or not.
    /// </summary>
    /// <returns>Returns `true` if the play area cursor GameObject is active.</returns>
    public virtual bool IsActive()
    {
        return (playAreaCursor != null ? playAreaCursor.activeInHierarchy : false);
    }

    /// <summary>
    /// 返回創(chuàng)建的GameObject道偷,其中包含游戲區(qū)域光標表示
    /// The GetPlayAreaContainer method returns the created GameObject that holds the play area cursor representation.
    /// </summary>
    /// <returns>The GameObject that is the container of the play area cursor.</returns>
    public virtual GameObject GetPlayAreaContainer()
    {
        return playAreaCursor;
    }

    /// <summary>
    /// 啟用或禁用播放區(qū)域光標渲染器以允許查看或隱藏光標
    /// The ToggleVisibility method enables or disables the play area cursor renderers to allow the cursor to be seen or hidden.
    /// </summary>
    /// <param name="state">The state of the cursor visibility. True will show the renderers and false will hide the renderers.</param>
    public virtual void ToggleVisibility(bool state)
    {
        if (playAreaCursor != null && boundaryRenderers.Length == 0)
        {
            boundaryRenderers = playAreaCursor.GetComponentsInChildren<Renderer>();
        }

        for (int i = 0; i < boundaryRenderers.Length; i++)
        {
            if (boundaryRenderers[i] != null)
            {
                boundaryRenderers[i].enabled = state;
            }
        }
    }

    protected virtual void Awake()
    {
        VRTK_SDKManager.AttemptAddBehaviourToToggleOnLoadedSetupChange(this);
    }

    protected virtual void OnEnable()
    {
        VRTK_PlayerObject.SetPlayerObject(gameObject, VRTK_PlayerObject.ObjectTypes.Pointer);

        headset = VRTK_DeviceFinder.HeadsetTransform();
        playArea = VRTK_DeviceFinder.PlayAreaTransform();
        playAreaCursorBoundaries = new GameObject[4];
        InitPlayAreaCursor();
    }

    protected virtual void OnDisable()
    {
        if (playAreaCursor != null)
        {
            Destroy(playAreaCursor);
        }
    }

    protected virtual void OnDestroy()
    {
        VRTK_SDKManager.AttemptRemoveBehaviourToToggleOnLoadedSetupChange(this);
    }

    protected virtual void Update()
    {
        if (enabled && IsActive())
        {
            UpdateCollider();
        }
    }

    protected virtual PlayAreaCursorEventArgs SetEventPayload(Collider collider)
    {
        PlayAreaCursorEventArgs e;
        e.collider = collider;
        return e;
    }

    protected virtual void EmitEvent(Collider collider)
    {
        if (collider != null)
        {
            if (playAreaCursorCollided)
            {
                OnPlayAreaCursorStartCollision(SetEventPayload(collider));
            }
            else
            {
                OnPlayAreaCursorEndCollision(SetEventPayload(collider));
            }
        }
    }

    protected virtual void InitPlayAreaCursor()
    {
        if (playArea == null)
        {
            VRTK_Logger.Error(VRTK_Logger.GetCommonMessage(VRTK_Logger.CommonMessageKeys.SDK_OBJECT_NOT_FOUND, "PlayArea", "Boundaries SDK"));
            return;
        }

        Vector3[] cursorDrawVertices = VRTK_SDK_Bridge.GetPlayAreaVertices();
        if (validLocationObject != null)
        {
            GeneratePlayAreaCursorFromPrefab(cursorDrawVertices);
        }
        else
        {
            if (cursorDrawVertices == null || cursorDrawVertices.Length < 8)
            {
                cursorDrawVertices = new Vector3[] {
                    new Vector3(0.8f, 0f, -0.8f),
                    new Vector3(-0.8f, 0f, -0.8f),
                    new Vector3(-0.8f, 0f, 0.8f),
                    new Vector3(0.8f, 0f, 0.8f),
                    new Vector3(1f, 0f, -1f),
                    new Vector3(-1f, 0f, -1f),
                    new Vector3(-1f, 0f, 1f),
                    new Vector3(1f, 0f, 1f) };
            }
            GeneratePlayAreaCursor(cursorDrawVertices);
        }

        if (playAreaCursor != null)
        {
            playAreaCursor.SetActive(false);
            VRTK_PlayerObject.SetPlayerObject(playAreaCursor, VRTK_PlayerObject.ObjectTypes.Pointer);
            CreateCursorCollider(playAreaCursor);
            playAreaCursor.AddComponent<Rigidbody>().isKinematic = true;

            VRTK_PlayAreaCollider playAreaCursorScript = playAreaCursor.AddComponent<VRTK_PlayAreaCollider>();
            playAreaCursorScript.SetParent(this);
            playAreaCursorScript.SetIgnoreTarget(targetListPolicy);
            playAreaCursor.layer = LayerMask.NameToLayer("Ignore Raycast");
        }
    }

    protected virtual void SetCursorColor(GameObject cursorObject, Color color)
    {
        Renderer playareaRenderer = cursorObject.GetComponentInChildren<Renderer>();

        if (playareaRenderer != null && playareaRenderer.material && playareaRenderer.material.HasProperty("_Color"))
        {
            playareaRenderer.material.color = color;
            playareaRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
            playareaRenderer.receiveShadows = false;
        }
    }


    protected virtual void ToggleValidPlayAreaState(bool state)
    {
        if (playAreaCursorValidChild != null)
        {
            playAreaCursorValidChild.SetActive(state);
        }
        if (playAreaCursorInvalidChild != null)
        {
            playAreaCursorInvalidChild.SetActive((displayOnInvalidLocation ? !state : false));
        }
    }

    protected virtual string GeneratePlayAreaCursorName()
    {
        return VRTK_SharedMethods.GenerateVRTKObjectName(true, gameObject.name, "PlayAreaCursor");
    }

    protected virtual void GeneratePlayAreaCursorFromPrefab(Vector3[] cursorDrawVertices)
    {
        playAreaCursor = new GameObject(GeneratePlayAreaCursorName());

        float width = cursorDrawVertices[btmRightOuter].x - cursorDrawVertices[topLeftOuter].x;
        float length = cursorDrawVertices[topLeftOuter].z - cursorDrawVertices[btmRightOuter].z;
        if (playAreaCursorDimensions != Vector2.zero)
        {
            width = (playAreaCursorDimensions.x == 0 ? playAreaCursor.transform.localScale.x : playAreaCursorDimensions.x);
            length = (playAreaCursorDimensions.y == 0 ? playAreaCursor.transform.localScale.z : playAreaCursorDimensions.y);
        }
        float height = 0.01f;

        playAreaCursorValidChild = Instantiate(validLocationObject);
        playAreaCursorValidChild.name = VRTK_SharedMethods.GenerateVRTKObjectName(true, "ValidArea");
        playAreaCursorValidChild.transform.SetParent(playAreaCursor.transform);

        if (invalidLocationObject != null)
        {
            playAreaCursorInvalidChild = Instantiate(invalidLocationObject);
            playAreaCursorInvalidChild.name = VRTK_SharedMethods.GenerateVRTKObjectName(true, "InvalidArea");
            playAreaCursorInvalidChild.transform.SetParent(playAreaCursor.transform);
        }

        playAreaCursor.transform.localScale = new Vector3(width, height, length);
        playAreaCursorValidChild.transform.localScale = Vector3.one;
        if (invalidLocationObject != null)
        {
            playAreaCursorInvalidChild.transform.localScale = Vector3.one;
        }
        playAreaCursor.SetActive(false);
    }

    protected virtual void GeneratePlayAreaCursor(Vector3[] cursorDrawVertices)
    {
        if (playAreaCursorDimensions != Vector2.zero)
        {
            float customAreaPadding = VRTK_SDK_Bridge.GetPlayAreaBorderThickness();

            cursorDrawVertices[btmRightOuter] = new Vector3(playAreaCursorDimensions.x / 2, 0f, (playAreaCursorDimensions.y / 2) * -1);
            cursorDrawVertices[btmLeftOuter] = new Vector3((playAreaCursorDimensions.x / 2) * -1, 0f, (playAreaCursorDimensions.y / 2) * -1);
            cursorDrawVertices[topLeftOuter] = new Vector3((playAreaCursorDimensions.x / 2) * -1, 0f, playAreaCursorDimensions.y / 2);
            cursorDrawVertices[topRightOuter] = new Vector3(playAreaCursorDimensions.x / 2, 0f, playAreaCursorDimensions.y / 2);

            cursorDrawVertices[btmRightInner] = cursorDrawVertices[btmRightOuter] + new Vector3(-customAreaPadding, 0f, customAreaPadding);
            cursorDrawVertices[btmLeftInner] = cursorDrawVertices[btmLeftOuter] + new Vector3(customAreaPadding, 0f, customAreaPadding);
            cursorDrawVertices[topLeftInner] = cursorDrawVertices[topLeftOuter] + new Vector3(customAreaPadding, 0f, -customAreaPadding);
            cursorDrawVertices[topRightInner] = cursorDrawVertices[topRightOuter] + new Vector3(-customAreaPadding, 0f, -customAreaPadding);
        }

        float width = cursorDrawVertices[btmRightOuter].x - cursorDrawVertices[topLeftOuter].x;
        float length = cursorDrawVertices[topLeftOuter].z - cursorDrawVertices[btmRightOuter].z;
        float height = 0.01f;

        playAreaCursor = new GameObject(GeneratePlayAreaCursorName());
        playAreaCursor.transform.SetParent(null);
        playAreaCursor.transform.localScale = new Vector3(width, height, length);

        float playAreaBoundaryX = playArea.transform.localScale.x / 2;
        float playAreaBoundaryZ = playArea.transform.localScale.z / 2;
        float heightOffset = 0f;

        DrawPlayAreaCursorBoundary(0, cursorDrawVertices[btmLeftOuter].x, cursorDrawVertices[btmRightOuter].x, cursorDrawVertices[btmRightInner].z, cursorDrawVertices[btmRightOuter].z, height, new Vector3(0f, heightOffset, playAreaBoundaryZ));
        DrawPlayAreaCursorBoundary(1, cursorDrawVertices[btmLeftOuter].x, cursorDrawVertices[btmLeftInner].x, cursorDrawVertices[topLeftOuter].z, cursorDrawVertices[btmLeftOuter].z, height, new Vector3(playAreaBoundaryX, heightOffset, 0f));
        DrawPlayAreaCursorBoundary(2, cursorDrawVertices[btmLeftOuter].x, cursorDrawVertices[btmRightOuter].x, cursorDrawVertices[btmRightInner].z, cursorDrawVertices[btmRightOuter].z, height, new Vector3(0f, heightOffset, -playAreaBoundaryZ));
        DrawPlayAreaCursorBoundary(3, cursorDrawVertices[btmLeftOuter].x, cursorDrawVertices[btmLeftInner].x, cursorDrawVertices[topLeftOuter].z, cursorDrawVertices[btmLeftOuter].z, height, new Vector3(-playAreaBoundaryX, heightOffset, 0f));
    }

    protected virtual void DrawPlayAreaCursorBoundary(int index, float left, float right, float top, float bottom, float thickness, Vector3 localPosition)
    {
        GameObject playAreaCursorBoundary = GameObject.CreatePrimitive(PrimitiveType.Cube);
        playAreaCursorBoundary.name = VRTK_SharedMethods.GenerateVRTKObjectName(true, gameObject.name, "PlayAreaCursorBoundary", index);
        VRTK_PlayerObject.SetPlayerObject(playAreaCursorBoundary, VRTK_PlayerObject.ObjectTypes.Pointer);

        float width = (right - left) / 1.065f;
        float length = (top - bottom) / 1.08f;
        float height = thickness;

        playAreaCursorBoundary.transform.localScale = new Vector3(width, height, length);
        Destroy(playAreaCursorBoundary.GetComponent<BoxCollider>());
        playAreaCursorBoundary.layer = LayerMask.NameToLayer("Ignore Raycast");

        playAreaCursorBoundary.transform.SetParent(playAreaCursor.transform);
        playAreaCursorBoundary.transform.localPosition = localPosition;

        playAreaCursorBoundaries[index] = playAreaCursorBoundary;
    }

    protected virtual void CreateCursorCollider(GameObject cursor)
    {
        playAreaCursorCollider = cursor.AddComponent<BoxCollider>();
        playAreaCursorCollider.isTrigger = true;
        playAreaCursorCollider.center = new Vector3(0f, 65f, 0f);
        playAreaCursorCollider.size = new Vector3(1f, 1f, 1f);
    }

    protected virtual void UpdateCollider()
    {
        float playAreaHeightAdjustment = 1f;
        float newBCYSize = (headset.transform.position.y - playArea.transform.position.y) * 100f;
        float newBCYCenter = (newBCYSize != 0 ? (newBCYSize / 2) + playAreaHeightAdjustment : 0);

        playAreaCursorCollider.size = new Vector3(playAreaCursorCollider.size.x, newBCYSize, playAreaCursorCollider.size.z);
        playAreaCursorCollider.center = new Vector3(playAreaCursorCollider.center.x, newBCYCenter, playAreaCursorCollider.center.z);
    }
}

public class VRTK_PlayAreaCollider : MonoBehaviour
{
    protected VRTK_PlayAreaCursor parent;
    protected VRTK_PolicyList targetListPolicy;

    public virtual void SetParent(VRTK_PlayAreaCursor setParent)
    {
        parent = setParent;
    }

    public virtual void SetIgnoreTarget(VRTK_PolicyList list = null)
    {
        targetListPolicy = list;
    }

    protected virtual void OnDisable()
    {
        if (parent != null)
        {
            parent.SetPlayAreaCursorCollision(false);
        }
    }

    protected virtual void OnTriggerStay(Collider collider)
    {
        if (parent != null && parent.enabled && parent.gameObject.activeInHierarchy && ValidTarget(collider))
        {
            parent.SetPlayAreaCursorCollision(true, collider);
        }
    }

    protected virtual void OnTriggerExit(Collider collider)
    {
        if (parent != null && ValidTarget(collider))
        {
            parent.SetPlayAreaCursorCollision(false, collider);
        }
    }

    protected virtual bool ValidTarget(Collider collider)
    {
        return (!collider.isTrigger && !VRTK_PlayerObject.IsPlayerObject(collider.gameObject) && !(VRTK_PolicyList.Check(collider.gameObject, targetListPolicy)));
    }
  }
 }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市记劈,隨后出現(xiàn)的幾起案子勺鸦,更是在濱河造成了極大的恐慌,老刑警劉巖目木,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件换途,死亡現(xiàn)場離奇詭異,居然都是意外死亡刽射,警方通過查閱死者的電腦和手機军拟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來誓禁,“玉大人懈息,你說我怎么就攤上這事∧∏。” “怎么了辫继?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長俗慈。 經(jīng)常有香客問我姑宽,道長穿肄,這世上最難降的妖魔是什么繁成? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮记焊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瘦穆。我一直安慰自己纪隙,他們只是感情好,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布扛或。 她就那樣靜靜地躺著瘫拣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪告喊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天派昧,我揣著相機與錄音黔姜,去河邊找鬼。 笑死蒂萎,一個胖子當著我的面吹牛秆吵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播五慈,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼纳寂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了泻拦?” 一聲冷哼從身側(cè)響起毙芜,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎争拐,沒想到半個月后腋粥,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡架曹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年隘冲,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绑雄。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡展辞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出万牺,到底是詐尸還是另有隱情罗珍,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布脚粟,位于F島的核電站靡砌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏珊楼。R本人自食惡果不足惜通殃,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧画舌,春花似錦堕担、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至朋腋,卻和暖如春齐疙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背旭咽。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工贞奋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人穷绵。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓轿塔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親仲墨。 傳聞我的和親對象是個殘疾皇子勾缭,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容