②物品槽基类(Slot):重点实现了物品槽里物品的各个交互功能
using UnityEngine; using System.Collections; using UnityEngine.EventSystems; /// <summary> /// 物品槽类 /// </summary> public class Slot : MonoBehaviour,IPointerEnterHandler,IPointerExitHandler,IPointerDownHandler{ public GameObject itemPrefab;//需要存储的物品预设 /// <summary> ///(重点) 向物品槽中添加(存储)物品,如果自身下面已经有Item了,那就Item.amount++; /// 如果没有,那就根据ItemPrefab去实例化一个Item,放在其下面 /// </summary> public void StoreItem(Item item) { if (this.transform.childCount == 0)//如果这个物品槽下没有物品,那就实例化一个物品 { GameObject itemGO = Instantiate<GameObject>(itemPrefab) as GameObject; itemGO.transform.SetParent(this.transform);//设置物品为物品槽的子物体 itemGO.transform.localScale = Vector3.one;//正确保存物品的缩放比例 itemGO.transform.localPosition = Vector3.zero;//设置物品的局部坐标,为了与其父亲物品槽相对应 itemGO.GetComponent<ItemUI>().SetItem(item);//更新ItemUI } else { transform.GetChild(0).GetComponent<ItemUI>().AddItemAmount();//默认添加一个 } } //根据索引器得到当前物品槽中的物品类型 public Item.ItemType GetItemType() { return transform.GetChild(0).GetComponent<ItemUI>().Item.Type; } //根据索引器得到当前物品槽中的物品ID public int GetItemID() { return transform.GetChild(0).GetComponent<ItemUI>().Item.ID; } //判断物品个数是否超过物品槽的容量Capacity public bool isFiled() { ItemUI itemUI = transform.GetChild(0).GetComponent<ItemUI>(); return itemUI.Amount >= itemUI.Item.Capacity; //true表示当前数量大于等于容量,false表示当前数量小于容量 } //接口实现的方法,鼠标覆盖时触发 public void OnPointerEnter(PointerEventData eventData) { if (this.transform.childCount > 0) { string toolTipText = this.transform.GetChild(0).GetComponent<ItemUI>().Item.GetToolTipText(); InventroyManager.Instance.ShowToolTip(toolTipText);//显示提示框 } } //接口实现的方法,鼠标离开时触发 public void OnPointerExit(PointerEventData eventData) { if (this.transform.childCount > 0) { InventroyManager.Instance.HideToolTip();//隐藏提示框 } } public virtual void OnPointerDown(PointerEventData eventData)//为虚函数,方便子类EquipmentSlot重写 { if (eventData.button == PointerEventData.InputButton.Right)//鼠标右键点击直接实现穿戴,不经过拖拽 { if (transform.childCount > 0 && InventroyManager.Instance.IsPickedItem == false)//需要穿戴的物品得有,并且鼠标上要没有物品,否则就发生:当鼠标上有物品,在其他物品上点击鼠标右键也能穿上这种情况。 { ItemUI currentItemUI = transform.GetChild(0).GetComponent<ItemUI>(); if (currentItemUI.Item is Equipment || currentItemUI.Item is Weapon)//只有装备和物品才可以穿戴 { Item currentItem = currentItemUI.Item;//临时存储物品信息,防止物品UI销毁导致物品空指针 currentItemUI.RemoveItemAmount(1);//当前物品槽中的物品减少1个 if (currentItemUI.Amount <= 0)//物品槽中的物品没有了 { DestroyImmediate(currentItemUI.gameObject);//立即销毁物品槽中的物品 InventroyManager.Instance.HideToolTip();//隐藏该物品的提示框 } CharacterPanel.Instance.PutOn(currentItem);//直接穿戴 } } } if (eventData.button != PointerEventData.InputButton.Left) return; //只有鼠标左键能够点击物品拖拽 //情况分析如下: //一:自身是空 ///1.pickedItem != null(即IsPickedItem == true),pickedItem放在这个位置 ////①按下Ctrl键,放置当前鼠标上的物品的一个 ////②没有按下Ctrl键,放置当前鼠标上物品的所有 ///2.pickedItem==null(即IsPickedItem == false),不做任何处理 //二:自身不是空 ///1.pickedItem != null(即 IsPickedItem == true) ////①自身的id == pickedItem.id //////A.按下Ctrl键,放置当前鼠标上的物品的一个 //////B.没有按下Ctrl键,放置当前鼠标上物品的所有 ///////a.可以完全放下 ///////b.只能放下其中一部分 ////②自身的id != pickedItem.id,pickedItem跟当前物品交换 ///2.pickedItem == null(即IsPickedItem == false) ////①按下Ctrl键,取得当前物品槽中物品的一半 ////②没有按下Ctrl键,把当前物品槽里面的物品放到鼠标上 if (transform.childCount > 0) //二:自身不是空 { ItemUI currentItem = transform.GetChild(0).GetComponent<ItemUI>();//取得当前的物品 if (InventroyManager.Instance.IsPickedItem == false)///2.pickedItem == null。如果当前没有选中任何物品,即当前鼠标上没有物品 { if (Input.GetKey(KeyCode.LeftControl))////①按下Ctrl键,取得当前物品槽中物品的一半 { int amountPicked = (currentItem.Amount + 1) / 2;//如果物品为偶数就拾取刚好一般,如果为奇数就拾取一半多一个 InventroyManager.Instance.PickUpItem(currentItem.Item, amountPicked); int amountRemained = currentItem.Amount - amountPicked;//拾取后剩余的物品个数 if (amountRemained<=0)//如果物品槽中没有剩余的物品了,就销毁ItemUI { Destroy(currentItem.gameObject); } else//如果物品槽中还有剩余的物品,就让它的数量减去被拾取的数量 { currentItem.SetAmount(amountRemained); } } else ////②没有按下Ctrl键,把当前物品槽里面的物品放到鼠标上 { //InventroyManager.Instance.PickedItem.SetItemUI(currentItem);//把当前物品槽里的物品复制给PickedItem(跟随鼠标移动) //InventroyManager.Instance.IsPickedItem = true;//注释的这两句合并为下面的一句 InventroyManager.Instance.PickUpItem(currentItem.Item, currentItem.Amount); Destroy(currentItem.gameObject);//复制完之后销毁当前物品槽中的物品 } } else { ///1.pickedItem != null(即 IsPickedItem == true) ////①自身的id == pickedItem.id //////A.按下Ctrl键,放置当前鼠标上的物品的一个 //////B.没有按下Ctrl键,放置当前鼠标上物品的所有 ///////a.可以完全放下 ///////b.只能放下其中一部分 ////②自身的id != pickedItem.id,pickedItem跟当前物品交换 if (currentItem.Item.ID == InventroyManager.Instance.PickedItem.Item.ID) { if (Input.GetKey(KeyCode.LeftControl)) { if (currentItem.Item.Capacity > currentItem.Amount)//如果物品槽里的物品容量大于当前物品数量,那就说明物品槽里还能再放 { currentItem.AddItemAmount();//增加物品槽中物品数量 InventroyManager.Instance.ReduceAmountItem();//让鼠标上的物品减掉一个(默认移除一个) } else//如果物品槽里的物品容量小于当前物品数量,那就说明物品槽里不能再放了 { return; } } else { if (currentItem.Item.Capacity > currentItem.Amount)//如果物品槽里的物品容量大于当前物品数量,那就说明物品槽里还能再放 { int itemRemain = currentItem.Item.Capacity - currentItem.Amount;//物品槽还可以再放的数量 if (itemRemain >= InventroyManager.Instance.PickedItem.Amount)//如果物品槽还可以再放的数量大于等于鼠标上的数量, 那就可以完全放下 { currentItem.AddItemAmount(InventroyManager.Instance.PickedItem.Amount); InventroyManager.Instance.ReduceAmountItem(itemRemain); } else//只能放下其中一部分 { currentItem.AddItemAmount(itemRemain); InventroyManager.Instance.PickedItem.RemoveItemAmount(itemRemain); } } else//如果物品槽里的物品容量小于当前物品数量,那就说明物品槽里不能再放了 { return; } } } else//②自身的id != pickedItem.id,pickedItem跟当前物品交换 { //保存当前鼠标捡起物品,用于和物品槽中的物品交换 Item pickedItemTemp = InventroyManager.Instance.PickedItem.Item; int pickedItemAmountTemp = InventroyManager.Instance.PickedItem.Amount; //保存当前物品槽中的物品,用于和鼠标上的物品交换 Item currentItemTemp = currentItem.Item; int currentItemAmountTemp = currentItem.Amount; //两者交换 currentItem.SetItem(pickedItemTemp, pickedItemAmountTemp);//把当前鼠标上的物品放入物品槽 InventroyManager.Instance.PickedItem.SetItem(currentItemTemp, currentItemAmountTemp);//把当前物品槽中的物品放在鼠标上 } } } else//一:自身是空 { ///1.pickedItem != null(即IsPickedItem == true),pickedItem放在这个位置 ////①按下Ctrl键,放置当前鼠标上的物品的一个 ////②没有按下Ctrl键,放置当前鼠标上物品的所有 ///2.pickedItem==null(即IsPickedItem == false),不做任何处理 if (InventroyManager.Instance.IsPickedItem == true) { if (Input.GetKey(KeyCode.LeftControl)) { this.StoreItem(InventroyManager.Instance.PickedItem.Item); InventroyManager.Instance.ReduceAmountItem(); } else//②没有按下Ctrl键,放置当前鼠标上物品的所有 { for(int i = 0 ; i<InventroyManager.Instance.PickedItem.Amount ; i++) { this.StoreItem(InventroyManager.Instance.PickedItem.Item); } InventroyManager.Instance.ReduceAmountItem(InventroyManager.Instance.PickedItem.Amount); } } else { return; } } } }③处理角色面板的物品槽类(EquipmentSlot),继承自Slot类:
using UnityEngine; using System.Collections; using UnityEngine.EventSystems; /// <summary> /// 处理角色面板上的装备物品槽类(有特殊限制的Slot:只能存放装备),不同格子只能存放这个格子应该有的装备。 /// </summary> public class EquipmentSlot :Slot { public Equipment.EquipmentType equipmentSoltType;//角色装备里每个物品槽的物品类型。因为每个物品槽能装备的物品类型不同,所以才分类型,比如说,头部只能放头部,腿部只能放腿部之类的。主手只能放武器。 public Weapon.WeaponType wpType;//武器类型,只有副手和主手能有武器,其他为Null public override void OnPointerDown(UnityEngine.EventSystems.PointerEventData eventData)//重写父类Slot的方法 { if (eventData.button == PointerEventData.InputButton.Right)//鼠标右键点击直接实现脱掉,不经过拖拽 { if (transform.childCount > 0 && InventroyManager.Instance.IsPickedItem == false)//需要脱掉的物品得有,并且鼠标上要没有物品,否则就发生:当鼠标上有物品,在其他物品上点击鼠标右键也能脱掉这种情况。 { ItemUI currentItemUI = transform.GetChild(0).GetComponent<ItemUI>(); Item item = currentItemUI.Item;//临时保存物品信息,防止下面一销毁就没了 DestroyImmediate(currentItemUI.gameObject);//立即销毁物品槽中的物品 transform.parent.SendMessage("PutOff", item);//脱掉物品放入背包里(发送消息方式) InventroyManager.Instance.HideToolTip();//隐藏该物品的提示框 } } if (eventData.button != PointerEventData.InputButton.Left) return; //只有鼠标左键能够点击物品拖动 //情况分析: //一:鼠标上有物品 //1.当前装备槽有装备 //2.当前装备槽无装备 //二:鼠标上没有物品 //1.当前装备槽有装备 //2.当前装备槽无装备(不做任何处理) bool isUpdataProperty = false;//是否需要更新角色属性 if (InventroyManager.Instance.IsPickedItem == true)//一:鼠标上有物品 { ItemUI pickedItemUI = InventroyManager.Instance.PickedItem;//鼠标上的物品 if (transform.childCount > 0)//1.当前装备槽有装备 { ItemUI currentItemUI = transform.GetChild(0).GetComponent<ItemUI>();//当前物品槽中的物品 if (IsRightItem(pickedItemUI.Item) && pickedItemUI.Amount == 1)//如果鼠标上的物品是否适合放在该位置并且鼠标上的物品只有一个时,那就交换,否则不做处理 { pickedItemUI.Exchange(currentItemUI); isUpdataProperty = true;//需要更新角色属性 } } else//2.当前装备槽无装备 { if (IsRightItem(pickedItemUI.Item))//如果鼠标上的物品是否适合放在该位置,那就把该物品放入角色面板,并且鼠标上的物品减少一个,否则不做处理 { this.StoreItem(pickedItemUI.Item); InventroyManager.Instance.ReduceAmountItem(1); isUpdataProperty = true;//需要更新角色属性 } } } else//二:鼠标上没有物品 { if (transform.childCount>0) //1.当前装备槽有装备,把装备去到鼠标上,销毁物品槽中的物品 { ItemUI currentItemUI = transform.GetChild(0).GetComponent<ItemUI>(); InventroyManager.Instance.PickUpItem(currentItemUI.Item, currentItemUI.Amount); Destroy(currentItemUI.gameObject); isUpdataProperty = true;//需要更新角色属性 } //2.当前装备槽无装备(不做任何处理) } if (isUpdataProperty == true) { transform.parent.SendMessage("UpdatePropertyText"); } } //判断鼠标上的物品是否适合放在该位置 public bool IsRightItem(Item item) { if ((item is Equipment && ((Equipment)(item)).EquipType == this.equipmentSoltType) || (item is Weapon && ((Weapon)(item)).WpType == this.wpType))//如果此物品是装备并且此物品的装备类型和当前物品槽中的装备类型相同 或者 此物品是武器并且此武器的类型和当前物品槽中的武器类型相同,那就可以合适放在该位置,否则不合适。 { return true; } else { return false; } } }④处理商店购买物品面板的物品槽类(VendorSlot),同样继承自Slot类:
using UnityEngine; using System.Collections; public class VendorSlot : Slot { //重写父类Slot的鼠标点击方法,但是什么都不用做,因为不需要交互,商贩只管卖物品 public override void OnPointerDown(UnityEngine.EventSystems.PointerEventData eventData) { if (eventData.button == UnityEngine.EventSystems.PointerEventData.InputButton.Right)//在商贩那里点击右键直接购买物品 { if (transform.childCount > 0 && InventroyManager.Instance.IsPickedItem == false)//首先商贩得有物品,其次鼠标上没有物品 { Item currentItem = transform.GetChild(0).GetComponent<ItemUI>().Item;//取得当前点击的要买的物品 transform.parent.parent.SendMessage("BuyItem",currentItem); } } else if (eventData.button == UnityEngine.EventSystems.PointerEventData.InputButton.Left && InventroyManager.Instance.IsPickedItem == true)//在背包鼠标左键拖动售卖物品 { transform.parent.parent.SendMessage("SellItem"); } } }⑤物品UI处理类(ItemUI):
using UnityEngine; using System.Collections; using UnityEngine.UI; public class ItemUI : MonoBehaviour { public Item Item { get; private set; } //UI上的物品 public int Amount { get; private set; }//物品数量 private Image itemImage;//获取item的Image组件 private Text amountText;//获取item下子物体用于显示数量的组件 private float targetScale = 1f;//目标缩放大小 private Vector3 animationScale = new Vector3(1.4f, 1.4f, 1.4f); private float smothing = 4f;//动画平滑过渡时间 void Awake() //可用 属性get方式替代 { itemImage = this.GetComponent<Image>(); amountText = this.GetComponentInChildren<Text>(); } void Update() { if (this.transform.localScale.x != targetScale)//设置物品动画 { float scaleTemp = Mathf.Lerp(this.transform.localScale.x, targetScale, smothing*Time.deltaTime); this.transform.localScale = new Vector3(scaleTemp, scaleTemp, scaleTemp); if (Mathf.Abs(transform.localScale.x-targetScale) < 0.02f)//插值运算达不到临界值,比较耗性能,加上临界值判断能更好的控制 { this.transform.localScale = new Vector3(targetScale, targetScale, targetScale); } } } /// <summary> ///更新item的UI显示,默认数量为1个 /// </summary> /// <param name="item"></param> public void SetItem(Item item, int amount = 1) { this.transform.localScale = this.animationScale;//物品更新时放大UI,用于动画 this.Item = item; this.Amount = amount; this.itemImage.sprite = Resources.Load<Sprite>(item.Sprite); //更新UI if (this.Amount > 1) { this.amountText.text = Amount.ToString(); } else { this.amountText.text = ""; } } /// <summary> /// 添加item数量 /// </summary> /// <param name="num"></param> public void AddItemAmount(int num = 1) { this.transform.localScale = this.animationScale;//物品更新时放大UI,用于动画 this.Amount += num; if (this.Amount> 1)//更新UI { this.amountText.text = Amount.ToString(); } else { this.amountText.text = ""; } } //设置item的个数 public void SetAmount(int amount) { this.transform.localScale = this.animationScale;//物品更新时放大UI,用于动画 this.Amount = amount; if (this.Amount > 1)//更新UI { this.amountText.text = Amount.ToString(); } else { this.amountText.text = ""; } } //减少物品数量 public void RemoveItemAmount(int amount = 1) { this.transform.localScale = this.animationScale;//物品更新时放大UI,用于动画 this.Amount -= amount; if (this.Amount > 1)//更新UI { this.amountText.text = Amount.ToString(); } else { this.amountText.text = ""; } } //显示方法 public void Show() { gameObject.SetActive(true); } //隐藏方法 public void Hide() { gameObject.SetActive(false); } //设置位置方法 public void SetLocalPosition(Vector3 position) { this.transform.localPosition = position; } //当前物品(UI)和 出入物品(UI)交换显示 public void Exchange(ItemUI itemUI) { Item itemTemp = itemUI.Item; int amountTemp = itemUI.Amount; itemUI.SetItem(this.Item, this.Amount); this.SetItem(itemTemp, amountTemp); } }⑥信息提示框类(ToolTip),处理提示框的各种功能:
using UnityEngine; using System.Collections; using UnityEngine.UI; /// <summary> /// 提示框类 /// </summary> public class ToolTip : MonoBehaviour { private Text toolTipText;//提示框的父Text,主要用来控制提示框的大小 private Text contentText;//提示框的子Text,主要用来显示提示 private CanvasGroup toolTipCanvasGroup;//提示框的CanvasGroup组件,用来制作显示和隐藏功能 private float targetAlpha = 0.0f ;//设置提示框的Alpha值,0代表隐藏,1代表显示 public float smothing = 1.0f;//用于显示和隐藏的插值运输 void Awake() { toolTipText = this.GetComponent<Text>(); contentText = this.transform.Find("Content").GetComponent<Text>(); toolTipCanvasGroup = this.GetComponent<CanvasGroup>(); } // Update is called once per frame void Update () { if (toolTipCanvasGroup.alpha != targetAlpha) { toolTipCanvasGroup.alpha = Mathf.Lerp(toolTipCanvasGroup.alpha, targetAlpha, smothing*Time.deltaTime); if (Mathf.Abs(targetAlpha - toolTipCanvasGroup.alpha) < 0.01f)//如果当前提示框的Alpha值与目标Alpha值相差很小,那就设置为目表值 { toolTipCanvasGroup.alpha = targetAlpha; } } } //提示框的显示方法 public void Show(string text) { this.toolTipText.text = text; this.contentText.text = text; this.targetAlpha = 1; } //提示框的隐藏方法 public void Hide() { this.targetAlpha = 0; } //设置提示框自身的位置 public void SetLocalPosition(Vector3 postion) { this.transform.localPosition = postion; } }⑦模拟主角行为类(Player):
using UnityEngine; using System.Collections; using UnityEngine.UI; /// <summary> /// 模拟主角类 /// </summary> public class Player : MonoBehaviour { //角色基本属性: private int basicStrength = 10; public int BasicStrength { get { return basicStrength;} }//基本力量 private int basicIntellect = 10; public int BasicIntellect { get { return basicIntellect; } }//基本智力 private int basicAgility = 10; public int BasicAgility { get { return basicAgility; } }//基本敏捷 private int basicStamina = 10; public int BasicStamina { get { return basicStamina; } }//基本体力 private int basicDamage = 10; public int BasicDamage { get { return basicDamage; } }//基本伤害 private Text coinText;//对金币Text组件的引用 private int coinAmount = 100;//角色所持有的金币,用于从商贩那里购买物品 public int CoinAmount { get { return coinAmount; } set { coinAmount = value; coinText.text = coinAmount.ToString(); } } // Use this for initialization void Start () { coinText = GameObject.Find("Coin").GetComponentInChildren<Text>(); coinText.text = coinAmount.ToString(); } // Update is called once per frame void Update () { //按G键随机得到一个物品 if (Input.GetKeyDown(KeyCode.G)) { int id = Random.Range(1, 23); Knapscak.Instance.StoreItem(id); } //按下B键控制背包的显示和隐藏 if (Input.GetKeyDown(KeyCode.B)) { Knapscak.Instance.DisplaySwitch(); } //按下H键控制箱子的显示和隐藏 if (Input.GetKeyDown(KeyCode.H)) { Chest.Instance.DisplaySwitch(); } //按下V键控制角色面板的显示和隐藏 if (Input.GetKeyDown(KeyCode.V)) { CharacterPanel.Instance.DisplaySwitch(); } //按下N键商店小贩面板的显示和隐藏 if (Input.GetKeyDown(KeyCode.N)) { Vendor.Instance.DisplaySwitch(); } //按下M键锻造面板的显示和隐藏 if (Input.GetKeyDown(KeyCode.M)) { Forge.Instance.DisplaySwitch(); } } //消费金币 public bool ConsumeCoin(int amount) { if (coinAmount >= amount) { coinAmount -= amount; coinText.text = coinAmount.ToString();//更新金币数量 return true;//消费成功 } return false;//否则消费失败 } //赚取金币 public void EarnCoin(int amount) { this.coinAmount += amount; coinText.text = coinAmount.ToString();//更新金币数量 } }好了,一个较为完整的背包系统整理完毕。如果其中有错请与我及时联系改正,期待与你交流!若有需要源项目工程的,请留言!