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类型,所以用FindObjectOfType来查找.
canvas = GameObject.Find(
"Canvas"
).GetComponent
pickedItem
= GameObject.Find(
"PickedItem"
).GetComponent();
//通过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(item.Sprite);
//itemImage.sprite表示在itemImage下面的sprite组件.也就是这个组件的渲染图片
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().Item.ID)
//格子和鼠标物体不一样
{
//交换鼠标和格子上的物体.
}
else
//格子和鼠标物体一样.
{
if
(Input.GetKey(KeyCode.LeftControl))
//按下Ctrl
{
//鼠标上的一个Item放到格子上
}
else
//不按Ctrl
{
if
(InventoryManager.Instance.PickedItem.Item.Capacity >=
transform.GetChild(0).GetComponent().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();
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().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().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的交互功能就完成了.