- Home /
Yield Causing function not to be called on multitouch script
Hi, I've been working on a multitouch swipe script, however i seem to have run into a little snag. It occured when I was going to merge the multitouch with the swipe (both of which worked perfectly on their own). It seems a yield within a while loop I use to track the swipe is causing the entire function it is within to go ignored. This yield wassn't a problem in the original script however now it suddenly won't play nice. :P
The loop in question:
while (Input.touchCount > 0){
var ray = mainCamera.ScreenPointToRay(touch.position);
var thepoint:Vector3 =ray.GetPoint(distance);
springJoint.transform.position = thepoint;
yield;
}
This is contained within a function that is called on each update. The touch position is dependent on a touch manager script (however i have checked that it is indeed recieving coordinates, etc.).
Here's both the update and the DragObject function which contains the loop:
function Update(touch:Touch){
this.touch = touch;
isUpdate = true;
/*if(!isSelect)
{*/
// We need to actually hit an object
var hit : RaycastHit;
if (!Physics.Raycast(mainCamera.ScreenPointToRay(touch.position), hit, 100)) {
isSelect = false;
return;
}
// We need to hit a rigidbody that is not kinematic
if (!hit.rigidbody || hit.rigidbody.isKinematic) {
isSelect = false;
return;
}
if (!springJoint)
{
var go = new GameObject("Rigidbody dragger");
var body : Rigidbody = go.AddComponent ("Rigidbody") as Rigidbody;
springJoint = go.AddComponent ("SpringJoint");
body.isKinematic = true;
isSelect = true;
}
else
{isSelect = true;}
springJoint.transform.position = hit.point;
springJoint.spring = spring;
springJoint.damper = damper;
springJoint.maxDistance = distance;
springJoint.connectedBody = hit.rigidbody;
DragObject(hit.distance, hit.point, touch);
//}
}
function DragObject(distance : float, hitpoint : Vector3, touch : Touch)
{
var startTime = Time.time;
var oldDrag = springJoint.connectedBody.drag;
var oldAngularDrag = springJoint.connectedBody.angularDrag;
springJoint.connectedBody.drag = drag;
springJoint.connectedBody.angularDrag = angularDrag;
while (Input.touchCount > 0)
{
var ray = mainCamera.ScreenPointToRay(touch.position);
var thepoint:Vector3 =ray.GetPoint(distance);
springJoint.transform.position = thepoint;
yield;
}
if (springJoint.connectedBody)
{
springJoint.connectedBody.drag = oldDrag;
springJoint.connectedBody.angularDrag = oldAngularDrag;
springJoint.connectedBody = null;
}
}
I have tried using returns instead of the yield but it doesn't seem to result in the same effect. I hope someone can help me out as it would be much appreciated :)
Regards MB
I've been using "debug.Log" a lot and that's how i found that the function seems to be skipped due to the yield. From what I've found the entire update function works like a charm and all the variables are returning the correct data. However due to the yield it seems to ignore the DragObject class. Like i stated in my original question: I have tested with returns, in which case the function is run, however to the undesired outcome. The drag functioned well when it was on it's own (taking only Input.GetTouch(0)), however when merged with the mul$$anonymous$$ch script the yield suddenly refuses to work (even when only taking info from finger one). I would greatly appreciate it if someone knew what could be causing this.
You cannot yield from a function called by Update unless you start it as a coroutine. Basically it never executes anything after the first time it yields.
@whydoidoit: But in UnityScript you don't need to call StartCoroutine explicitly. The compiler calls StartCoroutine implicitly when you just "run" a Coroutine / generator (a function that yields). You only have to use StartCoroutine when you want to yield another coroutine.
Answer by Mithosbluefish · Aug 12, 2013 at 12:40 AM
Problem was that if you make a coroutine within a class in UnityScript it will need a StartCoroutine.
Note that (as Bunny mentions above) in fact you generally DON'T need a StartCoroutine in Unityscript. It will do it for you automatically. (It even says so in the Unity doco.)
But I will tell you just the problem you're having....
The problem is that your routine DragObject .....
"sometimes" it is a coroutine, and "sometimes" it is NOT a coroutine.
Note that in the code in DragObject, it is not guaranteed to call the yield.
It's the same issue I was having here...
http://answers.unity3d.com/questions/471783/freaky-cant-return-out-of-an-ienumerator.html
The problem is you have two paths, one with yield in it and one with no yield in it.
It just seems to be "too much" for the Javascript to automagically make decisions about, or something.
I completely investigated this Javascript curiosity when it came up - but actually I forget the result!
(None of this will come up in c#)
Among other things you may want to explicitly declare that the function is a coroutine, eg,
function DragObject(distance : float, hitpoint : Vector3, touch : Touch):IEnumerator
The bottom line is you just "shouldn't write code like that" -- in Javascript in an implicit coroutine always call yield -- don't make a "two path" routine.
So: the simple solution .. where you
while (Input.touchCount > 0)
if so, just break away to a different routine (ie, it will be your yielding coroutine) - it's that simple.
Hey, thanks for the feedback, this problem was actually solved a while ago but i thought i should write how I solved it. The code works fine in C# and UnityScript when it's not in a class, it is only when it is within a class that the function needs to explicitly be called as a coroutine. As for the function it self (on and off coroutining), I based it on a unity tutorial from one of the unity pages, but will definitely revise my technique for next time. Thanks again for the feedback :).
Sounds good. The salient facts are:
(1) In fact in U/S, as Bunny says, you don't need to explicitly call StartCoroutine. (You could possibly say that in a sense, if you DO have to do that there is a problem.)
(2) There is a problem in U/S, relating to coroutines. Since it "automatically" figures out if it is a coroutine (basically, if it contains yield), you can have trouble if there are TWO PATHS within a routine, one of which does and one of which does not contain a yield concept.
Essentially, for anyone reading in the future, just don't do that. IE, type the extra 12 or 13 keystrokes and just make that "path" a separate function.
Hope it helps someone!
Answer by Mithosbluefish · Sep 23, 2012 at 02:54 AM
I managed to solve it, turns out my mistake was in a part i didn't include here as i thought it wasn't relevant. Turns out it was due to my class not being derived from monodevelop and hence didn't work.
So i added:
class Coroutiner extends MonoBehaviour
{
}
and called:
coroutineRunner.StartCoroutine(DragObject(hit.distance, hit.point, touch);
and not it works perfectly :D
Your answer
![](https://koobas.hobune.stream/wayback/20220613081328im_/https://answers.unity.com/themes/thub/images/avi.jpg)