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

Unity中如何使用Raycast触发交互脚本及修复现有代码问题

现有代码问题
  • 逻辑顺序错误:向上朝向的射线检测分支中,dialogueA.enabled = false 写在return之后,属于永远不会执行的死代码,射线未命中时无法禁用交互脚本
  • 射线参数不合理:射线长度仅为0.01f,几乎检测不到前方物体;默认射线偏移量为(5,0,0),会从角色右侧5个单位的位置发射射线,完全偏离角色本体
  • 代码冗余:向上、向下两个朝向的射线检测逻辑完全重复,违反DRY(不要重复代码)原则,后续修改需要改两处,容易出错
  • 命名不规范:move、movefoward两个变量名完全无法体现「朝向」的含义,且movefoward实际对应向下朝向,和字面意思完全相反
  • 功能逻辑缺失:没有判断玩家和交互对象的距离是否在有效半径内,也没有给Interactable属性赋值的逻辑,导致回车触发交互的代码永远不会执行
  • 触发逻辑不符合需求:当前射线检测绑定在E键,和需求要求的回车触发不一致
需求实现方案

核心调整思路

  1. 新增可配置的交互半径、射线长度参数,抽离公共的射线检测方法避免重复代码
  2. 按下回车时同步执行射线检测、距离校验、交互触发三个逻辑,未命中有效对象时自动禁用交互脚本
  3. 优化朝向判断逻辑,不用单独绑定W/S按键,适配所有移动场景的朝向识别

修改后完整代码

using UnityEngine;

public class Player : MonoBehaviour
{
    [SerializeField] private DialogueUI dialogueUI;
    [Header("交互配置")]
    [SerializeField] private float interactRadius = 2f; // 有效交互半径,可在Inspector调整
    [SerializeField] private float rayLength = 1.5f; // 射线检测长度,可在Inspector调整
    [SerializeField] private LayerMask interactLayer; // 可选:指定可交互对象的层,过滤无关碰撞体,性能更好

    private DialogueActivator dialogueA;
    private float MoveSpeed = 7f;
    public Animator animator;
    public Rigidbody2D rb;

    public DialogueUI DialogueUI => dialogueUI;
    public Interactable Interactable { get; set; }

    Vector2 movement;
    Vector2 lookDirection = Vector2.up; // 保存角色当前朝向,默认向上

    private void Start()
    {
        dialogueA = GetComponent<DialogueActivator>();
        rb = GetComponent<Rigidbody2D>();
    }

    private void Update()
    {
        if (DialogueUI.IsOpen) return;

        movement.x = Input.GetAxisRaw("Horizontal");
        movement.y = Input.GetAxisRaw("Vertical");

        // 更新朝向:只要有上下方向输入就更新朝向,左右移动时保留最后一次上下朝向
        if (movement.y > 0.1f)
        {
            lookDirection = Vector2.up;
            animator.SetBool("Lookingfoward", true);
        }
        else if (movement.y < -0.1f)
        {
            lookDirection = Vector2.down;
            animator.SetBool("Lookingfoward", false);
        }

        // 冲刺逻辑
        MoveSpeed = Input.GetKey(KeyCode.LeftShift) ? 10f : 7f;

        // 回车触发检测+交互逻辑
        if (Input.GetKeyDown(KeyCode.Return))
        {
            if (CheckInteractable(out Interactable targetInteractable))
            {
                Interactable = targetInteractable;
                Interactable.enabled = true;
                dialogueA.enabled = true;
                Interactable.Interact(this);
            }
            else
            {
                // 未命中有效对象,清空状态禁用脚本
                if (Interactable != null)
                {
                    Interactable.enabled = false;
                    Interactable = null;
                }
                dialogueA.enabled = false;
            }
        }
    }

    void FixedUpdate()
    {
        rb.MovePosition(rb.position + movement * MoveSpeed * Time.fixedDeltaTime);
    }

    // 抽离公共射线检测方法,返回是否命中有效交互对象,同时输出命中的Interactable组件
    private bool CheckInteractable(out Interactable target)
    {
        target = null;
        // 射线起点加少量朝向偏移,避免从角色碰撞体内部发射导致检测失效
        Vector2 rayOrigin = (Vector2)transform.position + lookDirection * 0.2f;
        // 可选:如果配置了交互层就用层过滤,否则用原来的Tag判断
        RaycastHit2D hit = Physics2D.Raycast(rayOrigin, lookDirection, rayLength, interactLayer);
        
        if (!hit) return false;
        // 判断是否在有效交互半径内
        if (Vector2.Distance(transform.position, hit.transform.position) > interactRadius) return false;
        // 校验Tag+获取Interactable组件
        if (hit.collider.CompareTag("Object"))
        {
            target = hit.transform.GetComponent<Interactable>();
        }
        // 调试用,正式版可以删掉
        Debug.DrawRay(rayOrigin, lookDirection * rayLength, target != null ? Color.green : Color.red, 1f);
        return target != null;
    }
}

配套设置说明

  1. 可交互对象需要挂Interactable脚本,Tag设置为Object,如果用Layer过滤需要先在Unity层级设置里新增交互层,然后把可交互对象设置为该层,再在Player脚本的Inspector面板选中对应层
  2. interactRadius和rayLength可以根据你的游戏实际尺寸在Inspector面板调整,不用改代码
额外优化建议
  • 增加交互提示:如果需要对准可交互对象就显示「按回车交互」的提示,可以把CheckInteractable方法放到Update里每帧执行,命中时显示提示,未命中隐藏,性能消耗很低
  • 空值校验补充:可交互对象获取Interactable组件后可以加日志提醒,避免挂了Tag没挂脚本导致的交互无响应问题
  • 输入管理优化:后续可以改用Unity的Input System管理按键,不用写死KeyCode,改键和多端适配更方便

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 21:54:03