Unity3D UGUI组件跟随鼠标运动

Unity3D UGUI组件跟随鼠标运动,第1张

因项目的需求,在制作中需要让UGUI中的组件,追随鼠标的运动轨迹。由于个人在以前使用中对于UGUI的坐标系了解不深,在使用中产生了一些问题,在此对UGUI的坐标系做一个简单的记录,以备后面查询。

Unity3D 采用InputmousePosition来获取当前鼠标的位置,获取的位置是相对于屏幕坐标系的,而UGUI使用的坐标系和屏幕坐标系不是同一个坐标系,

在UGUI中组件使用的坐标都是2D在Rect中的一个相对坐标,所以在实际使用中需要进行转换。

<pre>

public class test : MonoBehaviour

{

public RectTransform myRectTransform; // 目标组件

public Canvas myCanvas; // 当前画布

// Update is called once per frame

void Update ()

{

Vector2 vT = Vector2zero;

// 通过此函数,将鼠标坐标,从屏幕坐标,转换到UGUI坐标

RectTransformUtilityScreenPointToLocalPointInRectangle(myCanvastransform as RectTransform, InputmousePosition, myCanvasworldCamera, out vT);

myRectTransformlocalPosition = vT;

}

}

</pre>

#######附带一说,在Unity3D中可以使用函数ScreenshowCursor(老版本)、UnityEngineCursorvisible来显示和隐藏鼠标

    UGUI制作小地图的方法和NGUI也没多大区别,同样是通过Camera+RenderTexture来实现。细节方面的美化可以自行通过美工来完善。为了更好的适应新的UI系统,学习NGUI之余也使用UGUI来制作同样效果的东西。

       首先,我们创建一个Camera对象,改名为MiniMapCamera,设置Rotation让其视野朝下,面向地面,修改Projection为Orthographic。通过Size来调整摄像机高度。

       然后,Create——UI——RawImage,生成Canvas和RawImage,在Canvas下创建一个空物体叫做MiniMap,然后在MiniMap下创建一个Image对象,并给Image对象添加Mask组件(达到圆形效果),修改Image对象名字为Mask,修改组件Image的SourceImage为Knob(Unity自带圆形Image)将RawImage拖拽到Mask下。

       接下来,在Pojects面板内创建一个RenderTexture,并将其拖拽到MiniMapCamera的TargetTexture中。设置RawImage的对象为该Texture。此时便能有一个初步的小地图了。

      为了美化这个简陋的小地图,我们可以在MiniMap下再添加一个RawImage,选择一个喜欢的图作为遮罩,确保该RawImage排在Mask下,这样便能覆盖Mask作为外遮罩对象。然后修改MiniMapCamera的CulingMask来选择小地图能看见的层。具体细节可以按自己的喜好来调节。

      这样小地图便完成了,给上一个DIY效果图(依旧是官方案例作为素材)。

关键点:

0自适应的测试:通过设置多种的屏幕大小进行测试,测试时最好要打开Maximize on Play,在屏幕放大的情况下容易观察自适应情况

1所谓的自适应,就是:

a保持相对位置不变。例如UI设计在屏幕的左上角,那么在各种的分辨率下都应该在左上角

b保持宽高比例不变。由于分辨率有很多种,所以保持宽高等比例缩放是做不到的,要么是宽拉伸缩放的程度大些,要么是高拉伸缩放的程度大些

2在UGUI中,可以通过设置UI的描点来设置UI的相对位置;可以通过设置Canvas下的Canvas Scaler来设置UI的缩放比例(Canvas下的Canvas是用来处理UI遮挡关系的)

3Canvas Scaler组件:

a当UIScaleMode为Constant Pixel Size时,UI在任何分辨率下都不会进行缩放拉伸,只有通过改变Scale Factor才会进行缩拉,因此不推荐使用该模式(而这种模式的优点就是你可以通过写自适应算法来改变Scale Factor的值,代替unity的自适应算法)

b当UIScaleMode为Scale With Screen Size时,相当于使用unity的自适应算法,此时unity会根据屏幕分辨率自动调节Scale Factor的值。在做自适应时,一般要先选择一种比较主流的分辨率(即比较多的机型都采用这种分辨率)进行UI的设计,例如采用1024x576,在这里就是设置Reference Resolution的值了。

然后就是Screen Match Mode这个东西了:

当值为Match Width Or Height时:当值为0即处于Width那端时,表示屏幕高度对于UI大小完全没有任何影响,只有宽度会对UI大小产生影响。例如设置屏幕为800600,然后改变为800300,屏幕高度变小了,但UI并没有进行缩拉;同理当值为1即处于Height那端时,表示屏幕宽度对于UI大小完全没有任何影响,只有高度会对UI大小产生影响

当值为Expand时:举个例子,设计了一个button宽高为200100,即宽高比为2:1,放在4:3的屏幕内;然后把这个button放在16:9的屏幕内,显然地,此时button是不能进行等比例的缩放的,即无法保持2:1的宽高比了,Expand的意思就是尽可能地使UI拉伸来适应屏幕

