首页 > 解决方案 > 在没有扫描目标的情况下生成游戏对象

问题描述

我有多个游戏对象作为 ImageTarget 的孩子。

Ar 相机 世界中心模式= first_target 跟踪设备姿态检查和定位

当我启动游戏模式时。

所有对象开始下落(球体碰撞器和网格渲染器关闭)。

当我扫描目标时,物体已经穿过我在它们下面的平面(平面上有一个网格对撞机)。

如果我在启动游戏模式后立即扫描目标,一切都按计划进行,球体会与飞机相撞并停留在其顶部。

是否可以在扫描目标之前冻结对象的 Y 轴以及如何启用扩展跟踪(只要我将相机从目标移开并重新扫描目标,对象就会穿过平面)。

标签: unity3dvuforia

解决方案


Vuforia 有DefaultTrackableEventHandler.. 代码很难找到(源代码),但它看起来像这样

/*==============================================================================
Copyright (c) 2017 PTC Inc. All Rights Reserved.
Copyright (c) 2010-2014 Qualcomm Connected Experiences, Inc.
All Rights Reserved.
Confidential and Proprietary - Protected under copyright and other laws.
==============================================================================*/

/*
 * Modified by PauloSalvatore on 04/03/2018 - 15:38 (GMT-3)
 *
 * Change Log:
 *
 * Track Events added on Inspector
 * Custom events can be added to be invoked during initialization,
 * when appear start, when object is appearing and when disappear start.
 */

using UnityEngine;
using UnityEngine.Events;
using Vuforia;

[System.Serializable]
public class TrackEvents
{
    #region PUBLIC_EVENTS

    public UnityEvent onInitialized;
    public UnityEvent onAppear;
    public UnityEvent isAppearing;
    public UnityEvent onDisappear;

    #endregion PUBLIC_EVENTS
}

/// <summary>
///     A custom handler that implements the ITrackableEventHandler interface.
/// </summary>
public class DefaultTrackableEventHandler : MonoBehaviour, ITrackableEventHandler
{
    #region PUBLIC_EVENTS

    public TrackEvents trackEvents;

    #endregion PUBLIC_EVENTS

    #region PRIVATE_MEMBER_VARIABLES

    protected TrackableBehaviour mTrackableBehaviour;

    #endregion PRIVATE_MEMBER_VARIABLES

    #region UNTIY_MONOBEHAVIOUR_METHODS

    protected virtual void Start()
    {
        mTrackableBehaviour = GetComponent<TrackableBehaviour>();
        if (mTrackableBehaviour)
            mTrackableBehaviour.RegisterTrackableEventHandler(this);

        // onInitialized custom events
        if (trackEvents.onInitialized != null)
            trackEvents.onInitialized.Invoke();
    }

    protected virtual void Update()
    {
        // isAppearing custom events
        if (trackEvents.isAppearing != null)
            trackEvents.isAppearing.Invoke();
    }

    #endregion UNTIY_MONOBEHAVIOUR_METHODS

    #region PUBLIC_METHODS

    /// <summary>
    ///     Implementation of the ITrackableEventHandler function called when the
    ///     tracking state changes.
    /// </summary>
    public void OnTrackableStateChanged(
        TrackableBehaviour.Status previousStatus,
        TrackableBehaviour.Status newStatus)
    {
        if (newStatus == TrackableBehaviour.Status.DETECTED ||
            newStatus == TrackableBehaviour.Status.TRACKED ||
            newStatus == TrackableBehaviour.Status.EXTENDED_TRACKED)
        {
            Debug.Log("Trackable " + mTrackableBehaviour.TrackableName + " found");
            OnTrackingFound();
        }
        else if (previousStatus == TrackableBehaviour.Status.TRACKED &&
                 newStatus == TrackableBehaviour.Status.NOT_FOUND)
        {
            Debug.Log("Trackable " + mTrackableBehaviour.TrackableName + " lost");
            OnTrackingLost();
        }
        else
        {
            // For combo of previousStatus=UNKNOWN + newStatus=UNKNOWN|NOT_FOUND
            // Vuforia is starting, but tracking has not been lost or found yet
            // Call OnTrackingLost() to hide the augmentations
            OnTrackingLost();
        }
    }

    #endregion PUBLIC_METHODS

    #region PRIVATE_METHODS

    protected virtual void OnTrackingFound()
    {
        var rendererComponents = GetComponentsInChildren<Renderer>(true);
        var colliderComponents = GetComponentsInChildren<Collider>(true);
        var canvasComponents = GetComponentsInChildren<Canvas>(true);

        // Enable rendering:
        foreach (var component in rendererComponents)
            component.enabled = true;

        // Enable colliders:
        foreach (var component in colliderComponents)
            component.enabled = true;

        // Enable canvas:
        foreach (var component in canvasComponents)
            component.enabled = true;

        // onAppear custom events
        if (trackEvents.onAppear != null)
            trackEvents.onAppear.Invoke();
    }

