unity3d 缩放和移动光线投射命中的游戏对象,并在Unity中重置为原始对象

9udxz4iz  于 2023-04-21  发布在  其他
关注(0)|答案(1)|浏览(130)

我在Unity中使用Vuforia进行AR设置。我将下面的脚本放在一个空的GameObject上(它不是我的imagetarget的子对象),并在检查器中分配公共值。当找到Imagetarget时,会出现GameObjects。然后我通过Raycast(AR相机)选择对象。当涉及到缩放和移动GameObject时,会出现问题。
我无法将值设置回默认变换。我为localScale和position做了一个变通方案,其中我将一些值作为“limits”。但这实际上不是我想实现的。位置的行为非常奇怪。我唯一想实现的是命中对象-按值缩放并将对象向y移动-当未命中时,对象应该简单地重置为它的原始值。如果有人能帮助我解决这个问题就太好了。
先谢谢你了milla
我正在测试Unity3d 2021.3.9f和Vuforia 10.14.4。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ScaleOnHit : MonoBehaviour
{
    public Camera arCamera; // Reference to the AR camera in the scene

    [SerializeField] private string selectableTag = "Selectable";
   
    public Vector3 targetScale = new Vector3(0.02f, 0.02f, 0.02f);
    public Vector3 defaultScale = new Vector3(0.008f, 0.008f, 0.008f);
    public float duration = 2.0f;
    public float moveY = 0.01f;
    public AnimationCurve curve;
    private Transform _selection;

    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (_selection != null)
        {
            for (float time = 0; time < duration; time += Time.deltaTime)
            {
                // Calculate the current scale based on the elapsed time and set it
                float t = time / duration;
                var easing = curve.Evaluate(t);
                _selection.localScale = Vector3.Lerp(targetScale, defaultScale, easing);
                
            }
            _selection = null;
        }
        RaycastHit hit;
        Ray ray = new Ray(arCamera.transform.position, arCamera.transform.forward); // Create a ray from the AR camera position in the direction it's facing

        if (Physics.Raycast(ray, out hit)) // Check if the ray hits an object
        {
            GameObject store = hit.collider.gameObject;
        
            var selection = hit.transform;
        
            if (selection.CompareTag(selectableTag))
            {
                if (hit.transform.position.y < -1.0f || hit.transform.position.y > -0.5f)
                {
                    selection.position = new Vector3(
                       hit.transform.position.x,
                       hit.transform.position.y + moveY,
                       hit.transform.position.z);
                }
                for (float time = 0; time < duration; time += Time.deltaTime)
                {
                    float t = time / duration;
                    var easing = curve.Evaluate(t);
                    selection.localScale = Vector3.Lerp(defaultScale, targetScale, easing);  
                }
                
                _selection = selection;
            }
        }
    }
}
oalqel3c

oalqel3c1#

当前实现的问题是,缩放和移动代码在Update()函数中执行,该函数每帧调用一次。这意味着对于对象被选中的每一帧,缩放和移动代码将再次执行,从而导致意外行为。
要解决此问题,可以使用协程在一段时间内处理缩放和移动动画,然后在动画完成后将对象重置为默认值。
下面是ScaleOnHit脚本的更新版本,其中包含协程实现:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ScaleOnHit : MonoBehaviour
{
    public Camera arCamera; // Reference to the AR camera in the scene
[SerializeField] private string selectableTag = "Selectable";

public Vector3 targetScale = new Vector3(0.02f, 0.02f, 0.02f);
public Vector3 defaultScale = new Vector3(0.008f, 0.008f, 0.008f);
public float duration = 2.0f;
public float moveY = 0.01f;
public AnimationCurve curve;
private Transform _selection;
private bool isScaling = false;

void Update()
{
    RaycastHit hit;
    Ray ray = new Ray(arCamera.transform.position, arCamera.transform.forward); // Create a ray from the AR camera position in the direction it's facing

    if (Physics.Raycast(ray, out hit)) // Check if the ray hits an object
    {
        GameObject store = hit.collider.gameObject;

        var selection = hit.transform;

        if (selection.CompareTag(selectableTag))
        {
            if (hit.transform.position.y < -1.0f || hit.transform.position.y > -0.5f)
            {
                selection.position = new Vector3(
                   hit.transform.position.x,
                   hit.transform.position.y + moveY,
                   hit.transform.position.z);
            }

            if (_selection != selection && !isScaling)
            {
                StartCoroutine(ScaleAndMoveObject(selection));
            }

            _selection = selection;
        }
    }
    else if (_selection != null && !isScaling)
    {
        StartCoroutine(ResetObject());
    }
}

private IEnumerator ScaleAndMoveObject(Transform selection)
{
    isScaling = true;

    float timeElapsed = 0f;
    Vector3 startingScale = selection.localScale;
    Vector3 targetPosition = new Vector3(selection.position.x, selection.position.y + moveY, selection.position.z);

    while (timeElapsed < duration)
    {
        float t = timeElapsed / duration;
        var easing = curve.Evaluate(t);
        selection.localScale = Vector3.Lerp(startingScale, targetScale, easing);
        selection.position = Vector3.Lerp(selection.position, targetPosition, easing);
        timeElapsed += Time.deltaTime;
        yield return null;
    }

    isScaling = false;
}

private IEnumerator ResetObject()
{
    isScaling = true;

    float timeElapsed = 0f;
    Vector3 startingScale = _selection.localScale;
    Vector3 startingPosition = _selection.position;

    while (timeElapsed < duration)
    {
        float t = timeElapsed / duration;
        var easing = curve.Evaluate(t);
        _selection.localScale = Vector3.Lerp(startingScale, defaultScale, easing);
        _selection.position = Vector3.Lerp(startingPosition, new Vector3(startingPosition.x, startingPosition.y - moveY, startingPosition.z), easing);
        timeElapsed += Time.deltaTime;
        yield return null;
    }

    _selection = null;
    isScaling = false;
}

}

相关问题