5-14 Discard Item And Control Panel Display
今天要來教大家製作『丟棄物品』和『控制介面顯示』的功能,將物品用滑鼠移動到背包外面並點擊滑鼠左鍵,該物品就會被丟棄,以及使用快捷鍵和介面右上角的叉叉按鈕,就可以開關介面。
首先,在InventorySystem.cs的Update中,額外增加下列的程式碼,使用EventSystem的IsPointerOverGameObject方法,可以判斷滑鼠左鍵有沒有點擊到GameObject,若沒有,則將PickedItem隱藏,並將isPickedItem設為false。下次滑鼠點擊背包的其他物體時,PickedItem資訊會被重整,相當於上一個狀態的物體被丟棄。
InventorySystem.cs的完整程式碼如下:
新增一個Script名為Panel.cs,這個腳本要用來控制介面的隱藏和顯示。
撰寫完成後,請在Chest Panel的Inspector視窗新增Canvas Group組件。
並新增Panel.cs,Hot Key的部分請大家選擇自己喜歡的快捷鍵,此處我選擇 C。
同理,在Knapsack Panel中也要新增Canvas Group組件和Panel.cs,此處的HotKey我選擇K。
接著,選擇Knapsack Panel底下的Close Btn。
在Inspector視窗中應該能看見之前新增的Button組件,在On Click()的地方應會顯示List is Empty,請大家按下『+』按鈕。
然後將Knapsack Panel拖曳到小框框中,如下圖。接著在No Function的地方選擇Panel/Hide()。
同理,在Chest Panel底下的Close Btn也要新增事件,只不過請注意這邊要拖曳的是Chest Panel,No Function的部分也選擇Panel/Hide()。
然後,執行遊戲看看,按下右上角的叉叉按鈕就可以關閉介面了。
按下快捷鍵也同樣可以關閉介面,再按一次快捷鍵則會打開介面。
接著調整一個小問題,我們在之前的文章中,沒有處理『當滑鼠抓著的物體與Slot中的物體不是同一個時,要將抓著的物體與Slot的交換』。所以,我們在Slot.cs中,如下圖撰寫部分程式碼改善。
Slot.cs:
執行遊戲看看吧,我用滑鼠點擊了背包內的能量瓶。
然後朝著血量瓶的位置點擊下去,能量瓶就會放下去,然後滑鼠上抓著血量瓶。
首先,在InventorySystem.cs的Update中,額外增加下列的程式碼,使用EventSystem的IsPointerOverGameObject方法,可以判斷滑鼠左鍵有沒有點擊到GameObject,若沒有,則將PickedItem隱藏,並將isPickedItem設為false。下次滑鼠點擊背包的其他物體時,PickedItem資訊會被重整,相當於上一個狀態的物體被丟棄。
InventorySystem.cs的完整程式碼如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.UI;
using UnityEngine.EventSystems;
namespace RPG.Inventory{
public class InventorySystem : MonoBehaviour {
[SerializeField] ToolTip toolTip;
[SerializeField] ItemUI pickedItem;
public bool isPickedItem = false;
ItemList itemList;
Slot[] slotList;
void Start () {
ParseItemsJson ();
slotList = GetComponentsInChildren ();
}
void Update(){
// 測試程式碼,手動生成物品
if (Input.GetKeyDown (KeyCode.G)) {
StoreItem (Random.Range(1,3));
}
if (isPickedItem) {
// 將滑鼠座標轉換成Canvas上的座標
Vector2 position;
Canvas canvas = GetComponentInParent
新增一個Script名為Panel.cs,這個腳本要用來控制介面的隱藏和顯示。
Panel.cs的完整程式碼如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Panel : MonoBehaviour {
[SerializeField] float panelAlpha = 1;
[SerializeField] float smoothAlphaMultiplier = 4;
[SerializeField] KeyCode hotKey;
CanvasGroup canvasGroup;
void Start () {
canvasGroup = GetComponent ();
}
void Update () {
if (Input.GetKeyDown (hotKey)) {
DisplaySwitch ();
}
if (canvasGroup.alpha != panelAlpha) {
// 用Lerp函數控制Alpha的漸變
canvasGroup.alpha = Mathf.Lerp (canvasGroup.alpha, panelAlpha, Time.deltaTime * smoothAlphaMultiplier);
if (Mathf.Abs (canvasGroup.alpha - panelAlpha) < 0.01f) {
canvasGroup.alpha = panelAlpha;
}
}
}
public void Show(){
canvasGroup.blocksRaycasts = true;
panelAlpha = 1;
}
public void Hide(){
canvasGroup.blocksRaycasts = false;
panelAlpha = 0;
}
public void DisplaySwitch(){
if (panelAlpha == 1) {
Hide ();
} else {
Show ();
}
}
}
撰寫完成後,請在Chest Panel的Inspector視窗新增Canvas Group組件。
並新增Panel.cs,Hot Key的部分請大家選擇自己喜歡的快捷鍵,此處我選擇 C。
同理,在Knapsack Panel中也要新增Canvas Group組件和Panel.cs,此處的HotKey我選擇K。
接著,選擇Knapsack Panel底下的Close Btn。
在Inspector視窗中應該能看見之前新增的Button組件,在On Click()的地方應會顯示List is Empty,請大家按下『+』按鈕。
然後將Knapsack Panel拖曳到小框框中,如下圖。接著在No Function的地方選擇Panel/Hide()。
同理,在Chest Panel底下的Close Btn也要新增事件,只不過請注意這邊要拖曳的是Chest Panel,No Function的部分也選擇Panel/Hide()。
然後,執行遊戲看看,按下右上角的叉叉按鈕就可以關閉介面了。
按下快捷鍵也同樣可以關閉介面,再按一次快捷鍵則會打開介面。
接著調整一個小問題,我們在之前的文章中,沒有處理『當滑鼠抓著的物體與Slot中的物體不是同一個時,要將抓著的物體與Slot的交換』。所以,我們在Slot.cs中,如下圖撰寫部分程式碼改善。
Slot.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
namespace RPG.Inventory{
public class Slot : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler {
[SerializeField] GameObject itemPrefab;
public void StoreItem(Item item){
// 若Slot底下沒有Item,則Instantiate一個
if (transform.childCount == 0) {
GameObject itemObject = Instantiate (itemPrefab, transform);
itemObject.GetComponentInChildren ().SetItem (item);
} else {
// 已存在該Item,所以增加數量即可
transform.GetComponentInChildren ().AddAmount ();
}
}
public int GetItemID(){
return transform.GetComponentInChildren ().Item.ID;
}
public bool IsFilled(){
ItemUI itemUI = transform.GetComponentInChildren ();
return itemUI.Amount >= itemUI.Item.Capacity;
}
public void OnPointerEnter(PointerEventData eventData){
if (transform.childCount > 0) {
Item item = GetComponentInChildren ().Item;
GetComponentInParent ().ShowToolTip (item.GetToolTipText ());
}
}
public void OnPointerExit(PointerEventData eventData){
GetComponentInParent ().HideToolTip ();
}
public void OnPointerDown(PointerEventData eventData){
InventorySystem invetorySystem = GetComponentInParent ();
// Slot內是否已經有物體
if (transform.childCount > 0) {
// 取得目前滑鼠點擊Slot的ItemUI
ItemUI clickedItemUI = GetComponentInChildren ();
// 當滑鼠沒有Item時
if (invetorySystem.isPickedItem == false) {
if (Input.GetKey (KeyCode.Z)) {
// 壓住Z鍵時,只會取出一半的數量
PickupHalfOfSlotItem(clickedItemUI, invetorySystem);
} else {
// 取出全部
PickupAllSlotItem (clickedItemUI, invetorySystem);
}
// 當滑鼠有Item時
} else if (invetorySystem.isPickedItem == true) {
// 當放入Item的是同一個時
if (clickedItemUI.Item.ID == invetorySystem.GetPickedItem ().Item.ID) {
if (Input.GetKey (KeyCode.Z)) {
// 壓住Z鍵時,只會一個一個的放入物體
PutInOneItem (invetorySystem);
} else {
// 放入所有物體
PutInAllItem (clickedItemUI, invetorySystem);
}
} else {
// 當放入的Item不是同一個時,將Slot與PickedItem交換
ChangeSlotAndPickedItem(clickedItemUI, invetorySystem);
}
}
} else {
if (invetorySystem.isPickedItem == true) {
if (Input.GetKey (KeyCode.Z)) {
// 壓住Z鍵時,只會一個一個的放入物體
PutInOneItem (invetorySystem);
} else {
// 放入所有物體
PutInAllItemToEmptySlot (invetorySystem);
}
}
}
}
private void PickupHalfOfSlotItem(ItemUI clickedItemUI, InventorySystem invetorySystem){
int amountToPick = (clickedItemUI.Amount + 1) / 2;
int amountRemained = clickedItemUI.Amount - amountToPick;
// 將PickedItem的ItemUI設置為目前滑鼠點中的ItemUI
invetorySystem.PickupItem (clickedItemUI.Item, amountToPick);
if (amountRemained == 0) {
Destroy (clickedItemUI.gameObject);
} else {
clickedItemUI.SetAmount (amountRemained);
}
}
private void PickupAllSlotItem(ItemUI clickedItemUI, InventorySystem invetorySystem){
// 將PickedItem的ItemUI設置為目前滑鼠點中的ItemUI
invetorySystem.PickupItem (clickedItemUI.Item, clickedItemUI.Amount);
// 因為已經選中物體了,要將Slot內的ItemUI刪除
Destroy (clickedItemUI.gameObject);
}
private void PutInOneItem(InventorySystem invetorySystem){
this.StoreItem (invetorySystem.GetPickedItem ().Item);
invetorySystem.ReducePickedItem (1);
}
private void PutInAllItem(ItemUI clickedItemUI, InventorySystem invetorySystem){
if (clickedItemUI.Item.Capacity > clickedItemUI.Amount) {
int slotRemained = clickedItemUI.Item.Capacity - clickedItemUI.Amount;
if (slotRemained >= invetorySystem.GetPickedItem ().Amount) {
// 若Slot內的空間足以放下滑鼠拿著的全部物體
clickedItemUI.SetAmount (clickedItemUI.Amount + invetorySystem.GetPickedItem ().Amount);
invetorySystem.ReducePickedItem (invetorySystem.GetPickedItem ().Amount);
} else {
// Slot內的空間不夠放,只能放下部分滑鼠拿著的物體
clickedItemUI.SetAmount (clickedItemUI.Amount + slotRemained);
invetorySystem.ReducePickedItem (slotRemained);
}
}
}
private void PutInAllItemToEmptySlot(InventorySystem invetorySystem){
for (int i = 0; i < invetorySystem.GetPickedItem ().Amount; i++) {
this.StoreItem (invetorySystem.GetPickedItem().Item);
}
invetorySystem.ReducePickedItem (invetorySystem.GetPickedItem().Amount);
}
private void ChangeSlotAndPickedItem(ItemUI clickedItemUI, InventorySystem invetorySystem){
Item item = clickedItemUI.Item;
int amount = clickedItemUI.Amount;
clickedItemUI.SetItem(invetorySystem.GetPickedItem().Item, invetorySystem.GetPickedItem().Amount);
invetorySystem.GetPickedItem ().SetItem (item, amount);
}
}
}
執行遊戲看看吧,我用滑鼠點擊了背包內的能量瓶。
然後朝著血量瓶的位置點擊下去,能量瓶就會放下去,然後滑鼠上抓著血量瓶。














留言
張貼留言