目录

  • 常用rectTransform的api脚本
  • 搭建背包
  • 全部代码


常用rectTransform的api脚本

何为常用?被我碰到那就是常用的

RectTransform.anchoredPosition
瞄点的中心点坐标

RectTransform.anchorMax
父 RectTransform 中右上角锚定到的标准化位置。

RectTransform.anchorMin
父 RectTransform 中左下角锚定到的标准化位置。

RectTransform.GetWorldCorners
获取计算的矩形在世界空间中的各个角

RectTransform.offsetMax
矩形右上角相对于右上锚点的偏移。
提醒,如果当前ui跟随父物体上下左右都保持边距为5,offsetMax要取反

RectTransform.offsetMin
矩形左下角相对于左下锚点的偏移

RectTransform.sizeDelta
瞄点之间的距离,如果跟随父物体在父物体的4个角上,即宽高

搭建背包

我的做法:

还是用grid layout group搭建背包的格子,然后在格子下放图片,在加载对应类型之前要清空图片,点击对应类型的toggle显示对应的图片在背包最上面,否则不实例化。

这样每次点击都先清空,再实例化,后序再优化

效果图:

unity 自定义 URP管线 unity自定义package_ui


当修改ui预制体的canvas层级,请不要直接将assets里的预制体添加canvas组件,然后修改层级,这样会导致ui显示不出来而是将预制体拖到hierarchy面板下的canvas下,再添加canvas组件和Graphic Raycaster,然后修改层级,就可以正常显示

unity 自定义 URP管线 unity自定义package_unity 自定义 URP管线_02

unity 自定义 URP管线 unity自定义package_ui_03

unity 自定义 URP管线 unity自定义package_ui_04


需求分析:

1.比如当我们点击鞋子类别时,如何将对应的所有item都显示在最上面的格子呢?

这个只需要遍历格子,判断当前格子里的item是否为空,为空就可以加载了

2.实现物品的拖拽功能

导入using UnityEngine.EventSystems;
继承IDragHandler,IBeginDragHandler,IEndDragHandler3个接口,并实现接口

下面是我自己写的,有点bug,在拖拽物体离格子越远的时候,鼠标会逐渐偏离拖拽物体,有大佬解决下吗

public void OnBeginDrag(PointerEventData eventData)
{
	mousePosition = Input.mousePosition;
    onStarDrag?.Invoke();
}

public void OnDrag(PointerEventData eventData)
{     
    rect.localPosition += (Input.mousePosition - mousePosition);
    rect.anchoredPosition += (Vector2)(Input.mousePosition - mousePosition);
    mousePosition = Input.mousePosition;
    onDrag?.Invoke();
}

public void OnEndDrag(PointerEventData eventData)
{
    onEndDrag?.Invoke();
}

网上的话,是通过将屏幕坐标转化为世界坐标进行坐标的赋值,点这里

private void SetDraggedPosition(PointerEventData eventData)
    {
        Vector3 globalMousePos;
        //把屏幕坐标转换为世界坐标,参数2-》参数4
        if (RectTransformUtility.ScreenPointToWorldPointInRectangle(rect, eventData.position, eventData.pressEventCamera, out globalMousePos))
        {
            rect.position = globalMousePos;
        }
        //print(globalMousePos);
    }

eventData 为拖拽物体的信息
ScreenPointToWorldPointInRectangle:将一个屏幕空间点转换为世界空间中位于给定 RectTransform 平面上的一个位置
PointerEventData.pressEventCamera(对于单击功能)获取正确的摄像机。这会为给定事件自动使用正确的摄像机(或 null)

IPointerEnterHandler,IPointerExitHandler接口可以监听鼠标的进入与退出

ICanvasRaycastFilter接口:如果顶级元素被命中,它还能进一步“检查”该位置是否有效。
当拖拽物品到对应格子上时,都会对格子的背景进行实时更新

提醒:背包本来就是一个比较大的模块,代码量也比较多,当然我只做了搭建背包和拖拽功能及优化和toggle的绑定,仍存在缺陷,量力而行

