Play模式下禁用Player脚本后Jump功能仍触发的问题咨询
问题与解答
问题场景
场景中有2个Player对象,每个都挂载了负责Jump功能的Player脚本。正常运行时点击Jump按钮,两个Player都会跳跃,符合预期。但在Play模式下禁用其中一个Player的脚本后,点击Jump按钮,两个Player依然会跳跃,这是为什么?
用到的代码如下:
查找按钮代码
private void Start() { characterColliderTrigger = transform.GetComponentInChildren<BoxCollider2D>(); characterCollider = transform.GetComponent<BoxCollider2D>(); GameObject[] movementButtons = GameObject.FindGameObjectsWithTag("MovementButtons"); foreach (GameObject buttonObject in movementButtons) { Button button = buttonObject.GetComponent<Button>(); if (button != null) { if (button.name == "MoveLeftButton") { MoveLeftButton = button; } else if (button.name == "MoveRightButton") { MoveRightButton = button; } else if (button.name == "JumpButton") { JumpButton = button; } } } StartCoroutine(AssignButtons()); }
绑定按钮代码
IEnumerator AssignButtons() { yield return new WaitForSeconds(0.5f); //JUMP BUTTON EventTrigger jumpEventTrigger = JumpButton.gameObject.AddComponent<EventTrigger>(); EventTrigger.Entry jumpPointerDown = new EventTrigger.Entry(); jumpPointerDown.eventID = EventTriggerType.PointerDown; jumpPointerDown.callback.AddListener((data) => { Jump(); }); jumpEventTrigger.triggers.Add(jumpPointerDown); }
Jump函数代码
public void Jump() { if(canJump && !someoneOnTop) { rb.velocity = new Vector2(rb.velocity.x,25); canJump = false; } }
问题原因
- 重复绑定事件:每个Player脚本启动时,都会给同一个JumpButton添加
EventTrigger组件,并把自己的Jump()方法绑定到按钮的点击事件上。最终按钮的回调列表里有两个Jump()方法,分别对应两个Player实例。 - 禁用脚本不清理回调:Player脚本被禁用时,只是暂停了它的生命周期函数(比如
Update),但已经绑定到按钮事件里的方法引用不会自动消失。点击按钮时,依然会调用这两个Jump()方法。 - Jump方法未检查脚本状态:即使脚本被禁用,
Jump()方法里没有判断当前脚本是否启用,所以只要被调用就会执行跳跃逻辑。
解决办法
方法1:在禁用脚本时移除回调,或在Jump里检查状态
- 给Player脚本添加
OnDisable()方法,移除按钮上的对应回调:
private void OnDisable() { if(JumpButton == null) return; EventTrigger trigger = JumpButton.GetComponent<EventTrigger>(); if(trigger == null) return; // 找到PointerDown类型的事件条目,移除自己的Jump回调 foreach(var entry in trigger.triggers.Where(e => e.eventID == EventTriggerType.PointerDown)) { entry.callback.RemoveListener((data) => Jump()); } }
- 或者直接在
Jump()方法开头判断脚本是否启用:
public void Jump() { if(!enabled) return; // 脚本禁用时直接退出 if(canJump && !someoneOnTop) { rb.velocity = new Vector2(rb.velocity.x,25); canJump = false; } }
方法2:改用集中式的按钮事件处理
不让每个Player去绑定按钮,而是给按钮单独写一个处理脚本,点击时主动找所有启用的Player调用跳跃:
public class ButtonHandler : MonoBehaviour { private Button jumpButton; private void Start() { jumpButton = GetComponent<Button>(); jumpButton.onClick.AddListener(TriggerJump); } private void TriggerJump() { // 只找启用状态的Player脚本 Player[] activePlayers = FindObjectsOfType<Player>(includeInactive: false); foreach(Player player in activePlayers) { player.Jump(); } } }
这种方式下,禁用的Player会被自动排除,无需额外处理。
内容的提问来源于stack exchange,提问作者Raj
相关产品推荐
相关产品推荐