    protected virtual void OnTrackingLost()
    {
        var rendererComponents = GetComponentsInChildren<Renderer>(true);
        var colliderComponents = GetComponentsInChildren<Collider>(true);
        var canvasComponents = GetComponentsInChildren<Canvas>(true);

        // Disable rendering:
        foreach (var component in rendererComponents)
            component.enabled = false;

        // Disable colliders:
        foreach (var component in colliderComponents)
            component.enabled = false;

        // Disable canvas:
        foreach (var component in canvasComponents)
            component.enabled = false;

        // onDisappear custom events
        if (trackEvents.onDisappear != null)
            trackEvents.onDisappear.Invoke();
    }

    #endregion PRIVATE_METHODS
}

这应该放置在相应的 ImageTarget 或您正在使用的任何目标上,默认为 afaik。如您所见,如果目标丢失,他们将禁用Renderer,Collider等等……我个人总是会删除它,而是将其替换为,UnityEvent以便我以后可以决定应该发生什么,不应该发生什么。

由于这两种方法OnTrackingFound()OnTrackingLost()virtual可以继承DefaultTrackableEventHandler并覆盖/替换它们的功能。通过不调用base.OnTrackingFound()或者base.OnTrackingLost()我们告诉 c#执行父类最初实现的任何内容,而使用我们实现的内容:

// This is used to directly pass a string value into the event
// I'll explain why later ...
[Serializable]
public class VuforiaTargetFoundEvent : UnityEvent<string, Transform> { }

public MyTrackableEventHandler : DefaultTrackableEventHandler
{
    // Give this specific VuforiaTarget a certain custom ID
    // We will pass it dynamically into the UnityEvent
    // so every listener automatically also knows WHICH target
    // was lost or found
    public string TargetID;

    public VuforiaTargetEvent _OnTrackingFound;
    public VuforiaTargetEvent _OnTrackingLost;

    protected override void OnTrackingFound()
    {
        // call _OnTrackingFound with your specific target ID and
        // also pass in the Transform so every listener can know
        // WHICH target was found and WHERE it is positioned
        _OnTrackingFound?
    }

    protected override void OnTrackingLost()
    {
        // call _OnTrackingLost with your specific target ID and
        // also pass in the Transform so every listener can know
        // WHICH target was lost and WHERE it was last positioned
        _OnTrackingLost?
    }
}

只需将它放在 Vuforia 目标上,而不是DefaultTrackableEventHandler(如果它已经存在的话),所以现在默认情况下,不会禁用子级中的Renderer,等。Collider(如果您仍然需要它,您当然可以再次添加base.OnTrackingLost()base.OnTrackingFound()或者在单独的脚本中实现它,并在我们刚刚添加的回调中引用相应的方法UnityEvents;))


现在到你的坠落物体。一开始设置useGravityfalse这样他们就不会再跌倒了。然后作为回调一旦找到图像目标启用它。

public GravityEnabler : MonoBehaviour
{
    // either reference this in the Inspector ...
    public RigidBody _rigidBody;

    // also this either reference it in the Inspector ...
    public MyTrackableEventHandler target;

    // ... or get them on runtime
    private void Awake()
    {
        if(!_rigidBody) _rigidBody = GetComponent<RigidBody>();
        if(!target= target = FindObjectOfType<MyTrackableEventHandler>();

        // before start disable gravity
        _rigidBody.useGravity = false;

        // setup the callback for the target
        target._OnTrackingFound.AddListener(OnTargetScanned);
        target._OnTrackingLost.AddListener(OnTargetLost);
    }

    privtae void OnDestroy()
    {
        // If this object gets destroyed be sure to remove the callbacks
        // otherwise you would get exceptions because the callbacks
        // would still exist but point to a NULL reference
        target._OnTrackingFound.RemoveListener(OnTargetScanned);
        target._OnTrackingLost.RemoveListener(OnTargetLost);
    }

    public void OnTargetFound(string targetID, Transform targetTransform)
    {
        _rigidBody.useGravity = true;
    }

    public void OnTargetLost(string targetID, Transform targetTransform)
    {
        // If you need to do anything here
        // maybe you want to stop the falling again when the target is lost
        _rigidBody.useGravity = false;
        _rigidBody.velocity = Vector3.zero;
    }
}

把它放在你的每一个失败的对象上,如果可能的话,可能已经在 Inspector 中设置了引用(效率更高一点)。


推荐阅读