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

Unity打印机纸张投递故障:仅首张可投递问题求助

解决Unity纸张投递仅首张生效的问题

我开发的Unity游戏核心机制是向打印机投递纸张,但现在只有第一张纸能正常投递,后续纸张完全没反应。我发现问题出在DepositPaper脚本里的Paper变量是绑定的固定对象,试过用CompareTag修复,但没效果。相关代码如下:

纸张投递脚本(DepositPaper.cs)

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
using TMPro;

public class DepositPaper : MonoBehaviour
{
    public GameObject Paper;
    public int PaperCount = 0;

    public TextMeshPro paperText;

    public float raycastDistance = 100f;
    public LayerMask interactableLayer;

    void Start()
    {

    }

    void destroyPaper()
    {
        Destroy(Paper);
    }

    void Update()
    {
        Ray ray = new Ray(transform.position, transform.forward);

        if (Physics.Raycast(ray, out RaycastHit hit, raycastDistance, interactableLayer) && hit.collider.gameObject.CompareTag("Printer"))
        {
            if(Input.GetKeyDown("e") )
            {
                destroyPaper();
                PaperCount++;
                paperText.text = "Paper:" + PaperCount.ToString() + "/11";
            }
        }

        if(PaperCount == 2)
        {
            GameObject[] deadTaggedObjects = GameObject.FindGameObjectsWithTag("Dead_1");
            foreach (GameObject deadtagged in deadTaggedObjects)
            {
                deadtagged.SetActive(false);
            }
        }
    }
}

可拾取物品声明脚本(PickableItem.cs)

using UnityEngine;
/// <summary>
/// 挂载此脚本可让物体变为可拾取状态
/// </summary>
[RequireComponent(typeof(Rigidbody))]
public class PickableItem : MonoBehaviour
{
    // 刚体组件引用
    private Rigidbody rb;
    public Rigidbody Rb => rb;
    /// <summary>
    /// 初始化时调用
    /// </summary>
    private void Awake()
    {
        // 获取刚体组件引用
        rb = GetComponent<Rigidbody>();
    }
}

物品拾取脚本(SimpleGrabSystem.cs)

using UnityEngine;
/// <summary>
/// 简单的物品抓取系统示例
/// </summary>
public class SimpleGrabSystem : MonoBehaviour
{
    // 角色相机引用
    [SerializeField]
    private Camera characterCamera;

    // 放置拾取物品的插槽引用
    [SerializeField]
    private Transform slot;

    // 当前持有的物品引用
    public PickableItem pickedItem;

    /// <summary>
    /// 每帧调用
    /// </summary>
    private void Update()
    {
        // 仅在按下F键时执行逻辑
        if (Input.GetKeyDown("f"))
        {
            // 检查是否已持有物品
            if (pickedItem)
            {
                 // 如果是,放下当前物品
                 DropItem(pickedItem);
            }
            else
            {
                // 如果没有,尝试拾取前方物品
                // 从屏幕中心发射射线
                var ray = characterCamera.ViewportPointToRay(Vector3.one * 0.5f);
                RaycastHit hit;
                // 发射射线寻找可拾取物体
                if (Physics.Raycast(ray, out hit, 1.5f))
                {
                    // 检查物体是否可拾取
                    var pickable = hit.transform.GetComponent<PickableItem>();

                    // 如果物体带有PickableItem组件
                    if (pickable)
                    {
                        // 拾取物品
                        PickItem(pickable);
                    }
                }
            }
        }
    }

    /// <summary>
    /// 拾取物品的方法
    /// </summary>
    /// <param name="item">要拾取的物品</param>
    private void PickItem(PickableItem item)
    {
         // 赋值当前持有物品引用
         pickedItem = item;

         // 禁用刚体并重置速度
         item.Rb.isKinematic = true;
         item.Rb.linearVelocity = Vector3.zero;
         item.Rb.angularVelocity = Vector3.zero;

         // 将插槽设为父物体
         item.transform.SetParent(slot);

         // 重置位置和旋转
         item.transform.localPosition = Vector3.zero;
         item.transform.localEulerAngles = Vector3.zero;

    }

    /// <summary>
    /// 放下物品的方法
    /// </summary>
    /// <param name="item">要放下的物品</param>
    private void DropItem(PickableItem item)
    {
        // 清空持有物品引用
        pickedItem = null;

        // 移除父物体
        item.transform.SetParent(null);

        // 启用刚体
        item.Rb.isKinematic = false;
   
        // 添加力让物品被抛出一点距离
       item.Rb.AddForce(item.transform.forward * 2, ForceMode.VelocityChange);
    }
}

脚本挂载在相机上


问题根源与修复方案

核心问题是DepositPaper脚本里的Paper变量是固定绑定的对象,销毁第一张纸后这个变量就变成了null,后续拾取的纸张根本没更新到这个变量里,而且投递系统和抓取系统完全脱节,没用到SimpleGrabSystem里的pickedItem引用。

修复步骤

  1. 关联抓取与投递系统:在DepositPaper中获取SimpleGrabSystem的引用,直接使用当前持有的物品进行投递。
  2. 添加纸张标签判断:确保只有纸张能被投递,避免误操作其他物品。
  3. 更新投递逻辑:销毁纸张后清空抓取系统的引用,避免无效操作。

修改后的DepositPaper.cs代码:

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
using TMPro;

public class DepositPaper : MonoBehaviour
{
    public int PaperCount = 0;
    public TextMeshPro paperText;
    public float raycastDistance = 100f;
    public LayerMask interactableLayer;
    // 引用抓取系统
    private SimpleGrabSystem grabSystem;

    void Start()
    {
        // 获取玩家身上的抓取系统组件
        grabSystem = GetComponent<SimpleGrabSystem>();
        // 初始化文本显示
        paperText.text = "Paper:" + PaperCount.ToString() + "/11";
    }

    void Update()
    {
        Ray ray = new Ray(transform.position, transform.forward);

        if (Physics.Raycast(ray, out RaycastHit hit, raycastDistance, interactableLayer) && hit.collider.CompareTag("Printer"))
        {
            if(Input.GetKeyDown("e") && grabSystem.pickedItem != null)
            {
                // 判断当前持有的是纸张
                if(grabSystem.pickedItem.CompareTag("Paper"))
                {
                    // 销毁当前持有纸张
                    Destroy(grabSystem.pickedItem.gameObject);
                    // 清空抓取系统的引用
                    grabSystem.pickedItem = null;
                    PaperCount++;
                    paperText.text = "Paper:" + PaperCount.ToString() + "/11";
                }
            }
        }

        if(PaperCount == 2)
        {
            GameObject[] deadTaggedObjects = GameObject.FindGameObjectsWithTag("Dead_1");
            foreach (GameObject deadtagged in deadTaggedObjects)
            {
                deadtagged.SetActive(false);
            }
        }
    }
}

额外注意事项

  • 给所有纸张对象添加Paper标签,确保判断逻辑生效。
  • 确保DepositPaper和SimpleGrabSystem挂载在同一个玩家对象上,如果不在同一对象,可改用FindObjectOfType<SimpleGrabSystem>()获取引用。
  • 移除原来的Paper公共变量,因为已无需固定绑定对象。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 18:47:04