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

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);
                    }
                }
            }
        }
    }
}

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

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

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

  • 26
    点赞
  • 150
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值