在前面的文章中我介绍了背包系统的Json生成与解析、UI的设计
在本文介绍整个背包制作流程,由于背包系统制作涉及挺多内容,大家如果想了解透,建议下载本文工程源码点击打开链接
【开发物品类及其子类】
物品类(KnapsackGood)是一切物品的基类
其中物品分为消耗物品(Consumable)、装备物品(Equitment)、武器物品(Weapon)、材料物品(Material)都继承自物品类(KnapsackGood)
KnapsackGood.cs
using UnityEngine;
using System.Collections;
///
/// 物品共有属性类
///
public class BaseProperty
{
public int ID { get; set; }
public string name { get; set; }
public string description { get; set; }
public int capacity { get; set; }
public int buyPrice { get; set; }
public int sellPrice { get; set; }
public string sprite { get; set; }
public KnapsackGood.GoodType goodType { get; set; }
public KnapsackGood.GoodQuality goodQuality { get; set; }
public BaseProperty()
{}
public BaseProperty(int ID, string name, string description, int capacity, int buyPrice, int sellPrice, string sprite, KnapsackGood.GoodType goodType, KnapsackGood.GoodQuality goodQuality)
{
this.ID = ID;
this.name = name;
this.description = description;
this.capacity=capacity;
this.buyPrice = buyPrice;
this.sellPrice = sellPrice;
this.sprite = sprite;
this.goodType = goodType;
this.goodQuality = goodQuality;
}
}
///
/// 物品基类
///
public class KnapsackGood
{
public BaseProperty goodProperty { get; set; }
public KnapsackGood()
{
}
public KnapsackGood(BaseProperty goodProperty)
{
this.goodProperty = goodProperty;
}
///
/// 物品类型
///
public enum GoodType
{
Consumable, //消耗品
Equipment, //装备
Weapon, //武器
Meterial //材料
}
///
/// 物品品质
///
public enum GoodQuality
{
Common, //普通
Uncommon, //不普通
Rare, //稀有
Epic, //史诗
Legendary //传奇
}
public virtual string GetDescribe()
{
string color = "";
switch (goodProperty.goodQuality)
{
case KnapsackGood.GoodQuality.Common:
color = "white";
break;
case KnapsackGood.GoodQuality.Epic:
color = "lime";
break;
case KnapsackGood.GoodQuality.Legendary:
color = "navy";
break;
case KnapsackGood.GoodQuality.Rare:
color = "magenta";
break;
case KnapsackGood.GoodQuality.Uncommon:
color = "orange";
break;
default:
break;
}
string describe = string.Format("{1} \n购买价格:{2} 出售价格:{3} \n{4} ", color, goodProperty.name, goodProperty.buyPrice, goodProperty.sellPrice, goodProperty.description);
return describe;
}
}
【创建KnapsackManager(面板与物品之间的媒介)】
KnapsackManager这个类管理面板背包面板与物品,相当于面板与物品之间的媒介,方便管理
using UnityEngine;
using System.Collections;
using UnityEditor;
using LitJson;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System;
public class KnapsackManager : MonoBehaviour
{
private static KnapsackManager _instance;
public static KnapsackManager GetInstance
{
get
{
if (_instance == null)
{
_instance = GameObject.Find("Camera").GetComponent();
}
return _instance;
}
}
private bool isShowToolTilePanel = false;
public GameObject pickGood;
public GoodUI GetPickGoodUI
{
get
{
return pickGood.GetComponent();
}
}
public Vector3 GetPickGoodLocalPos
{
get
{
return pickGood.transform.localPosition;
}
}
public bool isPickGood = false;
///
/// 存储多个物品对象(从json解析过来)
///
private List goodList;
void Awake()
{
ParseGoodsJson();
}
private GameObject toolTilePanel;
private GameObject canvase;
// Use this for initialization
void Start ()
{
toolTilePanel = GameObject.Find("ToolTilePanel");
canvase = GameObject.Find("Canvas");
pickGood = GameObject.Find("PickGoodUI");
}
// Update is called once per frame
void Update ()
{
if (isPickGood)
{
Vector2 point = Vector2.zero;
//该函数是将屏幕坐标转化以第一个参数对象的子节点坐标
//参数一:需要转换的坐标以该对象作为父节点
//参数二:鼠标点
//参数三:参数一对象以哪个摄像机渲染(由于该参数一画布没有相机渲染,故为null)
//参数四:返回一个需要转换的目标点
RectTransformUtility.ScreenPointToLocalPointInRectangle(canvase.GetComponent
【创建面板类Inventory】
面板类管理面板中各个物品槽,当存储物品是,寻找合适的物品槽并且管理将物品存储到该物品槽内,并且控制面板的显示和隐藏
Inventory.cs
using UnityEngine;
using System.Collections;
public class Inventory : MonoBehaviour
{
public Slot[] slotList;
///
/// 控制面板的透明度从而控制显示或隐藏
///
private float targetAlpha=1;
private CanvasGroup cg;
private float lerpSpeed=2.0f;
protected virtual void Start()
{
slotList = this.GetComponentsInChildren();
cg = this.GetComponent();
}
void Update()
{
if (targetAlpha != this.cg.alpha)
{
this.cg.alpha = Mathf.Lerp(this.cg.alpha, targetAlpha, lerpSpeed * Time.deltaTime);
if (Mathf.Abs(this.cg.alpha - targetAlpha) <= 0.01f)
{
this.cg.alpha = targetAlpha;
}
}
}
public bool StoreGood(int ID)
{
KnapsackGood good = KnapsackManager.GetInstance.GetGoodWithID(ID);
return StoreGood(good);
}
public bool StoreGood(KnapsackGood good)
{
if (good == null)
{
Debug.Log("需要存储的物品为空");
return false;
}
if (good.goodProperty.capacity == 1)//如果该物品在物品槽中只能存放一个
{//直接找到一个还没有使用的物品槽
Slot slot = FindEmptySlot();
if (slot != null)//如果找到了空的物品槽,那么将该物品发进去
{
slot.StoreGood(good);
}
else//如果没有找到,则将说明背包以满
{
Debug.Log("没有找到空的物品槽,可能是背包以满");
return false;
}
}
else
{//先寻找是否已经有存放了该物品的物品槽
Slot slot = FindFreeSlot(good.goodProperty.ID);
if (slot != null)
{
slot.StoreGood(good);
}
else
{
Slot s = FindEmptySlot();
if (s != null)
{
s.StoreGood(good);
}
else
{
Debug.Log("没有找到空的物品槽,可能是背包以满");
return false;
}
}
}
return true; ;
}
///
/// 根据ID寻找存储了该物品的物品槽
///
///
private Slot FindFreeSlot(int ID)
{
foreach (Slot s in slotList)
{
if (s.transform.childCount > 0 && s.GetGoodID() == ID&&s.IsFill()==false)
{
return s;
}
}
return null;
}
private Slot FindEmptySlot()
{
foreach (Slot s in slotList)
{
//还没有存放物品的物品槽中也没有添加GoodUI,根据该物品槽中是否有子节点这个线索来判断是否存放物品
if (s.transform.childCount == 0||s.transform.gameObject.activeInHierarchy==false)
{
return s;
}
}
//没有找到空的物品槽,说明背包以满
return null;
}
public void ShowPanel()
{
targetAlpha = 1;
this.cg.blocksRaycasts = true;
}
public void HidePanel()
{
targetAlpha = 0;
this.cg.blocksRaycasts = false;
}
}
using UnityEngine;
using System.Collections;
public class KnapsackPanel : Inventory
{
private static KnapsackPanel _instance;
public static KnapsackPanel GetInstance
{
get
{
if (_instance == null)
{
_instance = GameObject.Find("KnapsackPanel").GetComponent();
}
return _instance;
}
}
}
【创建物品槽类】
物品槽类控制显示物品UI,提示面板的显示和隐藏
该类是挂载到物品槽上
using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using System;
public class Slot : MonoBehaviour ,IPointerEnterHandler,IPointerExitHandler,IPointerDownHandler
{
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
}
public int GetGoodID()
{
if (this.transform.childCount == 0)
{
return -1;
}
GoodUI gu = this.transform.GetChild(0).GetComponent();
return gu.good.goodProperty.ID;
}
public bool IsFill()
{
GoodUI gu = this.transform.GetChild(0).GetComponent();
return gu.good.goodProperty.capacity <= gu.amount;//物品的容量小于物品当前的数量
}
public GameObject goodPrefab;
public void StoreGood(KnapsackGood good,int amount=1)
{
if (this.transform.childCount == 0)//如果该物品槽为空,则在这物品槽里新建一个GoodUI
{
GameObject obj = GameObject.Instantiate(goodPrefab);
obj.transform.SetParent(this.transform);
obj.transform.localPosition = Vector3.zero;
obj.transform.localScale = Vector3.one;
obj.GetComponent().SetGood(good,amount);
}
else
{
if (this.transform.GetChild(0).gameObject.activeInHierarchy == false)
{
this.transform.GetChild(0).GetComponent().Show();
this.transform.GetChild(0).GetComponent().SetGood(good,amount);
}
else
{
this.transform.GetChild(0).GetComponent().AddGood();
}
}
}
public void OnPointerEnter(PointerEventData eventData)
{
Debug.Log("鼠标进入物品槽");
if (this.transform.childCount > 0)
{
//获得描述文本
string text = this.transform.GetChild(0).GetComponent().good.GetDescribe();
KnapsackManager.GetInstance.ShowToolTilePanel(text);
}
}
public void OnPointerExit(PointerEventData eventData)
{
if (this.transform.childCount > 0)
{
KnapsackManager.GetInstance.HideToolTilePanel();
}
}
///
/// 鼠标抬下
///
/// **************************方法说明*************************************
/// *//物品槽里没有物品 *
/// * //1.IsPickGood=true 将PickGood里的物品放置到该物品槽内 *
/// * //2.IsPickGood=false 不做任何处理 *
/// *//物品槽里存在物品 *
/// * //1.IsPickGood=true 将该物品槽的物品替换PickGood里的物品 *
/// * //2.IsPickGood=false 将该物品槽的物品放置在PickGood里 *
/// ***********************************************************************
///
///
public virtual void OnPointerDown(PointerEventData eventData)
{
if (this.transform.childCount == 0 || this.transform.GetChild(0).gameObject.activeInHierarchy == false)
{
if (KnapsackManager.GetInstance.isPickGood)
{
Debug.Log(KnapsackManager.GetInstance.GetPickGoodUI.amount);
StoreGood(KnapsackManager.GetInstance.GetPickGoodUI.good, KnapsackManager.GetInstance.GetPickGoodUI.amount);
KnapsackManager.GetInstance.GetPickGoodUI.SetLocalPosition(new Vector3(-420,2,0));//将pickGoodUI位置归零
KnapsackManager.GetInstance.isPickGood = false;
}
else
{
//无需做处理
}
}
else
{
if (KnapsackManager.GetInstance.isPickGood)
{
StorageSlot.slot.StoreGood(this.transform.GetChild(0).GetComponent().good, this.transform.GetChild(0).GetComponent().amount);
//this.transform.GetChild(0).GetComponent().Exchange(Slot.GetInstance.transform.GetChild(0).GetComponent());
//StoreGood(KnapsackManager.GetInstance.GetPickGoodUI.good, KnapsackManager.GetInstance.GetPickGoodUI.amount);
this.transform.GetChild(0).GetComponent().SetGood(KnapsackManager.GetInstance.GetPickGoodUI.good, KnapsackManager.GetInstance.GetPickGoodUI.amount);
KnapsackManager.GetInstance.GetPickGoodUI.SetLocalPosition(new Vector3(-420, 2, 0));//将pickGoodUI位置归零
KnapsackManager.GetInstance.isPickGood = false;
}
else
{
StorageSlot.slot = this;
KnapsackManager.GetInstance.GetPickGoodUI.ReplaceGoodUI(transform.GetChild(0).GetComponent());
KnapsackManager.GetInstance.isPickGood = true;
//将自身物品槽的UI销毁
Destroy(this.transform.GetChild(0).gameObject);
}
}
}
}
该类挂载在物品槽的子对象上
控制物品现在在物品槽内
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class GoodUI : MonoBehaviour
{
public KnapsackGood good { get; private set; }//物品槽中存放的物品
public int amount { get; private set; }//物品槽存放物品的数量
private Image GoodUIImage
{
get
{
return this.transform.GetComponent();
}
}
private Text GoodUIText
{
get
{
return this.transform.GetComponentInChildren();
}
}
public void SetGood(KnapsackGood good, int amount = 1)
{
this.good = good;
this.amount = amount;
GoodUIImage.sprite = Resources.Load(good.goodProperty.sprite);
if (good.goodProperty.capacity > 1)
{
GoodUIText.text = this.amount.ToString();
}
else
{
GoodUIText.text = "";
}
}
public void AddGood(int amount = 1)
{
this.amount += amount;
if (good.goodProperty.capacity > 1)
{
GoodUIText.text = this.amount.ToString();
}
else
{
GoodUIText.text = "";
}
}
public void ReplaceGoodUI(GoodUI gu)
{
this.good = gu.good;
this.amount = gu.amount;
Debug.Log(gu.amount);
SetGood(this.good, this.amount);
}
public void Exchange(GoodUI gu)
{
KnapsackGood tempGood = gu.good;
int tempAmount = gu.amount;
gu.SetGood(good, amount);
this.SetGood(tempGood, tempAmount);
}
public void SetLocalPosition(Vector3 point)
{
this.transform.localPosition = point;
}
public void Show()
{
this.gameObject.SetActive(true);
}
public void Hide()
{
this.gameObject.SetActive(false);
}
}
【测试】
创建一个UserPlaying.cs来测试代码
using UnityEngine;
using System.Collections;
public class UserPlaying : MonoBehaviour
{
// Update is called once per frame
void Update ()
{
if (Input.GetKeyUp(KeyCode.G))
{
int rand = Random.Range(1,8);
KnapsackPanel.GetInstance.StoreGood(rand);
}
}
}
按下G键,发现随机生成了物品并显示在物品槽中
建议大家下载我的源码学习,这样有助于理解,源码中也写了角色背包,角色面板的角色物品槽处理和背包不尽相同,大体差不多
好了,背包系统介绍到这里,有什么问题可以和我联系,就这样吧!!!
总结:
在这里我着重介绍两个知识点:
一.RectTransformUtility.ScreenPointToLocalPointInRectangle函数的使用
//该函数是将屏幕坐标转化以第一个参数对象的子节点坐标
//参数一:需要转换的坐标以该对象作为父节点
//参数二:鼠标点
//参数三:参数一对象以哪个摄像机渲染(由于该参数一画布没有相机渲染,故为null)
//参数四:返回一个需要转换的目标点
RectTransformUtility.ScreenPointToLocalPointInRectangle(canvase.GetComponent().transform as RectTransform,Input.mousePosition,null, out point);
以上接口的实现函数分别在鼠标移入该对象、移除该对象、点击该对象时触发调用
其中会传进一个参数UnityEngine.EventSystems.PointerEventData eventData
可以根据这个参数,解析你需要的事件
比如:
if (eventData.button != PointerEventData.InputButton.Left)
{
return;
}
本人也在寻找一份游戏开发实习工作,如果大佬们需要开发人员,请把我带走
这是我的简历:resume.liujunliang.com.cn/resume.pdf
作品的话可以私聊我哦!