首页 > 其他分享 >Unity游戏框架设计之背包管理器

Unity游戏框架设计之背包管理器

时间:2024-05-01 23:33:05浏览次数:18  
标签:背包 return int SlotSet Unity backpackMetadataSet 管理器 backpackName public

Unity游戏框架设计之背包管理器

简单介绍

背包系统通常分为两个部分,第一个部分是背包的 UI 界面,第二个部分是对背包进行逻辑操作的管理器。

在下述代码中,实现了对背包的基本逻辑操作,包括向背包添加物品,从背包中取出物品,移动背包中的物品和使用背包中的物品的基本操作,并将这些操作封装为背包管理器。

为实现完整的背包系统,我们需要背包 UI 资源,并基于 MVC 模式编写背包 UI 的脚本,并配合背包管理器进行实现。

代码设计

public class BackpackManager : SingletonMono<BackpackManager>
{
    private Dictionary<string, BackpackMetadata> _backpackMetadataSet;

    protected override void Awake()
    {
        base.Awake();
        _backpackMetadataSet = new Dictionary<string, BackpackMetadata>();
    }

    public void CreateBackpack(string backpackName, int height, int width)
    {
        if (!_backpackMetadataSet.TryAdd(backpackName, new BackpackMetadata(backpackName, height, width)))
        {
            return;
        }
    }

    public void RemoveBackpack(string backpackName)
    {
        if (!_backpackMetadataSet.ContainsKey(backpackName))
        {
            return;
        }
        _backpackMetadataSet.Remove(backpackName);
    }

    public (BackpackSlotMetadata metadata, int slotX, int slotY) AddItem(string backpackName, string itemID)
    {
        if (!_backpackMetadataSet.ContainsKey(backpackName))
        {
            return default;
        }
        BackpackMetadata backpackMetadata = _backpackMetadataSet[backpackName];
        (int putSlotX, int putSlotY) = backpackMetadata.AddItem(itemID);
        if (putSlotX == -1 || putSlotY == -1)
        {
            return (null, -1, -1);
        }
        return (backpackMetadata.FindItem(putSlotX, putSlotY), putSlotX, putSlotY);
    }

    public BackpackSlotMetadata TakeItem(string backpackName, int x, int y)
    {
        if (!_backpackMetadataSet.ContainsKey(backpackName))
        {
            return default;
        }
        return _backpackMetadataSet[backpackName].TakeItem(x, y);
    }

    public (BackpackSlotMetadata from, BackpackSlotMetadata to) MoveItem(string backpackName, int fromX, int fromY, int toX, int toY)
    {
        if (!_backpackMetadataSet.ContainsKey(backpackName))
        {
            return default;
        }
        return _backpackMetadataSet[backpackName].MoveItem(fromX, fromY, toX, toY);
    }

    public BackpackSlotMetadata UseItem<T>(string backpackName, int x, int y, T target, bool consume = true) where T : Component
    {
        if (!_backpackMetadataSet.ContainsKey(backpackName))
        {
            return default;
        }
        BackpackMetadata backpackMetadata = _backpackMetadataSet[backpackName];
        BackpackSlotMetadata slotMetadata = backpackMetadata.FindItem(x, y);
        if (ItemManager.Instance.UseItem(slotMetadata.ItemID, target))
        {
            if (consume)
            {
                return backpackMetadata.TakeItem(x, y);
            }
            else
            {
                return slotMetadata;
            }
        }
        return default;
    }

    public bool IsExistsItem(string backpackName, int x, int y)
    {
        if (!_backpackMetadataSet.ContainsKey(backpackName))
        {
            return default;
        }
        return _backpackMetadataSet[backpackName].SlotSet[x][y] != null;
    }

    public List<List<BackpackSlotMetadata>> GetBackpackItemSet(string backpackName)
    {
        if (!_backpackMetadataSet.ContainsKey(backpackName))
        {
            return default;
        }
        return _backpackMetadataSet[backpackName].SlotSet;
    }

    private class BackpackMetadata
    {
        public readonly string BackpackName;
        public readonly int Height;
        public readonly int Width;
        public readonly List<List<BackpackSlotMetadata>> SlotSet;

        public BackpackMetadata(string backpackName, int height, int width)
        {
            BackpackName = backpackName;
            Height = height;
            Width = width;
            SlotSet = new List<List<BackpackSlotMetadata>>(Height);
            for (int i = 0; i < Height; i++)
            {
                SlotSet.Add(new List<BackpackSlotMetadata>(Width));
                for (int j = 0; j < Width; j++)
                {
                    SlotSet[i].Add(null);
                }
            }
        }

