,Code in loop simultaneously executing on members of array rather than iterating one at a time
I'm making a little boxing game. I designed a function to accept a whole slew of arguments and then cause the enemy boxer to make attacks based on the data fed into the function. I have another class which sets a bunch of variables and then I read those values, assign them to local variables, and then run my function. Thing is that the code in my loop is executing on all members of the array instead of iterating over them one at a time, resulting in the enemy throwing many attacks at once that were intended to be thrown in sequence.
I'm going nuts, tried all the different types of iterators and got nowhere. I'm new to C#, no idea what I've done wrong here. The function that sets the variables in the other script is at the bottom of the code block.
using UnityEngine;
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, punchDelayTimer, patternDelayTimer;
private Vector2[] theCoords;
void Start()
{
enemyBoxer= GameObject.Find("enemyBoxer");
theRoll = gameObject.GetComponent<pianoRoll>();
punchDelayTimer = 0;
}
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();
attackOverdrive(thePatterns, thePunchDelay, thePatternDelay, theCoords);
}
public void 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")
{
int j = 0;
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)};
do
{
if (punchDelayTimer <= punchDelay)
{
punchDelayTimer += Time.deltaTime;
}
else
{
enemyBoxer.SendMessage("createAttack", triangleVectors[j]);
punchDelayTimer = 0;
j += 1;
}
} while (j < 3);
}
else if (patterns[i] == "square")
{
}
else if (patterns[i] == "circle")
{
}
else if ("verticalLine".CompareTo(patterns[i]) == -1)
{
var result = Regex.Match(patterns[i], @"\d+$", RegexOptions.RightToLeft);
if (result.Success)
{
//Debug.Log(result.Value);
}
}
}
}
}
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;
}
Answer by rage_co · Oct 01, 2021 at 11:20 AM
The loop is iterating through the array normally and one by one.....its just that all of this happens in a single frame....and since you are using a float based timer, it requires more than a single frame to work and the function will have to be called over and over, resetting the loop.....and creating new instances etc...it can be tackled with a while loop in a coroutine...or simply a waitforseconds command using coroutines
using UnityEngine;
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 triangleTime = 2f;
private float squareTime = 2f;
private float circleTime = 2f;
private float thePunchDelay, thePatternDelay, theCoordModAmount, punchDelayTimer, patternDelayTimer;
private Vector2[] theCoords;
void Start()
{
enemyBoxer= GameObject.Find("enemyBoxer");
theRoll = gameObject.GetComponent<pianoRoll>();
punchDelayTimer = 0;
}
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)):
}
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")
{
int j = 0;
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)};
do
{
yield return new WaitForSeconds(triangleTime):
enemyBoxer.SendMessage("createAttack", triangleVectors[j]);
punchDelayTimer = 0;
j += 1;
}
}
else if (patterns[i] == "square")
{
}
else if (patterns[i] == "circle")
{
}
else if ("verticalLine".CompareTo(patterns[i]) == -1)
{
var result = Regex.Match(patterns[i], @"\d+$", RegexOptions.RightToLeft);
if (result.Success)
{
//Debug.Log(result.Value);
}
}
}
}
}
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;
}
Maybe this will work....hope this helps
Thanks so much! I'll give this a try when I get home later today. I've had success using float based timers in other scripts - but I guess none of them were able to turn themselves on and off so it didn't create problems.
i think the major problem is that a function is only called once, so a float based timer will only work in update method, or in a while loop with a one frame wait
glad this worked, id also suggest using while loops with the simple TIme.deltaTime trick with the wait for 1 frame command (yield return 0) if you're planning to work with pause menus as coroutines obviously won't pause when the game does...so in that case, id recommend using a while loop inside an IEnumerator coroutine.....like this...
activeWaitTime = 0f;
while(activeWaitTime < waitTime0)
{
if(!gamePaused)
{
activeWaitTime += Time.deltaTime;
}
yield return 0;
}
activeWaitTime = 0f;
just replace the yield return new WaitForSeconds(); line with the given lines of code (be sure to swap the given variables (waitTime0 float and gamePaused bool) for what's applicable in your code...and remember to add this line at the very beginning of the coroutine
float activeWaitTime = 0f;
it might sound overwhel$$anonymous$$g, but its really simple and is gonna be a quality improvement as most probably you'll have a pause menu and you wouldn't want the coroutine to mess things up
Oh cool, thanks! This was the first time I've used a coroutine and I'm sure I would've had to implement some kind of pause function eventually, so this is a nice little freebie =]
Your answer
Follow this Question
Related Questions
Can someone explain what IEnumerators and for statements are? 1 Answer
if ALL items in array are something 1 Answer
Nested For loop Grouping 0 Answers
Random loop rigidbody? 0 Answers