本节最终效果演示
文章目录
- 本节最终效果演示
- 系列目录
- 前言
- 库存系统
- 素材
- 绘制简单的库存UI
- 控制库存开关
- 实现物品拖拽功能
- 拾取物品
- 添加更多物品
- 源码
- 完结
系列目录
前言
欢迎来到【制作100个Unity游戏】系列!本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第23篇中,我们将探索如何制作一个类似于七日杀和森林的生存游戏。
本篇内容会比较多,我会分几篇来实现,感兴趣的可以关注一下,以免错过内容更新。
本节主要一个简单的库存系统,并完善之前的拾取功能。
库存系统
之前我们做过不少库存系统,这次就实现一个
简单的
,想要更复杂的可以看看我之前的文章:
【制作100个unity实战之3】从零手戳一个库存背包系统(附项目源码)
【Unity实战】最全面的库存系统(一)
【用unity实现100个游戏之13】复刻类泰瑞利亚生存建造游戏——包括建造系统和库存系统(附项目源码)
【制作100个unity实战之6】手戳一个库存系统,非常适合RPG、Roguelike和星露谷物语之类的游戏(附项目源码)
【unity实战】unity3D中的PRG库存系统和换装系统(附项目源码)
素材
https://assetstore.unity.com/packages/2d/gui/icons/gui-parts-159068
绘制简单的库存UI
控制库存开关
新增脚本InventorySystem,控制库存开关
public class InventorySystem : MonoBehaviour
{
public static InventorySystem Instance { get; set; }
// 引入UI界面对象
public GameObject inventoryScreenUl;
// 记录物品系统是否打开的状态
[HideInInspector]
public bool isOpen;
private void Awake()
{
if (Instance == null)
{
Instance = this;
}
else
{
Destroy(gameObject);
}
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Tab))
{
// 打开物品系统界面
inventoryScreenUl.SetActive(!isOpen);
isOpen = !isOpen;
// 设置鼠标锁定模式为无锁定,允许鼠标在界面上移动
Cursor.lockState = isOpen ? CursorLockMode.None : CursorLockMode.Locked;
}
}
}
挂载配置脚本参数
打开库存,我们不希望人物视角还可以移动
修改MouseLook
void FreeLook()
{
if(InventorySystem.Instance.isOpen) return;
//。。。
}
效果
实现物品拖拽功能
新增DragDrop,控制物品拖拽
public class DragDrop : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler
{
// [SerializeField] private Canvas canvas;
// 缓存RectTransform和CanvasGroup组件
private RectTransform rectTransform;
private CanvasGroup canvasGroup;
// 定义公共静态变量,用于记录当前被拖拽的物体
public static GameObject itemBeingDragged;
// 记录物体拖拽前的起始位置和父级对象
private Vector3 startPosition;
private Transform startParent;
private void Awake()
{
rectTransform = GetComponent<RectTransform>();
canvasGroup = GetComponent<CanvasGroup>();
}
public void OnBeginDrag(PointerEventData eventData)
{
Debug.Log("OnBeginDrag");
// 在物体开始被拖拽时,降低其不透明度来给用户反馈
canvasGroup.alpha = 0.6f;
// 防止射线检测到当前拖拽的物体,以避免与其他UI元素冲突
canvasGroup.blocksRaycasts = false;
// 记录物体拖拽前的起始位置和父级对象
startPosition = transform.position;
startParent = transform.parent;
// 将物体从原有的父级对象移动到画布下,以便它始终在可见范围内
transform.SetParent(transform.root);
// 记录当前被拖拽的物体
itemBeingDragged = gameObject;
}
public void OnDrag(PointerEventData eventData)
{
// 在物体被拖拽时,使其位置跟随鼠标移动
rectTransform.anchoredPosition += eventData.delta;
// 由于Canvas缩放会影响鼠标移动量,因此使用canvas.scaleFactor来保持一致性
// rectTransform.anchoredPosition += eventData.delta / canvas.scaleFactor;
}
public void OnEndDrag(PointerEventData eventData)
{
itemBeingDragged = null;
// 如果物体被拖拽到了根节点上
if (transform.parent == transform.root)
{
// 将物体放回起始位置,并将其父对象设置为起始父对象
transform.position = startPosition;
transform.SetParent(startParent);
}
Debug.Log("OnEndDrag");
// 恢复物体的不透明度和射线检测,使其可以再次被拖拽
canvasGroup.alpha = 1f;
canvasGroup.blocksRaycasts = true;
}
}
新增ItemSlot脚本,控制物品插槽
public class ItemSlot : MonoBehaviour, IDropHandler
{
// 定义公共属性Item,用于获取或设置当前物品槽中的物体
public GameObject Item
{
get
{
// 如果物品槽中已经有物体,则返回其子对象,即当前的物体
if (transform.childCount > 0)
{
return transform.GetChild(0).gameObject;
}
// 否则返回null
return null;
}
}
// 当拖拽物体被放置到当前物品槽时
public void OnDrop(PointerEventData eventData)
{
Debug.Log("OnDrop");
// 如果当前物品槽中没有物体,则将拖拽的物体设置为当前物品槽的子对象
if (!Item)
{
DragDrop.itemBeingDragged.transform.SetParent(transform);
// 设置拖拽物体的本地坐标为(0,0),即与物品槽重合
DragDrop.itemBeingDragged.transform.localPosition = new Vector2(0, 0);
}
}
}
挂载脚本,并配置参数
物品插槽记得添加CanvasGroup组件
效果
拾取物品
修改InventorySystem
public class InventorySystem : MonoBehaviour
{
public static InventorySystem Instance { get; set; }
// 引入UI界面对象
public GameObject inventoryScreenUl;
// 记录物品系统是否打开的状态
[HideInInspector]
public bool isOpen;
// [HideInInspector]
public List<GameObject> slotList = new List<GameObject>();
public List<string> itemList = new List<string>();
private GameObject itemToAdd;//物品插槽
private GameObject whatSlotToEquip;//空闲的槽位
private void Awake()
{
if (Instance == null)
{
Instance = this;
}
else
{
Destroy(gameObject);
}
}
private void Start()
{
PopulateSlotList();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Tab))
{
// 打开物品系统界面
inventoryScreenUl.SetActive(!isOpen);
isOpen = !isOpen;
// 设置鼠标锁定模式为无锁定,允许鼠标在界面上移动
Cursor.lockState = isOpen ? CursorLockMode.None : CursorLockMode.Locked;
}
}
//遍历获取所有的插槽
private void PopulateSlotList()
{
// 遍历物品系统界面下的所有子物体
foreach (Transform child in inventoryScreenUl.transform.GetChild(0).transform)
{
// 如果子对象的标签为"Slot"
if (child.CompareTag("Slot"))
{
// 将子对象添加到slotList列表中
slotList.Add(child.gameObject);
}
}
}
//添加物品
public void AddToInventory(string itemName)
{
// 找到下一个空闲的槽位
whatSlotToEquip = FindNextEmptySlot();
// 根据物品名称实例化一个新的物体,并设置其位置和旋转信息为whatSlotToEquip的位置和旋转信息
itemToAdd = Instantiate(Resources.Load<GameObject>(itemName), whatSlotToEquip.transform.position, whatSlotToEquip.transform.rotation);
// 将新实例化的物体的父对象设置为whatSlotToEquip
itemToAdd.transform.SetParent(whatSlotToEquip.transform);
// 将物品名称添加到itemList中
itemList.Add(itemName);
}
//找到空闲的槽位
private GameObject FindNextEmptySlot()
{
// 遍历slotList列表中的每个槽位对象
foreach (GameObject slot in slotList)
{
// 如果槽位对象没有子对象(即为空闲)
if (slot.transform.childCount == 0)
{
// 返回该槽位对象
return slot;
}
}
// 如果没有找到空闲的槽位,则返回一个新的空游戏对象
return new GameObject();
}
//判断库存是否已满
public bool CheckIfFull()
{
int counter = 0;
// 遍历slotList列表中的每个槽位对象
foreach (GameObject slot in slotList)
{
// 如果槽位对象有子对象(即已被占用)
if (slot.transform.childCount > 0)
{
counter++;
}
}
// 如果占用的槽位数等于21(满了),返回true,否则返回false
if (counter == 21)
{
return true;
}
else
{
return false;
}
}
}
修改InteractableObject,调用添加库存功能
//拾取物品
public void PickUp(){
if(!InventorySystem.Instance.CheckIfFull()){
InventorySystem.Instance.AddToInventory(ItemName);
Destroy(gameObject);
}else{
Debug.Log("库存已满");
}
}
把石头物品插槽样式放到Resources文件夹
效果
添加更多物品
比如我这里再加一些小树枝
https://sketchfab.com/3d-models/collection-of-forest-branches-11df981a8ff7441a9bdded31cc770e5f
效果
源码
源码不出意外的话我会放在最后一节
完结
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,以便我第一时间收到反馈,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~