这一篇,主要讲解UI逻辑处理方面,以及UI和该篇中的数据两者之间的使用。
首先补充一个上篇中缺少的一个配方类:这个类主要是用来保存锻造的所需的材料及锻造出来的结果。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// 配方类:用来保存锻造的所需的材料及锻造出来的结果
/// </summary>
public class Formula{
public int Item1ID { get; private set; }//用来锻造的物品1的ID
public int Item1Amount { get; private set; }//用来锻造的物品1的数量
public int Item2ID { get; private set; }//用来锻造的物品2的ID
public int Item2Amount { get; private set; }//用来锻造的物品2的数量
public int ResID { get; set; }//保存锻造结果的ID
private List<int> needIDList = new List<int>();//保存锻造所需要材料的ID(相当于锻造的配方)
public List<int> NeedIDList { get { return needIDList; } }
public Formula(int item1ID, int item1Amount, int item2ID, int item2Amount, int resID )
{
this.Item1ID = item1ID;
this.Item1Amount = item1Amount;
this.Item2ID = item2ID;
this.Item2Amount = item2Amount;
this.ResID = resID;
//初始化配方ID
for (int i = 0; i < Item1Amount; i++)
{
needIDList.Add(Item1ID);
}
for (int i = 0; i < Item2Amount; i++)
{
needIDList.Add(Item2ID);
}
}
/// <summary>
/// 匹配所提供的物品是否 包含 锻造所需要的物品(利用ID匹配)
/// </summary>
/// <returns></returns>
public bool Match( List<int> idList )
{
List<int> tempIDList = new List<int>(idList);//临时保存函数参数数据(所拥有的物品ID),防止下面Remove代码移除时被修改
foreach (int id in needIDList)
{
bool isSuccess = tempIDList.Remove(id);
if (isSuccess == false)
{
return false;//拥有的物品和锻造所需的物品匹配失败
}
}
return true;//物品匹配成功
}
}
接着,重点部分就来了。正如第一部分图中那样。总的有5个面板:背包面板,箱子面板,角色面板,商店小贩面板,以及锻造面板。其中,每一个面板都有一个基类(Inventory类),因为这些面板中有一些相似的功能和方法,所以选择使用了继承。各自对应的代码如下:
①基类Inventory:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text;
/// <summary>
///存货类, 背包和箱子的基类
/// </summary>
public class Inventroy : MonoBehaviour {
protected Slot[] slotArray;//存放物品槽的数组
//控制背包的显示和隐藏相关变量
private float targetAlpha = 1f;//显示目标值
private float smothing = 4f;//渐变平滑速度
private CanvasGroup canvasGroupMy;
public CanvasGroup CanvasGroupMy //对CanvasGroup的引用,用于制作隐藏显示效果
{
get
{
if (canvasGroupMy == null)
{
canvasGroupMy = GetComponent<CanvasGroup>();
}
return canvasGroupMy;
}
}
// Use this for initialization
public virtual void Start () {//声明为虚函数,方便子类重写
slotArray = GetComponentsInChildren<Slot>();
if (canvasGroupMy == null)
{
canvasGroupMy = GetComponent<CanvasGroup>();
}
}
void Update()
{
if (this.CanvasGroupMy.alpha != targetAlpha)
{
this.CanvasGroupMy.alpha = Mathf.Lerp(this.CanvasGroupMy.alpha, targetAlpha, smothing * Time.deltaTime);
if (Mathf.Abs(this.CanvasGroupMy.alpha - targetAlpha)<.01f)
{
this.CanvasGroupMy.alpha = targetAlpha;
}
}
}
//根据Id存储物品
public bool StoreItem(int id)
{
Item item = InventroyManager.Instance.GetItemById(id);
return StoreItem(item);
}
//根据Item存储物品(重点)
public bool StoreItem(Item item)
{
if (item.ID == 0)
{
Debug.LogWarning("要存储物品的ID不存在");
return false;
}
if (item.Capacity == 1)//如果此物品只能放一个,那就找一个空的物品槽来存放即可
{
Slot slot = FindEmptySlot();
if (slot == null)//如果空的物品槽没有了
{
Debug.LogWarning("没有空的物品槽可供使用");
return false;//存储失败
}
else //空的物品槽还有,那就把物品添加进去
{
slot.StoreItem(item);
}
}
else//如果此物品能放多个
{
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()
{
foreach (Slot slot in slotArray)
{
if (slot.transform.childCount == 0)//物品槽下面无子类,说明该物品槽为空,返回它即可
{
return slot;
}
}
return null;
}
//查找存放的物品是相同的物品槽
private Slot FindSameIDSlot(Item item)
{
foreach (Slot slot in slotArray)
{
//如果当前的物品槽已经有物品了,并且里面的物品的类型和需要找的类型一样,并且物品槽还没有被填满
if (slot.transform.childCount >= 1 && item.ID == slot.GetItemID() && slot.isFiled() == false)
{
return slot;
}
}
return null;
}
//面板的显示方法
public void Show()
{
this.CanvasGroupMy.blocksRaycasts = true;//面板显示时为可交互状态
this.targetAlpha = 1;
}
//面板的隐藏方法
public void Hide()
{
this.CanvasGroupMy.blocksRaycasts = false;//面板隐藏后为不可交互状态
this.targetAlpha = 0;
}
//控制面板的显示及隐藏关系
public void DisplaySwitch()
{
if (this.CanvasGroupMy.alpha == 0)
{
Show();
}
if (this.CanvasGroupMy.alpha == 1)
{
Hide();
}
}
//控制物品信息的保存(ID,Amount数量)
public void SaveInventory()
{
StringBuilder sb = new StringBuilder();//用来保存物品信息的字符串
foreach (Slot slot in slotArray)
{
if (slot.transform.childCount > 0 )
{
ItemUI itemUI = slot.transform.GetChild(0).GetComponent<ItemUI>();
sb.Append(itemUI.Item.ID + "," + itemUI.Amount + "-");//用逗号分隔一个物品中的ID和数量,用 - 分隔多个物品
}
else
{
sb.Append("0-");//如果物品槽里没有物品就是0
}
}
PlayerPrefs.SetString(this.gameObject.name, sb.ToString());//保存字符串数据
}
//控制物品信息的加载(根据ID,Amount数量)
public void LoadInventory()
{
if (PlayerPrefs.HasKey(this.gameObject.name) == false) return;//判断保存的这个关键码Key是否存在,不存在就不做处理
string str = PlayerPrefs.GetString(this.gameObject.name);//获取上面保存的字符串数据
string[] itemArray = str.Split('-');//按照 - 分隔多个物品
for (int i = 0; i < itemArray.Length-1; i++)//长度减1是因为最后一个字符是 “-”,不需要取它
{
string itemStr = itemArray[i];
if (itemStr != "0")
{
string[] temp = itemStr.Split(',');//按照逗号分隔这个物品的信息(ID和Amoun数量)
int id = int.Parse(temp[0]);
Item item = InventroyManager.Instance.GetItemById(id);//通过物品ID得到该物品
int amount = int.Parse(temp[1]);
for (int j = 0; j < amount; j++)//执行Amount次StoreItem方法,一个一个的存
{
slotArray[i].StoreItem(item);
}
}
}
}
}
②背包面板:
using UnityEngine;
using System.Collections;
///
/// 背包类,继承自 存货类Inventroy
///
public class Knapscak : Inventroy {
//单例模式
private static Knapscak _instance;
public static Knapscak Instance {
get {
if (_instance == null)
{
_instance = GameObject.Find(“KnapscakPanel”).GetComponent();
}
return _instance;
}
}
}
③箱子面板
using UnityEngine;
using System.Collections;
/// <summary>
/// 箱子类,继承自 存货类Inventroy
/// </summary>
public class Chest : Inventroy {
//单例模式
private static Chest _instance;
public static Chest Instance
{
get
{
if (_instance == null)
{
_instance = GameObject.Find("ChestPanel").GetComponent<Chest>();
}
return _instance;
}
}
}
④角色面板
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
/// <summary>
/// 角色面板类,控制角色面板的逻辑
/// </summary>
public class CharacterPanel : Inventroy
{
//单例模式
private static CharacterPanel _instance;
public static CharacterPanel Instance
{
get
{
if (_instance == null)
{
_instance = GameObject.Find("CharacterPanel").GetComponent<CharacterPanel>();
}
return _instance;
}
}
private Text characterPropertyText;//对角色属性面板中Text组件的引用
private Player player;//对角色脚本的引用
public override void Start()
{
base.Start();
characterPropertyText = transform.Find("CharacterPropertyPanel/Text").GetComponent<Text>();
player = GameObject.FindWithTag("Player").GetComponent<Player>();
UpdatePropertyText();//初始化显示角色属性值
}
//更新角色属性显示
private void UpdatePropertyText()
{
int strength = 0, intellect = 0, agility = 0, stamina = 0, damage = 0;
foreach (EquipmentSlot slot in slotArray)//遍历角色面板中的装备物品槽
{
if (slot.transform.childCount > 0)//找到有物品的物品槽,获取里面装备的属性值
{
Item item = slot.transform.GetChild(0).GetComponent<ItemUI>().Item;
if (item is Equipment)//如果物品是装备,那就加角色对应的属性
{
Equipment e = (Equipment)item;
strength += e.Strength;
intellect += e.Intellect;
agility += e.Agility;
stamina += e.Stamina;
}
else if (item is Weapon)///如果物品是武器,那就加角色的伤害(damage)属性
{
Weapon w = (Weapon)item;
damage += w.Damage;
}
}
}
strength += player.BasicStrength;
intellect += player.BasicIntellect;
agility += player.BasicAgility;
stamina += player.BasicStamina;
damage += player.BasicDamage;
string text = string.Format("力量:{0}\n智力:{1}\n敏捷:{2}\n体力:{3}\n攻击力:{4}\n", strength, intellect, agility, stamina, damage);
characterPropertyText.text = text;
}
//直接穿戴功能(不需拖拽)
public void PutOn(Item item)
{
Item exitItem = null;//临时保存需要交换的物品
foreach (Slot slot in slotArray)//遍历角色面板中的物品槽,查找合适的的物品槽
{
EquipmentSlot equipmentSlot = (EquipmentSlot)slot;
if (equipmentSlot.IsRightItem(item)) //判断物品是否合适放置在该物品槽里
{
if (equipmentSlot.transform.childCount > 0)//判断角色面板中的物品槽合适的位置是否已经有了装备
{
ItemUI currentItemUI = equipmentSlot.transform.GetChild(0).GetComponent<ItemUI>();
exitItem = currentItemUI.Item;
currentItemUI.SetItem(item, 1);
}
else
{
equipmentSlot.StoreItem(item);
}
break;
}
}
if (exitItem != null)
{
Knapscak.Instance.StoreItem(exitItem);//把角色面板上是物品替换到背包里面
}
UpdatePropertyText();//更新显示角色属性值
}
//脱掉装备功能(不需拖拽)
public void PutOff(Item item)
{
Knapscak.Instance.StoreItem(item);//把角色面板上是物品替换到背包里面
UpdatePropertyText();//更新显示角色属性值
}
}
⑤商店小贩面板
using UnityEngine;
using System.Collections;
public class Vendor : Inventroy {
//单例模式
private static Vendor _instance;
public static Vendor Instance
{
get
{
if (_instance == null)
{
_instance = GameObject.Find("VendorPanel").GetComponent<Vendor>();
}
return _instance;
}
}
public int[] itemIdArray;//一个物品ID的数组,用于给商贩初始化
private Player player;//对主角Player脚本的引用,用于购买物品功能
public override void Start()
{
base.Start();
InitShop();
player = GameObject.FindWithTag("Player").GetComponent<Player>();
Hide();
}
//初始化商贩
private void InitShop()
{
foreach (int itemId in itemIdArray)
{
StoreItem(itemId);
}
}
//主角购买物品
public void BuyItem(Item item)
{
bool isSusscess = player.ConsumeCoin(item.BuyPrice);//主角消耗金币购买物品
if (isSusscess)
{
Knapscak.Instance.StoreItem(item);
}
}
//主角售卖物品
public void SellItem()
{
int sellAmount = 1;//销售数量
if (Input.GetKey(KeyCode.LeftControl))//按住坐标Ctrl键物品一个一个的售卖,否则全部售卖
{
sellAmount = 1;
}
else
{
sellAmount = InventroyManager.Instance.PickedItem.Amount;
}
int coinAmount = InventroyManager.Instance.PickedItem.Item.SellPrice * sellAmount;//售卖所获得的金币总数
player.EarnCoin(coinAmount);//主角赚取到售卖物品的金币
InventroyManager.Instance.ReduceAmountItem(sellAmount);//鼠标上的物品减少或者销毁
}
}
⑥锻造面板
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// 锻造类:实现材料锻造成装备或者武器
/// </summary>
public class Forge : Inventroy {
//单例模式
private static Forge _instance;
public static Forge Instance
{
get
{
if (_instance == null)
{
_instance = GameObject.Find("ForgePanel").GetComponent<Forge>();
}
return _instance;
}
}
private List<Formula> formulaList = null;//用来存放解析出来的材料
public override void Start()
{
base.Start();
ParseFormulaJSON();
Hide();
}
//解析武器锻造配方Jso文件
public void ParseFormulaJSON()
{
formulaList = new List<Formula>();
TextAsset formulaText = Resources.Load<TextAsset>("Formulas");
string formulaJson = formulaText.text;
JSONObject jo = new JSONObject(formulaJson);
foreach (JSONObject temp in jo.list)
{
int item1ID = (int)temp["Item1ID"].n;
int item1Amount = (int)temp["Item1Amount"].n;
int item2ID = (int)temp["Item2ID"].n;
int item2Amount = (int)temp["Item2Amount"].n;
int resID = (int)temp["ResID"].n;
Formula formula = new Formula(item1ID, item1Amount, item2ID, item2Amount, resID);
formulaList.Add(formula);
}
//Debug.Log(formulaList[1].ResID);
}
/// <summary>
/// 锻造物品功能:重点
/// </summary>
public void ForgeItem()
{
//得到当前锻造面板里面有哪些材料
List<int> haveMaterialIDList = new List<int>();//存储当前锻造面板里面拥有的材料的ID
foreach (Slot slot in slotArray)
{
if (slot.transform.childCount > 0)
{
ItemUI currentItemUI = slot.transform.GetChild(0).GetComponent<ItemUI>();
for (int i = 0; i < currentItemUI.Amount; i++)
{
haveMaterialIDList.Add(currentItemUI.Item.ID);//物品槽里有多少个物品,就存储多少个ID
}
}
}
//Debug.Log(haveMaterialIDList[0].ToString());
//判断满足哪一个锻造配方的需求
Formula matchedFormula = null;
foreach (Formula formula in formulaList)
{
bool isMatch = formula.Match(haveMaterialIDList);
//Debug.Log(isMatch);
if (isMatch)
{
matchedFormula = formula;
break;
}
}
// Debug.Log(matchedFormula.ResID);
if (matchedFormula != null)
{
Knapscak.Instance.StoreItem(matchedFormula.ResID);//把锻造出来的物品放入背包
//减掉消耗的材料
foreach (int id in matchedFormula.NeedIDList)
{
foreach (Slot slot in slotArray)
{
if (slot.transform.childCount > 0)
{
ItemUI itemUI = slot.transform.GetChild(0).GetComponent<ItemUI>();
if (itemUI.Item.ID == id && itemUI.Amount > 0)
{
itemUI.RemoveItemAmount();
if (itemUI.Amount <= 0)
{
DestroyImmediate(itemUI.gameObject);
}
break;
}
}
}
}
}
}
}