5-8 Show Items Tooltip - IPointerEnterHandler
今天要來製作道具的提示訊息,當滑鼠移動到道具上以後,旁邊會顯示一個小提示框標明道具的使用訊息。雖然從第5章開始的教學文章主要是想將遊戲改成移動平台,但如果有相關功能是用滑鼠操控的,我還是會跟大家分享。後面的文章會再將Tooltip改成彈框的形式。
首先,我們要來製作ToolTip的介面,在Canvas上新增UI/Text。
接著在剛剛新增的Text底下新增UI/Image。
將Image設定一個背景圖,請大家自己Google一下ToolTip的背景圖唷。然後先將該Image的Alpha值設低一些,以免看不清楚文字。
接著,在Text上新增Content Size Fitter組件,我們可以使用此組件讓Text的大小依照文字內容自動縮放,不過還需要進行一個設定。
請將Horizontal Fit跟Vertical Fit都設定為Preferred Size,如果對Content Size Fitter不熟悉,請大家先看看以下文章,對Auto Layout佈局的教學非常深刻。
Unity UGUI 原理篇(五):Auto Layout 自動佈局http://k79k06k02k.com/blog/542/unity/unity-ugui-%E5%8E%9F%E7%90%86%E7%AF%87%E4%BA%94%EF%BC%9Aauto-layout-%E8%87%AA%E5%8B%95%E4%BD%88%E5%B1%80
接著將Image的Anchor Presets設定為stretch stretch,這樣當Text縮放時,Image的底圖也會跟著縮放。
如下圖,修改Text的文字內容後,Text本身的大小會縮放,Image的底圖也會跟著縮放。
修改文字後,Image又改變了。
接著點選Text,選擇Duplicate複製一份。
複製的新的Text放在原本的Text底下,並將新的Text底下的Image刪除。
最後階層會如下圖,ToolTip是Text,ToolTip底下有Image跟Content,Content也是Text。我知道階層設計看起來滿奇怪的,ToolTip有用來自動縮放Image底圖的作用,Content文字則是真正可以蓋過Image底圖的文字。
完成後的預覽如下圖,可以看到Content文字會蓋過Image底圖,但是為了自動縮放,必須要在最上層也用相同的Text。如果有更好的做法,希望大家可以提供給我。
接著,在ToolTip上新增一個Canvas Group,這是為了使用Alpha屬性控制ToolTip的顯示與消失。
然後修改InventorySystem.cs,在InvetorySystem中提供方法讓ToolTip顯示跟隱藏,當Slot偵測到滑鼠事件時,告訴InventorySystem讓ToolTip顯示,相當於Mediator Pattern的概念。如果不了解Mediator Pattern,大家可以先看這篇文章了解一下:
C#设计模式(18)——中介者模式(Mediator Pattern)
http://blog.jobbole.com/78124/
InventorySystem.cs:
接著,我們要使用IPointerEnterHandler以及IPointerExitHandler,來判斷滑鼠的進入進出。
Slot.cs:
最後,我們來執行遊戲試看看吧!滑鼠移動到血量瓶,會跳出提示框顯示訊息了!
移動到能量瓶,也會顯示能量瓶的資訊。
首先,我們要來製作ToolTip的介面,在Canvas上新增UI/Text。
接著在剛剛新增的Text底下新增UI/Image。
將Image設定一個背景圖,請大家自己Google一下ToolTip的背景圖唷。然後先將該Image的Alpha值設低一些,以免看不清楚文字。
接著,在Text上新增Content Size Fitter組件,我們可以使用此組件讓Text的大小依照文字內容自動縮放,不過還需要進行一個設定。
請將Horizontal Fit跟Vertical Fit都設定為Preferred Size,如果對Content Size Fitter不熟悉,請大家先看看以下文章,對Auto Layout佈局的教學非常深刻。
Unity UGUI 原理篇(五):Auto Layout 自動佈局http://k79k06k02k.com/blog/542/unity/unity-ugui-%E5%8E%9F%E7%90%86%E7%AF%87%E4%BA%94%EF%BC%9Aauto-layout-%E8%87%AA%E5%8B%95%E4%BD%88%E5%B1%80
接著將Image的Anchor Presets設定為stretch stretch,這樣當Text縮放時,Image的底圖也會跟著縮放。
如下圖,修改Text的文字內容後,Text本身的大小會縮放,Image的底圖也會跟著縮放。
修改文字後,Image又改變了。
接著點選Text,選擇Duplicate複製一份。
複製的新的Text放在原本的Text底下,並將新的Text底下的Image刪除。
最後階層會如下圖,ToolTip是Text,ToolTip底下有Image跟Content,Content也是Text。我知道階層設計看起來滿奇怪的,ToolTip有用來自動縮放Image底圖的作用,Content文字則是真正可以蓋過Image底圖的文字。
完成後的預覽如下圖,可以看到Content文字會蓋過Image底圖,但是為了自動縮放,必須要在最上層也用相同的Text。如果有更好的做法,希望大家可以提供給我。
接著,在ToolTip上新增一個Canvas Group,這是為了使用Alpha屬性控制ToolTip的顯示與消失。
接著在Project視窗內新增一個Script名為ToolTip.cs。
撰寫ToolTip.cs程式碼:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ToolTip : MonoBehaviour {
[SerializeField] float smoothAlphaMultiplier = 5f;
[SerializeField] Vector2 tooltipOffset = new Vector2(100, -100);
Text toolTipText;
Text contentText;
CanvasGroup canvasGroup;
float tooltipAlpha = 0;
bool isTooltipShow = true;
void Start(){
toolTipText = GetComponent ();
contentText = GameObject.Find("Content").GetComponent ();
canvasGroup = GetComponent ();
}
void Update(){
if (canvasGroup.alpha != tooltipAlpha) {
// 用Lerp函數控制Alpha的漸變
canvasGroup.alpha = Mathf.Lerp (canvasGroup.alpha, tooltipAlpha, Time.deltaTime * smoothAlphaMultiplier);
if (Mathf.Abs (canvasGroup.alpha - tooltipAlpha) < 0.01f) {
canvasGroup.alpha = tooltipAlpha;
}
}
if (isTooltipShow) {
// 將滑鼠座標轉換成Canvas上的座標
Vector2 position;
Canvas canvas = GetComponentInParent
然後修改InventorySystem.cs,在InvetorySystem中提供方法讓ToolTip顯示跟隱藏,當Slot偵測到滑鼠事件時,告訴InventorySystem讓ToolTip顯示,相當於Mediator Pattern的概念。如果不了解Mediator Pattern,大家可以先看這篇文章了解一下:
C#设计模式(18)——中介者模式(Mediator Pattern)
http://blog.jobbole.com/78124/
InventorySystem.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.UI;
namespace RPG.Inventory{
public class InventorySystem : MonoBehaviour {
[SerializeField] ToolTip toolTip;
ItemList itemList;
Slot[] slotList;
void Start () {
ParseItemsJson ();
slotList = GetComponentsInChildren ();
// 測試程式碼,手動生成物品
StoreItem (1);
StoreItem (2);
StoreItem (1);
StoreItem (3);
}
public void ShowToolTip(string content){
toolTip.Show (content);
}
public void HideToolTip(){
toolTip.Hide ();
}
public bool StoreItem(int id){
Item item = GetItemByID (id);
return StoreItem (item);
}
public bool StoreItem(Item item){
if (item == null) {
return false;
}
// 若物品的儲存容量為1,則將該物品直接放進空的Slot
if (item.Capacity == 1) {
return StoreItemInEmptySlot (item);
}
// 將相同的Item放在同一個Slot
return StoreItemInSameSlot(item);
}
private bool StoreItemInSameSlot(Item item){
foreach (Slot slot in slotList) {
if (slot.transform.childCount >= 1 && slot.GetItemID () == item.ID &&
slot.IsFilled () == false) {
// 將新Item與同一個Item放在一起
slot.StoreItem (item);
return true;
}
}
// 若背包內不存在相同的Item,則放進空的Slot
return StoreItemInEmptySlot (item);
}
private bool StoreItemInEmptySlot(Item item){
foreach (Slot slot in slotList) {
if (slot.transform.childCount == 0) {
// 將Item存進該Slot
slot.StoreItem (item);
return true;
}
}
Debug.LogError ("No Empty Slot.");
return false;
}
private Item GetItemByID(int id){
foreach (Item entity in itemList.ItemEntityList) {
if (entity.ID == id) {
return entity;
}
}
return null;
}
private void ParseItemsJson(){
// 從Resource資料夾中讀取Items.json
TextAsset json = Resources.Load ("Items");
// 解析Json格式
itemList = JsonUtility.FromJson (json.text);
// 使用foreach迴圈讀取List中的Item資料
foreach (Item entity in itemList.ItemEntityList) {
// TODO 讀取Json有Bug
}
}
}
}
接著,我們要使用IPointerEnterHandler以及IPointerExitHandler,來判斷滑鼠的進入進出。
Slot.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
namespace RPG.Inventory{
public class Slot : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler {
[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 ();
}
}
}
最後,我們來執行遊戲試看看吧!滑鼠移動到血量瓶,會跳出提示框顯示訊息了!
移動到能量瓶,也會顯示能量瓶的資訊。
















留言
張貼留言