AddForce in Coroutine

Hi,

I am developing a game for Android and iOS in which the player taps the screen to gradually move left or right to avoid falling. I decided to implement this requirement with a coroutine that, when the screen is tapped, undergoes a while loop until a maximum horizontal velocity is reached; each loop it adds a force to the rigidbody. I have tested this and it works well on Android when I developed it on my Windows computers. However, I switched the whole project to Mac OS recently to be able to test and build for iOS. On iOS when I tap the screen, a force is applied but apparently much weaker than what it is on my Windows/Android workspace to the point that the player always falls because it cant move fast enough. I have been able to fix this by increasing the move speed of the player when turning on the iOS version. I am not satisfied with this solution because it seems that there is a much deeper bug in my system that will show its head on other devices. I have concluded two possible reasons for this issue.

  1. The coroutine context switching varies on device. This means that the addForce loop will apply differently on each device. Thus, causing the game on some devices to apply the force differently within a given time frame.
  2. This is probably far-fetched, but maybe Mac OS version of Unity applies forces differently. I reasoned this being a possibility because I never came across this issue when I developed the game on Windows while switching between my desktop and laptop (my desktop is way more powerful than the laptop so I would have run into this problem while testing on my laptop. Alas, this only occurs on my Mac test machine, both on running the game within the editor and on a physical iOS device).

Here is the gist of the code I believe is problematic.

void FixedUpdate () {
		if( isPlayerControlEnabled ){

			if( allowTurn ){

				if( moveDirection == Vector3.left ){
					StartCoroutine("newTurnLeft");
				}else if( moveDirection == Vector3.right ){
					StartCoroutine("newTurnRight");
				}else if (moveDirection == Vector3.down * 0f){
					StartCoroutine("newStopHorizontalMovement");
				}
				allowTurn = false;	
			}		
		}
	}

public IEnumerator newTurnLeft(){
		while(rigidBody.velocity.x > -maxHorizontalVelocityMagnitude){
			rigidBody.AddForce (Vector3.left * moveSpeed);
			yield return null;
		}
	}

public IEnumerator newTurnRight(){
		while(rigidBody.velocity.x < maxHorizontalVelocityMagnitude){
			rigidBody.AddForce (Vector3.right * moveSpeed);
			yield return null;
		}
	}

public IEnumerator newStopHorizontalMovement(){

		if( rigidBody.velocity.x > 0f ){
			while( rigidBody.velocity.x > 0f ){
				rigidBody.AddForce (Vector3.left * moveSpeed);
				yield return null;
			}
			rigidBody.velocity.Set (0f, 0f, 0f);
		}else if( rigidBody.velocity.x < 0f ){
			while( rigidBody.velocity.x < 0f ){
				rigidBody.AddForce (Vector3.right * moveSpeed);
				yield return null;
			}
			rigidBody.velocity.Set (0f, 0f, 0f);
		}
	}

Realistically, I feel that the first reason is the problem. Yet, I do not know enough on how Unity handles the physics update system and coroutine calls. I have learned that it is best to apply physics based updates inside the FixedUpdate method so my question boils down to this: can you apply addForce reliably inside a coroutine? Do I have to refactor my movement system so that each addForce call is being called explicitly inside the FixedUpdate method?

Any insight on this is greatly appreciated. Thank you for taking the time to read this.

When using yield return null you wait for the next update. If you instead use yield return new WaitForFixedUpdate(); it continues after a fixedUpdate has been called. A general comment is that it is not ideal to start a new Coroutine every fixed frame as it involves some overhead. Perhaps start it once and use a bool within the Coroutine instead and leave it running until it is no longer needed.