Unity: Rotation Controller
Posted by Dimitri | Jun 13th, 2011 | Filed under Programming
Another day, another Unity3D programming post. This tutorial contains not just one, but two scripts that rotates a game object around another one, based on the keyboard input. Again, like the previous tutorial, this was also inspired by retro games, such as S.T.U.N. Runner or the special stages from Sonic 2, where the player controls the main character by pressing left or right, making it complete a full circle in the screen. However, unlike those games, the below scripts aren’t applying gravity to the player, for the sake of simplicity. Everything explained here is available for download at the end of the tutorial.
For both of the scripts, we are going to need two game objects: the first is going to be the player, and the other one will be the pivot that the player rotates around. The process of creating both is the same, just click on GameObject->Create Other->Cube twice, naming the first one as Player and the other one as Player Pivot:
The Player Pivot game object will act as the rotation pivot for the Player game object. Now place both game objects at the same position, and center then at the world origin (X:0, Y:0, Z:0). The last thing to do is to move the camera to focus both objects and move the Player game object only at the Y axis, as shown:
The last thing to prepare on the scene is to assign a new tag to the Pivot game object, naming it Pivot. After creating it, assign the tag to the Pivot game object.
Finally, it is now possible to attach one of the scripts to the Player game object. The first one will rotate the player around the pivot counterclockwise when pressing left and clockwise when pressing right:
using UnityEngine; using System.Collections; public class RotationControllerSimple : MonoBehaviour { //the containing game object's Transform private Transform goTransform; //the pivot which the game object should rotate around at private Transform pivotTransform; //the velocity to rotate the game object public float vel = 2.0f; void Awake() { //get the game object's Transform goTransform = this.GetComponent<Transform>(); //get the pivot's Transform pivotTransform = GameObject.FindWithTag("Pivot").GetComponent<Transform>(); } // Update is called once per frame void FixedUpdate () { //rotate the player around the pivot goTransform.RotateAround(pivotTransform.position, Vector3.forward, Input.GetAxisRaw("Horizontal")*vel); } }
This simple script will work as described. Lines 7,9 and 11 declare two Transforms and a float. The first two are variables that will hold the containing game object Transform and the pivot game object Transform respectively. The third one is a float that determines the velocity in which the Player should rotate. The Awake() method, initializes the two Transform variables (lines 13 through 19). After that, the FixedUpdate() method just makes the attached game object (the Player) rotate around the Player Pivot game object at the determined speed (lines 22 through 26).
That works as expected, however, the above script will only rotate the object clockwise and counterclockwise with the left and right arrow keys, meaning that when the controllable object is over top half of the screen, the controls, will appear to be inverted, as shown:
While this is still a correct behavior, it can be counterintuitive for some players. And that’s the reason why we may need another script, that will invert the controls when the controllable game object is over the top half of the screen:
using UnityEngine; using System.Collections; public class RotationControllerRelative : MonoBehaviour { //the containing game object's Transform private Transform goTransform; //the pivot which the game object should rotate around at private Transform pivotTransform; //the velocity to rotate the game object public float vel = 2.0f; //a boolean that flags if the player is at the top side of the screen private bool topSide = false; //the direction (clockwise or counter clockwise) float motionDirection; void Awake() { //get the game object's Transform goTransform = this.GetComponent()<Transform>; //get the pivot's Transform pivotTransform = GameObject.FindWithTag("Pivot").GetComponent<Transform>(); } // Update is called once per frame void FixedUpdate () { //if one of the horizontal buttons were pressed and then released if(Input.GetButtonUp("Horizontal")) { //if the player is at the top half if(goTransform.position.y>0) { topSide = true; } else //player is at the bottom half { topSide = false; } } //if the player is at the top half of the screen if(topSide) { //Right => Clockwise. Left => Counterclockwise motionDirection = -Input.GetAxisRaw("Horizontal"); } else { //Right => Counterclockwise. Left => Clockwise motionDirection = Input.GetAxisRaw("Horizontal"); } //rotate the player around the pivot goTransform.RotateAround(pivotTransform.position, Vector3.forward, motionDirection*vel); } }
This second script is just like the first one: it takes the containing game object’s Transform and the Player Pivot game object Transform and the float vel. But additionally, it declares the boolean topSide, that flags whether the Player game object is at the top side of the screen; and the float motionDirection that tells if the game object should rotate clockwise or counterclockwise (lines 7 to 15). The Awake() method works exactly as the first script: it initializes the Transform member variables.
The FixedUpdate(), is where things are completely different. The first if statement checks if one of the horizontal keys were released. Case that’s true, another if statement checks the position of the Player game object, setting the topSide boolean to true, in the event that the player is at the top half of the screen, and sets it to false otherwise (lines 29 to 40).
The second if statement checks the value of topSide. If it’s value is true, pressing the right arrow key will rotate the controllable game object clockwise, storing the direction at the motionDirection float variable. Pressing left, will rotate it counterclockwise. If false, right rotates it counterclockwise and left, clockwise, also storing this result at the motionDirection variable (lines 43 through 52). Finally, the motion is applied, by calling the game object’s RotateAround() method, passing the containing game object’s Transform, the pivot’s Transform, and the motionDirection multiplied by the velocity (vel) as parameters.
In short, here’s an image to better illustrate what this script does:
Still, it will be counterintuitive to many players. There is one other option: instead of inverting the controls at the top half of the screen, it’s possible to invert the motion vertically, separating the screen in right and left sides. Just replace line 32 for the following:
if(goTransform.position.x<0)
Hope that was useful for something.
Thanks for your script it works great!
Extremely thanks man !