I am trying to add some delay in my script. But it does not execute yield statement. Here is my script . Please help me out in solving this issue. It goes inside DO function it print first statement too in Do function but after that it does not execute further.
ok, your missing an understanding of general process of Unity.
Error #1:
First, a Coroutine is a process that can persist beyond one frame. This means it does something until it quits.
Update runs once per frame, after the frame is drawn.
The two are very dissimilar. In your code, you state that you are going to start a coroutine every frame, that coroutine persists past the update and waits for 3 seconds then quits. (effectively) Couple this with you running 100 frames per second over 3 seconds and that is now 300 coroutines that are going on before they quit. NOT GOOD.
Error #2:
Every frame you are adding 3 units to your local scale.x. You then check to see if localScale.x is exactly 201. Due to some problems with the floating point percision in computer language, your answer may not be true. If you know you are going to 201 from something less. Your statement should read:
if(transform.localScale.x >= 201)
Thus allowing room for floating point error and such.
The actual way to write this:
var pauseFor = 3.0;
private var startTime=0.0;
function Start(){
startTime=Time.time;
}
function Update() {
// check the timer, if it is not time, just get out of the update.
if(Time.time - startTime < startTime + pauseFor)
return;
// add to the scale
transform.localScale.x += 3.0;
if(transform.localScale.x >= 201){
// if the scale is greater than the max
// make it the max
transform.localScale.x = 201;
Debug.Log("Reached");
gameObject.active = false;
}
}
thanks for correcting me. I really appreciate for that.
I have one more question.
Once object is at max scale(200)… At this point of time if i need to give some delay and then object should be invisible then what am suppose to do in that case?
A coroutine must be started with StartCoroutine and is fed the function that you want to call. It also may have parameters. The coroutine should contain a yield statement of some kind, but is not 100% nessecary. (but whats the point of calling a coroutine if you are not going to skip a couple of frames. )
So in the script provided you would call a coroutine when you want to initiate the game object is going to go inactive. To do this you will need a way to stop it from constantly calling the coroutine.
During the coroutine you will need to just check the time against an end time, yield each frame until you are ready then inactivate the item.
There are a couple of cleanup things in there, but you get the gist of it.
var pauseFor = 3.0;
private var startTime=0.0;
private var delayInactiveActive = false
function Start(){
startTime=Time.time;
}
function Update() {
// check the timer, if it is not time, just get out of the update.
if(Time.time - startTime < startTime + pauseFor)
return;
// add to the scale
transform.localScale.x += 3.0;
if(transform.localScale.x >= 201){
// if the scale is greater than the max
// make it the max
transform.localScale.x = 201;
Debug.Log("Reached");
//gameObject.active = false;
if(!delayInactiveActive)StartCoroutine(delayInactive(2.0));
}
}
function delayInactive(seconds : float){
delayInactiveActive=true;
var inactiveAt = Time.time + seconds;
while(true){
if(Time.time > inactiveAt){
gameObject.active = false;
delayInactiveActive=false;
return;
}
yield;
}
}
Yeah, you guys seem real clued up on coroutines so perhaps you can help me with an issue I am having, please…
Whenever I put a yield statement inside a method of a custom class, that entire method never executes. Why?
Example:
class crFriend extends Object
{
var selected : boolean = false;
var _name : String;
var icon : Texture;
function crFriend(nm : String, icon: String)
{
_name = nm;
LoadIcon(icon);
}
function LoadIcon(nm: String)
{
url = "http://www.mysite.com/actorIcons/"+nm;
Debug.Log(url); return;
var img : WWW = new WWW(url);
yield img;
icon = img.texture;
}
}
Simpy because that yield statement is in there, that entire method is simply never called… That Debug message is never shown… Why? What am I doing wrong?
So out of desperation I created a new js file. Called it crFriend.js
then did this in my original file:
obj = new crFriend();
obj.Init(data[1], data[0]);
and now I get a “NullReferenceException” on this line:
I mean… How is that even possible to get a null reference on a function name???
to test wether the function gets called up to the yield statement or not even to to there. the fact that it is there and the function still does nothing proves that the yield statement causes the entire method to be ignored.
comment out the yield statement and the debug message prints just fine…
uncomment the yield statement and nothing prints
Well I can’t really help, I just rewrote and tested it in c# and works fine, I just don’t know how javascript compiling works without explicitly calling a coroutine. (Which is why I prefer c#, it’s a lot clearer what is happening.)
Correct me if I’m wrong but imo this code is faulty. I think it should rather be:
// check the timer, if it is not time, just get out of the update.
if(Time.time - startTime < pauseFor)
return;
Think of the following case: For some reason unity takes 10 seconds to start up. startTime is thus 10. At the point Time.time has reached 14, the old fragment reads:
14 - 10 < 10 + 3 ==> 4 < 13
which means it still returns although 4 seconds have passed (which is more than the 3 seconds wait time we wanted to have). The code works as long as Start() gets called with Time.time being close enough to 0, but it will exhibit unwanted behaviour with Start() being called later on in the game or when generally setting startTime some time later in the game.
thanks for trying, though, but this is definitely a JS thing, I think. My reason for saying so is because all CS classes have to be declared, even if you just make a simple “base.cs” file, you still have to declare a base class. So CS is all about the custom classes.
In JS, the class declaration is basically handled for you and so may times people have tried to convince me that in JS we should try to NEVER create custom classes. Rather put each class in a file of it’s own… But that is soooo not intuitive for what I want to do…
In this example, I want to create a custom window control. I want to have a base window that can contain a bunch of self contained, custom button controls. So first there is the button class that will create multiple instances of itself to place it inside the window class that will also have multiple instances of itself declared inside the same script.
But to make matters worse, when I declare my own classes, I can create instances thereof in my scripts. If I create a script of each class then I have to create a prefab to drag into my scripts for each instance I want thereof…
Can you imagine? I just want a struct to store a name and a surname so I have to create a new script with only those tow fields in it and then create multiple prefabs each one containing that single script jet so I can drag it into an array in my main script? That is just plain daft… Simply saying myObjects = new crMyObject[10]; is soooo much less fuss… So to whoever is going to tell me to not create custom classes, read the above again…
Now the problem is that each and every class I create, whenever I place a yield statement inside any of it’s methods… That method no longer does anything… Great! So yeah. Definitely a JS thing because if this were true for CS then no CS script would ever work…
I am wondering if perhaps the base class I am extending isn’t the problem… What is the smallest base class I can use that does NOT contain a Transform or GameObject class?
Not necessary in JS (under normal circumstances). StartCoroutine is called automatically if you call a function that happens to be a coroutine.
I think you must have misunderstood; nobody (who is sane ) would say that. I’ve never seen anyone say that.
That’s not the issue. It’s just a matter of inheritance–StartCoroutine is a MonoBehaviour function, your class doesn’t extend MonoBehaviour, hence it doesn’t have access to StartCoroutine. This is the same regardless of whether you’re using C# or JS.
Eric:
Is that the answer to all my troubles? Extend MonoBehaviour not Object? If that is the case then that will solve my problems right there. Thanks. Let me go give that a try.
Edit:
Nope. Not it.
This is the actual code I am using:
class crFriends extends MonoBehaviour
{
var selected : boolean = false;
var _name : String;
var profile : String;
var status : int;
var icon : Texture;
function Init(nm : String, pf: String)
{
maxLength=20;
if (nm.length >= maxLength)
_name = nm.Substring(0,maxLength);
else
_name = nm;
profile = pf;
LoadIcon(); <-- I get a NullReferenceException right here
}
function LoadIcon()
{
url = "https://graph.facebook.com/"+profile+"/picture";
var img : WWW = new WWW(url);
yield img;
icon = img.texture;
}
function DrawWide(thisArea)
{
GUI.BeginGroup(thisArea);
GUI.Box(Rect(0,0,thisArea.width, thisArea.height), _name);
if (icon)
GUI.DrawTexture(Rect(2,2,thisArea.height-4, thisArea.height-4), icon);
GUI.Toggle(Rect(0,thisArea.height-16,16,16),selected,"");
if (GUI.Button(Rect(0,0,thisArea.width, thisArea.height),"", "Label"))
selected = !selected;
GUI.EndGroup();
}
}
function GetFriends()
{
var form = new WWWForm();
form.AddField( "online", 0 );
form.AddField( "action", 1);
var w = WWW(((Project.instance.Online) ? Project.instance.onlineURL : Project.instance.offlineURL) + "kocfbcalls.php", form);
yield w;
message = w.text;
if (w.error != null)
{
Debug.Log("Error " + w.text);
} else
{
fields = w.text.Split(":"[0]);
w.Dispose();
if (fields[0] == "1")
return;
pals = fields[1].Split("|"[0]);
for (var s: String in pals)
{
data = s.Split("="[0]);
obj = new crFriends();
obj.Init(data[1], data[0]);
friendsArray.Add(obj);
}
}
}
This is what I am trying to do. As you can see it works perfectly if I load the textures externally and then assign it to the relevant button afterwards, but I would really like to be able to create clean code where each object is in charge of loading it’s own values. This icon is the only remaining piece of the puzzle
So this bring me to the very simply question. Just a yes/no answer…:
Is it at all possible to have coroutines inside custom JavaScript classes?
Edit:
Wait, hold on… I think I answered my own question… So basically… it is possible if it derives from MonoBehaviour so what I want to do in terms of myWindows = new myWindowClass[3] is not possible. The only way to make this happen is to create my array, then add my class via AddComponent and use the added instance to populate my array… Interesting… So now I just have to go experiment with wether I can actually call AddComponent on a custom class… I wonder if this will solve the method call being a nullreferenceerror… I think I might be making leeway here. Thanks Eric.
Yes, if they inherit from MonoBehaviour. If they don’t, you can start a function from a class that itself inherits from MonoBehaviour. StartCoroutine is part of MonoBehaviour. No MonoBehaviour, no StartCoroutine. Nothing to do with C# or JS.
class Foo {
function Test () {
yield WaitForSeconds(1);
Debug.Log ("x");
}
}
function Start () {
var foo = new Foo();
StartCoroutine(foo.Test());
}
That’s one of those cases where you do need to use StartCoroutine explicitly in JS.