Coroutine only firing once - c#

I'm trying to run a script that will generate a "ramps" upon touch between point a and b. This code receives a list of where the elements of the ramps should be and then instanciates and places them on the screen.
However the coroutine is only running once and I can't understand why. Can anyone give me some advice?
Thank you very much in advance
public IEnumerator CreateRamp(List<Vector3> lP, float angle)
{
int i = 1;
while (i <= lP.Count)
{
Debug.Log("Iteration " + i + " of " + lP.Count + " position is " + lP[i]);
GameObject item = Instantiate(Resources.Load("floor")) as GameObject;
item.transform.position = current_Position;
item.transform.eulerAngles = new Vector3(0, 0, UnityEngine.Random.Range(0f, 360f));
item.GetComponent<Ramp>().strtPos = item.transform.position;
item.GetComponent<Ramp>().strtRot = item.transform.eulerAngles;
item.GetComponent<Ramp>().strtScale = new Vector3(0.4f, 0.4f, 1);
item.GetComponent<Ramp>().tgtRot = new Vector3(0, 0, angle);
item.GetComponent<Ramp>().tgtPos = lP[i-1];
i += 1;
yield return new WaitForSeconds(0.2f);
}
}

I suspect your condition i <= lP.Count is true only once. (Maybe lP.Count == 1, I think).
The way co-routine works is that, the code inside the CreateRamp function is executed across multiple frames.
When you StartCoroutine(CreateRamp(...)), it is immediately run until it hits yield statement. It will wait there for 0.2 seconds and will be run again from the statement right after the yield.
In the second execution, it evaluates the condition i <= lP.Count again and see that it is False => it jumps out of the loop and because it hits the end of the function, that co-routine will be stopped, no more execution in the future.

