【问题标题】:how to detect which gameobject is clicked如何检测点击了哪个游戏对象
【发布时间】:2020-03-13 07:34:20
【问题描述】:

我想知道在 2D 项目上用鼠标点击了哪个游戏对象

我用过

 void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            clickTime = DateTime.Now;
            mousePosition = Input.mousePosition;

            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction);

            if (hit != null && hit.collider != null)
            {


            }

        }
}

但它永远不会进入第二个 if 条件

编辑:我正在编写一个脚本并使用 GameObject.FindGameObjectWithTag() 从那里访问所有游戏对象,据我所知,这就是为什么主脚本中的对撞机代码没有触发的原因。 我添加了我的代码在 GameObject 中的屏幕截图

【问题讨论】:

  • 使用调试工具绘制光线并查看光线的走向
  • @BugFinder 我做了。无论是按钮还是图像都无法从点击中获取有关单击的游戏对象的任何信息
  • 您是否在游戏对象上设置了碰撞器??
  • hit != null 将始终为 true,因为它是 struct。所以看起来hit.collider 永远不是true .. 你可能在你试图点击的对象上没有任何碰撞器
  • @eomer 您的编辑没有解释任何内容...使用GameObject.FindGameObjectWithTag() 是完全独立的,与您的Physics2D.Raycast 无关...如果您认为这是必要的,请添加完整你如何以及在哪里使用你的东西的脚本

标签: unity3d gameobject


【解决方案1】:

此方法适用于桌面和移动应用程序:

  1. 为每个要检测其点击事件的对象添加一个碰撞器组件。
  2. 向您的项目添加一个脚本(我们将其命名为 MyObject.cs)。 该脚本必须实现 IPointerDownHandler 接口及其方法。并且此脚本必须将 Physics2DRaycaster 添加到相机。这个脚本的整个主体可能是这样的:

    public class MyObject : MonoBehaviour, IPointerDownHandler
    {
        private void Start()
        {
            AddPhysics2DRaycaster();
        }
    
        public void OnPointerDown(PointerEventData eventData)
        {
            Debug.Log("Clicked: " + eventData.pointerCurrentRaycast.gameObject.name);
        }
    
        private void AddPhysics2DRaycaster()
        {
            Physics2DRaycaster physicsRaycaster = FindObjectOfType<Physics2DRaycaster>();
            if (physicsRaycaster == null)
            {
                Camera.main.gameObject.AddComponent<Physics2DRaycaster>();
            }
        }
    }
    
  3. 将 MyObject.cs 脚本添加到您想要检测的每个对象单击它。之后,当您单击这些对象时,它们的名称将显示在控制台上。

  4. 确保 EventSystem 存在于您项目的层次结构中。如果没有,请右键添加。

P.S. MyObject.cs 脚本现在具有 IPointerDownHandler。这会在您触摸对象时立即检测到点击。您还可以将 IPointerUpHandlerIDragHandler 用于不同的目的!

抱歉我的英语不好。

【讨论】:

  • 我做了所有事情,但 OnPointerDown 没有触发
  • 不知道为什么,但我不是唯一一个遇到麻烦的人无法使用处理程序
  • 我很确定它对我有用。最近我又检查了一遍,没问题。请在您项目中的新游戏对象上对其进行测试,并准确完成所有 4 个部分。
  • 这对我不起作用,因为我的对象是 3D 的。如果您从 raycaster 中删除 2D,使其只是 PhysicsRaycaster,则此答案适用于 3D 对象。
【解决方案2】:

当你使用光线投射时,你应该在你的精灵上设置一个碰撞器

private void Update()
{
   if (Input.GetMouseButtonDown(0))
   {
      Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
      RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction);

      if (hit.collider != null) {
         Debug.Log ("CLICKED " + hit.collider.name);
      }
   }
}

这在统一 5.6 中对我有用

注意:“LeftClick”只是一个“GameObject”而已,我这样称呼它是为了更好地识别:)


已编辑

我为 UI 按钮测试了这个方法,但它不起作用;所以我使用了不同的方法。对于 UI 按钮,您可以像这样添加侦听器:

GameObject.Find ("YourButtonName").GetComponent<Button> ().onClick.AddListener (() => {

});

【讨论】:

  • 谢谢,但我必须在 gameobjects 自己的脚本中编写这段代码。但我正在处理一个位于具有相同相机层次结构的空对象中的单个脚本,并且无法从那里访问碰撞。如果我将你的脚本写到游戏对象本身,主脚本怎么知道?
  • @eomer 你知道什么是对撞机,对吗?如果您的对象上没有Collider2D 组件,那么Physics2D.Raycast 永远不会命中任何东西。您的脚本将“知道”,因为 hit.collider 将被设置为您实际击中的对象 .. 目前还没有
  • @Shamshirsaz.Navid 我编辑了您的代码,以便更好地了解 OP 更改了什么
  • 我有 collider2D 组件,但我的脚本不在游戏对象本身中。我添加了一个包含脚本的空对象,并从那里执行我的所有代码并在那里添加你的代码。在更新方法中,如果我在 Input.GetMousebuttondown(0) 中放置断点,它会在我单击游戏对象时停止,但在那之后什么都没有发生
  • @eomer 我认为这在你的脚本所在的位置并不重要 :) 我在更新方法中使用了这个 - 而且我也使用单个脚本
【解决方案3】:

考虑使用OnMouseOver() 方法(docs):

private void OnMouseOver() {
    if (!Input.GetMouseButtonDown(0)) return;

    // Your logic here.
}

此方法仅适用于附加到游戏对象的碰撞器,就像 Raycast 一样。

因为没有多个Update() 方法来迭代每一帧,所以它会更简洁且性能略高一些。如果您有数十个或数百个可点击对象,请记住这一点。

(尽管有报道称这种方法不适用于多台摄像机,其中一台是正交摄像机,在这种情况下,您不可以选择。)

【讨论】:

  • It would be cleaner and slightly more performant because there are no multiple Update() methods to iterate each frame. Something to keep in mind if you have dozens or hundreds of clickable objects. 是的,但是 OP 可能只在一个组件中进行光线投射,这也是干净和高效的;)
  • 谢谢,但我必须在 gameobjects 自己的脚本中编写这段代码。但我正在处理一个位于具有相同相机层次结构的空对象中的单个脚本,并且无法从那里访问碰撞。如果我把你的脚本写到游戏对象本身,主脚本怎么知道?
  • @eomer 啊,我明白了。在这种情况下,您必须:1)通过检查器为每个游戏对象手动创建和分配对主脚本的引用,2)使主脚本全局可见(静态/单例/服务位置),或 3)引入事件订阅/触发系统。这些系统肯定可以在其他游戏模块中受益,但是否要在项目中引入新的复杂系统取决于您。如果你想要简单的碰撞器点击逻辑,最好坚持使用 Raycast 版本。
猜你喜欢
  • 2022-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多