Unity 3D 实现拾取物品功能(一)

    xiaoxiao2021-03-25  151

    Unity 3D 实现拾取物品功能(一)


    刚刚接触Unity不久,为了记录自己学习的过程。我决定写写博客,哈哈哈。 在网上看了一些拾取物品的实现原理之后,自己摸索了一下,写了个小Demo,下面来介绍一下基本功能。 1)人物靠近物体,且视角朝向物体,改变物体颜色。 2)按E键拾取物品到背包,并销毁游戏对象。 3)按B键在背包中显示已有物品。 一般背包设定分为格子上限和负重上限两种,在这个Demo里我们使用格子上限的模式。且物品分为可叠加和不可叠加两种。

    首先,来预览一下成果。 在游戏场景中建立这么一些游戏对象,来模拟游戏里的真实物品。

    然后我们操作角色,移动到物体前。然后镜头指向游戏想,把默认颜色修改为红色。

    一般游戏都使用E键拾取物品,我也使用E键拾取。拾取成功后,我们就使用Destroy()函数,销毁游戏对象。从而达到物品被加入背包的感觉。 我们把ObjectItem挂到物体上,然后设置属性。 方块1数量为685,可叠加,最大叠加数量为1000。 方块2数量为888,可叠加,最大叠加数量为1000。 相同物品的判断使用ObjId字段,所以同类物品就设置ObjId一致就可以了。

    拾取以上两个方块后,按下B键,调用显示物品的函数,暂时显示到Debug控制台中。在后续的博客中再继续完善。 我们就可以看到,物品栏就有了两条记录。

    然后设置两个圆柱个数都为1,且不可叠加。拾取后按B键,查看控制台 就可以看到柱子的数量分别存在的单独的格子。

    把背包和物品属性抽象,形成两个类。Pack.cs和ObjectItem.cs

    Pack.cs代码如下:

    using UnityEngine; using System.Collections; using System.Collections.Generic; public class Pack : MonoBehaviour { //保存物品的List数组 public List<ItemEntity> items = null; //背包最大容量 public int maxItem = 32; // Use this for initialization void Start () { items = new List<ItemEntity>(); } //拾取物品 public ObjectItem getItem(ObjectItem item) { //使用中间过渡的实体类 ItemEntity itemEntity = ItemEntity.FillData(item); //如果物品不可合并 if (!itemEntity.IsCanAdd) { //背包有空余 if(items.Count < maxItem) { //获得物品 items.Add(itemEntity); item.count = 0; } else { //拾取失败 } } else { //空背包时,直接添加 if (items.Count < 1) { items.Add(itemEntity); item.count = 0; } else { //判断当前背包合并物品 foreach (ItemEntity currItem in items) { //相同物品,且可叠加,且分组未满 if (currItem.ObjId.Equals(itemEntity.ObjId) && currItem.Count < currItem.MaxAdd) { //数量叠加 currItem.Count = currItem.Count + itemEntity.Count; //如果超出叠加范围 if (currItem.Count - currItem.MaxAdd > 0) { //拾取物品的剩余数量变更 item.count = currItem.Count - currItem.MaxAdd; itemEntity.Count = item.count; //背包里的数量为最大值 currItem.Count = currItem.MaxAdd; } else { // 未超出叠加最大值,拾取成功 item.count = 0; } } else { //如果物品不是同类,或分组是满的,遍历下一个格子 continue; } } //物品超出分组,有剩余格子则添加。否则剩余部分无法拾取 if(item.count > 0 && items.Count < maxItem) { items.Add(itemEntity); item.count = 0; } } } return item; } //显示物品 public void showPack() { string show = "物品:\n"; int i = 0; foreach (ItemEntity currItem in items) { show += ++i + " [" + currItem.ObjName + "], 数量: " + currItem.Count + "\n"; } Debug.Log(show); } }

    ObjectItem代码如下

    using UnityEngine; using System.Collections; public class ObjectItem : MonoBehaviour { public string objId; public string objName; public int count; public string note; public int level; public bool isCanAdd; public int maxAdd; public bool isChecked; // Use this for initialization void Start () { isChecked = false; } // Update is called once per frame void Update () { if (isChecked) { GetComponent<MeshRenderer>().material.color = Color.red; } else { GetComponent<MeshRenderer>().material.color = Color.white; } isChecked = false; } }

    在使用过程中,使用List保存物品时,调用Destroy()函数后,List里面的对象也会被删除掉。 所以,我们在代码中使用一个中间类ItemEntity.cs,代码如下:

    public class ItemEntity { private string objId; private string objName; private int count; private string note; private int level; private bool isCanAdd; private int maxAdd; private bool isChecked; public static ItemEntity FillData(ObjectItem item) { ItemEntity itemEntity = new ItemEntity(); itemEntity.ObjId = item.objId; itemEntity.ObjName = item.objName; itemEntity.Count = item.count; itemEntity.Note = item.note; itemEntity.Level = item.level; itemEntity.IsCanAdd = item.isCanAdd; itemEntity.MaxAdd = item.maxAdd; itemEntity.IsChecked = item.isChecked; return itemEntity; } public string ObjId { get { return objId; } set { objId = value; } } public string ObjName { get { return objName; } set { objName = value; } } public int Count { get { return count; } set { count = value; } } public string Note { get { return note; } set { note = value; } } public int Level { get { return level; } set { level = value; } } public bool IsCanAdd { get { return isCanAdd; } set { isCanAdd = value; } } public int MaxAdd { get { return maxAdd; } set { maxAdd = value; } } public bool IsChecked { get { return isChecked; } set { isChecked = value; } } }

    最后,我们在玩家控制的角色上使用代码:

    using UnityEngine; using System.Collections; public class PlayerController : MonoBehaviour { private Transform tr; //背包类 private Pack pack; // Use this for initialization void Start () { tr = GetComponent<Transform>(); pack = GetComponent<Pack>(); } // Update is called once per frame void Update () { if (Input.GetKeyDown(KeyCode.B)) { pack.showPack(); } Debug.DrawRay(tr.position, tr.forward * 2.0f, Color.green); RaycastHit hit; if (Physics.Raycast (tr.position, tr.forward, out hit, 2.0f)) { //Debug.Log ("射线击中:" + hit.collider.gameObject.name + "\n tag:" + hit.collider.tag); GameObject gameObj = hit.collider.gameObject; ObjectItem obj = (ObjectItem)gameObj.GetComponent<ObjectItem>(); if (obj != null) { obj.isChecked = true; //Debug.Log(obj.objName); if (Input.GetKeyDown(KeyCode.E)) { obj = pack.getItem(obj); if(obj.count == 0) { //gameObj.SetActive(false); Destroy(gameObj); } } } } } }

    这样,我们就可以实现了拾取物品的基本功能。 当拾取超过了背包容量时,可以重叠的物品会叠加至最大数量,然后剩余数量依然存在于场景中。相当于只拾取了一部分。

    代码还有很多没有使用到的属性,也是临时的一些想法,方便后续拓展。 代码变量的命名规范及代码流程还可以有更多的优化。有大牛可以给我指点指点 >.<

    以上就是我摸索出来的拾取物品的一个大概模型。不知道你们是怎么实现的呢!

    转载请注明原文地址: https://ju.6miu.com/read-17388.html

    最新回复(0)