I was tasked to use iTween for Unity to create helicopter movement and rotor movement.

 

After looking through the iTween documentation which can be found here, I created a new scene and placed down a provided helicopter model and a camera, I then started to work on the script for the movement. After going over the documentation I worked with the hash table system as it seemed clearer to use when a few iTween movements where going to be used. But this ended up turning into long bits of code being repeated with minor changes all the way down:

// propeller

Hashtable prp_strt = new Hashtable();
Hashtable prp_strt_sp2 = new Hashtable();
Hashtable prp_strt_sp3 = new Hashtable();
Hashtable prp_cruise = new Hashtable();

// heli

Hashtable heli_up = new Hashtable();
Hashtable heli_move = new Hashtable();

//

void Awake(){
	prp_strt.Add("y",10);
	prp_strt.Add("speed",10);
	prp_strt.Add("time",3);
	//
	prp_strt_sp2.Add("y",20);
	prp_strt_sp2.Add("speed",50);
	prp_strt_sp2.Add("time",5);
	prp_strt_sp2.Add("delay",6);
	//
	prp_strt_sp3.Add("y",40);
	prp_strt_sp3.Add("speed",100);
	prp_strt_sp3.Add("time",5);
	prp_strt_sp3.Add("delay",9);
	//
	prp_cruise.Add("y",80);
	prp_cruise.Add("speed",200);
	prp_cruise.Add("time",5);
	prp_cruise.Add("delay",15);
	//

	// heli body
	heli_up.Add("y",5);
	heli_up.Add("time",3);
	heli_up.Add("delay",17);
	//
	heli_move.Add("z",20);
	heli_move.Add("time",3);
	heli_move.Add("delay",22);

}

void Start () {

	iTween.RotateBy(propel, prp_strt);
	iTween.RotateBy(propel, prp_strt_sp2);
	iTween.RotateBy(propel, prp_strt_sp3);
	iTween.RotateBy(propel, prp_cruise);
	iTween.MoveBy(heli, heli_up);
	iTween.MoveBy(heli, heli_move);

}

This system also turned out to be jerky on each animation end due to easing types or relative speed on the animations being played after, aswell as being unable to control the speed of the propeller animation in a good way.

 

This script was scrapped and i started on a new script using callback feature on the iTween code, This Callback method runs a function when the animation ends. I am also breaking each bit of the script into the relative tasks here.

 

Task 1, Create a fixed point camera, at a high point to follow the helicopter at all times:

This one was an easy one, only requiring a few lines as shown,

public GameObject heli;
public Camera camera;

void Update(){
		Vector3 heliPos = heli.transform.position;

		camera.transform.position = new Vector3(heliPos.x - 10.0f, heliPos.y + 4.0f, heliPos.z);
	}

Using Update void, That runs every frame, This code gets the current position of the helicopter and creates a vector3 (X,Y,Z coordinates) from it. This is then passed into the camera to set its position to this as-well, but offsetting it by 10 units on the Z axis to put it to the left and 4 units on the Y axis to set its position above the heli. The rotation was done in the editor so the script does not need to change it.

 

Task 2, start turning the rotor until achieves a cruising rotation speed:

 

I still chose to use a hashtable for this but instead, using callback on the method and clearing and resetting the hashtable with new values each time. First I started it off with a simple slow start,

Hashtable prop_start = new Hashtable();
Vector3 PropAmount = new Vector3(0,0.2f,0);
float propTime = 4.0f;

void Start(){
	prop_start.Add("amount",PropAmount);
	prop_start.Add("time",propTime);
	prop_start.Add("easetype","easeInSine");
	prop_start.Add("oncomplete","rotate");
	prop_start.Add("onCompleteTarget",heli);
	rotate();
}

void rotate(){
	iTween.RotateBy(propeller,prop_start);
}

To then increase the speed in such a way a heli would I real life, I chose to increase both the distance the animation rotates in the time given and decrease the time periodically, Like so.