        public (int, int) AddItem(string itemID)
        {
            (int sameItemSlotX, int sameItemSlotY) = FindSameItemSlotCoordinate(itemID);
            if (sameItemSlotX != -1 && sameItemSlotY != -1)
            {
                SlotSet[sameItemSlotX][sameItemSlotY].Quantity++;
                return (sameItemSlotX, sameItemSlotY);
            }
            (int emptySlotX, int emptySlotY) = FindNextEmptySlotCoordinate();
            if (emptySlotX == -1 || emptySlotY == -1)
            {
                return (-1, -1);
            }
            ItemMetadata itemMetadata = ItemManager.Instance.FindItemMetadataByItemID(itemID);
            SlotSet[emptySlotX][emptySlotY] = new BackpackSlotMetadata(itemID, itemMetadata.IconItemAssetPath, 1);
            return (emptySlotX, emptySlotY);
        }

        public (BackpackSlotMetadata from, BackpackSlotMetadata to) MoveItem(int fromX, int fromY, int toX, int toY)
        {
            BackpackSlotMetadata fromSlotMetadata = SlotSet[fromX][fromY];
            BackpackSlotMetadata toSlotMetadata = SlotSet[toX][toY];
            if (fromSlotMetadata != null && toSlotMetadata != null && fromSlotMetadata.ItemID.Equals(toSlotMetadata.ItemID))
            {
                ItemMetadata itemMetadata = ItemManager.Instance.FindItemMetadataByItemID(fromSlotMetadata.ItemID);
                int itemMaxStackQuantity = itemMetadata.MaxStackQuantity;
                if (itemMaxStackQuantity - toSlotMetadata.Quantity >= fromSlotMetadata.Quantity)
                {
                    SlotSet[toX][toY].Quantity += fromSlotMetadata.Quantity;
                    SlotSet[fromX][fromY] = null;
                }
                else
                {
                    int moveQuantity = itemMaxStackQuantity - toSlotMetadata.Quantity;
                    SlotSet[toX][toY].Quantity += moveQuantity;
                    SlotSet[fromX][fromY].Quantity -= moveQuantity;
                }
                return (SlotSet[fromX][fromY], SlotSet[toX][toY]);
            }
            (SlotSet[fromX][fromY], SlotSet[toX][toY]) = (SlotSet[toX][toY], SlotSet[fromX][fromY]);
            return (SlotSet[fromX][fromY], SlotSet[toX][toY]);
        }

        public BackpackSlotMetadata TakeItem(int x, int y)
        {
            BackpackSlotMetadata backpackSlotMetadata = SlotSet[x][y];
            if (backpackSlotMetadata == null)
            {
                return default;
            }
            backpackSlotMetadata.Quantity--;
            if (backpackSlotMetadata.Quantity <= 0)
            {
                SlotSet[x][y] = null;
                backpackSlotMetadata.Quantity = 0;
            }
            return backpackSlotMetadata;
        }

        public BackpackSlotMetadata FindItem(int x, int y)
        {
            if (SlotSet[x][y] == null)
            {
                return default;
            }
            return SlotSet[x][y];
        }

        private (int, int) FindSameItemSlotCoordinate(string itemID)
        {
            int maxStackQuantity = ItemManager.Instance.FindItemMetadataByItemID(itemID).MaxStackQuantity;
            for (int i = 0; i < Height; i++)
            {
                for (int j = 0; j < Width; j++)
                {
                    BackpackSlotMetadata backpackSlotMetadata = SlotSet[i][j];
                    if (backpackSlotMetadata == null)
                    {
                        continue;
                    }
                    string slotItemID = backpackSlotMetadata.ItemID;
                    if (itemID.Equals(slotItemID) && backpackSlotMetadata.Quantity < maxStackQuantity)
                    {
                        return (i, j);
                    }
                }
            }
            return (-1, -1);
        }

        private (int, int) FindNextEmptySlotCoordinate()
        {
            for (int i = 0; i < Height; i++)
            {
                for (int j = 0; j < Width; j++)
                {
                    BackpackSlotMetadata backpackSlotMetadata = SlotSet[i][j];
                    if (backpackSlotMetadata == null)
                    {
                        return (i, j);
                    }
                }
            }
            return (-1, -1);
        }
    }
}

代码说明

(一)实现创建背包、删除背包的功能。

