Unity记录7.4-界面-UI的缩放、菜单、菜单关闭、预制体UI

汇总:Unity 记录
开源地址:asd123pwj/asdGame
摘要:UI的缩放、右键菜单、菜单失焦关闭,以及从预制体中加载UI。
UI缩放-2024/05/21
- 最好的缩放方式肯定是Windows那样的,然而UI位置、UI尺寸、鼠标位置的坐标系不是同一个,我转换不来。
- 所以妥协了一下,只能缩放两个方向,向右和向下。
- 代码如下
- 一个关键点是,UI的
RectTransform.pivot
得是(0, 1)
,即左上角。 - 和拖动不同,缩放用的鼠标位置是
ScreenPointToLocalPointInRectangle
。
- 一个关键点是,UI的
public class UIResizeButtom: UIComponentBase{
public UIResizeButtom(GameObject parent): base(parent, "ResizeButtom"){
_image_name = "ResizeButtom";
_set_UIPos = _set_UIPos_RightBottom;
_sizeDelta = new (50, 50);
// _rotation = Quaternion.Euler(0, 0, 90);
}
public override void _init_eventInteraction(){
// ----- set top
_Cfg._Event._event_PointerDown.Add(_Cfg._Interact._set_top);
// ----- resize right
_Cfg._Event._event_PointerDown.Add(_Cfg._Interact._update_mouseDown_mousePos);
_Cfg._Event._event_PointerDown.Add(_Cfg._Interact._update_mouseDown_size);
_Cfg._Event._event_Drag.Add(_Cfg._Interact._update_mouseHold_mousePos);
_Cfg._Event._event_Drag.Add(_Cfg._Interact._resize);
}
}
public void _update_mouseDown_size(PointerEventData eventData){
mouseDown_size = rt.sizeDelta;
}
public void _update_mouseDown_mousePos(PointerEventData eventData){
RectTransformUtility.ScreenPointToWorldPointInRectangle(rt, eventData.position, eventData.pressEventCamera, out mouseDown_mousePos_world);
RectTransformUtility.ScreenPointToLocalPointInRectangle(rt, eventData.position, eventData.pressEventCamera, out mouseDown_mousePos_local);
}
public void _update_mouseHold_mousePos(PointerEventData eventData){
RectTransformUtility.ScreenPointToWorldPointInRectangle(rt, eventData.position, eventData.pressEventCamera, out mouseHold_mousePos_world);
RectTransformUtility.ScreenPointToLocalPointInRectangle(rt, eventData.position, eventData.pressEventCamera, out mouseHold_mousePos_local);
}
public void _resize(PointerEventData eventData){
if (!_check_downL(eventData)) return;
rt.sizeDelta = new(mouseDown_size.x + mouseHold_mousePos_local.x - mouseDown_mousePos_local.x, mouseDown_size.y - mouseHold_mousePos_local.y + mouseDown_mousePos_local.y);
}
右键打开子菜单-2024/05/21
- 实现起来较简单,只要把
rt.anchoredPosition
设为鼠标点击时的ScreenPointToLocalPointInRectangle
即可。 - 此外,子菜单的pivot需要和UI一致,我这里都是左上角。
public class UIRightMenu: UIComponentBase{
public UIRightMenu(GameObject parent, Vector2 position): base(parent, "RightMenu"){
_image_name = "RightMenu";
_set_UIPos_LeftTop();
_anchoredPosition = position;
_sizeDelta = new (300, 200);
}
public override void _init_eventInteraction(){
// ----- set top
_Cfg._Event._event_PointerDown.Add(_Cfg._Interact._set_top);
}
}
public void _open_rightMenu(PointerEventData eventData) {
if (!_check_downR(eventData)) return;
UIRightMenu rightMenu = new(Cfg._parent, mouseDown_mousePos_local);
}
失焦关闭菜单-2024/05/21
- 这需要用到
deselect
事件,- 而
deselect
事件又需要有一个可选择的组件的navigation
, - 因此,在生成右键菜单组件时,同时给该组件附加一个按钮
buttom
, - 由于按钮的选中状态会改变外观,因此需要设置
buttom.transition = Selectable.Transition.None
- 而
- 为
deselect
事件设置一个关闭方法,上篇的Close一样,设置GameObject.SetActive(false)
- 这样,当鼠标按下菜单外的任何位置时,将关闭该菜单。
- 此外,每次打开菜单应该是打开同一个,
- 因此,仅需在第一次时创建右键菜单,
- 后续打开时,先将菜单挪至鼠标位置,再启用
GameObject.SetActive(true)
。
- 此外,我修改为
pointerClick
事件触发,- 即按下并松开后,打开菜单
- 因此,使用的位置是松开时的鼠标位置,或是拖动时的鼠标位置,
- 由于我是给背景添加的右键菜单,背景同时还记录的拖动位置,因此我用拖动位置。
public class UIRightMenu: UIComponentBase{
public UIRightMenu(GameObject parent, Vector2 position): base(parent, "RightMenu"){
_image_name = "RightMenu";
_set_UIPos_LeftTop();
_anchoredPosition = position;
_sizeDelta = new (300, 200);
_enableNavigation = true;
}
public override void _init_eventInteraction(){
// ----- set top
_Cfg._Event._event_PointerDown.Add(_Cfg._Interact._set_top);
// ----- Close
_Cfg._Event._event_Deselect.Add(_Cfg._Interact._closeSelf);
}
}
// ---------- Interacton ----------
public void _enableSelf(){ _Cfg._self.SetActive(true); }
public void _enableSelf(Vector2 pos){
_Cfg._self.GetComponent<RectTransform>().position = pos;
_Cfg._self.SetActive(true);
}
void set_navigation(){
if (!_enableNavigation) return;
Button btm = _self.AddComponent<Button>();
btm.transition = Selectable.Transition.None;
EventSystem.current.SetSelectedGameObject(_self);
}
滚动窗口-2024/05/25
- Unity的UI-Scroll View即滚动窗口
- 创建后,在Scroll View的子对象Viewport的子对象Content中,添加
Grid Layout Group
组件,即可网格式排列子对象。 - 其排列的内容,为Content的子对象。
- 创建后,在Scroll View的子对象Viewport的子对象Content中,添加
- Grid的大小与间隔空间、Scroll View的RectTransform宽高、滚动条ScrollBar的宽高是一个坐标系。
- 例如,Grid大小为100,间隔为10,ScrollView宽度为1200时,11个Grid刚好填满
- 1200 = (100+10) (11-1) + 100 1
- 当存在滚动条时,滚动条默认宽度为20,则ScrollView宽度为1220时,11个Grid刚好填满
- 1220 = (100+10) (11-1) + 100 1 + 20
- 这意味着能够自动调整最适应的网格行列数。
- 内容的添加后续实现,因为从空GameObject创建一个滚动窗口麻烦,所以打算从预制体来。
从预制体加载UI-2024/05/26
- 这个步骤和"Unity记录6.2-动作-角色生成"几乎一致,因为都是加载prefab,不像上篇7.3,是加载图片。
{
"version": "0.0.1",
"UIPrefabs":{
"ScrollView":{
"name": "ScrollView",
"path": "Assets/Resources_addressable/Prefab/UI/ScrollView.prefab"
}
}
}
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using Cysharp.Threading.Tasks;
using Unity.VectorGraphics;
public struct UIPrefabInfo{
public string name;
public string path;
}
public struct UIPrefabsInfo{
public string version;
public Dictionary<string, UIPrefabInfo> UIPrefabs;
}
public class UIPrefabList{
GameConfigs _game_configs;
public UIPrefabsInfo _UIPrefabs_info;
public Dictionary<string, GameObject> _name2UIPrefab = new();
public UIPrefabList(GameConfigs game_configs){
_game_configs = game_configs;
load_UIPrefabs();
}
public bool _check_UIPrefab_loaded(string name){
return _name2UIPrefab.ContainsKey(name);
}
public GameObject _get_UIPrefab(string name){
return _name2UIPrefab[name];
}
async UniTaskVoid load_UIPrefab(string name){
string UIPrefab_path = _UIPrefabs_info.UIPrefabs[name].path;
AsyncOperationHandle<GameObject> handle = Addressables.LoadAssetAsync<GameObject>(UIPrefab_path);
handle.Completed += action_UIPrefab_loaded;
await UniTask.Yield();
}
void load_UIPrefabs(){
string jsonText = File.ReadAllText(_game_configs.__UIPrefabsInfo_path);
_UIPrefabs_info = JsonConvert.DeserializeObject<UIPrefabsInfo>(jsonText);
foreach (var object_kv in _UIPrefabs_info.UIPrefabs){
load_UIPrefab(object_kv.Key).Forget();
}
}
void action_UIPrefab_loaded(AsyncOperationHandle<GameObject> handle){
if (handle.Status == AsyncOperationStatus.Succeeded) _name2UIPrefab.Add(handle.Result.name, handle.Result);
else Debug.LogError("Failed to load prefab: " + handle.DebugName);
Addressables.Release(handle);
}
}
文章目录
关闭
共有 0 条评论