Raycast同时点击2个对象

发布于 2025-02-11 08:19:52 字数 2560 浏览 0 评论 0原文

我最近开发了Unity,并且使用Raycast有问题。 我创建了3个脚本:

  • Interactor:挂在玩家中,它管理所有的raycast功能
  • 互动对象:挂在需要动画
  • 互动式播放的对象上:挂在需要销毁的对象上,

一切都起作用,唯一的问题是当动画的动画游戏对象发生(在我的情况下,游戏对象是枕头),另一个游戏对象(在枕头下)在动画开始的同时被销毁。 我的目标是首先移动枕头,然后单击要销毁的游戏对象,我该怎么办? 预先感谢您的帮助

Interactor.cs

public class Interactor : MonoBehaviour
{
    [SerializeField]
    private float _interctRange;
    private InteractionObject _interactObject;
    private InteractionRaycast _interactionRaycast;
    private Camera _camera;
    private RaycastHit _hit;
// Start is called before the first frame update
void Start()
{
    _camera = Camera.main;
}

// Update is called once per frame
void Update()
{
    if (Input.GetButton("Fire1"))
    {
        Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out _hit, _interctRange);
        if (_hit.transform)
        {
            _interactObject = _hit.transform.GetComponent<InteractionObject>();
            
        }
        if (_interactObject)
        {
            _interactObject.PerfomAction();
            
        }
   
    }
}
}

contractactionObject.cs

public class InteractionObject : MonoBehaviour
{
    [SerializeField]
    private Vector3 _openPosition, _closePosition;
    [SerializeField]
    private float _animationTime;
    private Hashtable _iTweenArgs;
    [SerializeField]
    public  bool _isOpen;

// Start is called before the first frame update
void Start()
{
    _iTweenArgs = iTween.Hash();
    _iTweenArgs.Add("position", _openPosition);
    _iTweenArgs.Add("time", _animationTime);
    _iTweenArgs.Add("islocal", true);
}

public void PerfomAction()
{
    if (Input.GetButton("Fire1"))
    {
        if (_isOpen)
        {
            _iTweenArgs["position"] = _closePosition;
        }
        else
        {
            _iTweenArgs["position"] = _openPosition;

        }

        _isOpen = !_isOpen;

        iTween.MoveTo(gameObject, _iTweenArgs);


    }
}



} 

conteractactraycast.cs

public class InteractionRaycast : MonoBehaviour
{
    [SerializeField]
    private float _range;
    Ray _myRay;
    RaycastHit _hit;

// Update is called once per frame
void Update()
{
    if (Input.GetButton("Fire1"))
    {
        Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out _hit, _range);
        if (_hit.transform)
        {
            Destroy(gameObject);
        }


    }

}
}

I have recently developed in unity and I have a problem with using the raycast.
I created 3 scripts:

  • Interactor: Hooked to the player, it manages all the raycast features
  • InteractionObject: Hooked to the objects that need to animate
  • InteractionRaycast: Hooked to objects that need to be destroyed

Everything works, the only problem is that when the animation of the gameobject takes place (In my case the gameobject was a pillow), the other gameobject (It is under the pillow) is destroyed at the same time as the animation begins.
My goal is to first move the pillow and then click on the gameobject to be destroyed, what can I do?
Thank you in advance for your help

Interactor.cs

public class Interactor : MonoBehaviour
{
    [SerializeField]
    private float _interctRange;
    private InteractionObject _interactObject;
    private InteractionRaycast _interactionRaycast;
    private Camera _camera;
    private RaycastHit _hit;
// Start is called before the first frame update
void Start()
{
    _camera = Camera.main;
}

// Update is called once per frame
void Update()
{
    if (Input.GetButton("Fire1"))
    {
        Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out _hit, _interctRange);
        if (_hit.transform)
        {
            _interactObject = _hit.transform.GetComponent<InteractionObject>();
            
        }
        if (_interactObject)
        {
            _interactObject.PerfomAction();
            
        }
   
    }
}
}

InteractionObject.cs

public class InteractionObject : MonoBehaviour
{
    [SerializeField]
    private Vector3 _openPosition, _closePosition;
    [SerializeField]
    private float _animationTime;
    private Hashtable _iTweenArgs;
    [SerializeField]
    public  bool _isOpen;

// Start is called before the first frame update
void Start()
{
    _iTweenArgs = iTween.Hash();
    _iTweenArgs.Add("position", _openPosition);
    _iTweenArgs.Add("time", _animationTime);
    _iTweenArgs.Add("islocal", true);
}

public void PerfomAction()
{
    if (Input.GetButton("Fire1"))
    {
        if (_isOpen)
        {
            _iTweenArgs["position"] = _closePosition;
        }
        else
        {
            _iTweenArgs["position"] = _openPosition;

        }

        _isOpen = !_isOpen;

        iTween.MoveTo(gameObject, _iTweenArgs);


    }
}



} 

InteractionRaycast.cs

public class InteractionRaycast : MonoBehaviour
{
    [SerializeField]
    private float _range;
    Ray _myRay;
    RaycastHit _hit;

// Update is called once per frame
void Update()
{
    if (Input.GetButton("Fire1"))
    {
        Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out _hit, _range);
        if (_hit.transform)
        {
            Destroy(gameObject);
        }


    }

}
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

错々过的事 2025-02-18 08:19:52

提示:使用raycastall()并根据条件过滤所需的对象。

尽管您首先要注意@derhugo的答案,但它可能会帮助您解决问题。它指出了许多方面,您需要在代码中改进。

Tip: Use RaycastAll() and filter out the objects you want based on conditions.

