Unity中使用IEnumerator实现FireGun函数延迟失效,需求为每秒生成一颗子弹的问题咨询
Unity中使用IEnumerator实现FireGun函数延迟失效,需求为每秒生成一颗子弹的问题咨询
嘿,我明白你的困扰了——你想实现按住鼠标时每秒发射一颗子弹,但现在代码不仅没实现延迟,反而疯狂生成子弹根本停不下来,对吧?咱们来一步步拆解问题出在哪,然后给你解决办法。
问题根源分析
你的代码现在有两个核心问题:
- 输入检测逻辑错误:在
PlayerController2的Update里,你用了Input.GetButton("Fire1")——这个函数会每帧返回true,只要玩家按住鼠标左键。这就导致每帧都会调用weaponscript.fireGun(),同时启动一堆WaitASecond协程,等于每帧都在预约1秒后生成子弹,最后会有几十上百颗子弹同时爆发,完全失控。 - 协程的使用方式不对:你在
WeaponScript里的fireGun只是启动一个延迟生成单颗子弹的协程,但没有做“同一时间只能有一个发射协程运行”的限制,也没控制发射间隔的逻辑,本质上只是给单颗子弹加了延迟,而不是实现“每秒一颗”的发射节奏。
解决方案(两种可选,按需选择)
方案1:用冷却时间变量控制发射间隔(简单直接)
这种方式适合“点击一次发射一颗,必须等1秒才能再次发射”,或者“按住时持续每秒发射”的需求。
第一步,修改PlayerController2,添加冷却时间控制:
// 在PlayerController2的私有变量里加一行 private float fireCooldown = 0f; void Update() { // 保留你原来的其他逻辑(经验升级、生命值判断等)... if (Input.GetButton("Fire1") && gamepause == false) { // 检查冷却是否结束 if (fireCooldown <= 0f) { // 根据状态调用对应发射函数 if (doubleshot) { weaponscript.fireDoubleGun(); } else { weaponscript.fireGun(); } // 重置冷却时间为1秒 fireCooldown = 1f; } // 每帧减少冷却时间 fireCooldown -= Time.deltaTime; } // 其他原有代码... }
第二步,简化WeaponScript的fireGun,去掉多余的协程(因为冷却已经在Player端控制了):
public void fireGun() { // 直接生成子弹,不用延迟 GameObject projectile = Instantiate(bullet, firepoint.position, firepoint.rotation); projectile.GetComponent<Rigidbody2D>().AddForce(firepoint.up * fireForce, ForceMode2D.Impulse); }
方案2:用协程持续控制发射节奏(适合按住持续发射)
如果你的需求是“按住鼠标就持续每秒发射一颗,松开就停止”,可以用这种方式,让Weapon自己管理发射循环:
第一步,修改WeaponScript:
// 在WeaponScript里加一个标记,防止重复启动协程 private bool isFiring = false; // 改成循环发射的协程 private IEnumerator ContinuousFireRoutine() { isFiring = true; // 循环发射直到停止 while (true) { GameObject projectile = Instantiate(bullet, firepoint.position, firepoint.rotation); projectile.GetComponent<Rigidbody2D>().AddForce(firepoint.up * fireForce, ForceMode2D.Impulse); // 等待1秒再发射下一颗 yield return new WaitForSeconds(1f); } } // 新增启动发射的方法 public void StartContinuousFire() { if (!isFiring) { StartCoroutine(ContinuousFireRoutine()); } } // 新增停止发射的方法 public void StopContinuousFire() { if (isFiring) { StopCoroutine(ContinuousFireRoutine()); isFiring = false; } } // 保留原来的fireDoubleGun不变 public void fireDoubleGun() { GameObject projectile = Instantiate(bullet, firepoint.position, firepoint.rotation); projectile.GetComponent<Rigidbody2D>().AddForce(firepoint.up * fireForce, ForceMode2D.Impulse); GameObject projectile2 = Instantiate(bullet, firepoint.position, firepoint.rotation); projectile2.GetComponent<Rigidbody2D>().AddForce(firepoint.up * fireForce, ForceMode2D.Impulse); }
第二步,修改PlayerController2的输入逻辑,用GetButtonDown和GetButtonUp来控制启动/停止:
void Update() { // 保留原有其他逻辑... // 按下鼠标时启动发射 if (Input.GetButtonDown("Fire1") && gamepause == false) { if (doubleshot) { weaponscript.fireDoubleGun(); } else { weaponscript.StartContinuousFire(); } } // 松开鼠标时停止发射 if (Input.GetButtonUp("Fire1")) { weaponscript.StopContinuousFire(); } // 其他原有代码... }
为什么原来的代码不行?
再帮你理一遍:
Input.GetButton("Fire1")每帧触发,等于每帧都在预约新的延迟生成任务,1秒后这些任务会同时执行,导致子弹爆炸式生成;- 你原来的协程只是给单颗子弹加了延迟,但没有控制“同一时间只能有一个发射流程”,完全没实现“每秒一颗”的节奏限制。
备注:内容来源于stack exchange,提问作者GeniusCoder
相关产品推荐
相关产品推荐