操作:

1.BagPanel挂载BagPanel脚本,Grid挂载BagGrid脚本

随便做一个image,命名为articleItem作为预制体,添加4个组件

unity 自定义 URP管线 unity自定义package_ide_05

全部代码

BagPanel.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BagPanel : ViewBase
{
    public MenuPanel menuPanel;

    public GameObject ArticleItemPre;
    private BagGrid[] bagGrids;
    //存article的信息
    public List<Article> articles = new List<Article>();
    //当前鼠标所处格子
    public BagGrid currentMouseGrid;
    //当前拖拽物体article
    public ArticleItem currentDragArticle;

    public static BagPanel instance;

    public override void Hide()
    {
        base.Hide();
        menuPanel.Show();
    }
    private void Awake()
    {
        instance = this;
        Init();
        bagGrids = transform.GetComponentsInChildren<BagGrid>();
    }
    // Start is called before the first frame update
    void Start()
    {
        LoadData();
    }
    public void Init()
    {
        articles.Add(new Article("枪", "Sprite/weapon1", ArticleType.Weapon, 1));
        articles.Add(new Article("刀", "Sprite/weapon2", ArticleType.Weapon, 2));
        articles.Add(new Article("剑", "Sprite/weapon3", ArticleType.Weapon, 3));
        articles.Add(new Article("仙剑", "Sprite/weapon4", ArticleType.Weapon, 4));

        articles.Add(new Article("饺子", "Sprite/drug1", ArticleType.Drug, 1));
        articles.Add(new Article("鸡肉", "Sprite/drug2", ArticleType.Drug, 2));
        articles.Add(new Article("药丸", "Sprite/drug3", ArticleType.Drug, 3));
        articles.Add(new Article("仙丹", "Sprite/drug4", ArticleType.Drug, 4));

        articles.Add(new Article("枪", "Sprite/shoe1", ArticleType.Shoes, 1));
        articles.Add(new Article("枪", "Sprite/shoe2", ArticleType.Shoes, 2));
        articles.Add(new Article("枪", "Sprite/shoe3", ArticleType.Shoes, 3));
        articles.Add(new Article("枪", "Sprite/shoe4", ArticleType.Shoes, 4));


        articles.Add(new Article("枪", "Sprite/book1", ArticleType.Book, 1));
        articles.Add(new Article("枪", "Sprite/book2", ArticleType.Book, 2));
        articles.Add(new Article("枪", "Sprite/book3", ArticleType.Book, 3));
        articles.Add(new Article("枪", "Sprite/book4", ArticleType.Book, 4));
    }
    //获取一个空闲的格子
    public BagGrid GetBagGrid()
    {
        for (int i = 0; i < bagGrids.Length; i++)
        {
            if (bagGrids[i].ArticleItem == null)
            {
                return bagGrids[i];
            }
        }
        return null;
    }
    //加载格子里的页面在对应的格子
    public void LoadData()
    {
        HideAllArticleItems();
        for (int i = 0; i < articles.Count; i++)
        {
            bagGrids[i].SetArticleItem(LoadArticleItem(articles[i]));
        }
    }

    public void LoadData(ArticleType articleType)
    {
        HideAllArticleItems();
        for (int i = 0; i < articles.Count; i++)
        {
            if (articles[i].articleType == articleType)
            {
                GetBagGrid().SetArticleItem(LoadArticleItem(articles[i]));
            }              
        }
    }
    //加载格子页面
    public ArticleItem LoadArticleItem(Article article)
    {
        GameObject obj = GameObject.Instantiate(ArticleItemPre);
        ArticleItem articleItem = obj.GetComponent<ArticleItem>();
        //加载格子页面的图片
        articleItem.SetArticle(article);
        return articleItem;
    }
    //清空格子下的item
    public void HideAllArticleItems()
    {
        for (int i = 0; i < bagGrids.Length; i++)
        {
            if(bagGrids[i].ArticleItem!=null)
            {
                bagGrids[i].ClearGrid();
            }
        }
    }
    #region 点击1事件
     public void OnAllToggleValueEvent(bool v)
    {
        if(v)
        {
            LoadData();
        }
    }
    public void OnWeaponToggleValueEvent(bool v)
    {
        if(v)
        {
            LoadData(ArticleType.Weapon);
        }
    }
    public void OnShoesToggleValueEvent(bool v)
    {
        if (v)
        {
            LoadData(ArticleType.Shoes);
        }
    }
    public void OnBookToggleValueEvent(bool v)
    {
        if (v)
        {
            LoadData(ArticleType.Book);
        }
    }
    public void OnDrugToggleValueEvent(bool v)
    {
        if (v)
        {
            LoadData(ArticleType.Drug);
        }
    }
    #endregion
}