Since this function is an IEnumerable it should be treated by other code as a list of Ramp objects. I suspect (there isn't enough of your code to know), that the way you are calling this function is incorrect.
On a side note, with your yield returning a waitforX, It would be better in the long term to either perform the wait outside of this function (where you are calling it from) or at the very least add the wait period as a parameter to the function. Hard coded values like that will end up biting you later on, especially if your game's code-base grows. I recommend it be exposed as a setting on your GameObject, so it can be tweaked from the editor.
One other thing, How do you destroy these Ramp objects when you are done with them? It might be good to consider storing references to them as you create them so you can destroy them later.

Related

Unity - Instantiated objects spawn on the same position in Coroutine, while instantiate them directly do spawn correctly

What i want to achieve:
Im creating a procedural generated city. I got the roads working, together with the spawning of the houses, they spawn along the road and dont get spawned if they are colliding with either the road and/or another building. Now since i sometimes i want to load a big city, this costs a lot of computing time, so i wanted to put in a Coroutine to slowly load in all the houses. (Please tell me if there is a better way, or a "correct" way, this is the only thing that i knew that could work).
What i did / Problem:
So what i did, is all the segments i use to create a house i put in a list, and once all the houses are pregenerated (not spawned/instantiated yet) i want to use the coroutine to spawn them individually. But whenever i use the coroutine to spawn them, they spawn inside eachother.
While if i spawn them directly from their script (still using the list) they do spawn correctly, i have no clue what i am doing wrong and how to fix this.
public void Spawner(Vector3 buildingPosition, Quaternion buildingRotation, int buildingHeight, GameObject buildingParent, LayerMask m_LayerMask, BuildingGenerator buildGenerator)
{
GameObject baseBuilding = buildingBase[Random.Range(0, buildingBase.Count)];
baseBuilding.transform.position = buildingPosition;
baseBuilding.transform.rotation = buildingRotation;
Debug.Log(baseBuilding.transform.position);
Collider[] hitColliders = Physics.OverlapBox(baseBuilding.transform.position, baseBuilding.GetComponentInChildren<Renderer>().bounds.extents /2, Quaternion.identity, m_LayerMask);
if (hitColliders.Count() > 1)
{
return;
}
buildGenerator.Segments.Add(baseBuilding);
buildingPosition.y += baseBuilding.GetComponentInChildren<Renderer>().bounds.max.y - buildingPosition.y;
for (int i = 0; i <= buildingHeight; i++)
{
buildingRotation *= Quaternion.Euler(0, 0, 0);
GameObject middleBuilding = buildingMiddle[Random.Range(0, buildingMiddle.Count)];
middleBuilding.transform.position = buildingPosition;
middleBuilding.transform.rotation = buildingRotation;
//buildGenerator.Segments.Add(middleBuilding);
buildingPosition.y += middleBuilding.GetComponentInChildren<Renderer>().bounds.max.y - buildingPosition.y;
}
if (buildingRoof.Count != 0)
{
GameObject roofBuilding = buildingRoof[Random.Range(0, buildingRoof.Count)];
roofBuilding.transform.position = buildingPosition;
roofBuilding.transform.rotation = buildingRotation;
buildGenerator.Segments.Add(roofBuilding);
}
Instantiate(buildGenerator.Segments[1]); //If i use this, they spawn on the correct place.
Debug.Log(buildGenerator.Segments.Count);
}
{
StartCoroutine(LoadSegments(buildingParent));
}
public IEnumerator LoadSegments(GameObject buildingParent)
{
for (int i = 0; i < Segments.Count; i++)
{
GameObject SpawnedSegment = Instantiate(Segments[i]);
//SpawnedSegment.transform.parent = buildingParent.transform;
yield return new WaitForEndOfFrame();
}
}
Extra info:
I make use of 3 scripts to spawn the whole city, the roadGenerator, which will spawn the roads, those road points get stored in a list. After the roads are generater the roadgenerator will call the building Generator. The building generator will go through the whole list of all the roads, and create buildings aside them, the buildings are created via a 3rd script (not instantiated). The building script, this script contains the building segments, and will piece them together and also check for collisions (First code block). Once these buildings are all created and put into a list, the buildingGenerator will start the coroutine and instantiate all these buildings (thus on the wrong position)(Second code block).
Hope i provided enough information, else id be happy to provide more.
Okay so i finally got it working. The problem was not at the coroutine, but at the list. My code would constantly override my list objects. So i created a new script, with basic attributes like the object, the position and rotation. So then i add those new scripts to the list, and spawn them in the coroutine. (In my comment i said i had some other problems after i fixed this, this is because i used .bounds.max.y, while i should have used .bounds.size.y. This is thus also the fix for that).
I hope someone in the future might find this helpful!

In while loops list compare of coroutine not work sometimes - C# Unity3D Rhythm Game

I'm going to make a rhythm game.
music playing time is variable which change by music playing in millisecond
List is a float list which have the time(float second) I filled , let me to access it and use for compare with music playing time to instance object .
when list time = music time then instant object.
but sometimes will missing(not found value in list but value is really exist in list).
Here is my assumption.
I think List.indexOf performance are not good and thread have some delay.
Music playing time change every millisecond , a little delay from unity or others will cause missing(doesn't entering if statement)
I don't know if it's correct.
Could any one help me.
Here is my code.
IEnumerator Execute(MethodDelegate Start,MethodDelegate Stop)
{
while (true) {
int res = result.IndexOf ((float)System.Math.Round (GameObject.Find ("Music").GetComponent<AudioSource> ().time, DigitalAdjust)-TimeAdjust);
if (res!=-1) {
if (res == result.Count-2) {
Stop.Invoke ();
print ("CoroutineStop");
StopCoroutine (_Execute);
}
//execute
num=Positoin[res];
print (res);
Start.Invoke();
}
yield return null;
}
}
Thanks.
Chances are that you are correct. You might miss some if statement because you don't match the millisecond exactly. Here are some things that could help:
It you game reaches 60 FPS (the usual rate for a smooth rendering), each frame will take around 16 milliseconds. If you have events that must trigger at exact milliseconds you will miss some because your Execute function calls are separated by around 16ms (a coroutine is called once per frame).
A solution to this is remember the last time the Execute function was called and check everything in between:
private float _lastTime;
IEnumerator Execute(MethodDelegate Start,MethodDelegate Stop)
{
while (true) {
// here your code must check all the event between _lastTime and Time.time
var lastTimeMilliseconds = (int)(_lastTime*1000);
var currentTimeMilliseconds = (int)(Time.time*1000);
for(int time = lastTimeMilliseconds+1; time <= currentTimeMillisedons; time++)
{
// let's say last frame was at time 1000ms
// This frame occurs at time 1016ms
// we have to check your list for events that have occured since last frame (at time 1001, 1002, 1003, ...)
// so we have a for loop starting at 1001 until 1016 and check the list
int res = result.IndexOf ((float)System.Math.Round (time, DigitalAdjust)-TimeAdjust);
if (res!=-1)
{
if (res == result.Count-2)
{
Stop.Invoke ();
print ("CoroutineStop");
StopCoroutine (_Execute);
}
//execute
num=Positoin[res];
print (res);
Start.Invoke();
}
}
// At the end, remember the time:
_lastTime = Time.time;
yield return null;
}
}
Check the Time class, you also have access to Time.deltaTime to know the time elapsed between two frames, if that helps.
EDIT:
As you requested in comment, I added some bit of code from your example to explain better this idea. Note that I don't know what your variables do so you will have to adapt. For instance, Time.time gives that time since app start. You will likely need to adapt this use the time since you started the audio
Another important thing:
GameObject.Find must look in all the objects. It is really slow and shouldn't be used every frame
GetComponent looks for all your scripts and is slow as well. It shouldn't be used every frame.
Instead, do this:
private AudioSource _audioSource;
private void Start()
{
_audioSource = GameObject.Find ("Music").GetComponent<AudioSource> ();
}
This will retrieve the source only once. Then in your code you simply call
_audioSource.time;

Which to use Coroutine or Update to slow down animation

I want to do
gradually stop car animation as it collildes with another car
gradually speed up car animation as it exit the collider
And I have two ways to acheive this thing(means to run my logic in).
Update
Co-routine
for coroutine I used this
IEnumerator IncreaseSpeedGradually1(AnimationControlSpeed lastGOHitScript)
{
//stop if decrease speed in progress
StopCoroutine("DecreaseSpeedGradually");
float decrementValue = ((lastHitVehicleSpeed / 2) * 2);
while (lastGOHitScript.Speed <= lastHitVehicleSpeed)
{
lastGOHitScript.Speed += decrementValue * Time.deltaTime;
yield return 0;
}
//setting speed to the last speed
lastGOHitScript.Speed = lastGOHitScript.iniSpeeed;
}
While for update I just make this criteria:
if (carAnimState == carAnimationState.starting)
{
carAnimState = carAnimationState.running;
}
if (carAnimState == carAnimationState.stoping)
{
carAnimState = carAnimationState.running;
}
These two ways I know but i want to ask that which is right way to do this job? to slow down animation speed and hence get my objective? I guess corroutine later can be problematic in my game and what are the performance concerns?
Not perfectly clear what your goal exactly is. What you describe is clear, but the two code snippets you posted do completely different things. BUT, basically, for something this small I would use Update() as it's easier to debug if something blows up and there's nothing -theoretically- in your code that wishes "threading" / "side tasking" (which coroutines are for, basically: do something -most probably a side task- async).
As a side note, the code in your Update() can be optimized a little so it will look something like this:
if (carAnimState == carAnimationState.starting) {
carAnimState = carAnimationState.running;
} else if (carAnimState == carAnimationState.stoping) {
carAnimState = carAnimationState.running;
} //this way the 2nd "if" won't be unnecessarily evaluated when animstate was .starting
I'd also add a method instead and call that from Update(). The pre-compiler will inline it most probably (cannot be forced in Unity) and your code is more readable.

Retrieving data from a database in another thread(Unity3D)

I currently have a code which retrieves data from a database and visualizes it in unity3D. However, everytime it retrieves data in the FixedUpdate() function, it spikes dramatically every 1 second. I'm thinking about using threading to do this but i'm not sure what i'm doing wrong.
This is the Function i call in the thread.
public void retrievefromDB(){
if (timeStep - prevTimeStep > 99) {
timeStep -= 1; //special for this dataset
query = "SELECT * FROM GridData2 WHERE timestep=" + timeStep;
if (showParent)
query += " AND (Level != 10)";
else
query += " AND (Level == 10)";
query += " AND temperature >= " + minTemp + " AND temperature <= " + maxTemp;
dt.Rows.Clear ();
dt = sqlDB.ExecuteQuery (query);
prevTimeStep = timeStep;
}
}
This code lags the scene every 1 second therefore i tried to put it into a thread.
void FixedUpdate()
{
Thread testthread = new Thread(new ThreadStart(retrievefromDB));
testthread.Start ();
}
After putting it in a thread, it keeps crashing the scene after awhile.
Can anyone tell me what I did wrongly? And how do i solve it?
The cause of your original issue is relatively obvious: database access is slow. If you put a database call inline in the FixedUpdate method, you're going to essentially pause your game's movement while the DB access happens (which may well take a second if you have to initialise a connection, for example).
The main issue with your threaded code as posted is that you are starting a new thread every time FixedUpdate is called. That means you're starting 60 new threads per second (by default) which will very quickly cripple your game!
While it's fine to use C# threads in Unity for this sort of work, a better approach would be to create a single thread and allow that to manage the timing, rather than creating a new thread each time the job runs. That would mean creating the thread in Awake() or Start() instead, and then using Thread.Sleep or similar to handle the timing.
Coroutines (as suggested by Mihai in his answer) are great for fixing the timing of events, but they still run on the game thread: if you put your DB code in a coroutine, you'll still see pauses when it runs. If you must run this DB access every second, you need it in a proper thread.
That said, have you considered that the DB access might be unnecessary? A more performant model might be to cache all of the data up front and use it from memory when you need it. (This might not be possible if the data is very dynamic, or if you're running in a memory-restricted environment like a mobile device...)
Whatever you do, you need to stop accessing your database every frame.
You only need the result only once every 60 or frames. You can do this easily by using a variable in which you add up the time passed since last call.
As for multi-threading in Unity, you have three options:
A multi-threading framework for Unity, like
https://www.assetstore.unity3d.com/en/#!/content/7285
C# built-in threading
You need to be careful not to call Unity specific API from the secondary threads you spawn. It's OK to send over data structures like Vector3, Color, etc., but don't call reference objects like GameObjects or Components.
https://msdn.microsoft.com/en-us/library/dd321439%28v=vs.110%29.aspx
Unity Coroutines
Coroutines are Unity's way of simulating multiple threads. It's quite a powerful tool for getting things to run asynchronously in the same thread
http://docs.unity3d.com/Manual/Coroutines.html
using System.Threading.Tasks;
public class Example
{
void StartOnDifferentThread()
{
Task.Factory
.StartNew(() =>
{
FunctionToRun();
})
.ContinueWith(task =>
{
if (task.IsCompleted)
{
// handle result
}
else if (task.IsFaulted)
{
// handle error
}
});
}
void FunctionToRun()
{
// do stuff
}
}
It finally works now. Just had to add these in retrievefromDB()
public void retrievefromDB(){
while(true){
if (timeStep - prevTimeStep > 99) {
timeStep -= 1; //special for this dataset
query = "SELECT * FROM GridData2 WHERE timestep=" + timeStep;
if (showParent)
query += " AND (Level != 10)";
else
query += " AND (Level == 10)";
query += " AND temperature >= " + minTemp + " AND temperature <= " + maxTemp;
dt.Rows.Clear ();
dt = sqlDB.ExecuteQuery (query);
prevTimeStep = timeStep;
}
Thread.Sleep(1);
}
}
And put this into the Start() function
testThread = UnityThreadHelper.CreateThread (() =>
{
UnityThreadHelper.TaskDistributor.Dispatch (() => retrievefromDB ());
});
testThread.Start ();
I'm using the threadhelper from
http://forum.unity3d.com/threads/unity-threading-helper.90128/
so u can go and check it out.
Thanks to everyone who helped! :)

Unity IEnumerator, waiting but no longer executing called function fully anymore

I am writing a game with some logic that records player actions and then replays them in the same sequence at the same timing but with other influences involved at a later date.
So far I have the code sort of working, it records perfectly as I require it, and then plays back the sequence perfectly, but the issue has been timing.
As an simple example. If the character is to walk from A -> B -> C but to wait for x time at B, then the code easily traverses the path, but will not stop at B for the given time.
So I wrote a couple of functions that I thought might handle this as you can see here.
private IEnumerator followSequence()
{
// Loop through each action steps in sequence.
foreach (Action step in sequence)
{
//Check if the action time is less than the current clock time.
Debug.Log("Step.tick: " + step.tick + " || Clock.tick: " + clock.getTick());
if (clock.getTick() < step.tick)
{
//If so wait out the difference to resync the action.
yield return new WaitForSeconds(step.tick - clock.getTick());
}
// Carry out the step.
play(step);
}
yield break;
}
private void play(Action step)
{
Debug.Log(step.type);
// Set up a followpath script
FollowPath follow = (player.GetComponent<FollowPath>() ? player.GetComponent<FollowPath>() : player.AddComponent<FollowPath>());
// Tell the follow path script that object is not a guard.
follow.isGuard = false;
// Create a new point object on the map
Transform aPoint = (Transform)Instantiate(PathPoint, step.point, Quaternion.identity);
path.points.Add(aPoint);
// Initiate movement.
follow.Path = path;
follow.TravelPath();
// Check if action is an objective.
if (step.type == Action.Type.Action)
{
step.actions.OnClick();
}
}
Now if I comment out the *yield return new WaitForSeconds()* part in the first function, the code works as expected and completes the step in the sequence just not to the given timing.
When the same code is not commented out, then the timings work perfectly and the 2nd *Debug.log("step.type")* is called at the exact right time, however the character no longer moves, I.E. the *follow.TravelPath()* never seems to be executed.
I have tried making the 2nd function an IEnmerator and yielding to it. I have tried a custom wait() function. I have tried yielding to the TravelPath() function.
Has anyone any more ideas I have follow up or where I could look to try and resolve this?
Edit:
Code that calls followSequence() as requested:
private void playActions()
{
// Reset player immediately to the starting position
player.transform.position = sequence[0].point;
// Stop the character and freeze the scene when alarm sounds!.
player.GetComponent<IncrementController>().freeze();
player.GetComponent<IncrementController>().enabled = false;
// Restart the clock and scene.
clock.Restart();
sceneManager.restart();
// Activate guard and remove sphere.
guard.SetActive(true);
guardShere.SetActive(false);
// Stop recording;
recording = false;
line.SetActive(false);
// Start playback sequence.
StartCoroutine(followSequence());
}
The behavior is as expected, on the line there you do yield return the execution of the context is paused until you do MoveNext() (which does apparently never happen) on the enumerator, which is returned by followSequence.
But as far as I can see from the comments, you just want to wait for some seconds for resync so you don't need to return at all. In your case I don't see any reason why you might need an Enumerable of WaitForSeconds if you just want to skip some time. Without to know how you you call the function and the implementation of WaitForSeconds I would suggest you to change it's return type to void.
private void followSequence()
{
// Loop through each action steps in sequence.
foreach (Action step in sequence)
{
//Check if the action time is less than the current clock time.
Debug.Log("Step.tick: " + step.tick + " || Clock.tick: " + clock.getTick());
if (clock.getTick() < step.tick)
{
//If so wait out the difference to resync the action.
new WaitForSeconds(step.tick - clock.getTick());
}
// Carry out the step.
play(step);
}
}

Categories