游戏中几乎都存在大大小小的背包系统,接下来我将讲述背包系统具体是如何实现的(完整源码)
以下是使用unity+NGUI实现(使用txt配置的方法,后续更新UGUI+Json实现的背包系统敬请期待!)
背包中的物品我们常常将其制作成预设体,通过改变预设体图片来产生不同的物品,以下是物品以及管理格子系统的逻辑:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static UnityEditor.Progress;
/// <summary>
/// 一个用于控制背包內物品的类
/// </summary>
public class InventoryItem : UIDragDropItem
{
//关联物品的图片
public UISprite sprite;
private int id;
//关联显示窗口
public UISprite tipWindow1;
public UIButton tipbtnOk;
public UIButton tipbtnCancel;
void Update()
{
if (isHover)
{
//显示提示信息
InventoryDes._instance.Show(id);
if(Input.GetMouseButtonDown(1))
{
//按下鼠标右键开始穿戴
//显示窗口
tipWindow1.gameObject.SetActive(true);
tipbtnOk.onClick.Add(new EventDelegate(() =>
{
bool success = EquipmentUI._instance.Dress(id);
if(success)
{
transform.parent.GetComponent<InventoryItemGrid>().MinusNumber();
}
tipWindow1.gameObject.SetActive(false);
}));
tipbtnCancel.onClick.Add(new EventDelegate(() =>
{
tipWindow1.gameObject.SetActive(false);
}));
}
}
}
protected override void OnDragDropRelease(GameObject surface)
{
base.OnDragDropRelease(surface);
//测试
if (surface != null)
{
if (surface.tag == Tags.inventory_item_grid)
{
//拖放至空格子里面
if (surface == this.transform.parent.gameObject)
{
//拖放在自己的格子里面
}
else
{
InventoryItemGrid oldParent = this.transform.parent.GetComponent<InventoryItemGrid>();
this.transform.parent = surface.transform;
//zhuyi
ResetPosition();
InventoryItemGrid newParent = surface.GetComponent<InventoryItemGrid>();
newParent.SetId(oldParent.id, oldParent.num);
oldParent.ClearInfo();
}
}
else if (surface.tag == Tags.inventory_item)
{
//拖放在有物品的格子里面
InventoryItemGrid grid1 = this.transform.parent.GetComponent<InventoryItemGrid>();
InventoryItemGrid grid2 = surface.transform.parent.GetComponent<InventoryItemGrid>();
int id = grid1.id; int num = grid1.num;
grid1.SetId(grid2.id, grid2.num);
grid2.SetId(id, num);
}
else if(surface.tag==Tags.shortcut)
{
//拖动到快捷栏当中
surface.GetComponent<ShortCutGrid>().SetInventory(id);
}
}
else
{
}
ResetPosition();
}
//重置位置
void ResetPosition()
{
transform.localPosition = Vector3.zero;
}
//注意这里
//public void SetId(int id)
//{
// ObjectInfo info=ObjectsInfo._instance.GetObjectInfoById(id);
// sprite.spriteName = info.icon_name;
//}
public void SetIconName(int id, string icon_name)
{
sprite.spriteName = icon_name;
this.id = id;
}
//public void SetIconName(string icon_name)
//{
// if (icon_name == null)
// {
// sprite.spriteName = "Icon-potion1";
// Debug.Log("null");
// }
// else
// Debug.Log("NOT NULL" + icon_name);
// // sprite.spriteName = icon_name;
//}
private bool isHover = false;
public void OnHoverOver()
{
isHover = true;
}
public void OnHoverOut()
{
isHover = false;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 一个用于管理背包內所有格子的类
/// </summary>
public class Inventory : MonoBehaviour
{
public static Inventory _instance;
private TweenPosition tween;
//定义金币的数量 初始化为1000
private int coinCount = 1000;
//使用List将格子们存储起来
public List<InventoryItemGrid> itemGridList = new List<InventoryItemGrid>();
//关联金币文本,控制数量
public UILabel coinNumberLabel;
public GameObject inventoryItem;
//关联背包的显示和隐藏(按钮)
public UIButton btnBag;
public UIButton btnClose;
private bool isShow=false;
void Awake()
{
_instance = this;
tween=this.GetComponent<TweenPosition>();
}
private void Start()
{
btnBag.onClick.Add(new EventDelegate(() =>
{
Show();
}));
btnClose.onClick.Add(new EventDelegate(() =>
{
Hide();
}));
}
public void Show()
{
isShow=true;
tween.PlayForward();
}
public void Hide()
{
isShow=false;
tween.PlayReverse();
}
public void TransformState()
{
if(isShow==false)
{
Show();
}
else
{
Hide();
}
}
//增加金币的方法
public void AddCoin(int count)
{
coinCount += count;
coinNumberLabel.text = coinCount.ToString();//更新金币的显示
}
//取款方法
public bool GetCoin(int count)
{
if(coinCount>=count)
{
coinCount-=count;
coinNumberLabel.text = coinCount.ToString();//更新金币显示
return true;
}
return false;
}
//测试背包系统的方法
void Update()
{
if (Input.GetKeyDown(KeyCode.X))
{
GetId(Random.Range(2001,2023));
}
}
//拾取到物品 添加到物品栏里面
//处理拾取物品的功能
public void GetId(int id,int count=1)
{
//查找所有物品中是否存在该物品
//存在就数量+1
InventoryItemGrid grid = null;
foreach (InventoryItemGrid temp in itemGridList)
{
if (temp.id == id)
{
grid = temp;
break;
}
}
if (grid != null)
{
grid.PlusNumber(count);
}
else
{
//不存在的情况
foreach (InventoryItemGrid temp in itemGridList)
{
if (temp.id == 0)
{
grid = temp;
break;
}
}
//不存在就放在空的格子里面
if (grid != null)
{
GameObject itemGo = NGUITools.AddChild(grid.gameObject, inventoryItem);
itemGo.transform.localPosition = Vector3.zero;
itemGo.GetComponent<UISprite>().depth = 4;
grid.SetId(id,count);
}
}
}
public bool MinusId(int id,int count=1)
{
InventoryItemGrid grid=null;
foreach(InventoryItemGrid temp in itemGridList)
{
if (temp.id == id)
{
grid = temp;
break;
}
}
if (grid == null)
{
return false;
}
else
{
bool isSuccess = grid.MinusNumber(count);
return isSuccess;
}
}
}
与物品相关的就是物品的描述了,将鼠标移动到物品上面时就会显示物品的信息,那么物品显示又应该怎么制作呢?废话不多说,直接上代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 一个用于控制物品信息显示的类
/// </summary>
public class InventoryDes : MonoBehaviour
{
public static InventoryDes _instance;
public UILabel label;
//计时器
private float timer = 0;
void Awake()
{
_instance = this;
this.gameObject.SetActive(false);
}
void Update()
{
if (this.gameObject.activeInHierarchy == true)
{
timer -= Time.deltaTime;
if (timer <= 0)
{
this.gameObject.SetActive(false);
}
}
}
//显示的方法
public void Show(int id)
{
this.gameObject.SetActive(true);
timer = 0.1f;
transform.position = UICamera.currentCamera.ScreenToWorldPoint(Input.mousePosition);
ObjectInfo info = ObjectsInfo._instance.GetObjectInfoById(id);
string des = "";
switch (info.type)
{
case ObjectType.Drug:
des = GetDrugDes(info);
break;
case ObjectType.Equip:
des = GetEquipDes(info);
break;
}
//更新显示
label.text = des;
}
string GetDrugDes(ObjectInfo info)
{
string str = "";
str +="名称:" + info.name + "\n";
str += "+HP:" + info.hp + "\n";
str += "+MP:" + info.mp + "\n";
str += "出售价:" + info.price_sell + "\n";
str += "购买价:" + info.price_buy;
return str;
}
string GetEquipDes(ObjectInfo info)
{
string str = "";
str += "名称" + info.name + "\n";
switch(info.dressType)
{
case DressType.Headgear:
str += "穿戴类型:头盔\n";
break;
case DressType.Armor:
str += "穿戴类型:盔甲\n";
break;
case DressType.LeftHand:
str += "穿戴类型:左手\n";
break;
case DressType.RightHand:
str += "穿戴类型:右手\n";
break;
case DressType.Shoe:
str += "穿戴类型:鞋\n";
break;
case DressType.Accessory:
str += "穿戴类型:饰品\n";
break;
}
switch(info.applicationType)
{
case ApplicationType.Swordman:
str += "适用类型:剑士\n";
break;
case ApplicationType.Magician:
str += "适用类型:魔法师\n";
break;
case ApplicationType.Common:
str += "适用类型:通用\n";
break;
}
str += "伤害值:" + info.attack + "\n";
str += "防御值:" + info.def + "\n";
str += "速度值:" + info.speed + "\n";
return str;
}
}
格子的逻辑:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 一个用于控制背包单个格子的类
/// </summary>
public class InventoryItemGrid : MonoBehaviour
{
public static InventoryItemGrid _instance;
public int id = 0;
private ObjectInfo info = null;
public int num = 0;
public UILabel numLabel;
void Awake()
{
_instance = this;
//一开始隐藏文本
numLabel.enabled= false;
}
public void SetId(int id, int num = 1)
{
this.id = id;
info = ObjectsInfo._instance.GetObjectInfoById(id);
InventoryItem item = this.GetComponentInChildren<InventoryItem>();
item.SetIconName(id, info.icon_name);
numLabel.enabled = true;
this.num = num;
numLabel.text = num.ToString();
}
public void PlusNumber(int num = 1)
{
this.num += num;
//更新显示
numLabel.text = this.num.ToString();
}
//用于减去数量的 表示装备是否减去成功
public bool MinusNumber(int num=1)
{
if(this.num>=num)
{
this.num -= num;
numLabel.text = this.num.ToString();
if(this.num==0)
{
//清空物品
ClearInfo();
GameObject.Destroy(this.GetComponentInChildren<InventoryItem>().gameObject);
}
return true;
}
return false;
}
//public void PlusNumber(int num = 1)
//{
// if (this.num < 10)
// {
// this.num = num + this.num;
// //更新显示
// numLabel.text = this.num.ToString();
// if (this.num <= 1)
// numLabel.enabled = false;
// else
// numLabel.enabled = true;
// }
//}
//设置一个清空的方法
public void ClearInfo()
{
id = 0;
info = null;
num = 0;
numLabel.enabled = false;
}
}
其中最最重要的就是接下来的类了,一个关于物品信息的类,有了它才能操控背包系统正常运作,其中文本读取的是txt的文本,其中的定义规则你可以自己定义,然后拿给策划填写就可以了,注意不要空格!!!!而且符号是英文的符号,更重要的一点是你脚本里面写的一定要和策划填写的一样!如果出现报空错误一定要仔细检查txt文本是否有误,一定要让策划仔细检查三遍!!!!!(我之前是这样写的,结果我的其它协作者使用报错了,原因是策划期间修改了文本,并且没有仔细检查,所以大家一定要注意!)
以下是完整代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 一个用于管理所有Object对象信息的类
/// </summary>
public class ObjectsInfo : MonoBehaviour
{
public static ObjectsInfo _instance;
//使用字典的方法存储起来 默认为空
//使用ID拿取物品
public Dictionary<int, ObjectInfo> objectInfoDict = new Dictionary<int, ObjectInfo>();
//可读取文本
public TextAsset objectsInfoListText;
void Awake()
{
_instance = this;
//测试是否成功
ReadInfo();
}
/// <summary>
/// 写一个向外界提供物品信息的方法
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public ObjectInfo GetObjectInfoById(int id)
{
ObjectInfo info = null;
//根据ID获取信息
objectInfoDict.TryGetValue(id, out info);
return info;
}
//写一个读取的类
void ReadInfo()
{
string text = objectsInfoListText.text;
//拆分一行
string[] strArray = text.Split('\n');
//将每一行都拆分成一个一个的
foreach (string str in strArray)
{
string[] proArray = str.Split(',');
//new一个ObjectInfo存储物品信息
ObjectInfo info = new ObjectInfo();
//将文本一行内容一个一个读取,存到新new的对象里面去
int id = int.Parse(proArray[0]);
string name = proArray[1];
string icon_name = proArray[2];
string str_type = proArray[3];
//首先定义一种类型
ObjectType type = ObjectType.Drug;
switch (str_type)
{
case "Drug":
type = ObjectType.Drug;
break;
case "Equip":
type = ObjectType.Equip;
break;
case "Mat":
type = ObjectType.Mat;
break;
//其它的物品种类就在后面添加即可
}
//存进去
info.id = id; info.name = name; info.icon_name = icon_name; info.type = type;
//药品系列赋值
if (type == ObjectType.Drug)
{
int hp = int.Parse(proArray[4]);
int mp = int.Parse(proArray[5]);
int price_sell = int.Parse(proArray[6]);
int price_buy = int.Parse(proArray[7]);
//存进去
info.hp = hp;
info.mp = mp;
info.price_sell = price_sell;
info.price_buy = price_buy;
}
//装备系列赋值
if(type==ObjectType.Equip)
{
info.attack = int.Parse(proArray[4]);
info.def = int.Parse(proArray[5]);
info.speed = int.Parse(proArray[6]);
info.price_sell = int.Parse(proArray[9]);
info.price_buy = int.Parse(proArray[10]);
string str_dresstype = proArray[7];
switch(str_dresstype)
{
case "Headgear":
info.dressType = DressType.Headgear;
break;
case "Armor":
info.dressType = DressType.Armor;
break;
case "LeftHand":
info.dressType = DressType.LeftHand;
break;
case "RightHand":
info.dressType = DressType.RightHand;
break;
case "Shoe":
info.dressType = DressType.Shoe;
break;
case "Accessory":
info.dressType = DressType.Accessory;
break;
}
string str_apptype = proArray[8];
switch(str_apptype)
{
case "Swordman":
info.applicationType = ApplicationType.Swordman;
break;
case "Magician":
info.applicationType = ApplicationType.Magician;
break;
case "Common":
info.applicationType = ApplicationType.Common;
break;
}
}
//将他们添加到字典之中
objectInfoDict.Add(id, info);
}
}
}
/// <summary>
/// 用于管理物品种类的枚举
/// 建立一个枚举 方便日后更多品种的物品信息添加
/// </summary>
public enum ObjectType
{
//药品系列
Drug,
Equip,
Mat
}
/// <summary>
/// 用于处理装备的信息
/// </summary>
public enum DressType
{
Headgear,
Armor,
RightHand,
LeftHand,
Shoe,
Accessory
}
/// <summary>
/// 用于处理不同类型的信息
/// </summary>
public enum ApplicationType
{
Swordman,//剑士
Magician,//魔法师
Common//通用
}
/// <summary>
/// 一个用于管理单个物品信息的类
/// </summary>
public class ObjectInfo
{
public int id; //索引值
public string name; //物品名字
public string icon_name; //物品加载的图片名字(存图集的名字)
public ObjectType type; //物品的种类
public int hp; //添加的HP值
public int mp; //添加的MP值
public int price_sell; //售卖的价格
public int price_buy; //卖出的价格(玩家)
public int attack;
public int def;
public int speed;
public DressType dressType;
public ApplicationType applicationType;
}
以上是背包系统的完整代码,如果你直接复制发现了报错,那可能是因为我在里面关联了其它系统,找出来修改一下就好了,或者直接问我,核心的内容就是这些,希望对你有所帮助,点个赞支持一下吧!