Unity3D:简易背包(自用)

引言:

        这个背包的实现是参照另外一位博主的代码然后修改之后的,因为我觉得那位博主的代码效率实在太低,并且难以拓展托拽的功能,所以我对博主的代码稍微做了调整,但是大致思路都是一样的.

        还有就是这个是基于ScriptObject实现的数据存储

实现思路:

        

代码实现流程:

这个是canvas的结构,这里的mainbag需要调整一下布局,才能达到游戏中的自动格式化填充,感觉和前端一样还是比较简单的。

关于item的代码

        这里我创建了一个脚本来区分每一个物体,并且将其做成预制体方便动态创建
 

public class ClassItem : MonoBehaviour
{
    public Image img;
    public Text text;

}

关于数据库的代码创建

        这里我用的是ScriptObject来创建相应的物体数据库

         

[CreateAssetMenu(fileName ="CubeDataSet",menuName ="Items/Cube",order = 0)]
public class ItemScriptObj : ScriptableObject
{
    public string Name;
    public Sprite sprite;
    public int num;
    [TextArea]
    public string info;
}

关于mainBag的代码

        既然有了物品,那就必须要有管理这些,或者说罗列这些物品的代码,所以说我们就只需要让背包知道自己有哪些类,然后去相应的类数据库中寻找就可以了

        所以代码也是很简洁

        

public class MainBag : MonoBehaviour
{
    public List<ItemScriptObj> ItemList;
}

关于实际道具的代码

        既然背包装的是一类物品,那么每一个物品都有的属性就是自己属于哪一类,所以每一个物品的脚本必须有一个数据库对象

        

public class CubeControl : MonoBehaviour
{
    public ItemScriptObj SelfType;
    public MainBag mainbag;

    public void OnCollisionEnter(Collision collision)
    {
        if(collision.transform.name == "Capsule")//这个capsule是玩家的名字,后期可以改成tag判断
        {
            SelfType.num++;
           if(!mainbag.ItemList.Contains(SelfType))
            {
                mainbag.ItemList.Add(SelfType);
                BagMannager.InsertIntoUi(SelfType);
            }
            BagMannager.UpdateUi(SelfType);
           Destroy(gameObject);
        }
    }

}

这样就将物品和他们对应的数据库对应起来了

关于Bagmannager的代码实现

        这里用的是一个单例模式,主要功能就是插入和更新数据,刚好和上面的实际道具代码耦合

public class BagMannager : MonoBehaviour
{
    public static BagMannager instance;
    public ClassItem itemClass;
    public MainBag bag;
    public GameObject mainBag;

    private void Awake()
    {
        if(instance == null)
            instance = this;
        else
            Destroy(gameObject);
    }

    private void Start()
    {
    }
    public static void InsertIntoUi(ItemScriptObj item)
    {
       ClassItem temp =  Instantiate(instance.itemClass, instance.bag.transform);
        temp.img.sprite = item.sprite;
        temp.text.text = item.num.ToString();
    }

    public static void UpdateUi(ItemScriptObj item)
    {
        for (int i = 0; i < instance.mainBag.transform.childCount; i++)
        {
            ClassItem temp = instance.mainBag.transform.GetChild(i).GetComponent<ClassItem>();
            if(temp.img.sprite == item.sprite)
            {
                temp.text.text = item.num.ToString() ;
            }
            break;
        }
    }


}

玩家控制代码

         这个就是实现了背包的开和闭,以及简单的移动

        

public class PlayerController : MonoBehaviour
{
    private Rigidbody rigid;
    private float VerticalInput;
    private float HorizontalInput;
    public float moveSpeed = 5f;


    public GameObject MainBag;
    public GameObject Background;
    // Start is called before the first frame update
    void Start()
    {
        rigid = GetComponent<Rigidbody>();
    }

    // Update is called once per frame
    void Update()
    {
        VerticalInput = Input.GetAxis("Vertical");
        HorizontalInput = Input.GetAxis("Horizontal");
        rigid.velocity = transform.forward * VerticalInput*moveSpeed + transform.right*HorizontalInput*moveSpeed;
        
        if(Input.GetKey(KeyCode.Tab))
        {
            MainBag.SetActive(true);
            Background.SetActive(true);
        }
        else
        {
            MainBag.SetActive(false);
            Background.SetActive(false);
        }
    }
}

物品的托拽并且交换功能的实现

        首先介绍两个东西,一个就是 EventSystem,这个是unity自带的事件监听器,可以响应鼠标点击,鼠标移动等等事件,但是要响应就必须实现响应的接口,IBeginDragHandler, IDragHandler, IEndDragHandler
        第二个就是 GraphicRaycaster用于UI的射线检测,一般是画布自带的

public class DragItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    private Vector2 vector;
    private RectTransform rectTransform;
    private EventSystem eventSystem;
    private GraphicRaycaster gra;

    private void Start()
    {
        eventSystem = EventSystem.current;
        gra = FindObjectOfType<GraphicRaycaster>();
        rectTransform = GetComponent<RectTransform>();
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        vector = transform.position;
    }

    public void OnDrag(PointerEventData eventData)
    {
        Vector3 pos;
        RectTransformUtility.ScreenPointToWorldPointInRectangle(rectTransform, eventData.position, eventData.enterEventCamera, out pos);
        rectTransform.position = pos;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        //表示是否有检测到物体
        List<GameObject> ITM = new List<GameObject>();
        List<RaycastResult> results =GetHitItems(Input.mousePosition);
        foreach(var item in  results)
        {
            if(item.gameObject.tag == "Item")
            {
               ITM.Add(item.gameObject);
            }
        }
        if(ITM.Count > 1) 
        {
            int index1 = ITM[0].transform.GetSiblingIndex();
            int index2 = ITM[1].transform.GetSiblingIndex();
            ITM[0].transform.SetSiblingIndex(index2);
            ITM[1].transform.SetSiblingIndex(index1);
        }
        else
        {
            transform.position = vector;
        }

        

    }

    public List<RaycastResult> GetHitItems(Vector2 pos)
    {
        List<RaycastResult> temp = new List<RaycastResult>();
        PointerEventData pd = new PointerEventData(eventSystem);
        pd.position = pos;
        gra.Raycast(pd, temp);
        return temp;
    }


}

实现思路就是

鼠标点击事件的开始保存了当前物体的世界坐标

当托拽事件发生的时候将鼠标的坐标以现有的recttransform为模板,转换到 世界坐标,这样就可以实现跟随移动了,最后通过射线判断是否有两个物体,如果有就交换顺序,从而实现物品的交换

 

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值