var projectilePrefab: Transform;
var projectileSpeed: float = 10;
var ClipSize: int = 600;
var Rounds: int = 6;
var ReloadTime: float = 2;
private var InChamber = 0;
private var reloading:boolean = false;
function Start(){
var InChamber = Rounds; //Startup reload
}
function FixedUpdate()
{
if (Input.GetButtonDown("Fire1")!reloading)
{
StartCoroutine(Firing());
}
}
function Firing(){
if(InChamber > 0){
var projectile = Instantiate(projectilePrefab,
GameObject.FindWithTag("projectileSpawnObject").transform.position,transform.rotation);
projectile.rigidbody.AddForce(transform.forward * (projectileSpeed * 100));
InChamber -= 1;
ClipSize -= 1;
} else { //Reload
reloading = true;
yield WaitForSeconds(ReloadTime);
InChamber = Rounds;
reloading = false;
}
}
You need to state the function as a coroutine if you want any code past the yield to run, (if Javascript holds true to the same laws as c# on that matter) and that while loop would not allow unity to update, it just causes an infinite loop. I used FixedUpdate to grab the inputs, as Update’s too fast and sometimes picks up multiples of the same keypress.
No, you don’t need to use StartCoroutine() in Javascript, all you need is yields and it will know they are coroutines. And even if that were true, you can never start a coroutine with any yield instructions from any Update() function (FixedUpdate() included), because they run every frame and will not yield, ever.
You are declaring a new variable by saying “var InChamber”, that is local to the Start() function, you’re not actually setting the value of the “private var InChamber” you defined up top. Just take away that “var” and you should be good. The rest of your code is solid (except your seemingly random use of CamelCase and camelCase).
else (like I said before) it creates an infinite loop, because not all code paths in the coroutine return a yield (if InChamber > 0 returns no yields). Also, simulating existing functionality such as Update() in unity is an unnecessary work-around
That’s definately one thing I didn’t pick up, sorry, you’re right on that part. But that was simply exposing a problem inherent in the reload part of the script (where the yields were). As you might notice, InChamber gets set as Rounds in the Coroutine. InChamber being zero should only cause a reload and which will re-enable firing. By adding a boolean to the reload state of the one part of the coroutine that holds yields, the script I posted allows Update to run the Coroutine correctly.
This code works to debug log when the script is fired and reloading/reloaded, I also implemented what I assume you were attempting with specifying the number of clips using what I have renamed as ClipCount.
to re-implement the projectiles, just remove the /* and */ characters and remove the debugs.
btw I also changed FixedUpdate() back to Update() as FixedUpdate() did not always recognize a mouseclick as I thought it would
var projectilePrefab: Transform;
var projectileSpeed: float = 10;
var ClipCount: int = 600;
var Rounds: int = 6;
var ReloadTime: float = 2;
private var InChamber = 0;
private var reloading:boolean = false;
function Start(){
InChamber = Rounds; //Startup reload
}
function Update()
{
if (Input.GetButtonDown("Fire1")!reloading)
{
StartCoroutine(Firing());
}
}
function Firing(){
if(InChamber > 0){
/* var projectile = Instantiate(projectilePrefab,
GameObject.FindWithTag("projectileSpawnObject").transform.position,transform.rotation);
projectile.rigidbody.AddForce(transform.forward * (projectileSpeed * 100));*/
InChamber -= 1;
Debug.Log("Fired");
} else if (ClipCount > 0) { //Reload
Debug.Log("Reloading");
reloading = true;
yield WaitForSeconds(ReloadTime);
InChamber = Rounds;
reloading = false;
ClipCount -= 1;
Debug.Log("Reloaded");
}
}
Sorry, when I said “Coroutine()” in there, I meant to imply that the coroutine had yield instructions.
No, you really can’t. It won’t break or give any errors, but even if you start a coroutine from Update() (or any variation of Update()), if that coroutine has any WaitForSeconds yields, they will NOT do anything. So you obviously didn’t fully test your code out there.
Here’s a simple test:
function Update()
{
StartCoroutine(PrintMessagePerSecond());
}
function PrintMessagePerSecond(){
print("This is a message");
yield WaitForSeconds(1.0);
}
You would in theory, think this would print one message per second, right? I promise you, it doesn’t work.
No, that calls PrintMEssagePerSecond every update call so of course it’ll print gajillions of times
Does this work? (I wish I had my computer back to run Unity and not have to ask >…<)
var go : boolean = true;
function Update() {
if ( go ) StartCoroutine( PrintMessagePerSecond() );
}
function PrintMessagePerSecond() {
go = false;
print( "Hi." );
yield WaitForSeconds( 1.0 );
go = true;
}
that’s because the print occurs before you assign the yield! So every update the coroutine starts, prints and then waits and ends the coroutine. Also you require what Vicenti has done which is implement a boolean that requires the Coroutine to have finished its’ last operation before calling it again.
I have tested my code, and obviously you have not. Copy and paste it into an empty project, and test it, then tell me i’m wrong.
Btw Vicenti, I tested your code and yes indeed it only updates every second.
Ahhh, I see what you guys are doing; sorry for the misunderstanding, I never thought of that. Yes, Vicenti your code does work, I just assumed I was right last night as I responded from my iPad in bed sheepish
You’re not actually pausing Update()… you are changing a boolean var that code in Update() depends upon to run, from a coroutine using WaitForSeconds… that’s pretty clever. But isn’t that still basically a workaround, and essentially the same as not using a coroutine and writing a timestamp timer?
When you write a coroutine with the “while(true){ … yield; }” you can just use WaitForSeconds freely, without needing to separate out a bunch of code and have a bunch of unnecessary boolean vars to selectively run segments of code in Update(), it seems much more elegant to me.
Here’s an example of your method appearing to work:
var i:float = 0;
function Start(){
while(true)
{i = Time.time;
StartCoroutine(Coroutine1());
StartCoroutine(Coroutine2());
yield WaitForSeconds(1);
}
}
function Coroutine1()
{
yield WaitForSeconds(0.25);
Debug.Log("first coroutine finished "+ (Time.time-i)+" seconds from the start of this loop");
}
function Coroutine2()
{
yield WaitForSeconds(0.75);
Debug.Log("last coroutine finished "+ (Time.time-i)+" seconds from the start of this loop");
}
and here’s an example of why it really doesn’t:
var i:float = 0;
function Start(){
while(true)
{i = Time.time;
StartCoroutine(Coroutine1());
StartCoroutine(Coroutine2());
yield WaitForSeconds(0.25);
}
}
function Coroutine1()
{
yield WaitForSeconds(0.25);
Debug.Log("first coroutine finished "+ (Time.time-i)+" seconds from the start of this loop");
}
function Coroutine2()
{
yield WaitForSeconds(0.75);
Debug.Log("last coroutine finished "+ (Time.time-i)+" seconds from the start of this loop");
}
in this later example, all debug logs will say 0.25 seconds have passed, even when the second coroutine runs.
because your method actually replicates the functionality Update() method (simply with an update rate that is different from update itself), without booleans your coding method for coroutines sucks just as much as your example earlier:
edit * this really should be a thread named, Update() and how to use it
The latter function there wouldn’t work, unless you set it up so that the StartCoroutine is boolean dependant, otherwise you’re trying to pause Update(), which isn’t possible.
You’d have to do something similar to what Vicenti provided above:
var syncInterval : float = 1.0;
var go : boolean = true;
function Update() {
if ( go ) StartCoroutine( CallTheServer() );
}
function CallTheServer() {
go = false;
yield WaitForSeconds( 1.0 );
go = true;
//more code here
}