当值为Shrink时:同理,就是尽可能地使UI缩放来适应屏幕

4一般来说,比较不错的设置就是:

Canvas Scaler 选择 Scale With Screen Size

Screen Match Mode 选择 Match Width Or Height,比例设为1,即只和高度进行适配。更多unity插件,就在纳金论坛上去查看。

效果图,素材是网上随便拉的

这是运行后的Hierarchy的界面,其中最下面的Item是放在摄像机不能拍到的位置,当做预设体,每个Item都有Toggle组件,在Grid上有Toggle Group 组件,并且将Itme上的Toggle组件中Group设置为Grid,这实现了点了一个之后,其他不会高亮。Grid上有组件 Grid Layout Group,该组件实现了当创建Item,并且将父物体设置为Grid后能够自动排版

这里我们需要写三个类,一个是自己捏造的数据类,放在Item上获取各种UI的类,还有能够创建Item并且能够对Item进行管理的类

public class ItemData//这个类存放的是数据

{

public int _starNum;//星星的数量(本来是想找星星的,现在就随便将就一下)

public string _icon;//这是名字

public string _itemName;//关卡的名字

public string _itemNum;//第几关

}

item上的类,用来获取item上的UI控件

public class Item : MonoBehaviour

{    

public Image _star1;    

public Image _star2;    

public Image _star3;    

public Image _icon;    

public Text _levelNum;    

public Text _levelName;    

void initializeItem()    

{        

_star1 = transformFind("StarGroup/star1")GetComponent<Image>();       

 _star2 = transformFind("StarGroup/star2")GetComponent<Image>();        

_star3 = transformFind("StarGroup/star3")GetComponent<Image>();

 _icon = transformFind("Icon")GetComponent<Image>();        

_levelName = transformFind("Levelname/name")GetComponent<Text>();        

_levelNum = transformFind("Levelname/Lv")GetComponent<Text>();

}

void Awake()

{

initializeItem();

}

}

这是个管理Item创建的类

public class MainMgr : MonoBehaviour 

{    

GameObject item;    

Transform Parent;    //这里需要得到Gird的Transform

List<ItemData> dataGroup = new List<ItemData>();   

void Awake()    

{        

CreateData();        

item = transformFind("Item")gameObject;        //获得一开始放在摄像机外的游戏对象,当做预设体

Parent = transformFind("Grid");    //保存Gird的Transform

}    

void CreateData()    //创建自己捏造的数据

{       

 dataGroupClear();//确保这个List没有其他数据        

ItemData itemdata = new ItemData();        

itemdata_icon = "1 (5)";       

itemdata_itemName = "小树林";        

itemdata_itemNum = "第一关";        

itemdata_starNum = 3;        

dataGroupAdd(itemdata);        

ItemData itemdata1 = new ItemData();        

itemdata1_icon = "1 (7)";        

itemdata1_itemName = "沼泽";       

 itemdata1_itemNum = "第二关";        

itemdata1_starNum = 1;        

dataGroupAdd(itemdata1);        

ItemData itemdata2 = new ItemData();        

itemdata2_icon = "1 (15)";        

itemdata2_itemName = "山海关";        

itemdata2_itemNum = "第三关";       

itemdata2_starNum = 1;        

dataGroupAdd(itemdata2);        

ItemData itemdata3 = new ItemData();        

itemdata3_icon = "1 (12)";        

itemdata3_itemName = "墓地";        

itemdata3_itemNum = "第四关";        

itemdata3_starNum = 2;        

dataGroupAdd(itemdata3);       

 ItemData itemdata4 = new ItemData();        

itemdata4_icon = "1 (32)";        

itemdata4_itemName = "神殿";       

 itemdata4_itemNum = "第五关";       

 itemdata4_starNum = 3;        

dataGroupAdd(itemdata4);        

ItemData itemdata5 = new ItemData();        

itemdata5_icon = "1 (25)";        

itemdata5_itemName = "天庭";        

itemdata5_itemNum = "第六关";        

itemdata5_starNum = 2;        

dataGroupAdd(itemdata5);        

ItemData itemdata6 = new ItemData();        

itemdata6_icon = "1 (30)";        

itemdata6_itemName = "心魔";        

itemdata6_itemNum = "第七关";        

itemdata6_starNum = 3;        

dataGroupAdd(itemdata6);   

 }    

GameObject tempItem; //创建临时的游戏对象   

void CreateTempItem()    //创建Item

{        

if (dataGroup != null)       //当这个List不为空时

{            

for (int i = 0; i < dataGroupCount; i++)            //循环创建Item

{                

tempItem = Instantiate(item) as GameObject;          //创建Item并且获取到这个游戏对象     

 tempItemtransformlocalPosition = Vector3zero;                //将其位置,缩放大小,旋转角度初始化

tempItemtransformlocalRotation = new Quaternion();                

tempItemtransformlocalScale = Vector3one;                

tempItemtransformSetParent(Parent);                //设置其父物体为Grid

Item itemSprite = tempItemAddComponent();  //为每一个创建的Item添加脚本

itemSprite_levelNametext = dataGroup[i]_itemName;//获取每一个关卡的名字获取,一下类似

itemSprite_levelNumtext = dataGroup[i]_itemNum;

string path = stringFormat("Icon/{0}", dataGroup[i]_icon);//字符串拼接

itemSprite_iconsprite = ResourcesLoad(path, typeof(Sprite)) as Sprite;

ShowStar(dataGroup[i]_starNum, itemSprite);//调用这个方法获得星星的显示

}

}

}

void ShowStar(int num,Item tempitem)//这个方法是用来显示星星

{

if (num == 1)

{

tempitem_star1gameObjectSetActive(true);

tempitem_star2gameObjectSetActive(false);

tempitem_star3gameObjectSetActive(false);

}

if (num == 2)

{

tempitem_star1gameObjectSetActive(true);

tempitem_star2gameObjectSetActive(true);

tempitem_star3gameObjectSetActive(false);

}

if (num == 3)

{

tempitem_star1gameObjectSetActive(true);

tempitem_star2gameObjectSetActive(true);

tempitem_star3gameObjectSetActive(true);

}

}

void Start () {

CreateTempItem();

}

}