(二)实现向背包添加物品、取出物品、移动物品和使用物品的功能。

后记

由于个人能力有限,文中不免存在疏漏之处,恳求大家斧正,一起交流,共同进步。

标签:背包,return,int,SlotSet,Unity,backpackMetadataSet,管理器,backpackName,public
From: https://www.cnblogs.com/kkelin/p/18169813

相关文章

  • Unity游戏框架设计之存档管理器
    Unity游戏框架设计之存档管理器存档管理器的主要功能是实现游戏进度的查询、存储(存档)、读取(读档)和删除(删档)。存档主要有三种实现方案。(一)PlayerPrefs。PlayerPrefs类用于在游戏中存储、删除、修改和访问玩家的数据。存储的数据是持久化的,即使玩家关闭游戏或重新启动设备,数据也......
  • Unity2D横版游戏之平台跳跃效果
    Unity2D横版游戏之平台跳跃效果简单介绍平台跳跃效果。玩家允许在平台下方跳跃到平台上方,并且可以在平台上方站立,同时玩家在平台上方允许通过下跳操作到达平台下方。实现步骤(一)将玩家的图片设置为Player、将平台的图层设置为Platform。(二)为平台游戏对象创建XXXCollider2D......
  • Unity2D横板游戏之背景视差与无限滚动效果
    Unity2D横板游戏之背景视差与无限滚动效果简单介绍背景视差效果。在2D横板游戏中,由若干个背景图片构成的背景,在背景移动的过程中,每一个背景图片的移动速度均不同,靠近玩家的背景图片移动速度快,而远离玩家的背景图片移动速度慢,从而形成背景的视差效果,使背景更加立体且富有层级。......
  • Unity游戏框架设计之UI管理器
    Unity游戏框架设计之UI管理器简单介绍在游戏开发过程中,我们通常需要管理UI游戏对象的加载、打开和销毁等操作,同时也需要管理游戏数据和游戏数据在UI上的显示,因此我们需要一个UI管理器来统一实现上述基础功能。我们可以基于MVC模式编写UI管理器,此时UI管理器将分为模......
  • Unity游戏框架设计之缓存池管理器
    Unity游戏框架设计之缓存池管理器简单介绍在游戏运行的过程中,我们可能遇到这样的需求,即创建大量相同类型的敌人。在传统方法中,我们将对每一个敌人都重新创建,但这样是效率低且占据内存的。为此我们可以这样做,所有敌人在创建时,都从敌人缓存池中取出敌人对象,当敌人死亡时,则将敌人......
  • 树上背包
    简介树上背包,顾名思义,就是在树上做背包。比如这道题:收费有线电视网计划转播一场重要的足球比赛。他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点。从转播站到转播站以及从转播站到所有用户终端的信号......
  • 密码管理器---KaPass v1.0.3
    伴随的网龄的增加,密码也随之增加,简单的密又怕不安全,复杂的密码怕记不住。就是在这样的情况下,KaPass密码管理器应运而生。一个密码管理器---KaPass,简洁的界面,功能齐全,一起了解一下KaPass: 1、登陆窗口2、主界面3、新增群组,可自定义群组图标4、新增密码,可以储存各式各样......
  • Unity游戏框架设计之音频管理器
    Unity游戏框架设计之音频管理器简单介绍在游戏中,主要的音频分为两种类型。第一种类型是BGM(背景音乐),第二种类型是音效。BGM的特点是音频持续时间长,一般在游戏中的同一时间内只能播放一个BGM。音效的特点是音频持续时间短,一般在游戏中的同一时间内允许同时播放多个音效。在下......
  • Unity性能分析(一)流程与工具的使用
    性能分析工作流对于游戏开发是“必备”的,从基本的三方面开始:在修改之前分析:建立基准线在开发过程中分析:确保修改不会影响性能在修改后分析:证明修改产生了预期效果分析工具是开发者的实用工具之一,可以帮助开发者定位代码中的内存问题和性能瓶颈,也能帮助了解Unity引擎底层的运......
  • Unity性能分析(二)CPU/GPU分析
    设置每帧时间预算帧率(fps)并不是衡量游戏稳定体验的理想指标。考虑以下情况:在运行时的前0.75s内渲染了59帧。然后接下来的1帧需要0.25s才能渲染完毕。虽然是60fps,但实际上会让玩家感觉卡顿。这是需要设置帧时间预算的重要原因之一。这为您提供了一个目标,在对游戏进行分析和优化时......