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

添加玩家ID后Unity抓钩脚本仅执行一次的问题求助

问题分析与修复方案

核心问题

  1. 冷却计时器未更新:grapplingCdTimer仅在StopGrapple中被赋值,但没有在Update中递减,导致一旦进入冷却,计时器永远大于0,无法再次触发抓钩。
  2. 输入检测逻辑错误:使用Input.GetButton会在按住按键期间持续触发StartGrapple,导致多次调用Invoke,逻辑混乱,应改为Input.GetButtonDown实现单次触发。
  3. Player1分支语法错误:return语句缺少分号,会导致编译报错。
  4. 未判断当前抓钩状态:即使处于抓钩过程中,仍能触发新的抓钩调用,导致状态冲突。

修复后的完整代码

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

public class Grappling : MonoBehaviour
{
    [Header("References")]
    private PlayerMovement pm;
    public Transform gunTip;
    public LayerMask whatIsGrappleable;
    public LineRenderer lr;

    [Header("Grappling")]
    public float maxGrappleDistance;
    public float grappleDelayTime;
    public float overshootYAxis;

    private Vector3 grapplePoint;

    [Header("Cooldown")]
    public float grapplingCd;
    private float grapplingCdTimer;

    private bool grappling;

    [Header("Different Players")]
    public int playerID;

    private void Awake()
    {
        // 根据GameObject标签分配玩家ID
        if (gameObject.CompareTag("Player1"))
        {
            playerID = 1;
        }
        else if (gameObject.CompareTag("Player2"))
        {
            playerID = 2;
        }
        else if (gameObject.CompareTag("Player3"))
        {
            playerID = 3;
        }
    }

    private void Start()
    {
        pm = GetComponent<PlayerMovement>();
    }

    private void Update()
    {
        // 更新冷却计时器
        if (grapplingCdTimer > 0)
        {
            grapplingCdTimer -= Time.deltaTime;
        }

        Grapple();
    }

    private void LateUpdate()
    {
        if (grappling)
            lr.SetPosition(0, gunTip.position);
    }

    private void Grapple()
    {
        if (playerID == 1)
        {
            // 使用GetButtonDown实现单次触发,避免持续调用
            if (Input.GetButtonDown("Fire1"))
            {
                StartGrapple();
                Debug.Log("Grappled!");
            }
            return; // 修复语法错误,添加分号
        }

        else if (playerID == 2)
        {
            if (Input.GetButtonDown("Fire2"))
            {
                StartGrapple();
                Debug.Log("Grappled!");
            }
        }

        else if (playerID == 3)
        {
            if (Input.GetButtonDown("Fire3"))
            {
                StartGrapple();
                Debug.Log("Grappled!");
            }
        }
    }

    private void StartGrapple()
    {
        // 增加当前是否正在抓钩的判断,避免状态冲突
        if (grapplingCdTimer > 0 || grappling) return;

        grappling = true;

        RaycastHit hit;
        if (Physics.Raycast(transform.position, transform.up + transform.right, out hit, maxGrappleDistance, whatIsGrappleable))
        {
            grapplePoint = hit.point;
            Invoke(nameof(ExecuteGrapple), grappleDelayTime);
        }
        else
        {
            grapplePoint = (transform.position + (transform.up + transform.right) * maxGrappleDistance);
            Invoke(nameof(StopGrapple), grappleDelayTime);
        }

        lr.enabled = true;
        lr.SetPosition(1, grapplePoint);
    }

    private void ExecuteGrapple()
    {
        Vector3 lowestPoint = new Vector3(transform.position.x, transform.position.y - 1f, transform.position.z);

        float grapplePointRelativeYPos = grapplePoint.y - lowestPoint.y;
        float highestPointOnArc = grapplePointRelativeYPos + overshootYAxis;

        if (grapplePointRelativeYPos < 0) highestPointOnArc = overshootYAxis;

        pm.JumpToPosition(grapplePoint, highestPointOnArc);

        Invoke(nameof(StopGrapple), 1f);
    }

    public void StopGrapple()
    {
        grappling = false;
        grapplingCdTimer = grapplingCd;
        lr.enabled = false;
    }

    public bool IsGrappling()
    {
        return grappling;
    }

    public Vector3 GetGrapplePoint()
    {
        return grapplePoint;
    }
}

关键修改说明

  • 添加冷却计时器更新:在Update中加入grapplingCdTimer -= Time.deltaTime,确保冷却时间正常递减。
  • 替换输入检测方法:将Input.GetButton改为Input.GetButtonDown,确保每次按键仅触发一次抓钩逻辑。
  • 修复语法错误:给Player1分支的return语句添加分号,解决编译报错。
  • 增加状态判断:在StartGrapple中加入grappling状态判断,避免抓钩过程中重复触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 04:04:15