以上就是简单的游戏关卡的选择界面的实现,如果有错误,或者更好的方法,望指正,万分感谢!

public class GetMousePos : MonoBehaviour

{

public Canvas canvas;//画布

private RectTransform rectTransform;//坐标

void Start()

{

canvas = GameObjectFind("Canvas")GetComponent<Canvas>();

rectTransform = canvastransform as RectTransform; //也可以写成thisGetComponent<RectTransform>(),但是不建议;

}

void Update()

{

if (InputGetMouseButtonDown(0))

{

Vector2 pos;

if (RectTransformUtilityScreenPointToLocalPointInRectangle(rectTransform, InputmousePosition, canvasworldCamera, out pos))

{

rectTransformanchoredPosition = pos;

DebugLog(pos);

}

}

}

}

新建场景,在场景中拖一个画布(Canvas),然后随便找个地方挂上这个脚本就好了。

1

RectTransformUtility:矩阵变换工具

RectTransformUtilityScreenPointToLocalPointInRectangle 从屏幕点到矩形内的本地点

Parameters 参数

rect The RectTransform to find a point inside

cam The camera associated with the screen space position

screenPoint Screen space position

localPoint Point in local space of the rect transform

Returns

bool Returns true if the plane of the RectTransform is hit, regardless of whether the point is inside the rectangle

Description 描述

Transform a screen space point to a position in the local space of a RectTransform that is on the plane of its rectangle

屏幕空间点转换为矩形变换内部的本地位置,该点在它的矩形平面上。

The cam parameter should be the camera associated with the screen point For a RectTransform in a Canvas set to Screen Space - Overlay mode, the cam parameter should be null

该cam 参数应该是该相机关联的屏幕点。对于在画布上的矩形变换设置该屏幕空间为-Overlay模式,cam 参数应该为空。

When ScreenPointToLocalPointInRectangle is used from within an event handler that provides a PointerEventData object, the correct camera can be obtained by using PointerEventDataenterEventData (for hover functionality) or PointerEventDatapressEventCamera (for click functionality) This will automatically use the correct camera (or null) for the given event

当ScreenPointToLocalPointInRectangle从事件处理器内部提供一个PointerEventData对象被使用时,相机可以通过使用PointerEventDataenterEventData(为悬停功能)或者 PointerEventDatapressEventCamera(为单击功能)被获取。该函数将会自动对指定事件使用正确的相机(或者空)。

RectTransform矩形变换

RectTransformanchoredPosition 锚点位置

The position of the pivot of this RectTransform relative to the anchor reference point

该矩形变换相对于锚点参考点的中心点位置。

The anchor reference point is where the anchors are If the anchors are not together, the four anchor positions are interpolated according to the pivot placement

锚点参考点是锚点的位置。如果锚点不在一起,四个锚点的位置是根据布置的中心点的位置插值替换的。

via @ >

现有的自适应方法,通常都是基于屏幕的分辨率。分辨率越高的设备上,UI显示的越小。这就造成了一些5寸左右的手机分辨率比ipad等平板设备还要高。UI在平板上显示太大。但是在高分辨率手机上显示太小。

以上脚本为基于屏幕物理尺寸自适应UI的一种方法。通过计算屏幕的DPI获取到屏幕的实际尺寸。然后根据一个标准的尺寸对UI的分辨率进行相对应的缩放。

可以改进的地方就是对于大屏幕或者小屏幕进行缩放的限制。避免类似ipad pro这类的设备上,UI有小的离谱。

配合这个脚本使用的同时。UI也需要用到锚点,进行初步的自适应,不然会造成UI的错乱。

以上就是关于Unity3D UGUI组件跟随鼠标运动全部的内容,包括:Unity3D UGUI组件跟随鼠标运动、Unity3D——使用UGUI制作小地图、unity中ui界面,使用的是ugui插件,创建的界面,如何自适应不同的窗口大小。等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9477613.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-28
下一篇2023-04-28

发表评论

登录后才能评论

评论列表(0条)

    保存