You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中如何从触发范围内抓取最近的物体?

解决抓取多个物体问题:仅抓取距离最近的物体

问题说明

当前使用的抓取脚本会同时抓取碰撞器范围内的所有物体,需要添加逻辑,只抓取距离玩家(抓取引导点)最近的物体。原脚本代码如下:

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

public class PickUp : MonoBehaviour {

    
    public float throwForce = 100;

    public bool canHold = true;
    public GameObject item;
    public GameObject tempParent;
    public GameObject poof;
    public GameObject vanish;
    public GameObject poofParent;
    public Transform guide;
    public bool isHolding = false;
    
    float distance;

 // Use this for initialization
 void Start () {
         
 }
 
 // Update is called once per frame
 void Update () {

        distance = Vector3.Distance(item.transform.position, guide.transform.position);

        if (Input.GetKeyDown("space"))
        
        if (distance <= 6f)
        {
            isHolding = true;
            item.transform.position = tempParent.transform.position;
            
            //Poof
            GameObject myPoof = Instantiate(poof, Vector3.zero, Quaternion.identity) as GameObject;
            myPoof.transform.parent = poofParent.transform;
            myPoof.transform.position = poofParent.transform.position;
            Destroy (myPoof, 2);
            
            //Particles
            GameObject myVanish = Instantiate(vanish, Vector3.zero, Quaternion.identity) as GameObject;
            myVanish.transform.parent = tempParent.transform;
            myVanish.transform.position = tempParent.transform.position;
            Destroy (myVanish, 4);
        }

        if (isHolding==true)
        {
            
            item.GetComponent<Rigidbody>().useGravity = false;
            item.GetComponent<Rigidbody>().detectCollisions = true;
            item.GetComponent<Rigidbody>().isKinematic = false;
            item.transform.parent = tempParent.transform;
            item.transform.position = tempParent.transform.position;
            if (Input.GetKeyUp("space"))
            {
                Debug.Log("Trying to throw");
                item.GetComponent<Rigidbody>().AddForce(guide.transform.forward * throwForce);
                isHolding = false;
            }
        }
        else
        {
            item.GetComponent<Rigidbody>().useGravity = true;
            item.GetComponent<Rigidbody>().isKinematic = false;
            item.transform.parent = null;
        }
 }

}

修改后的代码

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

public class PickUp : MonoBehaviour {

    public float throwForce = 100;
    public bool canHold = true;
    public GameObject tempParent;
    public GameObject poof;
    public GameObject vanish;
    public GameObject poofParent;
    public Transform guide;
    public bool isHolding = false;
    public float grabRange = 6f;
    // 给可抓取物体统一添加该标签
    public string grabbableTag = "Grabbable";

    private GameObject currentHeldItem;

    void Update () {
        if (Input.GetKeyDown("space"))
        {
            if (!isHolding)
            {
                // 查找范围内最近的可抓取物体
                GameObject closestItem = FindClosestGrabbableItem();
                if (closestItem != null)
                {
                    currentHeldItem = closestItem;
                    isHolding = true;
                    currentHeldItem.transform.position = tempParent.transform.position;
                    
                    // 生成特效
                    GameObject myPoof = Instantiate(poof, poofParent.transform.position, Quaternion.identity);
                    myPoof.transform.parent = poofParent.transform;
                    Destroy(myPoof, 2);
                    
                    GameObject myVanish = Instantiate(vanish, tempParent.transform.position, Quaternion.identity);
                    myVanish.transform.parent = tempParent.transform;
                    Destroy(myVanish, 4);
                }
            }
        }

        if (isHolding && currentHeldItem != null)
        {
            Rigidbody rb = currentHeldItem.GetComponent<Rigidbody>();
            rb.useGravity = false;
            rb.detectCollisions = true;
            rb.isKinematic = false;
            currentHeldItem.transform.parent = tempParent.transform;
            currentHeldItem.transform.position = tempParent.transform.position;

            if (Input.GetKeyUp("space"))
            {
                Debug.Log("Trying to throw");
                rb.AddForce(guide.transform.forward * throwForce);
                isHolding = false;
                currentHeldItem.transform.parent = null;
                currentHeldItem = null;
            }
        }
    }

    // 查找范围内最近的可抓取物体
    private GameObject FindClosestGrabbableItem()
    {
        GameObject[] grabbableItems = GameObject.FindGameObjectsWithTag(grabbableTag);
        GameObject closest = null;
        float minDistance = Mathf.Infinity;

        foreach (GameObject item in grabbableItems)
        {
            float distance = Vector3.Distance(item.transform.position, guide.transform.position);
            if (distance <= grabRange && distance < minDistance)
            {
                minDistance = distance;
                closest = item;
            }
        }
        return closest;
    }
}

关键改动说明

  • 新增grabbableTag变量,用于标记可抓取物体(需要给所有可抓取物体添加对应标签,比如"Grabbable")
  • 移除原有的单个item变量,改用currentHeldItem存储当前抓取的物体
  • 添加FindClosestGrabbableItem()方法,遍历所有带指定标签的物体,计算与引导点的距离,筛选出范围内最近的物体
  • 修改抓取逻辑,按空格时先查找最近物体,再执行抓取操作
  • 优化抛出后的物体状态重置逻辑

内容的提问来源于stack exchange,提问作者diegojms

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 14:10:27