BagGrid.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

//管理格子
public class BagGrid : MonoBehaviour,IPointerEnterHandler,IPointerExitHandler
{
    private ArticleItem articleItem;

    private Image bagImage;
    private Color defaultColor;
    public ArticleItem ArticleItem
    {
        get
        {
            return articleItem;
        }
    }
    // Start is called before the first frame update
    void Start()
    {
        bagImage = transform.GetComponent<Image>();
        defaultColor = bagImage.color;
;    }
    //设置item
    public void SetArticleItem(ArticleItem articleItem)
    {
        this.articleItem = articleItem;

        this.articleItem.transform.parent = transform;

        //this.articleItem.transform.localPosition = Vector3.zero;

        this.articleItem.transform.localScale = Vector3.one;
        this.articleItem.MoveToOrign();
;
        this.articleItem.GetComponent<RectTransform>().offsetMin = new Vector2(5, 5);
        this.articleItem.GetComponent<RectTransform>().offsetMax= new Vector2(-5, -5);
    }
    //销毁item
    public void ClearGrid()
    {       
        if (articleItem.gameObject != null)
            Destroy(articleItem.gameObject);      
        articleItem = null;
    }
    //拖拽到对应格子
    public void DragToThisGrid(ArticleItem articleItem)
    {
        BagGrid preGrid = articleItem.transform.parent.GetComponent<BagGrid>();          
        if(this.articleItem==null)
        {                    
           //清空之前的格子
            preGrid.articleItem=null;
             SetArticleItem(articleItem);
        }
        else
        {
            //交换
            preGrid.SetArticleItem(this.articleItem);
            SetArticleItem(articleItem);
        }
    }
    //鼠标进入接口
    public void OnPointerEnter(PointerEventData eventData)
    {
        if(BagPanel.instance.currentDragArticle!=null)
        {
            //this为当前鼠标所在格子
            BagPanel.instance.currentMouseGrid = this;
            bagImage.color = Color.yellow;
        }
    }
    //鼠标退出接口
    public void OnPointerExit(PointerEventData eventData)
    {
        BagPanel.instance.currentMouseGrid = null;
        bagImage.color = defaultColor;
    }
}

ArticleItem.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;


//管理图片及对应信息
public class ArticleItem : MonoBehaviour
{
    private Image articleSprite;
    private Text number;

    private UIDrag uIDrag;
    private Article article;
    private Canvas canvas;
    private int defaultSort;

