Search Unity

Three conflicting rotation scripts

Discussion in 'Getting Started' started by JoshVIZfire, Jul 26, 2018.

  1. JoshVIZfire

    JoshVIZfire

    Joined:
    Jul 26, 2018
    Posts:
    14
    Hello!

    Very new to Unity and C# scripting. I have an Unreal background and have only used kismet or blueprinting before. I really want to start using Unity but could use some help learning some of basics. I would appreciate any suggestions I can get. I have combined 3 techniques I have learned from watching tutorials. These scripts work separately, however I am failing at executing all three together in one component. Ultimately I have an interactive sphere and would like to be able to rotate it three ways. One being an idle rotate. Two being a touch screen rotate. Three being rotation from a UI slider input.

    I am aiming to have One start if the screen is left idle for some time and then stop when Two or Three are active. Then Two and Three cancel each other out and can't happen at the same time.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class RotateEarth : MonoBehaviour
    7. {
    8.  
    9.  
    10.     // Constant Rotate
    11.     public float speed = 1f;
    12.     void FixedUpdate()
    13.     {
    14.         transform.Rotate(0, 0, -speed * Time.deltaTime);
    15.     }
    16.  
    17.  
    18.  
    19.     // Rotate On Touch or Swipe
    20.     public float horizontalSpeed = 2.0F;
    21.     //public float verticalSpeed = 2.0F;
    22.     void OnMouseDrag()
    23.     {
    24.         float h = -horizontalSpeed * Input.GetAxis("Mouse X");
    25.         //float v = verticalSpeed * Input.GetAxis("Mouse Y");
    26.         transform.Rotate(0f, 0f, h);
    27.     }
    28.  
    29.  
    30.  
    31.     //Rotate On Slider
    32.     public Slider slider;
    33.     public Component sphere;
    34.     private void Update()
    35.     {
    36.         transform.eulerAngles = new Vector3(-90, 0, slider.value);
    37.         //transform.Rotate(0, 0, slider.value);
    38.  
    39.     }
    40.  
    41.  
    42. }
    43.  
    44.  
    45.  
     
  2. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Do you have a question? Are you receiving an error?
     
  3. JoshVIZfire

    JoshVIZfire

    Joined:
    Jul 26, 2018
    Posts:
    14
    Thanks for the reply. Yes. So there isn't any errors. However the two interactive scripts (Rotate on Slider & Rotate On Touch or Swipe) are conflicting and is resulting in the slider option only working. I am trying to figure out an efficient way that both can happen. Would you have any suggestions?
     
  4. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    You will want to combine the scripts into one for easier development.
     
  5. JoshVIZfire

    JoshVIZfire

    Joined:
    Jul 26, 2018
    Posts:
    14
    OK gotcha. I have them in one script called out as Rotate Earth. Currently on the Main Component that I am looking to Rotate.
     
  6. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    This line is your problem. You are resetting the angles each frame. Try it instead this way:

    Code (CSharp):
    1. transform.eulerAngles = new Vector3(transform.eulerAngles.x, transform.eulerAngles.y, slider.value);
    You might still encounter problems with degeneracy and gimbal lock, but those are problems for another day.
     
  7. JoshVIZfire

    JoshVIZfire

    Joined:
    Jul 26, 2018
    Posts:
    14
    I see. Thanks! that works better. I am still having the problem of the Touch Rotate and the Slider Rotate don't work when both are active. Do you have any suggestions on how I can have both active at the same time?
     
  8. JoshVIZfire

    JoshVIZfire

    Joined:
    Jul 26, 2018
    Posts:
    14
    upload_2018-7-31_10-6-24.png
    I think I might have made a solution for them being active. I have them activating through a triggered collision. I am not sure if that is the most efficient way for this to happen but it works.
     
  9. jhocking

    jhocking

    Joined:
    Nov 21, 2009
    Posts:
    814
    The issue is that both Update and FixedUpdate are applying rotation every frame, without checking which rotation "state" you are in. You should have an 'if' statement or switch that checks which rotation state you are in so that only the right rotation code runs.

    btw I'm not entirely in agreement with the advice "You will want to combine the scripts into one for easier development." That is certainly one approach you could take, but you could also have the different rotation scripts turn on and off, so only one is active at a time.
     
    JoshVIZfire likes this.
  10. JoshVIZfire

    JoshVIZfire

    Joined:
    Jul 26, 2018
    Posts:
    14
    That make sense to me. I am going to break up the two interactive scripts and create an if statement that will control which one is active at a time.
     
  11. jhocking

    jhocking

    Joined:
    Nov 21, 2009
    Posts:
    814
    To go that direction, I would make each rotation state a separate script, and then have a fourth script (called RotationStateController or something) that turns the others on/off.
     
    JoshVIZfire likes this.
  12. JoshVIZfire

    JoshVIZfire

    Joined:
    Jul 26, 2018
    Posts:
    14
    Oh ok I see. 4 scripts on one component. One being the "director script" that would hold all the conditions of of the movements. I will try this out. Thank you!
     
  13. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Yes, separate classes in separate scripts makes sense. But not 4 scripts with Start, Update and FixedUpdate methods each for the same component! I wouldn't want to debug or provide code maintenance with that coding approach.
     
  14. jhocking

    jhocking

    Joined:
    Nov 21, 2009
    Posts:
    814
    Yep you understand the general idea I was saying, although a terminology correction:

    A script is a component, so this would be 4 components on one object, not 4 scripts on one component. And assuming this is the situation you're talking about Jeff, I'm not sure why you consider this situation a maintenance nightmare. I suppose there's a lot of spaghetti potential here, but mostly it depends how much these scripts are doing.

    EDIT: Perhaps you are thinking multiple scripts would be applying rotations at the same time? Because I would agree, that would be difficult to think through. However that's not what I'm suggesting. I'm talking about only having one rotation script at a time active. The rotation state controller would have logic like "if the slider is moving, then RotateWithSlider.enabled=true and RotateConstant.enabled=false and RotateOnSwipe.enabled=false".
     
    Last edited: Jul 31, 2018
  15. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Again, I would not have 4 scripts on the same object, each containing Start, Update and FixedUpdate event handlers, and separately manage their behavior with global variables. Just keep the logic in one file for easy debugging, and use method calls for each behavior. Or separate files for each method, but not sure why you would want to do that. As long as they don't contain the events I mentioned.
     
  16. jhocking

    jhocking

    Joined:
    Nov 21, 2009
    Posts:
    814
    Yes you've already mentioned that you think this is a bad idea, but what you haven't explained is why this is a bad idea. You did mention global variables, which may mean you misunderstand the situation, since I'm not talking about any global variables. Here, some code to help illuminate what I am talking about:

    Imagine 4 MonoBehaviours all placed as components on one object. RotateContinuous, RotateOnSwipe, and RotateWithSlider are the three rotation behaviors Josh already has working separately. The fourth is something like this (written off the top of my head):

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class RotationStateManager : MonoBehaviour {
    5.   [SerializeField] GameObject slider; // link the slider to this slot in the Inspector
    6.  
    7.   private RotateContinuous _rotateContinuous;
    8.   private RotateOnSwipe _rotateSwipe;
    9.   private RotateWithSlider _rotateSlider;
    10.  
    11.   private bool _isBeingDragged;
    12.  
    13.   void Start() {
    14.     _rotateContinuous = GetComponent<RotateContinuous>();
    15.     _rotateSwipe = GetComponent<RotateOnSwipe>();
    16.     _rotateSlider = GetComponent<RotateWithSlider>();
    17.  
    18.     DisableAll();
    19.   }
    20.  
    21.   void Update() {
    22.     DisableAll();
    23.  
    24.     if (EventSystem.currentSelectedGameObject == slider) {
    25.       _rotateSlider.enabled = true;
    26.     } else if (_isBeingDragged) {
    27.       _rotateSwipe.enabled = true;
    28.     } else {
    29.       _rotateContinuous.enabled = true;
    30.     }
    31.  
    32.     _isBeingDragged = false;
    33.   }
    34.  
    35.   void OnMouseDrag() {
    36.     _isBeingDragged = true;
    37.   }
    38.  
    39.   private void DisableAll() {
    40.     _rotateContinuous.enabled = false;
    41.     _rotateSwipe.enabled = false;
    42.     _rotateSlider.enabled = false;
    43.   }
    44. }
    45.  
    You might need to optimize the state switching so it won't keep setting enabled to true if it already is (I don't remember if that'll keep triggering OnEnabled every time). With this setup the code in each rotation script is completely separate from the other two, which nicely encapsulates things so making modifications in one rotation script has no effect on the others.
     
    Last edited: Aug 1, 2018
  17. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Agreed, as long as each script doesn't have their own Start method, etc. That's all I meant.
     
    jhocking likes this.