前几天看了一个教程,背包物品交换。由于教程中使用的是ngui,很多代码需要使用UGUI重新写,因此苦恼了几天。
我遇到了以下问题,在此详细罗列,以记录错误的原因和修改的方法,供日后阅读查找。
一、背包中的物品在拖拽之后放入指定的空格子(问题1:不知道该怎么获得指定的空格子;问题3:更新格子内的物品信息时找不到该物品);
二、背包中的物品在拖拽之后放入原来的格子(问题2:少了两行代码);
三、背包中的物品在拖拽之后,与另一个物品交换位置,并将自身信息更新在新的格子中(问题3:更新格子内的物品信息时找不到该物品;问题4:被交换的物体还在原来的位置待着)。
解决这些问题所参考的资料(原创者:不在同一频道上的呆子)
交换背包格子中的物体
要实现的功能是:
1.在开始拖拽时,保证被拖拽的UI对象(以下称该对象为A)始终显示在其他UI的上方;
2.在拖拽时,保证A在屏幕中始终在鼠标的位置处;
3.拖拽结束,释放鼠标之后,A存放在目标格子中(即,把目标格子设置为A的父物体)。分为三种情况:(1)如果目标格子中没有物体且不是A的原位置,则直接放入;(2)如果目标格子是原位置,则视觉上不做更改;(3)如果目标格子中有物品B,则A与B交换位置,并交换父物体。
unity拖放UI对象需要引入命名空间和接口:
using UnityEngine.EventSystems;
public class InventoryItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler,IPointerEnterHandler,IPointerExitHandler
主要实现以下三个接口,实现方法分别是:
public void OnBeginDrag(PointerEventData eventData) { }
public void OnDrag(PointerEventData eventData) { }
public void OnEndDrag(PointerEventData eventData) { }
问题1:不知道该怎么获得指定的空格子:
解决方法:让被拖拽的物体屏蔽射线检测,这样就能获得鼠标悬停下的UI对象
transform.GetComponent<Image>().raycastTarget = false;
问题2:将A放入原格子:
//nowParent是A被拖拽前的父物体
transform.SetParent(nowParent);
transform.localPosition = Vector3.zero;
问题:4:被交换的物体还在原来的位置待着
这是因为将被拖拽的物体A的位置重新设置,但是没有将被交换的物品B的位置重新设置。只需要加上一行语句即可:
Transform tmpItem = dropTarget.transform;
tmpItem.localPosition = Vector3.zero;
交换物品后更新格子内的物品信息
要实现的功能是:
在交换完成后,相应的背包格子内部关于物品的信息也要进行更新。
问题3:更新格子内的物品信息时找不到该物品
这是因为在调用另一个脚本时,一个临时变量为空导致的。在拖拽A时,A的原来的父物体找不到A,导致报空指针,因而出错。为了解决这个问题,需要将A的父亲进行更新(如果与B交换,则B的父亲需要同时更新)
dropTarget.transform.SetParent(nowParent);
完整的脚本如下:
InventoryItemGrid是背包的物品格子,InventoryItemCount是记录该格子中的物品数量。InventoryItem(Clone)是背包内的物品。
InventoryItem脚本挂载在每一个背包物品上面:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
/// <summary>
/// 管理背包格子内的物品
/// </summary>
public class InventoryItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler,IPointerEnterHandler,IPointerExitHandler
{
public Image sprite;
/// <summary>
/// 物品id
/// </summary>
private int itemId;
/// <summary>
/// 鼠标指针是否悬浮于物品上方
/// </summary>
private bool isHover = false;
/// <summary>
/// 图标的RectTransform组件
/// </summary>
private RectTransform rectTransform;
/// <summary>
/// Canvas组件,用于确定拖拽的缩放因子
/// </summary>
private Canvas canvas;
/// <summary>
/// 物体的目前父物体
/// </summary>
private Transform nowParent;
private void Start()
{
rectTransform = GetComponent<RectTransform>(); // 获取图标的RectTransform组件
canvas = GetComponentInParent<Canvas>(); // 获取父级Canvas组件
//originalPosition = rectTransform.anchoredPosition; // 记录图标的初始位置
}
private void Update()
{
if (isHover)
{
if (Input.GetMouseButtonDown(1))
{
bool success = EquipmentPanel._instance.Dress(itemId);
if (success)
{
transform.parent.GetComponent<InventoryItemGrid>().MinusNumber();
}
}
}
}
public void SetId(int id)
{
ObjectInfo info = ObjectsInfo._instance.GetObjectInfoById(id);
//更新显示
sprite.name = info.iconName;
}
public void SetIconName(int id, string iconName)
{
sprite.sprite = Resources.Load<Sprite>(Path.itemPath+iconName);
itemId = id;
}
public void OnBeginDrag(PointerEventData eventData)
{
if (transform.GetComponent<Image>().raycastTarget)
{
//让被拖拽的物体屏蔽射线检测,这样就能获得鼠标悬停下的UI对象
transform.GetComponent<Image>().raycastTarget = false;
}
nowParent = transform.parent; //nowparent为被拖拽物体的当前父物体
transform.SetParent(canvas.transform);//将当前拖拽的物体放在canvas下
}
public void OnDrag(PointerEventData eventData)
{
rectTransform.anchoredPosition += eventData.delta / canvas.scaleFactor; // 根据鼠标移动更新图标位置
}
public void OnEndDrag(PointerEventData eventData)
{
//用于存放鼠标当前悬停位置下的物体
GameObject dropTarget = eventData.pointerCurrentRaycast.gameObject;
if (dropTarget != null)
{
if (dropTarget.CompareTag(S_Tags.inventoryItemGrid)) // 当拖放到了一个空的格子里面
{
if (dropTarget.transform == nowParent)
{
transform.SetParent(nowParent);
}
else
{
// 处理拖拽到空格子的逻辑
InventoryItemGrid oldSlot = nowParent.GetComponent<InventoryItemGrid>();
transform.SetParent(dropTarget.transform);
ResetLocalPosition();
InventoryItemGrid newSlot = dropTarget.GetComponent<InventoryItemGrid>();
//int oldId = oldSlot.itemId;
//int oldCount = oldSlot.itemCount;
newSlot.SetId(oldSlot.itemId, oldSlot.itemCount);
oldSlot.CleanInfo();
}
}
else if (dropTarget.CompareTag(S_Tags.inventoryItem)) // 当拖放到了一个有物品的格子里面
{
// 处理拖拽到有物品的格子里面的逻辑
InventoryItemGrid slot1 = nowParent.GetComponent<InventoryItemGrid>();
InventoryItemGrid slot2 = dropTarget.transform.parent.GetComponent<InventoryItemGrid>();
Transform tmpItem = dropTarget.transform;
Transform tmpParent = dropTarget.transform.parent;
//交换父亲
//将被拖拽的物体的父亲更新为当前指针悬停位置物品的父亲
transform.SetParent(tmpParent);
//将指针悬停位置物品的父亲更新为被拖拽物品的原父亲
dropTarget.transform.SetParent(nowParent);
int id = slot1.itemId;
int num = slot1.itemCount;
slot1.SetId(slot2.itemId, slot2.itemCount);
slot2.SetId(id, num);
tmpItem.localPosition = Vector3.zero;
}
else
{
transform.SetParent(nowParent);
}
}
else
{
transform.SetParent(nowParent);
}
transform.GetComponent<Image>().raycastTarget = true;
ResetLocalPosition();
}
/// <summary>
/// 被拖拽物体返回原位置
/// </summary>
private void ResetLocalPosition()
{
transform.localPosition = Vector3.zero;
transform.SetAsFirstSibling();
}
/// <summary>
/// 鼠标指针进入时
/// </summary>
/// <param name="eventData"></param>
public void OnPointerEnter(PointerEventData eventData)
{
InventoryDes._instance.ShowDes(itemId);
isHover = true;
}
/// <summary>
/// 鼠标指针退出时
/// </summary>
/// <param name="eventData"></param>
public void OnPointerExit(PointerEventData eventData)
{
InventoryDes._instance.HideDes();
isHover = false;
}
}
InventoryItemGrid 挂载在每一个背包格子上文章来源:https://www.toymoban.com/news/detail-851892.html
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// 管理背包格子
/// </summary>
public class InventoryItemGrid : MonoBehaviour
{
/// <summary>
/// 表示当前背包格子里面存储了什么物品.默认为0,表示当前背包格子中什么也没有
/// </summary>
public int itemId = 0;
/// <summary>
/// 表示当前背包格子中的物品的数量。默认为0.
/// </summary>
public int itemCount = 0;
/// <summary>
/// 当前背包格子中的物品的信息
/// </summary>
private ObjectInfo info = null;
private Text txt_itemCount;
private void Start()
{
txt_itemCount = transform.Find("InventoryItemCount").GetComponent<Text>();
}
/// <summary>
/// 当背包格子中的物品发生变化时(包括类型、图标、数量等),就更新背包格子中关于物品的显示。
/// </summary>
/// <param name="id">物品的属性:id</param>
/// <param name="num">物品的数量,默认为1</param>
public void SetId(int id, int num = 1)
{
itemId = id;
//先得到物品信息
info = ObjectsInfo._instance.GetObjectInfoById(id);
//更新背包格子中的显示
InventoryItem item = GetComponentInChildren<InventoryItem>();
//用于检测是哪个格子失去了子物体
if (item == null)
{
print(transform.name);
}
item.SetIconName(id, info.iconName);//info.iconName是从txt文件中解析得来的
txt_itemCount.gameObject.SetActive(true);
itemCount = num;
txt_itemCount.text = itemCount.ToString();
txt_itemCount.gameObject.transform.SetAsLastSibling();
}
/// <summary>
/// 背包格子中的物体数目增加,相应的显示数字也应当变化
/// </summary>
/// <param name="num">物品增加的数量</param>
public void PlusNumber(int num = 1)
{
itemCount += num;
txt_itemCount.text = itemCount.ToString();
}
/// <summary>
/// 用于减去背包中物品的数量
/// </summary>
/// <param name="num"></param>
/// <return>是否减量成功</return>
public bool MinusNumber(int num = 1)
{
if (itemCount >= num)
{
itemCount -= num;
txt_itemCount.text = itemCount.ToString();
if (itemCount == 0)
{
//清空物品格子
CleanInfo();
//销毁物品
Destroy(GetComponentInChildren<InventoryItem>().gameObject);
}
return true;
}
return false;
}
/// <summary>
/// 清空背包格子中的物品信息
/// </summary>
public void CleanInfo()
{
itemId = 0;
info = null;
itemCount = 0;
txt_itemCount.gameObject.SetActive(false);
}
}
其中ObjectsInfo用于读取txt文本文件(记录了物品的各个属性)。文章来源地址https://www.toymoban.com/news/detail-851892.html
到了这里,关于unity拖拽背包物体,并交换两个物体的信息的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!