您现在的位置是:首页 >技术杂谈 >Unity MVC实现背包系统(2)网站首页技术杂谈

Unity MVC实现背包系统(2)

爱编程的鱼 2024-07-20 06:01:03
简介Unity MVC实现背包系统(2)

在上一篇中,我们写了背包系统的伪代码,也说了mvc的设计思路,那么这一篇的任务就是将伪代码补全。 

首先制作一个背包面板,我这里比较简单,就是一个滚动视图,还有一个提示文本,外加两个按钮,一个是使用物品,一个是增加物品,然后给滚动视图的Content添加上布局组件,这样当我们动态添加物品预制体的时候就会自动布局了。

这里我们将背包的mvc三层脚本都挂载在背包面板的根节点上,方便互相获取调用,因为我们本篇是针对背包的实现进行的,至于mvc这三层脚本如何获取调用,实际上是由UI框架去决定的,包括代码的周期等等,所以我们这里方便测试,直接挂载在面板根节点。

首先,我们的背包是用来存放物品的,因此必须有一个物品类,来体现这个物品所具有的属性。

public class Item
{
    public ulong onlyId;
    public int spriteId;
}
这里我只记录了onlyId和这个物品对应的图片id,首先onlyId这是一个物品的唯一标识,因为每个物品都是不同的,即使两个物品完全一样,那么他们也是独立出来的两个物品,结合实际就可以想象得知。而图片是为了等下演示方便大家可以看出来是不同物品,这里写的很简陋了,大家可以自行添加,这里只是讲解思路。

然后在看到数据层脚本。

public class BagData : MonoBehaviour
{
    BagCtrl ctrl;
    Dictionary items;  //存储背包中所有物品

    ulong onlyId;

    private void Awake()
    {
        onlyId = 0;
        ctrl = GetComponent();
        items = new Dictionary();

    }

    public void TestAddItem()
    {
        onlyId++;
        Item newItem = new Item();
        newItem.onlyId = onlyId;
        newItem.spriteId = Random.Range(1, 6);
        items.Add(newItem.onlyId, newItem);

    }

    public Item[] GetItems()
    {
        if (items.Count == 0)
            return null;
        Item[] temp = new Item[items.Count];
        items.Values.CopyTo(temp, 0);
        //返回背包中所有物品
        return temp;
    }

    public void AddItem()
    {
        //增加物品
    }

    public void DelItem(ulong onlyId)
    {
        if (items.ContainsKey(onlyId))
            items.Remove(onlyId);
        //删除物品
    }

    public void UpdateItem()
    {
        //更新物品
    }

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }
}
首先获取逻辑层的引用,然后是实例化我们的物品字典,根据物品的唯一标识来存储物品信息,然后还写了一个测试添加物品的方法,因为我们游戏当中物品来源有很多种,比如打怪掉落,或者是商城购买等等,我们这里就直接给一个按钮去调用这个方法,然后每次新增物品onlyId都去自增,保证onlyId不重复,然后随机给一张图片,从1-6,因为我只放了五张图片资源。这个方法也很简单了,new一个物品对象然后存储在字典中。

还有删除方法,根据外部传进来的onlyId删除物品,还有一个获取背包当前所有物品的方法,也是很简单,直接返回字典中的所有物品信息。

接着看到逻辑层。

public class BagCtrl : MonoBehaviour
{
    BagView view;
    BagData data;

    private void Awake()
    {
        view = GetComponent();
        data = GetComponent();
    }

    public Item[] GetItems()
    {
        if (data.GetItems() == null)
            return null;
        return data.GetItems();
    }

    public void AddItem()
    {
        data.AddItem();
        view.UpdateView();
    }

    public void Add()
    {
        data.TestAddItem();
        view.UpdateView();
    }

    public void UpdateItem()
    {
        data.UpdateItem();
    }

    public void UseItem(ulong id)
    {
        //使用物品使用效果

        //删除该物品或减少该物品数量
        data.DelItem(id);
        view.UpdateView();
    }

