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

Problems repositioning objects

Discussion in '2D' started by TheWebExpert, Sep 15, 2016.

  1. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    I have several GameObjects in my program, which I've reference using public GameObject x, where x is the variable name I'm giving it in code; I've dragged the appropriate item over to the Inspector window.

    During the game, I have the user rotate the camera via a button. You're either facing North, South, East or West. (I'm only doing East at the moment, to make IT work). When you click the button, the camera rotates (properly) and repositions (properly) so you can see what you're doing.

    I also have a canvas, and it's these items that are giving me the problems. I rotate the canvas along with the camera, the same 90 degrees. I then move the items on the canvas, as follows:

    Code (CSharp):
    1.             Background.transform.position= new Vector3(202F, -261F, 428F);
    2.             SliderXO.transform.position= new Vector3(-142F, -346F, 414F);
    3.             SliderYO.transform.position= new Vector3(-142F, -376F, 414F);
    4.             SliderZO.transform.position= new Vector3(-142F, -404F, 414F);
    5.  
    ...and so on.

    The objects ARE moving, but not to where I told them to move. When I look at each item, the x, y & z positions are completely different from what's shown here. If I manually type in the correct x, y & z numbers, the pieces go right where they're supposed to.

    But WHY, pray tell, aren't these things moving where I want them to? Does it have anything to do with where they're anchored (upper-right)? I've tried screen overlay, world camera, the works, and I can't seem to get these to move to my specified coordinates. I feel like it's something pretty simple that I'm missing here, but I can't see the forest for the trees.

    Can anyone help with this?
     
  2. PeaceLaced

    PeaceLaced

    Joined:
    Jun 2, 2015
    Posts:
    53
    Are the objects you are trying to move, child objects of a parent object?
     
  3. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Uh... yeah; they're attached to the canvas. Does this make a difference??
     
  4. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    For Transform components, the position shown in the inspector is the localPosition relative to the parent. If there is no parent, then the position is world-space.

    However, with a Canvas object you're dealing with the RectTransform component. RectTransforms have positions, as well as anchors for child objects to be positioned and sized relative to. So instead of just object space, you have object space relative to anchor points.

    So you'll need to get the RectTransform, and you can try setting anchoredPosition, which is likely the value you see in the inspector.

    I think you can do this:
    Code (CSharp):
    1. (transform as RectTransform).anchoredPosition =
    2. // or
    3. RectTransform rectTransform = (RectTransform)transform;
    4. rectTransform.anchoredPosition =
     
    Last edited: Sep 16, 2016
    PeaceLaced likes this.
  5. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Do you mean like this?

    Code (CSharp):
    1. Background.GetComponent<RectTransform>().transform.position= new Vector3(202F, -261F, 428F);
    It's having the same effect as the other - the object moves to a completely different set of coordinates. I have about a dozen items, and I'd need to move EACH of their RectTransforms.

    Moving the canvas is worse - I can't figure out where it is when I move it, so that's no good.
     
    Last edited: Sep 16, 2016
  6. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    I still need help with this! I now have this:

    Code (CSharp):
    1. RectTransform BRect = Background.GetComponent<RectTransform>();
    2. BRect.anchoredPosition = new Vector3(202F, -261F, 79F);
    So, the object is moved to the correct position in the X & Y axis, but NOT on the Z axis. The Z axis is staying the same as it is when the program isn't running. So, it's working better, but still not right. Any ideas?
     
    Last edited: Sep 19, 2016
  7. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Hey there, sorry I wasn't available yesterday (or over the weekend). "anchoredPosition" is a Vector2, so it doesn't have a Z value. The Vector3 you pass in is being cast to a Vector2, and the Z value is being zeroed out.

    Try using "BRect.anchoredPosition3D"

    Check out the docs for some more insight:
    https://docs.unity3d.com/ScriptReference/RectTransform.html
     
  8. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    I guess you missed the "Z" values in my first couple of posts. That was EXACTLY what it needed. Why these should be different... well, I guess the whole attachment to the canvas thing makes all the difference. At least it's where I want it X, Y, & Z now... all that's left is to play around with the other numbers to get their positions right.

    Thanks! Once again you've saved the day! :)
     
  9. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Actually I was unaware that anchoredPosition was a Vector2 until you told me that the Z axis wasn't working, I've never used anchoredPosition3D haha.

    Sorry! ¯\_(ツ)_/¯

    Glad its working for you now.
     
  10. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Thanks! I have a new problem, however... a mysterious object reference not set to an instance of an object. Here's the code:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using System.Collections;
    4.  
    5. public class GameScript : MonoBehaviour
    6.   {
    7.     public float  RotSpeed;
    8.     public Slider SliderX;
    9.     public Slider SliderY;
    10.     public Slider SliderZ;
    11.  
    12.     void Update()
    13.      {
    14.         if (Input.GetMouseButton(0))
    15.          {
    16.             var Angle = new Vector3(Input.GetAxis("Mouse Y"), Input.GetAxis("Mouse X"), 0);
    17.             this.transform.Rotate(Angle * RotSpeed);
    18.             SliderX.value = this.transform.eulerAngles.x;
    19.             SliderY.value = this.transform.eulerAngles.y;
    20.             SliderZ.value = this.transform.eulerAngles.z;
    21.          }
    22.      }
    23.   }
    That's all the code there is for this section; the error is coming from line 18. Somehow, inexplicably, this is showing as a null reference. The error is DEFINITELY coming from this (I commented things out to prove it). The Inspector has the proper slider dragged into each of the three spots, and yet...
     
    Last edited: Sep 22, 2016
  11. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Try using Debug.Log to print out the three sliders before you use them. See if any come back null.

    If you comment out the line with SliderX, does the SliderY line error?

    Is that the exact line that the error message points you to?
     
  12. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    If I comment out SliderX, the error comes from SliderY, etc. If I attempt to DO anything with the variable, I get the error. I can't print it, either.
     
  13. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Try this:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using System.Collections;
    4.  
    5. public class GameScript : MonoBehaviour {
    6.     public float RotSpeed;
    7.     public Slider SliderX;
    8.     public Slider SliderY;
    9.     public Slider SliderZ;
    10.  
    11.     void Update() {
    12.         if(Input.GetMouseButton(0)) {
    13.             var Angle = new Vector3(Input.GetAxis("Mouse Y"), Input.GetAxis("Mouse X"), 0);
    14.             this.transform.Rotate(Angle * RotSpeed);
    15.  
    16.             if(SliderX != null) {
    17.                 SliderX.value = this.transform.eulerAngles.x;
    18.             } else {
    19.                 print("slider x is null");
    20.             }
    21.  
    22.             if(SliderY != null) {
    23.                 SliderY.value = this.transform.eulerAngles.y;
    24.             } else {
    25.                 print("slider y is null");
    26.             }
    27.  
    28.             if (SliderZ != null) {
    29.                 SliderZ.value = this.transform.eulerAngles.z;
    30.             } else {
    31.                 print("slider z is null");
    32.             }
    33.         }
    34.     }
    35. }
    Where are you assigning these slider references? Are you certain that when the game is running, those fields have the references they need? Check out the inspector for this script on the actual object in the scene, while the game is running, or hit the pause button and check it out.
     
  14. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    This script is attached to my cube object in the main scene; whether in stop mode or play mode, the Inspector shows this:


    The code you've supplied above shows that SliderX, SliderY and SliderZ are ALL null. I'm clueless, here; they're assigned in the Inspector, and exist at runtime...
     
  15. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Well, it's just a matter of trial and error I suppose, I don't know why you're getting null values from that.

    Instead of taking Slider references, try passing in the GameObjects, and donig GetComponent<Slider>(). Keep null checking though so you know where the problems are.
     
  16. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Ok, here's what I have now:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using System.Collections;
    4.  
    5. public class GameScript : MonoBehaviour
    6.   {
    7.     public float  RotSpeed;
    8.       Slider SliderX;
    9.       Slider SliderY;
    10.       Slider SliderZ;
    11.     public GameObject SliderXO;
    12.     public GameObject SliderYO;
    13.     public GameObject SliderZO;
    14.  
    15.       void Update()
    16.         {
    17.             if (Input.GetMouseButton(0))
    18.               {
    19.             float x = Input.mousePosition.x;
    20.             float y = Input.mousePosition.y;
    21.             //print ("x "+x+" y "+y);
    22.             if (x >= 258 && x <= 576 && y >= 125 && y <= 353)
    23.               {
    24.                       var Angle = new Vector3(-Input.GetAxis("Mouse Y"), -Input.GetAxis("Mouse X"), 0);
    25.                       this.transform.Rotate(Angle * RotSpeed);
    26.                 SliderX = SliderXO.GetComponent<Slider>();
    27.                 SliderY = SliderYO.GetComponent<Slider>();
    28.                 SliderZ = SliderZO.GetComponent<Slider>();
    29.                 if(SliderX != null)
    30.                   {
    31.                     SliderX.value = this.transform.eulerAngles.x;
    32.                   }
    33.                 else
    34.                   {
    35.                     print ("SliderX is null");
    36.                   }
    37.                 if(SliderY != null)
    38.                   {
    39.                     SliderY.value = this.transform.eulerAngles.y;
    40.                   }
    41.                 else
    42.                   {
    43.                     print ("SliderY is null");
    44.                   }
    45.                 if(SliderZ != null)
    46.                   {
    47.                     SliderZ.value = this.transform.eulerAngles.z;
    48.                   }
    49.                 else
    50.                   {
    51.                     print ("SliderZ is null");
    52.                   }
    53.                       //SliderX.value = this.transform.eulerAngles.x;
    54.                       //SliderY.value = this.transform.eulerAngles.y;
    55.                       //SliderZ.value = this.transform.eulerAngles.z;
    56.               }
    57.               }
    58.         }
    59.   }
    I now get the error "UnassignedReferenceException: The variable SliderXO of GameScript has not been assigned.
    You probably need to assign the SliderXO variable of the GameScript script in the inspector."
     
  17. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    That is truly bizarre. You're absolutely certain there's no other instance of this script in the scene?

    Otherwise I'm out of ideas, sorry :(
     
  18. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Oh (he says, in a very tiny voice). That's what it was. There was another copy of the script attached to a different GameObject - and THAT version didn't have the references. You mean I beat my head against the wall all this time and the answer was THAT simple??? Argh! :mad:
     
    LiterallyJeff likes this.
  19. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    What a relief! I hate leaving people hanging lol

    You should be able to return to your original code with no issues then. Glad you figured it out.
     
  20. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Thanks - one final dumb one with this particular code. Here's the code:
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using System.Collections;
    4.  
    5. public class GameScript : MonoBehaviour
    6.   {
    7.     public float  RotSpeed;
    8.     public Slider SliderX;
    9.     public Slider SliderY;
    10.       public Slider SliderZ;
    11.  
    12.       void Update()
    13.         {
    14.             if (Input.GetMouseButton(0))
    15.               {
    16.             float x = Input.mousePosition.x;
    17.             float y = Input.mousePosition.y;
    18.             if (x >= 258 && x <= 576 && y >= 125 && y <= 353)
    19.               {
    20.                       var Angle = new Vector3(-Input.GetAxis("Mouse Y"), -Input.GetAxis("Mouse X"), 0);
    21.                       this.transform.Rotate(Angle * RotSpeed);
    22.                 SliderX.value = (int) this.transform.eulerAngles.x;
    23.                 SliderY.value = (int) this.transform.eulerAngles.y;
    24.                 SliderZ.value = (int) this.transform.eulerAngles.z;
    25.               }
    26.               }
    27.         }
    28.   }
    If you're clicking outside that particular "box" defined by 258, 125 to 576, 353, it will NOT adjust the sliders - or the cube. This is so the user can click on the sliders without moving the cube unintentionally.

    However, I have a fourth slider I'm using to control the rotation speed:

    Code (CSharp):
    1.     public void AdjustSpeed()
    2.       {
    3.         GameObject temp1 = GameObject.Find("SliderSpeed");
    4.         SliderSpeed = temp1.GetComponent<Slider>();
    5.         Text temp5 = GameObject.Find("Speed").GetComponent<Text>();
    6.         SliderSpeed = temp1.GetComponent<Slider>();
    7.         //Canvas.GetComponent<GameScript>().RotSpeed = SliderSpeed.value;
    8.         temp5.text = SliderSpeed.value.ToString();
    9.       }
    This is attached to the Canvas object, while the other is attached to the Cube object. When I first start the program, I can slide the SliderSpeed slider as much as I want. I can adjust the other sliders, then adjust the speed again. But once I've clicked in the cube area and adjusted the cube, I can't slide the speed slider at all, although I can still access the other sliders. Any ideas?
     
  21. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    It's hard to speculate on why that might be happening. If I were you I would stay away from hard-coded values in your code like that, and try to go towards a more cohesive system for detecting screen areas for clicks. Perhaps have a single canvas with all your sliders and stuff, and let the canvas panels define the areas that should be clickable for different purposes.

    With that kind of system, if you click a slider, then the slider will work, if you click off the slider, then you'll be clicking a (possibly invisible) UI panel below the slider, which will interact with the cube. Right now you have a conflict between your canvas elements detecting clicks thru GraphicRaycaster component, and your game object detecting clicks using GetMouseButton (which will detect all clicks, regardless if they were already handled by UI).
     
  22. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    So, you'd put the cube into its own canvas, and then detect the clicks/drags off of that?
     
  23. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    If you'll help me understand what exactly the use case is, I can recommend an implementation.

    So from what I'm imagining, you have one cube on screen and you want to drag anywhere on the screen to rotate the cube, or drag the sliders to rotate the cube?

    If that is accurate, then you can have one canvas as a root object, with your sliders as child objects positioned and anchored correctly on screen. Then you can have a panel in the same canvas with an invisible image to act as a clickable area. Clicking this panel should start a script watching the mouse delta as you drag, and will adjust the cube's rotation, as well as the sliders.

    The key difference here is that you're not listening for any click all the time, only when they're on the panel area. That way you can click the sliders and not register a click on the panel, and vice versa.
     
  24. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    I'm having the user drag on the cube to rotate it and/or use the sliders to do the same. I like your idea; I'll give it a try.

    I'm basically done with this file... so:

    I have a whole bunch of programs I wrote in VisualBasic; they are very clunky and memory-hogging, mostly due to graphics. Unity handles graphics MUCH better, especially animation.... therefore I've decided to translate ALL my VB programs to Unity C#.

    Quite an undertaking, I know. At the moment, I'm dealing with Unity's dropdown. I have it populated with code (just the way I want it). However, when the user clicks a radio button, I want the box's selected text to be empty. I've searched all over the web and can't find out how to do this. I also need a way to remove one single item from the list.

    Can anyone help with this?
     
  25. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
  26. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    I already did the radio buttons, although I'm using my own custom Buttons to replace the standard UI (I just like the way they looked, and the functionality was pretty easy).

    I've already done this:

    Code (CSharp):
    1.     void Fill_Startup()
    2.       {
    3.         int i;
    4.         dropdown.options.Clear();
    5.         for (i = 1; i <= GameCount; i++)
    6.           {
    7.             dropdown.options.Add(new Dropdown.OptionData(Game[i].Campaign));
    8.           }
    9.       }
    It clears the list, and repopluates it... but it does NOT affect what's in the selection box, and that's what I'm after at the moment. I've looked everywhere, but can't find it. I'm guessing it's too new, and there aren't many examples out there.
     
  27. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    Well I just made a default Dropdown UI element, and it appears that it's just a standard Text field that is the selected option.

    Looks like Dropdown has a "captionText" property reference to that component.
     
  28. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Yes, but I haven't been able to figure out how to access it from the code examples.

    So I have this:
    Text MyText = null;
    dropdown.captionText = MyText;
    Code (CSharp):
    1.         Text MyText = null;
    2.         dropdown.captionText = MyText;
    ...which DOES empty the caption, but does so ALL THE TIME!! I mean, when I make a selection, it doesn't appear in the selected box.

    I've moved this line to where the radio buttons are, and it still does the same thing. I'm stumped.
     
  29. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    The code that you've got there is replacing the Dropdown's reference to the Text component, not the actual text within the Text component.

    You want the Dropdown to keep the reference to the Text component, but you want to set the text property to an empty string.

    I think what you want to do is this (taking your previous code for clearing the list):

    Code (CSharp):
    1. void Fill_Startup() {
    2.     int i;
    3.     dropdown.options.Clear();
    4.     dropdown.captionText.text = string.Empty; // erase the selected option text
    5.     for(i = 1; i <= GameCount; i++) {
    6.         dropdown.options.Add(new Dropdown.OptionData(Game[i].Campaign));
    7.     }
    8. }
     
  30. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    Your example worked great! However: The dropdown "remembers" what was checked and that item remains checked. I've tried setting value = -1 (that chooses item #0) and value = GameCount + 1 (that chooses the Last item on the list); I want NO items checked. I'm SO close!!
     
  31. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    You could try experimenting with the Dropdown function "RefreshShownValue" after changing the options. I'm not sure if that will reset the selection or not.

    I would recommend reading through the documentation for Dropdown and trying out the many functions and variables you see there to get the result you're looking for. https://docs.unity3d.com/ScriptReference/UI.Dropdown.html
     
  32. TheWebExpert

    TheWebExpert

    Joined:
    Apr 14, 2015
    Posts:
    198
    I'd already read through that and tried a bunch of different options, all with no result. The only thing I could think of would be to destroy the list, recreated the actual object, and then start again... but that's pretty clunky.

    RefreshShownValue simply puts the text of the checked item back into the selection box - which we just finished clearing! There doesn't seem to be a "null" option with this. Perhaps in some future version of Unity....

    I'll just live with the check mark; there doesn't seem to be a way to do what I want.