添加玩家ID后Unity抓钩脚本仅执行一次的问题求助
问题分析与修复方案
核心问题
- 冷却计时器未更新:
grapplingCdTimer仅在StopGrapple中被赋值,但没有在Update中递减,导致一旦进入冷却,计时器永远大于0,无法再次触发抓钩。 - 输入检测逻辑错误:使用
Input.GetButton会在按住按键期间持续触发StartGrapple,导致多次调用Invoke,逻辑混乱,应改为Input.GetButtonDown实现单次触发。 - Player1分支语法错误:
return语句缺少分号,会导致编译报错。 - 未判断当前抓钩状态:即使处于抓钩过程中,仍能触发新的抓钩调用,导致状态冲突。
修复后的完整代码
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
相关产品推荐
相关产品推荐

