Unity物品系统设计与实现——3.物品栏设计与物品管理

前面我们设计的物品栏和物品引用信息,其中,利用物品引用信息,也即物品条目,我们可以建立物品栏。物品栏不仅包括玩家的背包,还包括了各种箱子、储具、生产设施等一切存储物品条目(而非实体)的实体

然而,物品栏不是物品条目的简单堆砌,它还需要包括:

 1.物品顺序信息,对于有些游戏,物品的排列可以是不连续的,如《minecraft》和《饥荒》,这些项目允许不同物品栏中间出现空位;而像《上古卷轴》等游戏的物品栏中是不允许出现空位的,也就数说,每次物品条目发生改变,物品栏内部就需要重新填补空缺;对于一些更复杂的系统,出于UI的美观或者资源管理玩法上的调整,物品可能还会占用不同的二维格子,例如《Kenshi》以及《巫师3》。对于第一种来说对玩家体验要提起重视;第二种当物品栏中条目过多时,由于涉及UI刷新、数组长度变更等可能影响性能的操作会比较需要考虑;并且这类游戏往往只针对物品的重量,而不是物品所占空间进行一维的限制,容易造成玩家出现“屯屯鼠综合征”;第三种则可能会造成UI杂乱、存储算法复杂,以及需要使用动态规划算法进行物品栏整理。这里我们着重考虑第二种

2.特殊的物品位置:例如,玩家装备的物品;生产设备的输入以及输出,这些位置只能存放个别物品,对于物品的存储和取出也有要求。《上古卷轴》等游戏中,“装备物品”这一动作是改变了特定的物品ID,例如装备了第9号槽位的斧头,换成装备第3号位的剑;这一装备过程中,物品的排列信息没有改变;有些例如《巫师3》,它的装备操作是将物品栏中的物品与特定槽位的物品进行了交换;有些是不同场合使用不同方式,例如《minecraft》中的工具和盔甲,还有些是一种“先选,后换”的混合式物品栏,例如《艾尔登法环》中的武器魔法的选择

2.1.快捷栏:游戏过程中,为了快速地使用药水等物品,我们会需要把物品放进一些比较显眼的、数量相对有限的栏位中;在有些游戏中,这些栏位中的物品不能随意更换(如黑魂中的魔法)。快捷栏的实现接近一般武器装备的实现

3.物品的综合信息:物品的总重量,占用空间等限制会改变玩家对道具取舍的策略;当涉及的物品项目过多时,如果我们能事先获知某些(类,个)物品存在与否、数量多少(例如剩余食物的量,是否存在远程武器等),并动态地修改和提供这些数据,不仅可以给玩家形成便利,也可以给AI管理的过程中提高性能

4.物品整理算法:将物品按照一定原则,例如无空位、价格优先等原则,整理成新的物品栏顺序;对于某些游戏,这些算法应当是在获得或损失物品的同时自动运行的。

5.物品获得、损失时的以及例外情况:当获得物品时,如何添加物品,是否需要重新排列;当获得物品时,背包空间不够时,如何处理;如何从背包中移除物品;如何检测物品是否损耗完毕;当物品栏发生改变时,如何通知AI重新装备物品;这些都是我们需要考虑的内容。

public class BasicStorage:monobehevior
{
    //之所以继承了mono,是因为如果考虑到实现物品腐烂等功能实现时,需要mono来实现计时
    public visual ItemSlot[] AllItem{get;}//所有物品
    public visual ItemSlot[] Items;//普通的物品;
    
    public int itemCount = 0//物品的数量

    //一些可选的功能
    //public float rotRate//腐烂速率,用于冰箱等效果
    ......

    public void TryRemoveItem(int id)
    {
        //失去物品
        //此物品栏设计不允许出现空位,在每个物品进入和移除时进行判断和重排
        //这里只需要将移除槽位的物品依次
        items[id] = null;
        
        for(int i=id;i<itemCount;i++)
        {
            items[id].itemRef == items[id + 1].itemRef;//上提
        }
        items[id + 1] = null;//将最后一个物品栏清除
        itemCount  -=1;
    }
    public bool TryAddItem(ItemRef itemRef)
    {
        bool canAdd = itemSlot[slotID].IsAllowedItem(itemRef);
        if(!canAdd)
        {
            Debug.logError("Unexcepted item kind");
            return false;//当对应槽位不允许对应物品时,返回false
            //对物品种类的限制更应该放在UI/AI相关脚本中分别完成,这里仅仅是作为一个备用功能
        }
        else
        {
            if(itemCount<items.length)
            {
                items[itemCount].itemRef = itemRef;
            }
        }
    }
    public void SwampItem(int slotID, itemRef item2)
    {
        //交换物品
    }
    public void SwampItem(int slotID1, int slotID2)
    {
        //一个用于交换通用槽位物品的重载
    }
}
public class ItemSlot
{
    //需要一个物品槽位类来限制存取
    public itemRef itemref;//此槽位存放的物品
    public class ItemDef {get{return itemRef == null?null:itemRef.itemDef}};
    public bool allowPutIn;//是否限制放入
    public bool allowTakeOut;//拿出
    public itemClass[] allowItemKind;//限制存储类型
    public int[] allowItemID;//限制存储物品
    public bool IsAllowedItem()//判断是否允许某物品
    {
        ....
    }
}
//箱子
public class Box : BasicStorage
{
    public int slotAmount = 16;
    public ItemKind itemKindAllowed;//可以装入的物品;
    public overwrite ItemSlot{get{return Items}};
    void Awake
    {
        //初始化Items栏位,生成slotAmount长度、限制装入itemKindAllowed类物品的ItemSlot数组
    }
}
//角色
public class CharacterInventory : BasicStorage
{
    public itemSlot[] quickSlots;
    public itemSlot weaponSlots;
    public itemSlot ArmorSlots;
    public override AllItems{ get {//将角色的装备与背包物品合并并重新排序}}
    void Awake()
    {
        //初始化Items栏位,生成slotAmount长度、限制装入itemKindAllowed类物品的ItemSlot数组
        //初始化装备槽位
    }
}

实际的代码比上述复杂,例如,完整的characterInventory类涉及了很多角色属性管理的内容;使用update()函数和Time.deltatime动态更新物品耐久度的功能也没有体现。上述代码仅仅提供了框架和示意的作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值