VRTK_PlayAreaCursor

提供跟踪指针光标位置的播放区域边界的可视化表示;

 // 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;//使用指针颜色:如果选中此项,则指针有效/无效颜色也将用于在碰撞/不碰撞时更改游戏区域光标的颜色
    [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;//播放区域光标尺寸:确定播放区域光标和对撞机的大小。如果值保留为零,则播放区域光标将调整为校准的播放区域空间。
    [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;//处理游戏区域光标碰撞:如果选中此项,则如果游戏区域光标与任何其他对象发生碰撞,则指针颜色将变为,Pointer Miss Color并且DestinationMarkerSet不会触发事件,这将阻止传送到游戏区域将发生碰撞的区域。
    [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;//耳机超出界限是碰撞:如果选中此项,则如果用户的耳机位于游戏区域光标范围之外,则即使游戏区域未与任何物体发生碰撞,也会将其视为碰撞。
    [Tooltip("If this is checked then the play area cursor will be displayed when the location is invalid.")]
    public bool displayOnInvalidLocation = true;//显示无效位置:如果选中此选项,则当位置无效时将显示播放区域光标
    [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;//方向指示器:用于确定游戏区域光标旋转的自定义指针方向指示器。
    [Tooltip("A custom GameObject to use for the play area cursor representation for when the location is valid.")]
    public GameObject validLocationObject;//有效位置对象:用于位置有效时的游戏区域光标表示的自定义GameObject。
    [Tooltip("A custom GameObject to use for the play area cursor representation for when the location is invalid.")]
    public GameObject invalidLocationObject;//无效的位置对象:用于播放区域光标表示的自定义GameObject,用于位置无效。

    /// <summary>
    /// Emitted when the play area collides with another object.
    /// </summary>
    public event PlayAreaCursorEventHandler PlayAreaCursorStartCollision;// 当游戏区域与另一个对象发生碰撞时发出。
    /// <summary>
    /// Emitted when the play area stops colliding with another object.
    /// </summary>
    public event PlayAreaCursorEventHandler PlayAreaCursorEndCollision;//当游戏区域停止与另一个物体碰撞时发出。

    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);//返回播放区域光标当前是否与另一个有效对象冲突的状态
    }

    /// <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;//确定在设置目标标记时是否应考虑耳机距游戏区域中心的偏移位置。如果true那时它将考虑偏移位置。
    }

    /// <summary>
    /// 确定是否应该使用播放区域光标考虑播放区域冲突
    /// 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>
    /// 设置播放区域光标上的当前材质颜色
    /// 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>
    /// 用于将世界空间中游戏区域光标的位置更新为给定位置
    /// 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>
    /// 启用或禁用播放区域光标的可见性
    /// 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>
    /// 返回游戏区域游标GameObject是否处于活动状态
    /// 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>
    /// 返回创建的GameObject,其中包含游戏区域光标表示
    /// 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>
    /// 启用或禁用播放区域光标渲染器以允许查看或隐藏光标
    /// 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)));
    }
  }
 }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容