    public void Discard(ulong id)
    {
        //删除该物品或减少该物品数量
        data.DelItem(id);
        view.UpdateView();
    }

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {

    }
}
在上一篇我们已经说了,逻辑层是视图层以及数据层的中介,所以要先获取这两者的引用。然后向外提供一个获取所有物品的方法,目的是让视图层获取数据层的物品信息,还有添加物品方法。使用物品丢弃物品,这里我们直接将物品给删了,物品的效果,这个大家自行扩展了,比如你打开的是一个礼包,那么就是调用数据层的添加物品方法,然后再把这个礼包给删了,实际上都是一些简单逻辑。处理完数据,在调用视图层的UpdateView方法,也就是刷新视图层的显示,因为物品已经改变了,这里实际上最好应该先判断一下,如果背包面板没有打开的话,是不需要去刷新的。

最后看到视图层,

public class BagView : MonoBehaviour
{

    BagCtrl ctrl;
    public Button btn_use;
    public Button btn_add;
    public Text txt_tips;
    public Transform img_content;

    ulong current_onlyId;

    List items;

    private void Awake()
    {
        ctrl = GetComponent();
        items = new List();
    }

    // Start is called before the first frame update
    void Start()
    {
        current_onlyId = 0;
        btn_use.onClick.AddListener(() =>
        {
            if (current_onlyId == 0)
                return;
            ctrl.UseItem(current_onlyId);
            current_onlyId = 0;
        });
        btn_add.onClick.AddListener(() =>
        {
            ctrl.Add();
            current_onlyId = 0;
        });

        UpdateView();

    }

    public void UpdateView()
    {
        txt_tips.text = "当前没有选中的物品";
        if(items.Count > 0)
        {
            for(int i = 0; i < items.Count; i++)
            {
                Destroy(items[i]);
            }
        }
        items.Clear();

        if (ctrl.GetItems() == null)
            return;

        Item[] newItems = ctrl.GetItems();
        GameObject itemRes = Resources.Load("Prefab/Item");
        for(int i = 0; i < newItems.Length; i++)
        {
            GameObject newItem = Instantiate(itemRes);
            newItem.transform.SetParent(img_content);
            items.Add(newItem);
            Sprite spr = Resources.Load("Sprite/" + newItems[i].spriteId);
            Image img = newItem.transform.GetChild(0).GetComponent();
            img.sprite = spr;
            ulong temp = newItems[i].onlyId;
            newItem.GetComponent().onClick.AddListener(() =>
            {
                current_onlyId = temp;
                txt_tips.text = "当前选中的物品的onlyId是:" + temp;
            });
        }

    }

    // Update is called once per frame
    void Update()
    {

    }
}
最上面的几个参数,currentOnlyId,这个是用来记录当前玩家选中的物品的,还有一个items列表,是用来保存当前背包面板下的所有物品游戏对象的也就是GameObject类型的。一开始先将currentOnlyId归零,获取逻辑层的引用。给两个按钮添加监听,当按下使用按钮,则调用逻辑层的使用物品按钮,将当前选中的物品的onlyId传进去,添加物品就直接调用逻辑层的使用物品方法即可,最后调用一下刷新方法。

刷新方法,首先把提示信息重置一下,当前没有选择任何物品,然后将items列表中的所有游戏对象销毁掉,也就是清空操作,然后再从逻辑层获取现有的所有物品重新进行生成,就是获取物品预制体,然后实例化,根据物品信息的图片给物品修改图片,将物品存进items列表,挂载再content物品下自动布局。最后给物品添加监听,当按下物品时修改提示文案和cuurentOnlyId。这样就是一次刷新操作了。

大家可以可以复制代码自行测试下效果,工程我会放在qq群上,大家也可以加群获取。

最后补充一下,本文章讲的是一个mvc实现背包的一个设计思路,比如说上面的销毁,实际上可以放在对象池,等等的一些优化操作,这个视项目而定,因为本文章面向的是还无法自己完成背包系统的同学,所以会尽可能的只针对背包来讲,希望本文章对大家有所帮助。

 

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。