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): Background.transform.position= new Vector3(202F, -261F, 428F); SliderXO.transform.position= new Vector3(-142F, -346F, 414F); SliderYO.transform.position= new Vector3(-142F, -376F, 414F); SliderZO.transform.position= new Vector3(-142F, -404F, 414F); ...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?
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): (transform as RectTransform).anchoredPosition = // or RectTransform rectTransform = (RectTransform)transform; rectTransform.anchoredPosition =
Do you mean like this? Code (CSharp): 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.
I still need help with this! I now have this: Code (CSharp): RectTransform BRect = Background.GetComponent<RectTransform>(); 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?
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
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!
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.
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): using UnityEngine; using UnityEngine.UI; using System.Collections; public class GameScript : MonoBehaviour { public float RotSpeed; public Slider SliderX; public Slider SliderY; public Slider SliderZ; void Update() { if (Input.GetMouseButton(0)) { var Angle = new Vector3(Input.GetAxis("Mouse Y"), Input.GetAxis("Mouse X"), 0); this.transform.Rotate(Angle * RotSpeed); SliderX.value = this.transform.eulerAngles.x; SliderY.value = this.transform.eulerAngles.y; SliderZ.value = this.transform.eulerAngles.z; } } } 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...
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?
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.
Try this: Code (CSharp): using UnityEngine; using UnityEngine.UI; using System.Collections; public class GameScript : MonoBehaviour { public float RotSpeed; public Slider SliderX; public Slider SliderY; public Slider SliderZ; void Update() { if(Input.GetMouseButton(0)) { var Angle = new Vector3(Input.GetAxis("Mouse Y"), Input.GetAxis("Mouse X"), 0); this.transform.Rotate(Angle * RotSpeed); if(SliderX != null) { SliderX.value = this.transform.eulerAngles.x; } else { print("slider x is null"); } if(SliderY != null) { SliderY.value = this.transform.eulerAngles.y; } else { print("slider y is null"); } if (SliderZ != null) { SliderZ.value = this.transform.eulerAngles.z; } else { print("slider z is null"); } } } } 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.
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...
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.
Ok, here's what I have now: Code (CSharp): using UnityEngine; using UnityEngine.UI; using System.Collections; public class GameScript : MonoBehaviour { public float RotSpeed; Slider SliderX; Slider SliderY; Slider SliderZ; public GameObject SliderXO; public GameObject SliderYO; public GameObject SliderZO; void Update() { if (Input.GetMouseButton(0)) { float x = Input.mousePosition.x; float y = Input.mousePosition.y; //print ("x "+x+" y "+y); if (x >= 258 && x <= 576 && y >= 125 && y <= 353) { var Angle = new Vector3(-Input.GetAxis("Mouse Y"), -Input.GetAxis("Mouse X"), 0); this.transform.Rotate(Angle * RotSpeed); SliderX = SliderXO.GetComponent<Slider>(); SliderY = SliderYO.GetComponent<Slider>(); SliderZ = SliderZO.GetComponent<Slider>(); if(SliderX != null) { SliderX.value = this.transform.eulerAngles.x; } else { print ("SliderX is null"); } if(SliderY != null) { SliderY.value = this.transform.eulerAngles.y; } else { print ("SliderY is null"); } if(SliderZ != null) { SliderZ.value = this.transform.eulerAngles.z; } else { print ("SliderZ is null"); } //SliderX.value = this.transform.eulerAngles.x; //SliderY.value = this.transform.eulerAngles.y; //SliderZ.value = this.transform.eulerAngles.z; } } } } 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."
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
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!
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.
Thanks - one final dumb one with this particular code. Here's the code: Code (CSharp): using UnityEngine; using UnityEngine.UI; using System.Collections; public class GameScript : MonoBehaviour { public float RotSpeed; public Slider SliderX; public Slider SliderY; public Slider SliderZ; void Update() { if (Input.GetMouseButton(0)) { float x = Input.mousePosition.x; float y = Input.mousePosition.y; if (x >= 258 && x <= 576 && y >= 125 && y <= 353) { var Angle = new Vector3(-Input.GetAxis("Mouse Y"), -Input.GetAxis("Mouse X"), 0); this.transform.Rotate(Angle * RotSpeed); SliderX.value = (int) this.transform.eulerAngles.x; SliderY.value = (int) this.transform.eulerAngles.y; SliderZ.value = (int) this.transform.eulerAngles.z; } } } } 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): public void AdjustSpeed() { GameObject temp1 = GameObject.Find("SliderSpeed"); SliderSpeed = temp1.GetComponent<Slider>(); Text temp5 = GameObject.Find("Speed").GetComponent<Text>(); SliderSpeed = temp1.GetComponent<Slider>(); //Canvas.GetComponent<GameScript>().RotSpeed = SliderSpeed.value; temp5.text = SliderSpeed.value.ToString(); } 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?
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).
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.
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?
Radio buttons have the event "onValueChanged" which you can use to react to input. Then you need to get a reference to the text you want to clear, and clear it. https://docs.unity3d.com/ScriptReference/UI.Toggle.html You can remove an item from the dropdown by calling ClearOptions and then AddOptions, with the choices array minus that one option. I think there's also a DestroyItem function. https://docs.unity3d.com/ScriptReference/UI.Dropdown.html
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): void Fill_Startup() { int i; dropdown.options.Clear(); for (i = 1; i <= GameCount; i++) { dropdown.options.Add(new Dropdown.OptionData(Game[i].Campaign)); } } 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.
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.
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): Text MyText = null; 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.
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): void Fill_Startup() { int i; dropdown.options.Clear(); dropdown.captionText.text = string.Empty; // erase the selected option text for(i = 1; i <= GameCount; i++) { dropdown.options.Add(new Dropdown.OptionData(Game[i].Campaign)); } }
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!!
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
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.