void rotate(){
	prop_start.Clear();

	if( propTime > 1.0f){
		propTime = propTime - 0.25f;
		PropAmount.y = PropAmount.y + 0.3f;
	}

	prop_start.Add("name","prop");
	prop_start.Add("amount",PropAmount);
	prop_start.Add("time",propTime);
	prop_start.Add("easetype","linear");
	prop_start.Add("oncomplete","rotate");
        prop_start.Add("onCompleteTarget",heli);

	iTween.RotateBy(propeller,prop_start);
}

This meant I had to then clear and set the hash table each run as well, I also changed the ease type from what the first animation takes to linear to try and give it a realistic speed up, not a slow speed up it took on the first.

Tasks 3-6:

  • once the cruising rotation speed achieved take off and lift the helicopter to a height of 5 units and at the same time rotating it 180 degrees

  • once the previous step finished move the helicopter in straight line for 20 units

  • when the previous step is concluded rotate the helicopter 180 degrees

  • when rotation finishes descend to the ground in 5 seconds

As these have to be done in order, I choose to do a callback on the same method again, but using an increasing int value on a Switch-case, Each one is done in hashtables once again.

void move(){

	heli_rot.Clear();
	heli_move.Clear();
	Vector3 rot;
	Vector3 move;

	switch (moveState)
	{
	    case 1:
			rot = new Vector3(0,0.5f,0);
			heli_rot.Add("amount",rot);
			heli_rot.Add("time",3.0f);
			heli_rot.Add("delay",4.0f);
			heli_rot.Add("easetype","easeInOutCubic");

			move = new Vector3(0,5.0f,0);
			heli_move.Add("amount",move);
			heli_move.Add("time",8.0f);
			heli_move.Add("easetype","easeInOutCubic");
			heli_move.Add("oncomplete","move");
			heli_move.Add("onCompleteTarget",heli);

			moveState = 2;

			iTween.RotateBy(heli,heli_rot);
			iTween.MoveBy(heli,heli_move);
	        break;

	    case 2:
			move = new Vector3(0,0,20.0f);
			heli_move.Add("amount",move);
			heli_move.Add("time",8.0f);
			heli_move.Add("easetype","easeInOutCubic");
			heli_move.Add("oncomplete","move");
			heli_move.Add("onCompleteTarget",heli);

			moveState = 3;

			iTween.MoveBy(heli,heli_move);
	        break;

	    case 3:

			rot = new Vector3(0,0.5f,0);
			heli_rot.Add("amount",rot);
			heli_rot.Add("time",3.0f);
			heli_rot.Add("easetype","easeInOutCubic");
			heli_rot.Add("oncomplete","move");
			heli_rot.Add("onCompleteTarget",heli);

			moveState = 4;

			iTween.RotateBy(heli,heli_rot);
	        break;

	case 4:

			move = new Vector3(0,-5.0f,0);
			heli_move.Add("amount",move);
			heli_move.Add("time",8.0f);
			heli_move.Add("easetype","easeInOutCubic");
			heli_move.Add("oncomplete","move");
			heli_move.Add("onCompleteTarget",heli);

			moveState = 5;

			iTween.MoveBy(heli,heli_move);

			break;
	}
}

 

Task 7, once you landed stop the rotation of the rotor:

This task involved would have had to be called upon the others ending, So this was done just by adding another case value into the switch above,

case 5:
	moveState = 1;
	propStart = false;
    break;

PropStart bool, was introduced to switch what mode the propeller would be doing each call. On false this simple flipped the if statements controlling the increase of time and rotation ammount in the exact same way.

