Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to have an object rotate with just 1 click

Discussion in 'Getting Started' started by Sunderer, Apr 25, 2015.

  1. Sunderer

    Sunderer

    Joined:
    Mar 16, 2015
    Posts:
    35
    Currently I am rotating an object successfully but only when I have my button held down with the following code. I am trying to figure out how to achieve this with just 1 click then the object rotates itself without stopping:
    Code (CSharp):
    1. {
    2.     public float lifetime;
    3.  
    4.  
    5.     void Update ()
    6.     {
    7.         if (Input.GetKey(KeyCode.Return))  
    8.         {
    9.         OpenWall1();
    10.         OpenWall2();
    11.         OpenWall3();
    12.         OpenWall4();
    13.         audio.Play();
    14.         }  
    15.        
    16.        
    17.     }  
    18.     void OpenWall1()  
    19.     {
    20.         if (tag == "Wall1")
    21.         {
    22.         Debug.Log("WALL 1 ACTIVE");
    23.         transform.Rotate(new Vector3(0.0f,0.0f,-15) * 1 * Time.deltaTime);
    24.         Destroy (gameObject, lifetime);
    25.         }
    26.        
    27.     }
    28.     void OpenWall2()  
    29.     {
    30.         if (tag == "Wall2")
    31.         {
    32.         Debug.Log("WALL 2 ACTIVE");
    33.         transform.Rotate(new Vector3(0.0f,0.0f,15) * 1 * Time.deltaTime);
    34.         Destroy (gameObject, lifetime);
    35.         }
    36.        
    37.     }
    38.     void OpenWall3()  
    39.     {
    40.         if (tag == "Wall3")
    41.         {
    42.         Debug.Log("WALL 3 ACTIVE");
    43.         transform.Rotate(new Vector3(15,0.0f,0.0f) * 1 * Time.deltaTime);
    44.         Destroy (gameObject, lifetime);
    45.         }
    46.        
    47.     }
    48.     void OpenWall4()
    49.     {
    50.         if (tag == "Wall4")
    51.         {
    52.         Debug.Log("WALL 4 ACTIVE");
    53.         transform.Rotate(new Vector3(-15,0.0f,0.0f) * 1 * Time.deltaTime);
    54.         Destroy (gameObject, lifetime);
    55.         }
    56.        
    57.     }
    58. }
     
  2. Sunderer

    Sunderer

    Joined:
    Mar 16, 2015
    Posts:
    35
  3. Schneider21

    Schneider21

    Joined:
    Feb 6, 2014
    Posts:
    3,512
    Disclaimer: I won't give code. I find it more beneficial to guide people to finding the answers themselves. Sort of the old "Teach a man to fish" mentality.

    So with that in mind, look at your code. Consider what you're doing. Within the Update method (which runs once every frame), you're checking on line 7 whether the Return key is being pressed. If it is, you're running your 4 OpenWall functions (not the most efficient way of doing this, I might add), and playing an audio clip. If the Return key isn't pressed for that frame, you do nothing.

    So in that sense, your code is working perfectly!

    If you want to change it to work the way you described, think through what you actually want to happen in programmatic terms. Every frame, you want to check and see if the Return key has been pressed. If it has, a condition has been met. The best way I know of to keep track of these binary conditional situations is a boolean value. Set that value to true once the return key is pressed. Separately, within the Update function, check the status of that variable. If it's true, run your OpenWall functions. If the walls can be stopped at any point, instead of just setting the value to true, consider toggling it (by setting it to the opposite of its current state).

    On the subject of your OpenWall# functions, any time you see repeated or very similar lines of code, that's a good sign you should be using a function with parameters to define the details. Consider rewriting this to have only one OpenWall function, and pass it values to define the specifics of what and how you're opening it. DRY -> Don't Repeat Yourself. It'll make your code much easier to maintain and modify as you go.
     
  4. Sunderer

    Sunderer

    Joined:
    Mar 16, 2015
    Posts:
    35
    Hi Schneider, yes this is what I finally concluded myself:

    Code (CSharp):
    1.         if (Input.GetKeyDown(KeyCode.Return))  
    2.         {
    3.             LetsGo = true;
    4.         }  
    5.        
    6.         if (LetsGo == true)
    7.         {
    8.             OpenWall1();
    9.             OpenWall2();
    10.             OpenWall3();
    11.             OpenWall4();
    12.         }
    13.        
    Thank you for the guidance. You did say that this is not the most efficient way of doing this. Could you guide me towards a more efficient way? Thanks
     
  5. Schneider21

    Schneider21

    Joined:
    Feb 6, 2014
    Posts:
    3,512
    Sure.

    Side note: As a convention, avoid variable names beginning with capital letters. Look into naming conventions to see why.

    Okay, so actually looking through this code in a bit more detail... I'm thinking this script is attached to the walls themselves, not some other object. So parameters wouldn't be the way to go here, necessarily. But still, you could clean this up a lot, like so:

    Code (CSharp):
    1. public class sfs : MonoBehaviour {
    2. public float objectLifetime;
    3. public float rotationSpeed = 15.0f;
    4. public bool shouldRotate = false;
    5.  
    6. // Update is called once per frame
    7. void Update () {
    8.     if (Input.GetKeyDown(KeyCode.Return)) {
    9.         shouldRotate = ! shouldRotate;
    10.     }
    11.  
    12.     if (shouldRotate) {
    13.         OpenWall();
    14.     }
    15. }
    16.  
    17. void OpenWall() {
    18.     Vector3 rotationDirection;
    19.  
    20.     switch (tag) {
    21.     case "Wall1":
    22.         rotationDirection = new Vector3(0.0f,0.0f,-rotationSpeed);
    23.         break;
    24.     case "Wall2":
    25.         rotationDirection = new Vector3(0.0f,0.0f,rotationSpeed);
    26.         break;
    27.     case "Wall3":
    28.         rotationDirection = new Vector3(rotationSpeed,0.0f,0.0f);
    29.         break;
    30.     case "Wall4":
    31.         rotationDirection = new Vector3(-rotationSpeed,0.0f,0.0f);
    32.         break;
    33.     default:
    34.         Debug.Log ("No tags found");
    35.         rotationDirection = Vector3.zero;
    36.         break;
    37.     }
    38.  
    39.     Debug.Log(tag + " active");
    40.     transform.Rotate(rotationDirection * Time.deltaTime);
    41.  
    42.     Destroy (gameObject, objectLifetime);
    43. }
    I know I said I wouldn't give code, but examples can be useful, too. :D

    So a couple things to note:
    • This script assumes it's attached to the Wall object you're referencing. It checks the tag, and if it's one of the 4 you described, it sets the rotation direction. It then rotates in the assigned direction. It does the same thing your code was doing, but saves having to write out the Rotate method multiple times.
    • I'm not saying this is good code, or a good way to solve the situation you're handling, but I am saying this is better code. ;)
    • Also, I switched out the magic number in your rotation with a variable. Look into magic numbers and why you should avoid them as well.
    • One further improvement you may be able to make is to only check the tag on key press, and set the rotation direction there. That way you're not looking up the object's tag every frame like you currently are.