目录
实现切换武器
DragItem 中添加物品属性和 SlotType 的匹配
对于非背包里的物品我们也可以交换但是要加以限制。
在 SlotHolder 中切换所属背包的数据库
当我们将Slot Holder放在不同的地方时,此时也要更改其所属的背包对应的数据库:
这样即可实现不同栏间的物品交换,并且数据库也会因此更新。
鼠标点击会使得人物移动的问题
换武器的方法
在characterStats中补充卸下武器的代码:
public void UnEquipWeapon()
{
if (weaponSlot.transform.childCount != 0)
{
for(int i = 0; i < weaponSlot.transform.childCount; i++)
{
Destroy(weaponSlot.transform.GetChild(i).gameObject);
}
}
}
卸下武器前就要还原成原来的攻击数据,因此需要有一个变量来记录初始时没武器的数据:
代码如下:
public void UnEquipWeapon()
{
if (weaponSlot.transform.childCount != 0)
{
for(int i = 0; i < weaponSlot.transform.childCount; i++)
{
Destroy(weaponSlot.transform.GetChild(i).gameObject);
}
}
attackData.ApplyWeanponData(baseAttackData);//卸下武器后还原之前的攻击力
//TODO:切换动画
}
public void ChangeWeapon(ItemData_SO weapon)
{
UnEquipWeapon();
EquipWeapon(weapon);
}
然后在SlotHolder更新一栏中更改武器:
可使用的物品
-
创建大蘑菇 并添加必要的组件
-
创建 UseableItemData_SO 制作可使用物品的属性模版
-
利用 IPointerClickHandler 接口实现双击使用物品
-
在 CharacterStats 中添加 ApplyHealth 实现血量变化
参考代码手册:
-
IPointerClickHandler :点击跳转
创建一个蘑菇的变量:
创建useable类型的SO:
然后在itemData中加入这种类型:
创建useable类型的SO:
并赋值:(为useable Item赋值)
然后在场景中创建一个mushroom并添加这些组件:
之后即可实现拾取蘑菇并且在格子和快捷栏里自由移动。
接下来实现使用物品的功能:
先在itemUI中写一个根据对应UI获取对应物品的方法:
在characterStats中书写一个函数:
使用需要实现一个接口,
在SlotHolder里实现该接口
public void OnPointerClick(PointerEventData eventData)
{
if (eventData.clickCount % 2 == 0)//代表是双击的话
{
UseItem();
}
}
public void UseItem()
{
if (itemUI.GetItem().itemType == ItemType.Useable&&itemUI.Bag.items[itemUI.Index].amount>0)
{
GameManager.Instance.playerStats.ApplyHealth(itemUI.GetItem().useableData.healthPoint);
itemUI.Bag.items[itemUI.Index].amount -= 1;
}
UpdateItem();
}
别忘了要进行数量减一,更新UI的操作。
但是之后发现一个bug,当蘑菇用完时图片仍然存在:
解决方法:
显示Player相关信息
设定一个相机让它观察player,并设定好各类信息:
创建texture然后放进去
然后将renderTexture给Stats里面创建的RawImage
记得将相机的设置放入prefab里面
然后可以显示:
接下来实现血量和伤害的显示:
然后在装备武器时进行信息的更新:
也可以在manager中更新:
随后即可实现血量和攻击的更新了:升级时也会改变
切换动画控制器
-
使用更多动画来创建 Animator override controller
-
ItemData_SO 中添加武器配套动画控制器
-
在 EquipWeapon 和 UnEquipment 中添加代码切换武器伴随动画
参考素材:
-
RPG Character Animation Pack Free :点击跳转
这两个作者的素材很好,有很多动作素材
下载这个只保留animation即可:
创建一个没武器的override controller:并导入动画
然后即可实现无武器的运行。
但是会有两个报错,是因为动画自带两个事件。删除即可。
我们希望给武器自己加上一个animation controller:
在此处更换装备。
初始时获取初始动画控制器:
卸武器时候还原:
这样就可以自由切换了。
有个问题在于人物的武器不能在属性中显示,将sword的预制体的layer设置为player即可。
物品信息显示栏
创建一个image,调整大小:
然后设定为了能根据不同的设置出不同的大小,添加这个组件
添加这个:
给信息一栏也添加Fitter:
这样就可以实现UI的信息的多少会随着栏的信息而改变:
创建代码,实现控制:
鼠标的悬停希望实现的接口:
让SlotHolder实现这两个接口:
public void OnPointerEnter(PointerEventData eventData)
{
if (itemUI.GetItem())
{
InventoryManager.Instance.tooltip.SetupTooltip(itemUI.GetItem());
InventoryManager.Instance.tooltip.gameObject.SetActive(true);
}
}
public void OnPointerExit(PointerEventData eventData)
{
InventoryManager.Instance.tooltip.gameObject.SetActive(false);
}
这样就可以实现悬停时出现。
接下来希望悬停时出现的位置是鼠标的位置:
效果:
但是出现的位置是在鼠标中心,并且还会闪烁。
是因为锚点是出现在中心:
修改方法:
代码如下:
public class ItemToolTip : MonoBehaviour
{
public Text itemNameText;
public Text itemInfoText;
RectTransform rectTransform;
private void Awake()
{
rectTransform = GetComponent<RectTransform>();
}
public void SetupTooltip(ItemData_SO item)
{
itemNameText.text = item.itemName;
itemInfoText.text = item.description;
}
void OnEnable()
{
//开始时会闪烁是因为没有定位好坐标,开始时先更新一下即可避免这种效果
UpdatePosition();
}
private void Update()
{
UpdatePosition();
}
public void UpdatePosition()
{
Vector3 mousePos = Input.mousePosition;
rectTransform.position = mousePos;
Vector3[] corners = new Vector3[4];
rectTransform.GetWorldCorners(corners);
float width = corners[3].x - corners[0].x;
float height = corners[1].y - corners[0].y;
if (mousePos.y < height)
rectTransform.position = mousePos + Vector3.up * height * 0.6f;
else if (Screen.width - mousePos.x > width)
rectTransform.position = mousePos + Vector3.right * width * 0.6f;
else
rectTransform.position = mousePos + Vector3.left * width * 0.6f;
}
}
还有个问题在于当你背包关闭时,信息仍然有显示,解决方法:
掉落物品
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LootSpawner : MonoBehaviour
{
[System.Serializable]
public class LootItem
{
public GameObject item;
[Range(0, 1)]
public float weight;
}
public LootItem[] lootItems;
public void Spawnloot()
{
float currentValue = Random.value;
for(int i = 0; i < lootItems.Length; i++)
{
if (currentValue <= lootItems[i].weight)
{
GameObject obj = Instantiate(lootItems[i].item);
obj.transform.position = transform.position + Vector3.up * 2;
}
}
}
}
给怪物添加以上代码
当敌人死亡时调用掉落:
这样即可实现掉落
完成背包
创建模板
保存加载数据:
开始时加载数据:
然后在inventory manager的inspector中修改:
如果我们需要在第二个场景中也使用背包系统,就将其作为预制体在第二个场景中载入:
并且记得添加eventSystem、
这样即可实现场景切换时保存的效果。
实现拖拽面板
给两个背包面板添加这个代码:
public class DragPanel : MonoBehaviour,IDragHandler
{
RectTransform rectTransform;
void Awake()
{
rectTransform = GetComponent<RectTransform>();
}
public void OnDrag(PointerEventData eventData)
{
rectTransform.anchoredPosition += eventData.delta;//让其锚点的位置的改变量和鼠标的改变量相同即可
}
}
即可实现拖拽。
但是有一点问题在于如果鼠标处于背包的边边部分进行拖拽时,此时面板的位移增量就比鼠标的位移增量要大了。
是因为面板中这个组件的存在:
方法:
但是移动背包时会被另外一个背包挡住:
观察可发现是因为顺序在下的被后渲染,后渲染的就会显示在前方
使用这个方法将其放在索引的最下方。
但是有一点,不能将其放在drag canvas索引的下方。要保证drag canvas始终在下方:
所以需要使用获取索引的方法。
将其索引设置在2即可。
这样就不会被遮挡。
但是此处又出现了一个新的问题,问题在于将物品拖拽放回原处的时候,背包里就看不见了。
解决方法在此处添加:
效果: