+ 1
Why is delaying with WaitForSeconds() partially working in Unity®? (Using C#)
I was trying to make a project of Tower of Hanoi with Unity. I was trying to instantiate GameObjects waiting 3 sec for each. So, I made a for loop in Start function, called StartCoroutine inside the loop and WaitForSeconds to wait 3 seconds. Now, I was expecting the for loop to wait for 3 seconds per iteration, but the result is that the project waits for 3 seconds before beginning and then executes all iterations without waiting. Why is this happening? How can I get the result I want?
10 odpowiedzi
+ 3
Can we see the code for the coroutine and loop?
Does it look like this by any chance:
void Start(){
for (Stuff){
StartCoroutine("someName");
}
}
IEnumerator someName(){
Instantiate(someObject);
yield return new WaitForSeconds(3);
}
If so, I believe the issue is that the coroutine is creating a new path to simutaneously run, but the code will still continue to run as per normal. So, the coroutine is created, waits, but the for loop is still running (it doesn't wait for the coroutine to finish).
Try placing the for loop within the coroutine, the yield statement within the for loop, and creating the object before the yield statement. Only call the coroutine once, it will handle everything.
+ 3
The problem is that the method void OnCollisionEnter(Collision), must be attached to one of the objects that collides.
So, unless you want to manually check if the object collides with the ground every frame without using that method, you'll have to attach it to one of the colliding objects.
You could name the script something like diskBuilder, in order to try to avoid confusion of why it's attached to the disks.
There are probably a few ways to check for collisions manually. One could be raycasting, or another might be checking if collidors overlap, or even checking the position of the falling object (if the terrain is flat or the disk's always fall on same spot).
Here's a tutorial with the raycasting:
https://unity3d.com/learn/tutorials/topics/physics/raycasting
You can keep track of a the reference to which disk you will cast a ray from. IE: the disk that's falling.
[SerializeField]
GameObject curDisk;
Here you can put the first disk as this variable from the inspector.
Then, cast a ray from curDisk towards the ground.
Everytime you instantiate a new disk, set the curDisk to be equal to the new disk you instantiate.
You might need to check if curDisk is close to the ground rather than actually touching the ground with raycasting. But, could probably make the difference un-noticable.
+ 2
I found the below code here:
https://answers.unity.com/questions/399104/why-does-yield-waitforseconds-only-run-once.html
Does it help?
// UnityScript
function Start(){
Do();
}
function Do() {
while(true) {
yield WaitForSeconds (2f);
print("Executed every 2 seconds");
}
}
+ 2
1604064_Sharif
I'm not 100% what the cause of that is but, you can surely instantiate them when they collide instead.
You can try adding a rigidbody, a collider, and a script to the object's prefab (If you haven't already).
With the script you can use a method called:
void OnCollisionEnter (Collision col)
When the rigidbody collides with another collidor this method will automatically be called.
You could then use a bool to determine if it has already collided with something. You can also use a static int to determine how many objects you want to create with this colliding method.
What the code might look like:
bool hasCollided;
// current # created
static int numInstances;
// n objects to create
const int MAX_INSTANCES = 5;
void OnCollisionEnter (Collision col) {
if (!hasCollided && numInstances < MAX_INSTANCES){
hasCollided = true;
++numInstances;
Instantiate(thisPrefab);
}
}
This is assuming each object you want to instantiate is the same prefab. Now you only need to have one of these objects to start, and the rest come with it.
Can also check out a tutorial on this, if interested:
https://unity3d.com/learn/tutorials/topics/physics/detecting-collisions-oncollisionenter
+ 2
1604064_Sharif
Sure, I'll have a look 👌
+ 1
Rrestoring Faith, the code was quite similar to the one you showed, except the instantiation was dome right after "yield return new WaitForSeconds(3);"
I think I understood what you said and thanks.
+ 1
Xan, thanks for your suggestion.
+ 1
Rrestoring faith, can you see why this isn't working?
https://www.sololearn.com/discuss/1249043/?ref=app
0
Rrestoring faith, as I've used the StartCoroutine function as you suggested.
But I didn't get quite the result I was expecting.
I was expecting that only the script I wrote will wait for 3 seconds. But I think it's making all scripts wait, especially the physics script.
I mean, the object (especially the object instantiated previous to the last object) falls for a few milliseconds, gets frozen in the air and then falls along with the last object.
Either the physics script is waiting, or my hardware is having trouble (which is possible, but less likely the case).
So, all I was looking for is to initiate the next object after the previous object lands (or even collides). Is there any suggestions on that?
0
Rrestoring faith, it seems the script you mentioned strictly belongs to the first object I initiate.
But can't I do it object-independently, so that making this code a part of any object (for example: the main camera) doesn't make a difference?
I'll later have to use this collision detection detection technique in recursion for tower of hanoi.