if(propStart){			
	if( propTime > 1.0f){
		propTime = propTime - 0.25f;
		PropAmount.y = PropAmount.y + 0.3f;

} else {
	if( propTime < 4.0f){
		propTime = propTime + 0.25f;
		PropAmount.y = PropAmount.y - 0.3f;
	}
}

 

after each task was done a few bits where changed to make sure it all goes together and runs fine, The end script looked like:

 

using UnityEngine;
using System.Collections;

public class move_script_2 : MonoBehaviour {

	// Public

	public GameObject heli;
	public GameObject propeller;
	public Camera camera;

	// private

	// -- propeller
	Vector3 PropAmount = new Vector3(0,0.2f,0);
	float propTime = 4.0f;
	bool propStart = true;
	bool moveFire = true;

	// -- Heli
	int moveState = 1;

	// hashtables
	Hashtable prop_start = new Hashtable();
	Hashtable heli_move = new Hashtable();
	Hashtable heli_rot = new Hashtable();

	void Start(){
		prop_start.Add("amount",PropAmount);
		prop_start.Add("time",propTime);
		prop_start.Add("easetype","easeInSine");
		prop_start.Add("oncomplete","rotate");
		prop_start.Add("onCompleteTarget",heli);
		rotate();
	}

	void rotate(){
		prop_start.Clear();

		if(propStart){			
			if( propTime > 1.0f){
				propTime = propTime - 0.25f;
				PropAmount.y = PropAmount.y + 0.3f;
			} else {
				if(moveFire){
					moveFire = false;
					move ();
				}
			}

			prop_start.Add("onCompleteTarget",heli);

		} else {
			if( propTime < 4.0f){
				propTime = propTime + 0.25f;
				PropAmount.y = PropAmount.y - 0.3f;

				prop_start.Add("onCompleteTarget",heli);

			} else {
				iTween.StopByName("prop");
			}
		}

		prop_start.Add("name","prop");
		prop_start.Add("amount",PropAmount);
		prop_start.Add("time",propTime);
		prop_start.Add("easetype","linear");
		prop_start.Add("oncomplete","rotate");

		iTween.RotateBy(propeller,prop_start);
	}

	void move(){

		heli_rot.Clear();
		heli_move.Clear();
		Vector3 rot;
		Vector3 move;

		switch (moveState)
		{
		    case 1:
				rot = new Vector3(0,0.5f,0);
				heli_rot.Add("amount",rot);
				heli_rot.Add("time",3.0f);
				heli_rot.Add("delay",4.0f);
				heli_rot.Add("easetype","easeInOutCubic");

				move = new Vector3(0,5.0f,0);
				heli_move.Add("amount",move);
				heli_move.Add("time",8.0f);
				heli_move.Add("easetype","easeInOutCubic");
				heli_move.Add("oncomplete","move");
				heli_move.Add("onCompleteTarget",heli);

				moveState = 2;

				iTween.RotateBy(heli,heli_rot);
				iTween.MoveBy(heli,heli_move);
		        break;

		    case 2:
				move = new Vector3(0,0,20.0f);
				heli_move.Add("amount",move);
				heli_move.Add("time",8.0f);
				heli_move.Add("easetype","easeInOutCubic");
				heli_move.Add("oncomplete","move");
				heli_move.Add("onCompleteTarget",heli);

				moveState = 3;

				iTween.MoveBy(heli,heli_move);
		        break;

		    case 3:

				rot = new Vector3(0,0.5f,0);
				heli_rot.Add("amount",rot);
				heli_rot.Add("time",3.0f);
				heli_rot.Add("easetype","easeInOutCubic");
				heli_rot.Add("oncomplete","move");
				heli_rot.Add("onCompleteTarget",heli);

				moveState = 4;

				iTween.RotateBy(heli,heli_rot);
		        break;

		case 4:

				move = new Vector3(0,-5.0f,0);
				heli_move.Add("amount",move);
				heli_move.Add("time",8.0f);
				heli_move.Add("easetype","easeInOutCubic");
				heli_move.Add("oncomplete","move");
				heli_move.Add("onCompleteTarget",heli);

				moveState = 5;

				iTween.MoveBy(heli,heli_move);

				break;
		case 5:
				moveState = 1;
				propStart = false;
			break;
		}
	}

	void Update () {

		if(Input.GetKeyUp(KeyCode.R)){
			Application.LoadLevel (Application.loadedLevelName);
			Debug.Log("test");
		}

		// Camera 

		int posAway = -15;
		Vector3 heliPos = heli.transform.position;
		camera.transform.position = new Vector3(heliPos.x - 10.0f, heliPos.y  + 10.0f, heliPos.z);
	}
}

 

Scene Viewable here:

Press R to reset.

[unity src=”787″]


Leave a Reply

Your email address will not be published.