    private Vector3 currentLocalPosition;
    private float Timer=0;
    private float MoveTime = 0.2f;
    private bool isMoving = false;
    // Start is called before the first frame update
    private void Awake()
    {
        articleSprite = transform.GetComponent<Image>();
        number=transform.Find("Text").GetComponent<Text>();
        canvas = transform.GetComponent<Canvas>();
        defaultSort = canvas.sortingOrder;
        //在BagGrid写了回调函数
        uIDrag = transform.GetComponent<UIDrag>();
        uIDrag.onStarDrag += this.OnStartDrag;
        uIDrag.onDrag += this.OnDrag;
        uIDrag.onEndDrag += this.OnEndDrag;
    }
    private void Update()
    {
        MovingOrign();
    }
    //回到原位置
    public void MovingOrign()
    {
        if (isMoving)
        {
            Timer += Time.deltaTime * (1 / MoveTime);
            transform.localPosition = Vector3.Lerp(currentLocalPosition, Vector3.zero, Timer);
            if (Timer >= 1)
            {
                Timer = 0;
                isMoving = false;
                canvas.sortingOrder = defaultSort;           
            }
        }
    }
    //设置article信息
    public void SetArticle(Article article)
    {
        this.article = article;
        //初始化图片
        articleSprite.sprite = Resources.Load<Sprite>(article.spritePath);
        number.text = article.count.ToString();

    }
    //开始拖拽
    public void OnStartDrag()
    {
        canvas.sortingOrder = defaultSort + 1;
        //this为当前开始拖拽的article
        BagPanel.instance.currentDragArticle = this;
    }
    //拖拽过程
    public void OnDrag()
    {

    }
    //拖拽结束
    public void OnEndDrag()
    {
        if(BagPanel.instance.currentMouseGrid!=null)
        {
            //移动到对应格子
            BagPanel.instance.currentMouseGrid.DragToThisGrid(BagPanel.instance.currentDragArticle);
            //修改层级
            canvas.sortingOrder = defaultSort; 
        }
        else
        {
            //当移动位置不合法则移动到原点
            MoveToOrign();
        }    
        BagPanel.instance.currentDragArticle = null;
    }
    //开始移动到起点的初始化
    public void MoveToOrign()
    {
        isMoving = true;
        Timer = 0;
        currentLocalPosition = transform.localPosition;
    }
}

UIDrag.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class UIDrag : MonoBehaviour,IDragHandler,IBeginDragHandler,ICanvasRaycastFilter,IEndDragHandler
{
    private RectTransform rect;
    private Vector3 mousePosition;
    //回调函数
    public Action onStarDrag;
    public Action onDrag;
    public Action onEndDrag;

    private bool isDraging = false;

    private void Start()
    {
        rect = transform.GetComponent<RectTransform>();
        
    }
    private void Update()
    {
        if (isDraging)
        {
            rect.localPosition += (Input.mousePosition - mousePosition);
            rect.anchoredPosition += (Vector2)(Input.mousePosition - mousePosition);
            mousePosition = Input.mousePosition;
            //SetDraggedPosition(eventData);
            onDrag?.Invoke();
        }
        if(Input.GetMouseButtonUp(0)&&isDraging)
        {
            isDraging = false;
        }

    }
    public void OnBeginDrag(PointerEventData eventData)
    {
        mousePosition = Input.mousePosition;
        //SetDraggedPosition(eventData);
        isDraging = true;
        onStarDrag?.Invoke();
    }

    public void OnDrag(PointerEventData eventData)
    {
        //rect.localPosition += (Input.mousePosition - mousePosition);
        //rect.anchoredPosition += (Vector2)(Input.mousePosition - mousePosition);
        //mousePosition = Input.mousePosition;
        SetDraggedPosition(eventData);
        //onDrag?.Invoke();
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        //SetDraggedPosition(eventData);
        onEndDrag?.Invoke();
    }
    private void SetDraggedPosition(PointerEventData eventData)
    {
        Vector3 worldMousePos;
        //把屏幕坐标转换为世界坐标
        if (RectTransformUtility.ScreenPointToWorldPointInRectangle(rect, Input.mousePosition,eventData.pressEventCamera, out worldMousePos))
        {
            rect.position = worldMousePos;
        }
    }

    public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
    {
        return !isDraging;
    }
}

Article .cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum ArticleType
{
    Weapon,
    Shoes,
    Book,
    Drug,
}

public class Article 
{
    public string name;
    public string spritePath;
    public ArticleType articleType;
    public int count;

    public Article(string name,string spritePath,ArticleType articleType,int count)
    {
        this.name = name;
        this.spritePath = spritePath;
        this.articleType = articleType;
        this.count = count;
    }
}