It might help you with your problem, although you first should pay attention to @derHugo answer. It points out many aspects that you will want to improve in your code.

信仰 2025-02-18 08:19:52

您的互动播放将销毁此自己的gameObject,无论您确切地击中什么,它都可以完全算了。

您要么要额外检查一下,例如

if (Input.GetButton("Fire1"))
{
    var ray = _camera.ViewportPointToRay(new Vector3(0.5f, 0.5f));
    if(Physics.Raycast(ray, out var hit, _interctRange))
    {
        // Is this actually the object that was hit?
        if(hit.transform == transform)
        {
            Destroy(gameObject);
        }
    }
}

- 通常我会这样做 - 而不是在您可以与您交互的每个对象上都有这样的组件并拍摄数百个冗余射线播,我宁愿在您的player对象上有一个组件,拍摄一个射线广播,并与您击中的任何内容进行互动。

您的两个目标对象都可以具有常见的接口

public interface IInteractionObject
{
    void PerfomAction();
}

这意味着两种类型都需要实现一个称为cormalaction没有参数的方法。

而是直接与之互动,

public class Interactor : MonoBehaviour
{
    [SerializeField]
    private float _interctRange;
   
    private Camera _camera;

    // Start is called before the first frame update
    void Start()
    {
        _camera = Camera.main;
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetButton("Fire1"))
        {
            var ray = _camera.ViewportPointToRay(new Vector3(0.5f, 0.5f));
            // was something hit at all? => Check the API and return values of methods!
            if(Physics.Raycast(ray, out var hit, _interctRange))
            {
                // Did we hit an IInteractionObject
                if(hit.transform.TryGetComponent<IInteractionObject>(out var interactable))
                {
                    // This class has no idea what exactly it is interacting with and doesn't need to know
                    interactable.PerfomAction();
                }
            }
        }
    }
}

然后您有不同的实现

public class AnimatedInteractionObject : MonoBehaviour, IInteractionObject
{
    [SerializeField] private Vector3 _openPosition;
    [SerializeField] private Vector3 _closePosition;
    [SerializeField] private float _animationTime;
    [SerializeField] public bool _isOpen;

    private Hashtable _iTweenArgs;

    private void Start()
    {
        _iTweenArgs = iTween.Hash();
        _iTweenArgs.Add("position", _openPosition);
        _iTweenArgs.Add("time", _animationTime);
        _iTweenArgs.Add("islocal", true);
    }
    
    public void PerfomAction()
    {
        _isOpen = !_isOpen;

        // use ternary makes it easier to read
        _iTweenArgs["position"] = _isOpen ? _openPosition : _closePosition;
    
        iTween.MoveTo(gameObject, _iTweenArgs);
    }
} 

public class DestroyInteractionObject : MonoBehaviour, IInteractionObject
{
    public void PerfomAction()
    {
        // This is only called by the Interactor 
        // it already does a key and raycast check so no need to do that here 
        Destroy(gameObject);
    }
}

Your InteractionRaycast will destroy this own gameObject it is attaced to completely regardless of what exactly you are hitting.

You either want to additionally check like e.g.

if (Input.GetButton("Fire1"))
{
    var ray = _camera.ViewportPointToRay(new Vector3(0.5f, 0.5f));
    if(Physics.Raycast(ray, out var hit, _interctRange))
    {
        // Is this actually the object that was hit?
        if(hit.transform == transform)
        {
            Destroy(gameObject);
        }
    }
}

Or - and in general I would do that - instead of having such a component on each and every object you can interact with and shooting hundreds of redundant raycasts, I would rather have a component on your player object, shoot one single raycast and interact with whatever you hit.

Both your target objects can have a common interface

public interface IInteractionObject
{
    void PerfomAction();
}

meaning both types need to implement a method called PerformAction without parameters.

And rather interact directly with that in

public class Interactor : MonoBehaviour
{
    [SerializeField]
    private float _interctRange;
   
    private Camera _camera;

    // Start is called before the first frame update
    void Start()
    {
        _camera = Camera.main;
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetButton("Fire1"))
        {
            var ray = _camera.ViewportPointToRay(new Vector3(0.5f, 0.5f));
            // was something hit at all? => Check the API and return values of methods!
            if(Physics.Raycast(ray, out var hit, _interctRange))
            {
                // Did we hit an IInteractionObject
                if(hit.transform.TryGetComponent<IInteractionObject>(out var interactable))
                {
                    // This class has no idea what exactly it is interacting with and doesn't need to know
                    interactable.PerfomAction();
                }
            }
        }
    }
}

and then you have different implementations:

public class AnimatedInteractionObject : MonoBehaviour, IInteractionObject
{
    [SerializeField] private Vector3 _openPosition;
    [SerializeField] private Vector3 _closePosition;
    [SerializeField] private float _animationTime;
    [SerializeField] public bool _isOpen;

    private Hashtable _iTweenArgs;

    private void Start()
    {
        _iTweenArgs = iTween.Hash();
        _iTweenArgs.Add("position", _openPosition);
        _iTweenArgs.Add("time", _animationTime);
        _iTweenArgs.Add("islocal", true);
    }
    
    public void PerfomAction()
    {
        _isOpen = !_isOpen;

        // use ternary makes it easier to read
        _iTweenArgs["position"] = _isOpen ? _openPosition : _closePosition;
    
        iTween.MoveTo(gameObject, _iTweenArgs);
    }
} 

and

public class DestroyInteractionObject : MonoBehaviour, IInteractionObject
{
    public void PerfomAction()
    {
        // This is only called by the Interactor 
        // it already does a key and raycast check so no need to do that here 
        Destroy(gameObject);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文