29.选中物体跟随鼠标移动
如图,Picked要用InventoryManager来管理.
首先把Prefab中的item添加入Canvas里面,改名PickedItem.
这个Item就是鼠标点击之后跟随鼠标移动的Item.
原理就是点击Slot里面的Item,把这个Item复制到PickedItem上面.
Slot里面的Item要Destroy掉.
然后把这个PickedItem放在鼠标下面,跟随鼠标移动.
在ItemUI中构造3个方法:
public void Show()//设置出现
{
gameObject.SetActive(true);
}
public void Hide()//设置隐藏
{
gameObject.SetActive(false);
}
public void SetLocalPosition(Vector3 position)//设置该物体的位置,LocalPosition画布位置.
{
transform.localPosition = position;
}
在InventoryManager中.
private ItemUI pickedItem;
void Start()
{
ParseItemJson();//开始解析Json
toolTip = GameObject.FindObjectOfType<ToolTip>();
//因为只有一个ToolTip类型,所以用FindObjectOfType来查找.
canvas = GameObject.Find("Canvas").GetComponent<Canvas>();
pickedItem = GameObject.Find("PickedItem").GetComponent<ItemUI>();
//通过ItemUI来控制PickedItem的状态.
}
这样我们就能在InventoryManager中得到ItemUI的显示/隐藏方法,同时也能设置他的位置.
那么,只要在InventoryManager中控制什么情况下显示/隐藏.
然后得到他应该显示的位置,然后把这个位置赋值给ItemUI中SetLocalPosition设置位置的方法就好了.
30.列出MUL关系图
一共是9种情况.
这个功能要做成点击Slot然后进行条件判断,所以这个功能要放在Slot脚本里面做.
首先给出一个接口检测鼠标按下 然后实现这个接口.
public class Slot : MonoBehaviour,IPointerEnterHandler,IPointerExitHandler,IPointerDownHandler
public void OnPointerDown(PointerEventData eventData)
{
//各种判断条件
}
31.捡起物品功能.
我们首先做捡起物品的功能,也就是PickedItem上面没有Item,Solt上有Item.
首先做这个的原因:因为别的功能会基于PickedItem不为空.
我们首先判断PickedItem是否为空.
那么就要在InventoryManager中得到该组件.
private bool isPickedItem=false;//判断当前的鼠标有没有选中物体
public bool IsPickedItem//构造一个函数方便外界调用.
{
get { return isPickedItem; }
}
private ItemUI pickedItem;//鼠标选中的物体(这里修改成public的话就可以不用下面的构造函数,但是会不安全.)
public ItemUI PickedItem//这里做这个构造函数主要是为了让外部可以访问他.
{
get { return pickedItem; }//这里只有get函数,只能访问不能修改.
}
如果想把Slot中的ItemUI复制给PickedItem,那么就要在ItemUI中做一个方法.
这里注意为什么是复制ItemUI而不是Item.
Item里面存储的是物品的基本属性.
而ItemUI里面存储的是 Item Amount 图片
所以这里Solt和PickedItem交换的都是ItemUI.
public void SetItem(Item item, int amount = 1)
{
this.Item = item;
this.Amount = amount;
ItemImage.sprite = Resources.Load<Sprite>(item.Sprite);
//itemImage.sprite表示在itemImage下面的sprite组件.也就是这个组件的渲染图片
//Resources.Load<a>(b);表示加载a类型的b路径的一个组件.
if (Item.Capacity > 1)
{
AmountText.text = Amount.ToString();
}
else
{
AmountText.text = "";
}
//表示让这个数量转化成字符串显示.
}
public void SetItem(ItemUI itemUI)//这个方法调用了上面的方法.虽然名字一样,但是参数不一样.
{
SetItem(itemUI.Item,itemUI.Amount);
}
然后再在Slot中做条件判断.
其实下面的表就是上面哪个图片用C#的形式表现出来.
//当在格子上鼠标按下的时候.
public void OnPointerDown(PointerEventData eventData)
{
if (transform.childCount != 0) //格子不空
{
if (InventoryManager.Instance.PickedItem == null) //鼠标是空
{
if (Input.GetKey(KeyCode.LeftControl))//按下Ctrl
{
//获取一半格子物品
}
else//不按Ctrl
{
//获取格子全部物品
}
}
else//鼠标不空
{
if (InventoryManager.Instance.PickedItem.Item.ID !=
transform.GetChild(0).GetComponent<ItemUI>().Item.ID) //格子和鼠标物体不一样
{
//交换鼠标和格子上的物体.
}
else//格子和鼠标物体一样.
{
if (Input.GetKey(KeyCode.LeftControl)) //按下Ctrl
{
//鼠标上的一个Item放到格子上
}
else//不按Ctrl
{
if (InventoryManager.Instance.PickedItem.Item.Capacity >=
transform.GetChild(0).GetComponent<ItemUI>().Amount +
InventoryManager.Instance.PickedItem.Amount)
//物品的最大容量不小于格子和鼠标上的和.
{
//放下鼠标的物体,并销毁
}
else//格子上放不下所有的物体
{
//格子放满,鼠标上留下剩下的物体.
}
}
}
}
}
else//格子是空
{
if (InventoryManager.Instance.PickedItem == null) //鼠标也为空.
{
//不做处理.
}
else//鼠标不为空.
{
if (Input.GetKey(KeyCode.LeftControl)) //按下Ctrl
{
//鼠标上的一个Item放到格子上
}
else//不按Ctrl
{
//放置全部Item.
}
}
}
}
31.完成捡起物品,捡起一半物品的功能.
首先在InventoryManager中添加捡起Item的方法
public void PickupItem(Item item,int amount)//捡起Item,并指定数量
{
PickedItem.SetItem(item,amount);//把Solt里面的ItemUI复制到鼠标上
isPickedItem = true;//把鼠标上是否有东西的标志位设置为true
}
在ItemUI中设置物品槽的物品数量,所以要添加一个方法
public void SetAmount(int amount)//设置当前slot位置上剩余的数量
{
this.Amount = amount;
//跟新UI显示
if (Item.Capacity > 1)
{
AmountText.text = Amount.ToString();
}
else
{
AmountText.text = "";
}
}
slot中的代码
if (transform.childCount > 0) //格子不空
{
ItemUI currentItem = transform.GetChild(0).GetComponent<ItemUI>();
if (InventoryManager.Instance.IsPickedItem == false) //鼠标是空
{
if (Input.GetKey(KeyCode.LeftControl))//按下Ctrl
{
//获取一半格子物品.
int amountPicked = (currentItem.Amount + 1) / 2;//这个只会对奇数产生影响.如果是偶数就没有影响
InventoryManager.Instance.PickupItem(currentItem.Item, amountPicked);
if (currentItem.Amount-amountPicked<=0)//当全部拿走的时候
{
Destroy(currentItem.gameObject);
}
else//格子里面还有剩余的时候
{
currentItem.SetAmount(currentItem.Amount - amountPicked);
}
}
else//不按Ctrl
{
//获取格子全部物品
InventoryManager.Instance.PickupItem(currentItem.Item,currentItem.Amount);
/*下面的这个方法在InventoryManager中用PickupItem代替.
* InventoryManager.Instance.PickedItem.SetItem(currentItem);
在ItemUI中有SetItem方法,能复制ItemUI.
InventoryManager.Instance.IsPickedItem = true;
当他得到物品之后就设置他的属性为true;*/
Destroy(currentItem.gameObject);
}
}
32.让选中的物体跟随鼠标移动
首先把隐藏的PickedItem显示出来.
在InventoryManager中
public void PickupItem(Item item,int amount)//捡起Item,指定数量
{
PickedItem.SetItem(item,amount);//把Solt里面的ItemUI复制到鼠标上
PickedItem.Show();
isPickedItem = true;//把鼠标上是否有东西的标志位设置为true
}
然后再Update中书写功能
if (isPickedItem)//如果鼠标选中物体,让物体跟随鼠标
{
Vector2 position;
//下面的函数用来得到鼠标的位置,并返回到position上.
RectTransformUtility.ScreenPointToLocalPointInRectangle
(canvas.transform as RectTransform, Input.mousePosition, null, out position);
pickedItem.SetLocalPosition(position);
}
在拿起物品的时候就不应该显示tooltip了
所以.Update下面的Tooltip就要用else if语句,先判断是不是有东西如果没有东西在进行判断是不是要给tooltip.
void Update()
{
if (isPickedItem)//如果鼠标选中物体,让物体跟随鼠标
{
xxxx
}else if (isToolTipShow)//如果ToolTip显示出来,让tooltip跟随鼠标
{
xxxx
}
}
在PickupItem的时候马上把当前tooltip隐藏掉.
public void PickupItem(Item item,int amount)//捡起Item,指定数量
{
PickedItem.SetItem(item,amount);//把Solt里面的ItemUI复制到鼠标上
isPickedItem = true;//把鼠标上是否有东西的标志位设置为true
PickedItem.Show();
this.toolTip.Hide();//如果鼠标上有东西就不显示该物体的tooltip
}
此外,在鼠标移动到别的Slot上面也不显示tooltip
public void ShowToolTip(string content)
{
if (isPickedItem)//如果鼠标上有东西就不显示tooltip 直接跳出
{
return;
}
isToolTipShow = true;//标志位,用来查看是否显示提示信息.
toolTip.Show(content);
}
33.物体选中的动画效果.
首先修改一个问题.
我们创建出来Item的时候,物体会在放Canvas的Slot里面.但是Canvas本身就要Scale.并且Scale不为1.
所以我们创建出来的物体,本身的大小会被缩放.
这时候我们要在Slot存储这个Item的时候把这个Item的Sacle设置成1.
public void StoreItem(Item item)//用于存储Item
{
if (transform.childCount == 0)//如果是个空物品槽,实例化出来一个
{
//实例化出来一个itemPrefab.把这个itemPrefab作为Gameobject
GameObject itemGameObject = Instantiate(itemPrefab) as GameObject;
//把父类的位置和自身的位置重合
itemGameObject.transform.SetParent(this.transform);
itemGameObject.transform.localScale = Vector3.one;//将准备存储在Slot的Item的比例缩放成1.
itemGameObject.transform.localPosition = Vector3.zero;
//这里他的父类和自身都是中心点设计,所以设置Vector3.zero(位置归零)
itemGameObject.GetComponent<ItemUI>().SetItem(item); //得到ItemUI组件,设置图片和数量.
}
这个时候,在创建出来的物体的比例就是1了.
接下来就可以做动画效果了.
所谓的动画效果就是让Item在选中的时候放大一下,然后在以一定的速率恢复到原来的大小.
因为这个动画是在Item上产生,所以要放在ItemUI上来做.
需要做动画效果的地方有SetItem SetAmount AddMount
#region 设置动画
//动画效果为:再点击或者增加的时候图片会瞬间变大,然后再慢慢缩小.
private float targetScale = 1f;//这个是最后的比例大小,动画最后一定是要还原的,所以这里的目标值为1
private Vector3 animationScale = new Vector3(1.2f, 1.2f, 1.2f);//这个是动画开始时候的效果,最开始的时候目标动画是放大的
private float smoothing = 4f;//缩小的速度
void Update()
{
if (transform.localScale.x != targetScale)//当图片目前的大小和目标大小/原大小(targetSacle)不一致的时候.
{
float scale = Mathf.Lerp(transform.localScale.x, targetScale, Time.deltaTime * smoothing);
//得到一个缩放比例插值,从当前的大小,变化到原大小.
//在物体被存储或者数量有变化的时候,在最开始,会把动画的最开始的大小赋值给图片.
//也就是把animationScale赋值给图片.
if (Mathf.Abs(transform.localScale.x - targetScale) < 0.01f)//为了减轻运算负担,当他们的差值小于0.01的时候我们就认为他们已经相等了.插值运算的当前值永远不会到达目标值
{
transform.localScale = Vector3.one;
}
//把得到的插值放到当前的图片比例当中.
transform.localScale = new Vector3(scale, scale, scale);
}
}
#endregion
在下面的三个函数中分别让他们能的初始大小变成animationScale大小.
也就是在他们的函数里面加入:transform.localScale = animationScale; 这句代码
public void SetItem(Item item, int amount = 1)
public void AddAmount(int amount = 1)
public void SetAmount(int amount)//设置当前slot位置上剩余的数量
这样就完成了动画效果.
34.完成鼠标和格子物品一样时候的按下Ctrl的功能.
这时候点击鼠标左键,会产生2个效果,slot里面的物品+1
鼠标上的物品-1
减少一个Item的数量,这个功能要做在ItemUI里面.
#region 减少鼠标上的物品数量
public void ReduceAmount(int amount = 1)
{
this.Amount -= amount;
transform.localScale = animationScale;
//跟新UI显示
if (Item.Capacity > 1)
{
AmountText.text = Amount.ToString();
}
else
{
AmountText.text = "";
}
}
#endregion
鼠标上减少一个物体,这个功能要做在inventoryManager里面.
因为是用InventoryManager来管理鼠标上的PickedItem的.
#region 减少鼠标上的一个Item
public void RemoveOneItem()
{
PickedItem.ReduceAmount();
if (pickedItem.Amount<=0)
{
isPickedItem = false;
pickedItem.Hide();
}
}
#endregion
Slot里面的存储功能.(按下Ctrl)
else//格子和鼠标物体一样.
{
if (Input.GetKey(KeyCode.LeftControl)) //按下Ctrl
{
//鼠标上的一个Item放到格子上
if (currentItem.Item.Capacity>currentItem.Amount)//如果当前的最大容量没有满
{
currentItem.AddAmount();//增加格子上一个物品的个数.
//鼠标上减少一个物品
InventoryManager.Instance.RemoveOneItem();
}
}
35.鼠标和格子上面有相同Item 将鼠标上的Item放置在格子里面.
不按Ctrl
else//不按Ctrl
{
if (InventoryManager.Instance.PickedItem.Item.Capacity >=
currentItem.Amount +
InventoryManager.Instance.PickedItem.Amount)
//物品的最大容量不小于格子和鼠标上的和.
{
//放下鼠标的物体,并销毁.格子上增加物体
currentItem.SetAmount(currentItem.Amount + InventoryManager.Instance.PickedItem.Amount);
InventoryManager.Instance.RemoveAllItem();
}
else//格子上放不下所有的物体
{
//格子放满,鼠标上留下剩下的物体.
InventoryManager.Instance.PickedItem.SetAmount(currentItem.Amount + InventoryManager.Instance.PickedItem.Amount - currentItem.Item.Capacity);
currentItem.SetAmount(currentItem.Item.Capacity);
}
}
36.格子为空.
分为2种情况,1鼠标上有物体 2鼠标上没有物体
else//格子是空
{
if (InventoryManager.Instance.IsPickedItem == false) //鼠标也为空.
{
//不做处理.
}
else//鼠标不为空.
{
if (Input.GetKey(KeyCode.LeftControl)) //按下Ctrl
{
//鼠标上的一个Item放到格子上
StoreItem(InventoryManager.Instance.PickedItem.Item);
InventoryManager.Instance.RemoveOneItem();
}
else//不按Ctrl
{
//放置全部Item.
StoreItem(InventoryManager.Instance.PickedItem.Item);
transform.GetChild(0).GetComponent<ItemUI>().SetAmount(InventoryManager.Instance.PickedItem.Amount);
InventoryManager.Instance.RemoveAllItem();
}
}
}
因为格子是空的,所以不能直接得到GetChild(0),所以要在这个格子上先实例化出来一个物体.
然后在改变这个物体的数量.
37.鼠标和格子物品交换.
else//鼠标不空
{
if (InventoryManager.Instance.PickedItem.Item.ID !=
currentItem.Item.ID) //格子和鼠标物体不一样
{
//交换鼠标和格子上的物体.
Item tempItem = InventoryManager.Instance.PickedItem.Item;
int tempAmount = InventoryManager.Instance.PickedItem.Amount;
//Item和Amount要分开记录.我也不知道为什么..
InventoryManager.Instance.PickedItem.SetItem(currentItem.Item, currentItem.Amount);
currentItem.SetItem(tempItem, tempAmount);
}
38.物品的丢弃.
物品的丢失功能是在鼠标选取物体之后,在空白的地方点击就会丢弃物品.
这个功能做在InventoryManager的Update中.
//丢弃物体的功能
//要符合三个条件才会丢弃物品
/// 1.鼠标上有物体
/// 2.按下鼠标左键
/// 3.当前的鼠标位置下面没有任何UI组件
if (isPickedItem&&Input.GetMouseButtonDown(0)&&UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject(-1)==false )
{
//UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject(-1)
//上面可以得到现在鼠标左键下是否有UI组件.false为没有 true为有.
isPickedItem = false;
pickedItem.Hide();
}
获取鼠标在屏幕上的位置:
UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject(-1)
这里的参数-1为鼠标左键.
记住就好.别问为什么.我也不知道.
这里有一点要注意:
如果一个UI添加了CanvasGroup组件.
而且他没有勾选Blocks Raycasts.那么这个UI就不会有交互.
也就是说这时候放置鼠标上的物体的时候,物体直接会消失.
到此,鼠标和Slot的交互功能就完成了.