背包系统Package包git地址:https://github.com/PigerYoung/InventorySystem.git
背包系统离不开物品,因此在设计背包系统时需要将物品(Item)的类图设置好,附上下发UML类图
首先,根据类图可以编写出Item这个父类,因为所有的装备都是继承自Item类的
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum ItemType//物品种类
{
Consumable,//消耗品
Equipment,//装备
Weapon,//武器
Material//材料
}
public enum Quality//物品品质
{
Common,
Uncommon,
Rare,
Epic,
Legendary,
Artifact
}
public class Item //物品基类
{
public int ID { get; set; }
public string Name { get; set; }
public ItemType ItemType { get; set; }
public Quality Quality { get; set; }
public string Description { get; set; }
public int Capicity { get; set; }
public int BuyPrice { get; set; }
public int SellPrice { get;set; }
public string Sprite { get; set; }//存放物品的图片路径,通过Resources加载
public Item(int iD, string name, ItemType itemType, Quality quality, string description, int capicity, int buyPrice, int sellPrice)
{
ID = iD;
Name = name;
ItemType = itemType;
Quality = quality;
Description = description;
Capicity = capicity;
BuyPrice = buyPrice;
SellPrice = sellPrice;
Sprite = sprite;
}
public Item() { }//无参构造函数,防止子类在没中没有显式定义构造函数,则会默认调用父类无参数构造
//函数。
}
再依次创建Item的子类,消耗品,装备,武器,材料类
using UnityEngine;
/// <summary>
/// 消耗品类
/// </summary>
public class Consumable : Item
{
public int HP { get; set; }//消耗品增加的血量
public int Mp { get; set; }//消耗品增加的蓝量
public Consumable(int hP, int mp, int iD, string name, ItemType itemType, Quality quality, string description, int capicity, int buyPrice, int sellPrice,string sprite) :base(iD,name,itemType,quality,description,capicity,buyPrice,sellPrice, sprite)
{
HP = hP;
Mp = mp;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum EquipType//装备类型枚举
{
Head,//头部
Neck,//脖子
Ring,//戒指
Leg,//腿
Bracer,//护腕
Boots,//靴子
Shoulder,//肩膀
Belt,//腰带
OffHand//副手
}
/// <summary>
/// 装备类
/// </summary>
public class Equipment : Item
{
public int Strength { get; set; }//力量
public int Intellect { get; set; }//智力
public int Agility { get; set; }//敏捷
public int Stamina { get; set; }//体力
public EquipType equipType { get; set; }//装备类型
public Equipment(int strength, int intellect, int agility, int stamina, EquipType equipType, int iD, string name, ItemType itemType, Quality quality, string description, int capicity, int buyPrice, int sellPrice,string sprite): base(iD, name, itemType, quality, description, capicity, buyPrice, sellPrice, sprite)
{
Strength = strength;
Intellect = intellect;
Agility = agility;
Stamina = stamina;
this.equipType = equipType;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Playables;
using UnityEngine;
/// <summary>
/// 武器类
/// </summary>
public enum WeaponType//武器类型
{
offHand,//副手
mianHand//主手
}
public class Weapon : Item
{
public int Damage { get; set; }
public WeaponType weaponType { get; set;}
public Weapon(int damage ,WeaponType weaponType,int iD, string name, ItemType itemType, Quality quality, string description, int capicity, int buyPrice, int sellPrice,string sprite) : base(iD, name, itemType, quality, description, capicity, buyPrice, sellPrice, sprite)
{
Damage = damage;
this.weaponType = weaponType;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 材料类
/// </summary>
public class Material : Item
{
public Material(int iD, string name, ItemType itemType, Quality quality, string description, int capicity, int buyPrice, int sellPrice, string sprite) : base(iD, name, itemType, quality, description, capicity, buyPrice, sellPrice, sprite)
{
}
public Material()
{ }
}
编写好物品的类后,用json的格式来创建出各种物品,然后再在代码中解析json,就可以达到解析出的json会把物品的各种信息赋值好,(简单方式就是将各种类的脚本挂载在物品上,制作成预制件,直接使用预制件(因为预制件保存了游戏对象的各种信息,这里json 的作用就是保存装备的各种信息),但是这种方法只适合装备数量不多的情况)(Litjson在解析文件时会区分大小写!!,因此json文件的字段名称应于类中的名称内容和大小写都应该保持一致)
(!!Listjson在在解析枚举类型时,不能"ItemType": "Consumable"解析这种类型的枚举,会自动解析成字符串,因此有两种解决方案:1.使用ISerializationCallbackReceiver接口,序列化完成后再将字符串转为枚举类型,这中需要类中即包含枚举类型有包含字符串类型(这两个要对应)具体参考参考链接。2.将json格式用int类型来表示,比如Consumable对应的枚举类型int就是0,因此这样写参考链接)
这是部分json文件内容,用来做测试用
[
{
"Id": 1,
"Name": "血瓶",
"ItemType": 0,
"Quality": 1,
"Description": "这是用来加血的",
"Capicity": 10,
"BuyPrice": 10,
"SellPrice": 5,
"Sprite": "Sprites/Items/hp",
"Hp": 100,
"Mp": 0
}
]
有了json文件后就可以创建InventoryManager类来 解析jison文件和管理,在解析json时,因为只用itemList集合(list中存放的是Item这个父类)来接收各种装备(子类),因此就需要用到动态解析json的方法,也就是用JsonData来接收(它可以把所有信息接收下来),随后再通过json中特定的标识符进行区分后再new出对应的子类对象放进itemList中
为了理清思路,先附上开发到该阶段时,InventoryManager类该有的东西(还未开发完,后续还会添加内容)
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using LitJson;
using System;
public class InventoryManager : MonoBehaviour
{
#region 单例模式
private static InventoryManager _instance;
public static InventoryManager Instance
{
get
{
if( _instance == null )
{
_instance = GameObject.Find("InventoryManager").GetComponent<InventoryManager>();//这里是在静态方法中,因此不能直接用this或者gameobject来获取组件
}
return _instance;
}
}
#endregion
#region 解析json
//这里设计的大概思想就像,首先json文件是一个写好的装备信息,改json文件是一个[{},{}],数组里面的类是继承自Item的,因此设定一个itemList集合
//将json文件解析到itemList(解析json到数组需要用到Litjson,unity内置的jsonutility不能解析成数组),如果使用itemList = JsonMapper.ToObject<List<Item>>(itemsjson);
//会出现一个问题,就是虽然能够成功解析到内容,但是因为是json数组里面存放的是Item的子类对象,子类有特定的一些属性就不能成功解析到itemList 集合的对象中(因为itemList存放的是Item对象,是父类对象),因此也就访问不到
//因此就需要动态解析json,也就是把所有的json信息都要解析出来,不能只将json解析为Item对象,因此就可以使用JsonData类,来接受json的解析,并且通过判断每一个对象的itemtype来newItem的子对象,并add到itemLis中(子类向上转型);如果要使用itemList对象时,就需要向下转型成对应的子类对象
private List<Item> itemList = new List<Item>();
private void Start()
{
ParseItemJson();
}
//解析物品信息
void ParseItemJson()
{
TextAsset itemText = Resources.Load<TextAsset>("Items");
string itemsjson = itemText.text;//物品信息的json格式
//itemList=JsonUtility.FromJson<List<Item>>(itemsjson);//jsonuti不能解析成数组
JsonData jsondata = JsonMapper.ToObject(itemsjson);
//itemList = JsonMapper.ToObject<List<Item>>(itemsjson);//将json解析到itemList中,用一个父类List集合保存所有子类对象(我觉得这里有设计缺陷)
Item itemtemp = null;
for (int i=0; i<jsondata.Count;i++)//用物品类型来区分
{
int id = (int)jsondata[i]["Id"];
string name = jsondata[i]["Name"].ToString();
ItemType itemType = (ItemType)((int)jsondata[i]["ItemType"]);
Quality quality = (Quality)((int)jsondata[i]["Quality"]);
string description = jsondata[i]["Description"].ToString();
int capicity = (int)jsondata[i]["Capicity"];
int buyprice = (int)jsondata[i]["BuyPrice"];
int sellprice = (int)jsondata[i]["SellPrice"];
string sprite = jsondata[i]["Sprite"].ToString();
switch (itemType)
{
case ItemType.Consumable:
int hp = (int)jsondata[i]["Hp"];
int mp = (int)jsondata[i]["Mp"];
itemtemp = new Consumable(hp, mp, id, name, itemType, quality, description, capicity, buyprice, sellprice, sprite);
break;
case ItemType.Equipment:
break;
case ItemType.Weapon:
break;
case ItemType.Material:
break;
default:
break;
}
itemList.Add(itemtemp);
}
Consumable test = (Consumable)itemList[0];
Debug.Log(test.HP + "+" + test.Mp);
}
#endregion
}
能够成功读取到json后,就可以进行UI的设计和搭建了
Unity搭建UI(这里就不详细讲解如何搭建,都学背包系统了还不会搭UI的!!!回去多搭几个)
设计UI需要注意的点:Slot和Item分别做成一个预制件,也就是格子和Item物品分开制作,方便后续添加隐藏(添加的思路就是将item设为格子的子物体,随后把局部坐标赋为0;隐藏同理)
目前搭建效果
UI搭建好后就可以根据UI来设计脚本,以背包面板举例,就会涉及四个脚本,1.Inventory,2.Knapsack,3.Slot,4.ItemUI (具体功能在脚本中)
1.Inventory类,是面板类的父类,面板类也就是背包面板,箱子面板等,这里以背包面板举例,其中就会有些面板类共有的方法属性,如List物品槽,调用存放物品函数,寻找空槽,寻找于item相同的槽等方法
2.Knapsack类,背包面板特有的方法属性(挂载到背包面板上)
3.Slot类,控制格子的脚本,如将Item存放进格子函数(Inventory类调用),获取slot下的item类型,判断当前槽是否装满某装备(挂载到Slot预制件上)
4.ItemUI类,控制Slot中的Item的UI脚本,其中包括Item和数量,设置Item等(挂载带Item预制件上)
下面附上开发到这个阶段的这个四个脚本的源码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 所有可以装物品面板的父类,用来装物品
/// </summary>
public class Inventory : MonoBehaviour
{
//所有装物品的面板都有Slot,因此可以用list集合来存放当前面板的所有slot
private List<Slot> slotList = new List<Slot>();
public virtual void Start()//因为还有背包,箱子等面板可能会用到Start函数,所以把它设为虚函数
{
slotList.AddRange(GetComponentsInChildren<Slot>());
}
/// <summary>
/// 存储物品函数
/// </summary>
/// <param name="id">存储id对应的Item</param>
/// <returns>是否存放成功</returns>
public bool StoreItem(int id)
{
Item item =InventoryManager.Instance.GetItemById(id);
if (item == null)
{
Debug.LogWarning("要储存的物品id不存在");
return false;
}
//如果要存储的物品id存在
if(item.Capicity==1)//如果容量为1
{
//放在一个新格子里面
Slot slot=FindEmptySlot();
if (slot==null)
{
Debug.LogWarning("没有空的物品槽");
return false;
}
else
{
slot.StoreItem(item);//把物品存储到空物品槽里面
}
}
else//如果容量不为1
{
//找一个和item的id一样的格子进行存放
Slot slot = FindSameIdSlot(item);
if (slot != null)
{
slot.StoreItem(item);
}
else
{
Slot emptySlot= FindEmptySlot();
if(emptySlot!=null)
{
emptySlot.StoreItem(item);
}
else
{
Debug.LogWarning("没有空的物品槽");
return false;
}
}
}
return true;
}
private Slot FindEmptySlot()//找空的物品槽Slot
{
foreach (Slot slot in slotList)
{
if(slot.transform.childCount==0)
{
return slot;
}
}
return null;
}
private Slot FindSameIdSlot(Item item)//找物品槽存放的item与参数itemID相同的slot
{
foreach (Slot slot in slotList)
{
if(slot.transform.childCount>=1&&slot.GetItemId()==item.Id&&slot.IsFilled()==false)
{
return slot;
}
}
return null;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Knapsack : Inventory
{
#region 单例模式
private static Knapsack _instance;
public static Knapsack Instance
{
get
{
if (_instance == null)
{
_instance = GameObject.Find("KnapsackPanel").GetComponent<Knapsack>();//这里是在静态方法中,因此不能直接用this或者gameobject来获取组件
}
return _instance;
}
}
#endregion
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 这是存储物品的格子脚本
/// </summary>
public class Slot : MonoBehaviour
{
public GameObject itemPrefab;//这里需要用预制件进行赋值
public void StoreItem(Item item)//将Item存储到slot格子中(把item放在自身下面),1.如果有item了就,amount++。2.如果没有item,就实例化item放在下面
{
if(transform.childCount==0)//如果格子为空时
{
GameObject itemGameObject=Instantiate(itemPrefab);
itemGameObject.transform.SetParent(transform);
itemGameObject.transform.localPosition = Vector3.zero;
itemGameObject.GetComponent<ItemUI>().SetItem(item);//!!!这里就是将外部的item和slot中的item同步
}
else
{
transform.GetChild(0).GetComponent<ItemUI>().AddAmount();
}
}
public int GetItemId()//获取到slot下的Item的Id
{
return transform.GetChild(0).GetComponent<ItemUI>().Item.Id;
}
public bool IsFilled()//判断当前槽是否装满该装备
{
ItemUI itemUI = transform.GetChild(0).GetComponent<ItemUI>();
return itemUI.Amount >= itemUI.Item.Capicity;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ItemUI : MonoBehaviour
{
public Item Item { get; private set; }
public int Amount { get; private set; }
private Image itemImage;//item中图片和数量
private Text amountText;
private void Awake()
{
itemImage = GetComponent<Image>();
amountText=GetComponentInChildren<Text>();
}
public void SetItem(Item item,int amount=1)//用参数item设置itemUI中的item
{
this.Item = item;
this.Amount= amount;
//更新UI
itemImage.sprite = Resources.Load<Sprite>(item.Sprite);//根据item中的sprite加载Resources文件中的图片并赋值给当前slot中的item
if(item.Capicity>1)//容量大于1才显示
amountText.text=Amount.ToString();
else
amountText.text="";
}
public void AddAmount(int amount=1)
{
this.Amount += amount;
//更新UI
amountText.text = Amount.ToString();
}
}
其中还有个Player脚本用来模拟装备的生成等操作
using UnityEngine;
public class Player : MonoBehaviour
{
void Update()
{
//G 按下G键,随机得到一个物品到背包中
if (Input.GetKeyDown(KeyCode.G))
{
int id = Random.Range(1, 2);//通过生成装备id来表示生成装备
Knapsack.Instance.StoreItem(id);
}
}
}
开发到该阶段,能实现的效果是,按下G键就能生成物品
开发完这个功能就可以开发ToolTip提示功能,UI就做个自适应的文本框即可(这里采用两个Text的采用代码同步的方式)
ToolTip脚本功能比较简单,就负责信息面板的显示,隐藏,和更改信息面板的显示内容,(需要在InventoryManager中调用)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ToolTip : MonoBehaviour
{
private Text toolTipText;
private Text contentText;
private CanvasGroup canvasGroup;
private float targetAlpha = 0;
private float smoothing = 6f;
private void Start()
{
toolTipText = GetComponent<Text>();
contentText=transform.Find("Content").GetComponent<Text>();
canvasGroup = GetComponent<CanvasGroup>();
}
private void Update()
{
if(canvasGroup.alpha!=targetAlpha)
{
canvasGroup.alpha = Mathf.MoveTowards(canvasGroup.alpha, targetAlpha, smoothing * Time.deltaTime);
if(Mathf.Abs(canvasGroup.alpha-targetAlpha)<0.01f)
{
canvasGroup.alpha=targetAlpha;
}
}
}
public void Show(string text)//显示提示信息
{
targetAlpha = 1;
toolTipText.text = text;
contentText.text = text;
}
public void Hide()//隐藏提示信息
{
targetAlpha = 0;
}
}
有了提示面板后,就需要触发提示面板的显示和隐藏,也就是当鼠标移入和移出Slot时判断(因此Slot脚本还需要实现两个鼠标移入移出事件的接口IPointerEnterHandler,IPointerExitHandler,这里还在Item脚本中添加了获取提示面板内容的函数)
Slot脚本添加的内容是: (需实现IPointerEnterHandler,IPointerExitHandler接口)
public void OnPointerExit(PointerEventData eventData)//鼠标移出事件
{
if (transform.childCount > 0)
InventoryManager.Instance.HideToolTip();
}public void OnPointerEnter(PointerEventData eventData)//鼠标移事件
{
if(transform.childCount>0)//要格子有item才能显示
{
string toolTipText=transform.GetChild(0).GetComponent<ItemUI>().Item.GetToolTipText();
InventoryManager.Instance.ShowToolTip(toolTipText);
}
}
InventoryManager脚本需添加的内容:
private ToolTip toolTip;//信息面板
private void Start()
{
ParseItemJson();
toolTip=GameObject.Find("ToolTip").GetComponent<ToolTip>();
}public void ShowToolTip(string content)//调用显示信息面板,并赋值内容
{
isToolTipsShow = true;
toolTip.Show(content);
}
public void HideToolTip()
{
isToolTipsShow = false;
toolTip.Hide();
}
Item中添加的脚本:
/// <summary>
/// 得到提示面板应该显示的内容(还没有完善,仅做测试)
/// </summary>
/// <returns></returns>
public virtual string GetToolTipText()
{
return Name;
}
做到这一步能够实现的效果
可以看见提示面板的显示和隐藏,接下来就是实现提示面板跟随鼠标的效果
就在ToolTip脚本中添加一个设置面板位置的函数,随后在InventoryManager调用即可(这里需要屏幕坐标和rect坐标的转换)
ToolTip脚本添加:
public void SetClocalPosition(Vector3 position)//设置信息面板位置
{
transform.localPosition = position;
}
InventoryManager脚本添加:
private bool isToolTipsShow = false;//提示面板是否显示的标志位
private Canvas canvas;
private Vector2 toolTipPositionOffset = new Vector2(10, -10);//因为中心轴设置的位置的原因,因此要有个偏差才能达到合适的效果private void Update()//在update中坐标转换并调用设置面板位置
{
if(isToolTipsShow)
{
Vector2 position;
RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.GetComponent<RectTransform>(), Input.mousePosition,null, out position);
toolTip.SetClocalPosition(position + toolTipPositionOffset);
}
}
效果:
做到这里,就可以把前面部分json物品信息的部分进行完善一下了,和完善提示面板信息的内容
这是完善后json文件的装备配置信息
[
{
"Id": 1,
"Name": "血瓶",
"ItemType": 0,
"Quality": 1,
"Description": "这是用来加血的",
"Capicity": 10,
"BuyPrice": 10,
"SellPrice": 5,
"Sprite": "Sprites/Items/hp",
"Hp": 100,
"Mp": 0
},
{
"Id": 2,
"Name": "蓝瓶",
"ItemType": 0,
"Quality": 1,
"Description": "这是用来加蓝的",
"Capicity": 10,
"BuyPrice": 10,
"SellPrice": 5,
"Sprite": "Sprites/Items/mp",
"Hp": 0,
"Mp": 10
},
{
"Id": 3,
"Name": "胸甲",
"ItemType": 1,
"Quality": 2,
"Description": "这是一个胸甲",
"Capicity": 1,
"BuyPrice": 20,
"SellPrice": 5,
"Sprite": "Sprites/Items/armor",
"Strength": 10,
"Intellect": 4,
"Agility": 9,
"Stamina": 1,
"equipType": 2
},
{
"Id": 4,
"Name": "皮腰带",
"ItemType": 1,
"Quality": 3,
"Description": "这皮腰带可以加速",
"Capicity": 1,
"BuyPrice": 20,
"SellPrice": 5,
"Sprite": "Sprites/Items/belts",
"Strength": 1,
"Intellect": 6,
"Agility": 10,
"Stamina": 10,
"equipType": 8
},
{
"Id": 5,
"Name": "靴子",
"ItemType": 1,
"Quality": 4,
"Description": "这靴子带可以加速",
"Capicity": 1,
"BuyPrice": 20,
"SellPrice": 10,
"Sprite": "Sprites/Items/boots",
"Strength": 10,
"Intellect": 5,
"Agility": 0,
"Stamina": 10,
"equipType": 6
},
{
"Id": 6,
"Name": "护腕",
"ItemType": 1,
"Quality": 2,
"Description": "这个护腕可以增加防御",
"Capicity": 1,
"BuyPrice": 20,
"SellPrice": 10,
"Sprite": "Sprites/Items/bracers",
"Strength": 1,
"Intellect": 2,
"Agility": 3,
"Stamina": 4,
"equipType": 5
},
{
"Id": 6,
"Name": "护腕",
"ItemType": 1,
"Quality": 2,
"Description": "这个护腕可以增加防御",
"Capicity": 1,
"BuyPrice": 20,
"SellPrice": 10,
"Sprite": "Sprites/Items/bracers",
"Strength": 1,
"Intellect": 2,
"Agility": 3,
"Stamina": 4,
"equipType": 5
},
{
"Id": 7,
"Name": "神奇手套",
"ItemType": 1,
"Quality": 0,
"Description": "这是暴击拳套",
"Capicity": 1,
"BuyPrice": 20,
"SellPrice": 5,
"Sprite": "Sprites/Items/gloves",
"Strength": 1,
"Intellect": 2,
"Agility": 3,
"Stamina": 4,
"equipType": 9
},
{
"Id": 8,
"Name": "头盔",
"ItemType": 1,
"Quality": 5,
"Description": "这是头盔",
"Capicity": 1,
"BuyPrice": 10,
"SellPrice": 5,
"Sprite": "Sprites/Items/helmets",
"Strength": 1,
"Intellect": 2,
"Agility": 3,
"Stamina": 4,
"equipType": 0
},
{
"Id": 9,
"Name": "项链",
"ItemType": 1,
"Quality": 5,
"Description": "这是很厉害的项链",
"Capicity": 1,
"BuyPrice": 10,
"SellPrice": 5,
"Sprite": "Sprites/Items/necklace",
"Strength": 1,
"Intellect": 2,
"Agility": 3,
"Stamina": 4,
"equipType": 1
},
{
"Id": 10,
"Name": "戒指",
"ItemType": 1,
"Quality": 0,
"Description": "这是很厉害的戒指",
"Capicity": 1,
"BuyPrice": 20,
"SellPrice": 10,
"Sprite": "Sprites/Items/rings",
"Strength": 10,
"Intellect": 2,
"Agility": 3,
"Stamina": 4,
"equipType": 3
},
{
"Id": 11,
"Name": "裤子",
"ItemType": 1,
"Quality": 1,
"Description": "这是很厉害的裤子",
"Capicity": 1,
"BuyPrice": 40,
"SellPrice": 20,
"Sprite": "Sprites/Items/pants",
"Strength": 20,
"Intellect": 20,
"Agility": 20,
"Stamina": 40,
"equipType": 4
},
{
"Id": 12,
"Name": "护肩",
"ItemType": 1,
"Quality": 4,
"Description": "这是很厉害的护肩",
"Capicity": 1,
"BuyPrice": 100,
"SellPrice": 20,
"Sprite": "Sprites/Items/shoulders",
"Strength": 20,
"Intellect": 30,
"Agility": 40,
"Stamina": 40,
"equipType": 7
},
{
"Id": 13,
"Name": "黑色切割者",
"ItemType": 2,
"Quality": 2,
"Description": "黑切适合半肉战士",
"Capicity": 1,
"BuyPrice": 50,
"SellPrice": 20,
"Sprite": "Sprites/Items/axe",
"Damage": 100,
"weaponType": 1
},
{
"Id": 14,
"Name": "暴风大剑",
"ItemType": 2,
"Quality": 3,
"Description": "用来合成无尽之刃",
"Capicity": 1,
"BuyPrice": 100,
"SellPrice": 50,
"Sprite": "Sprites/Items/sword",
"Damage": 50,
"weaponType": 0
},
{
"Id": 15,
"Name": "黑切的合成秘籍",
"ItemType": 3,
"Quality": 5,
"Description": "用来锻造黑切",
"Capicity": 2,
"BuyPrice": 100,
"SellPrice": 99,
"Sprite": "Sprites/Items/book"
},
{
"Id": 16,
"Name": "头盔的合成秘籍",
"ItemType": 3,
"Quality": 0,
"Description": "用来锻造头盔",
"Capicity": 2,
"BuyPrice": 50,
"SellPrice": 10,
"Sprite": "Sprites/Items/scroll"
},
{
"Id": 17,
"Name": "铁块",
"ItemType": 3,
"Quality": 0,
"Description": "用来锻造其他东西的材料",
"Capicity": 20,
"BuyPrice": 5,
"SellPrice": 4,
"Sprite": "Sprites/Items/ingots"
}
]
完善Item脚本中的GetToolTipText()方法,写为虚方法是为了指向不同种类的物品会显示不同的内容
/// <summary>
/// 得到提示面板应该显示的内容
/// </summary>
/// <returns></returns>
public virtual string GetToolTipText()
{
string color = "";
switch (Quality)
{
case Quality.Common:
color = "white";
break;
case Quality.Uncommon:
color = "lime";
break;
case Quality.Rare:
color = "navy";
break;
case Quality.Epic:
color = "magenta";
break;
case Quality.Legendary:
color = "orange";
break;
case Quality.Artifact:
color = "red";
break;
}string text = string.Format("<color={4}>{0}</color>\n购买价格:{1}出售价格:{2}\n<color=yellow>{3}</color>", Name, BuyPrice, SellPrice, Description,color);
return text;
}
随后再各个Item子脚本中重写GetToolTipText()方法,到达不同的效果
如消耗品Consumable脚本中,重写GetToolTipText()方法
public override string GetToolTipText()
{
string text= base.GetToolTipText();
string newText=string.Format("{0}\n\n<color=bulue>加血:{1}\n加蓝:{2}</color>",text, HP,Mp);
return newText;
}
后续的如装备,材料等信息的展示内容同理,具体重写的方法就不一一展示(可以参考最终版代码中的内容)
从这里开始由于是背包系统的附加功能,不展示阶段性的功能代码任何实现的,如有需要去看最终源码
做到这里,后续就是需要做装备的点击于拖动了,装备的拖动
这里的大概设计思想就是,创建一个Item的对象来跟随鼠标移动,并且用它来表示拾取到的物品,如果拾取到物品pickedItem就会变成Slot中的Item,那么对应的Slot中的物品就应该销毁或者减少,重点就在于Slot中鼠标按下时对当前点击的Slot的Item和已经跟随着鼠标的Item进行比较判断(还有丢弃物品功能)
箱子面板,面板的显示和隐藏,目前能到达的效果,由于代码耦合度较高,比较复杂,因此就不附上功能阶段性代码(因为该部分也不算是背包系统的重点),该部分重点在于介绍思想,如果想看源码,在文章最后有最终开发完全的源码
角色面板,功能包括对应槽只能穿戴对应装备,点击鼠标右键一键穿戴装备,一键卸载,装备替换等
开发角色属性数据,通过遍历角色面板中所有的Slot中的Item属性,定义一个更新函数,函数内容是遍历角色面板中的所有Slot中的Item属性,并相加(因此就不用做是穿戴装备还是脱去装备的区分)
接下来就是做商店功能,功能有买,卖商品,全部卖出和部分卖出的功能
锻造系统,锻造系统的设计需要一个配方类,配方类需要有材料的id数量还有合成结果的id,随后用json格式生成配置文件,json文件的内容就是一个存放配方类的数组;锻造功能的核心在于点击锻造时,利用配方数组进行匹配(算法关键在于两个List的匹配,自身手中物品的List和秘籍需要的物品的List)
保存加载功能,该部分功能主要原理就是将面板中的所有格子中的item读取成字符串的形式储存(每一个格子的内容都需要存储),随后读取时用Split进行分格,根据不同的字符串内容最后进行不同的操作
到这里整个背包系统就完结了,从背部系统的附加功能都没有附上代码,可以去参考源码!!(源码里面有详细的注释,推荐看看源码)
梳理一下思路,背包系统核心功能的设计
1.首先就是Item类的设计,item类是一个父类,所有的武器类,装备类,补给品类等都是继承自Item(区分物品的唯一标识就是ID),并且武器类,装备类等又有各自的特有属性
2.在设计完各个物品类后,就需要将物品的配置信息等读取到游戏中,将物品的信息进行配置成json文件,随后解析到游戏中;因为json配置的文件都是Item的各个子类,想要用一个集合把所有的Item子类都保存下来,那么就需要创建一个itemList<Item>这个List集合,接收的对象为Item类(item的子类也可以放进去,这里参考向上转型),这样就用一个父类List存放了所有子类装备(具体实现参考上方文章内容)文章来源:https://www.toymoban.com/news/detail-769879.html
3.解析完所有的装备信息后,就是需要设计物品槽和物品的搭建,实现面板和物品之间的交互比如移动物品,获得物品等,是将物品槽和物品都做成单独的预制件,在实现交互等功能(比如将物品储存在槽中,逻辑就是将Item设为槽的子物体,随后将局部坐标变为0就能实现),这里有需要创建多个面板的话(比如背包,商店等面板),就需要有个Inventory父类(是所有面板的父类),子类不同的面板有不同的功能,就可以单独设置文章来源地址https://www.toymoban.com/news/detail-769879.html
到了这里,关于Unity--背包系统(含锻造和装备系统)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!