Unity C#循环一次性执行全部数组成员代码而非逐次迭代问题排查
问题解决方法
根因分析
你遇到的问题是同步函数无法实现跨帧延迟逻辑:
Unity的普通C#方法会在单帧内执行完全部代码逻辑,你在循环中累加Time.deltaTime的写法没有预期效果:
- 同一帧内
Time.deltaTime为固定值,内层do while循环会在单帧内反复执行,快速把计时器累加到阈值,瞬间生成3次三角攻击 - 外层
for循环也会在同一帧遍历完所有pattern数组元素,导致所有批次的攻击同时触发,没有间隔
解决方案
将attackOverdrive改为Unity协程(Coroutine),通过yield return实现等待延迟,自动跨帧执行逻辑,不需要自己维护计时器。
修改后的完整代码如下:
using UnityEngine; using System.Collections; using System.Text.RegularExpressions; public class overdrivePiano : MonoBehaviour { private GameObject enemyBoxer; private pianoRoll theRoll; private string theCoordMod; private string[] thePatterns; private int howMany; private float thePunchDelay, thePatternDelay, theCoordModAmount, patternDelayTimer; private Vector2[] theCoords; void Start() { enemyBoxer= GameObject.Find("enemyBoxer"); theRoll = gameObject.GetComponent<pianoRoll>(); } private void readRoll() { thePatterns = theRoll.patterns; thePunchDelay = theRoll.punchDelay; thePatternDelay = theRoll.patternDelay; theCoords = theRoll.coords; theCoordMod = theRoll.coordMod; theCoordModAmount = theRoll.modAmount; } public void onSwitch() { theRoll.SendMessage("firstVerse"); readRoll(); // 启动协程 StartCoroutine(attackOverdrive(thePatterns, thePunchDelay, thePatternDelay, theCoords)); } // 改为返回IEnumerator的协程方法 public IEnumerator attackOverdrive(string[] patterns, float punchDelay, float patternDelay, Vector2[] coords, string coordMod = "none", float modAmount = 0) { for(int i = 0; i < patterns.Length; i++) { if (patterns[i] == "triangle") { Vector2[] triangleVectors = new Vector2[] {new Vector2(coords[i].x, coords[i].y + 0.75f), new Vector2(coords[i].x - 0.75f, coords[i].y - 0.75f), new Vector2(coords[i].x + 0.75f, coords[i].y - 0.75f)}; for(int j = 0; j < 3; j++) { // 等待punchDelay时间后再执行后续逻辑 yield return new WaitForSeconds(punchDelay); enemyBoxer.SendMessage("createAttack", triangleVectors[j]); } } else if (patterns[i] == "square") { // 后续pattern逻辑同理,用yield return实现延迟 } else if (patterns[i] == "circle") { } else if (patterns[i].StartsWith("verticalLine")) { var result = Regex.Match(patterns[i], @"\d+$", RegexOptions.RightToLeft); if (result.Success) { //Debug.Log(result.Value); } } // 不同pattern之间等待patternDelay yield return new WaitForSeconds(patternDelay); } } } // pianoRoll类中的firstVerse方法不需要修改 private void firstVerse() { patterns = new string[] {"triangle", "triangle", "triangle", "singleRandom", "singleRandom", "verticalLine5"}; coords = new Vector2[] {new Vector2(-1.3f, 2.5f), new Vector2(0f, -2.5f), new Vector2(1.3f, 2.5f), new Vector2(0,0), new Vector2(0,0), new Vector2(0, 4f)}; punchDelay = 0.5f; patternDelay = 0.5f; }
补充说明
- 协程遇到
yield return时会自动挂起,等等待时间结束后从挂起位置继续执行,完美匹配你按顺序延迟触发攻击的需求 - 不需要再手动维护
punchDelayTimer变量,WaitForSeconds会自动处理计时逻辑 - 如果需要中途终止攻击序列,可以调用
StopCoroutine()方法停止运行中的协程
内容的提问来源于stack exchange,提问作者Feudimonster
相关产品推荐
相关产品推荐

