I am working on 1920x1080 reference resolution. Am dynamically creating an UI element more than one. They are animating when they created. These UI elements instantiates from same prefab named "Drift_Stat_Tab". All of these created and animating UI elements using the same Animation motion.
Prefab looks like :
At the end of every animation, am getting the last Keyframe value from the played animation motion (that is "m_AnchoredPosition.y" property) and setting the local position of this UI element :
Stat_Sub_Tab.GetComponent<RectTransform>().localPosition = new Vector3(x_keys[3].value - 960, y_keys[3].value,0f);
When all UI elements created and their animations are finished looks like that at 1920x1080 (reference resolution) :
So far, so good. But when i use different resolution sizes, complications accurs. When try that on 2778x1284 there it goes :
I should be able to scale x and y axis differently. In the same time should set RectTransform.localPosition values differently too. For that i tried this approach :
int reference_x = 1920;
int reference_y = 1080;
int current_x = (int)gameObject.GetComponent<Canvas>().renderingDisplaySize.x;
int current_y = (int)gameObject.GetComponent<Canvas>().renderingDisplaySize.y;
// Y Position Calculate REGION
float const_y_scaler = 1;
float new_y_scale = 1;
float y_pos_gap = 13;
if (current_y > reference_y)
{
const_y_scaler = ((float)current_y - reference_y) / reference_y;
new_y_scale = 1 const_y_scaler;
y_pos_gap *= new_y_scale;
}
else if (current_y < reference_y)
{
const_y_scaler = ((float)reference_y-current_y) / reference_y;
new_y_scale = 1 - const_y_scaler;
y_pos_gap *= new_y_scale;
}
float y_pos= ((float)current_y/ 2)-100*new_y_scale -y_pos_gap;
float reduce_value = (200 * new_y_scale) * instantiate_order_Count;
y_pos -= reduce_value;
if (instantiate_order_Count > 0)
{
y_pos -= y_pos_gap* instantiate_order_Count;
}
Stat_Sub_Tab.GetComponent<RectTransform>().localScale = new Vector3(new_x_scale, new_y_scale, 1f);
In the code above getting a multiplier for scale the y, and changing the scale of it. In the same time using same multiplier for calculate the y position dynamically. At the end of function setting that "y_pos" value to RectTransform.localPosition.y as "y_keys3.value".
For some different resolutions that approach works fine but some of them like 2778x1284(should be iPhone 11 Pro or mini) not works. Am just drowned a little bit in the code. If is there any advice like using RectTransformUtility or methods like Camera.ViewportToScreenPoint, i would be glad. Thanks in advance
CodePudding user response:
By default, Unity's canvas system uses pixel coordinates. There's two (basic) solutions to supporting multiple different resolutions: using anchors, or a Canvas Scaler set to "Scale By Screen Size"
Anchors
Anchors are percentage-based coordinates (0.0-1.0), rather than absolute coordinates (0-1920px). Rather than saying "This UI element should be 100 pixels wide", you can rather use these percentage based coordinates: "This UI element should be take up half the screen, regardless of pixel size, on the X axis." (0-0.5)
You can set anchors within the RectTransform of the UI element, under the "anchors" tab.
Canvas Scaler
A Canvas Scaler lets you continue using these absolute pixel offsets, and will automatically scale the UI to match the screen's size. This does have the downside of having a fixed aspect ratio, requiring the canvas to either be shrunk/expand to fit. (Ex: 16:9 -> 4:3 will make the UI elements either shrink or stretch, depending on the width/height slider in the Canvas Scaler)
This is the easiest "drop-in" fix, though making the change to anchors might be worth it if you ever want to properly support arbitrary aspect ratios.
Also, a Vertical Layout Group seems like it would be useful here, it'll automatically lay out your elements in a vertical list so you don't have to position them manually in code. Add a layout group to a parent element, and the elements will arrange themselves according to the parent's size/scale/position.