NGUI制作弹窗

4 篇文章 0 订阅

准备工作



插件和工具



这篇教程还是有点复杂的,需要各个方面的力量帮助我们:
  • 既然是界面,那么就离不开NGUI。确保你的项目里有NGUI插件,以及必要的图集来制作消息框的背景(为了省事你可以直接只用NGUI例子中的Atlas)。如果你需要中文显示,那么还需要用NGUI制作一个中文字体。网络上有很多教程。
  • 单例脚本。这里需要单例模式主要是为了实现那种无需在面板中(指的是除消息框以外的其他对象)引用任何资源,这样你看起来就像是在VS2010下调用MessageBox.Show一样。
  • iTween插件。这个插件是免费的,而且非常小巧。使用它主要是为了美化消息框的弹出效果,例如放大弹出、从上向下弹出等等。本例使用的是从上向下弹出。

准备好了这些工具后,我们需要制作本地化文字,这是为了定义消息框中的按钮文字以及弹出时显示的标题和内容文字,当然你可以略去这一步,但是这是非常不建议的,因为在真正的项目中管理好所有的文本是很重要的。本地化是NGUI的功能,经常被用于转换多种语言,例如中文、英文等。你可以在NGUI的例子中找到对应的场景和教程(Example 10 - Localization),涉及到的脚本主要是Localization.cs(统一管理所有的可用语言)、UILocalize.cs(指明一个UILabel显示的文字)。这里假设你知道这些脚本是干嘛的。


本地化文本


要实现一个本地化文本非常容易。只需要两步:
  1. 创建一个纯文本文件,例如cn.txt,里面将定义所有用到的字符串。
    [plain]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
    1. Confirm = 确定  
    2. Cancel = 取消  
    3.   
    4. QuitConfirmTitle = 退出确认  
    5. QuitConfirmContent = 继续将退出游戏。\n确定退出?  

    对于我们的弹出框,只用到上述四个文本。等号左边的名字相当于这个字符串的ID,等号右边是内容。
  2. 制作一个Localization Prefab。这点和NGUI例子很相似,就是为了方便以后修改。对于我们的教程,如果你不制作成一个Prefab也是可以的,但是还是不建议,还是那句话,这种思维还是很重要的。制作好的prefab如下:

    细心的你可能发现除了上述提到的脚本,还有一个脚本:DontDestroyOnLoad.cs。代码如下:
    [csharp]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
    1. using UnityEngine;  
    2. using System.Collections;  
    3.   
    4. public class DontDestroyOnLoad : MonoBehaviour {  
    5.   
    6.     // Use this for initialization  
    7.     void Start () {  
    8.         DontDestroyOnLoad(this.gameObject);  
    9.     }  
    10. }  

    它的作用显而易见,就是为了不让我们的本地化文本在场景切换时被销毁。这样就不用每一个场景都实例化一个Localization Prefab,而只需要在游戏的第一个场景中包含一个Localization Prefab即可。
  3. 新建一个场景,并把之前的Localization Prefab拖进去。


实现



呼呼,下面的内容比较复杂,希望你能耐心看下去。


测试功能:检测退出按钮




我们首先写一个测试脚本,它的功能就是检测用户是否按下了退出按钮,否则就会尝试调用我们的消息框(当然这里还没有定义,我只是想从最高层向底层一层一层讲解)。
下面是KeyDetecter.cs:
[csharp]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. public class KeyDetecter : MonoBehaviour {  
  5.   
  6.     private CommonUIManager m_CommonUIManager = null;  
  7.   
  8.     void Start() {  
  9.         m_CommonUIManager = Singleton.getInstance("CommonUIManager"as CommonUIManager;  
  10.     }  
  11.   
  12.     // Update is called once per frame  
  13.     void Update () {  
  14.         if (Input.GetKey(KeyCode.Escape) && m_CommonUIManager != null) {          
  15.             m_CommonUIManager.ShowMessageBox(  
  16.                 Localization.instance.Get("QuitConfirmTitle"),   
  17.                 Localization.instance.Get("QuitConfirmContent"),  
  18.                 MessageBox.Style.OKAndCancel,  
  19.                 OnReceiveQuitConfirmResult);  
  20.         }  
  21.           
  22.     }  
  23.       
  24.     void OnReceiveQuitConfirmResult(MessageBox.Result result) {  
  25.         if (result == MessageBox.Result.OK) {  
  26.             Application.Quit();  
  27.         }  
  28.     }  
  29. }  


上述代码很短,最重要的部分是ShowMessageBox部分。由于我们还没有实现CommonUIManager,这里你可以理解ShowMessageBox就是弹出一个消息框,它的标题是Localization.instance.Get("QuitConfirmTitle")(根据cn.txt我们知道对应的文本是“退出确认”),内容是Localization.instance.Get("QuitConfirmContent")(根据cn.txt我们知道对应文本是“继续将退出游戏。\n确定退出?”),并且它的类型是包含OK和Cancel两个按钮的标准弹出框,用户点击后的回调函数是OnReceiveQuitConfirmResult

OnReceiveQuitConfirmResult函数根据用户选择结果来判断是否真正退出游戏。



界面



最麻烦的部分来了。我们使用NGUI制作界面。用NGUI创建一个全新的UI,并重新命名。按照类似下图的组织方式创建其他界面元素:



从最上面说起。
CommonUIRoot,即之前的UI Root,的位置很重要,由于弹出框界面引入了一个新的Camera,因此为了防止它的视野范围和其他场景中已有的Camera重合,应尽量把它的位置调整到一个完全空白的位置。本例设置的位置是(0,2000,-2000)。



Camera、Anchor和Panel。确保Anchor的Side设置成Center。如果你想要自适应多种大小的屏幕,那么就需要调整Camera的Size,并向Panel添加UIStretch脚本,具体过程请Google。


Window和WindowRoot。这两个主要是为了设置弹出动画而设置的,它们原本都是空对象,而后添加了一些脚本或者动画。
Window设置如下,可以看到它添加了iTween的一个脚本,主要用于实现从上向下弹出的移动效果。注意,它的位置和iTween脚本中From和To参数的设置有很大关系。

这里的WindowRoot就是一个空对象,但是如果需要自定义的动画时就需要可以再通过一些技巧设置WindowRoot。这里就不讲了。

后面的元素用红色的文字和方框注释过了。其中需要解释的就是LockCollider。它的作用就是通过一个BoxCollider挡住后面所有可点击的UI,使得用户只能点击消息框上的按钮。所以它的Z坐标比其他元素更靠后,而且大小应该超过屏幕的大小。



最后,还需要设置三个消息框按钮,包括它们的文字和回调函数。
OKAndCancelButtonGroup下一共包含两个按钮。首先为CancelButton添加回调函数,这是通过把NGUI的UIButtonMessage脚本添加到CancelButton对象上实现的(即调用CommonUIRoot上脚本的OnCancel函数,当然这里我们还没有实现这个脚本):

我们希望取消按钮上的文字为“取消”,因此向CancelButton对象下面的Label添加如下脚本(通过cn.txt我们知道Cancel对应的文本是“取消”):


同理,设置另外两个按钮。OKAndCancelButtonGroup的ConfirmButton和OnlyOKButtonGroup的ConfirmButton设置相同,它们的回调函数名为OnConfirm,UILocalize脚本的Key设置为Confirm。


最后!!!真的是最后了。。。我们需要用脚本管理上面这些界面元素。建立一个新的脚本CommonUIDetail.cs:
[csharp]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. public class CommonUIDetail : MonoBehaviour {  
  5.       
  6.     public TweenPosition messageBoxTween;  
  7.     public UILabel messageBoxTitle;  
  8.     public UILabel messageBoxContent;  
  9.     public GameObject[] buttonGroups = new GameObject[(int)MessageBox.Style.eNumCount];  
  10.       
  11.     public System.Action messageBoxConfirmCallback = null;  
  12.     public System.Action messageBoxCancelCallback = null;  
  13.       
  14.     void OnConfirm() {  
  15.         if (messageBoxConfirmCallback != null) {  
  16.             messageBoxConfirmCallback();  
  17.         }  
  18.     }  
  19.       
  20.     void OnCancel() {  
  21.         if (messageBoxCancelCallback != null) {  
  22.             messageBoxCancelCallback();  
  23.         }  
  24.     }  
  25. }  

并把该脚本添加到CommonUIRoot上,并给面板上的各个变量赋值:



调整所有UI的位置,使它们看起来像一个弹出框。

完成后,把整个CommonUIRoot及其所有子对象制作成一个Prefab,并且放在Assets/Resources文件夹下,这样才能通过Resources.Load来动态加载它。



单例脚本



还记得之前测试脚本里未实现的CommonUIManager吗?现在我们就来实现最关键的ShowMessageBox代码。CommonUIManager.cs如下:
[csharp]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. public class MessageBox {  
  5.     public delegate void OnReceiveMessageBoxResult(MessageBox.Result result);  
  6.       
  7.     public enum Style {  
  8.         OnlyOK,  
  9.         OKAndCancel,  
  10.         eNumCount  
  11.     }  
  12.       
  13.     public enum Result {  
  14.         OK,  
  15.         Cancel,  
  16.         eNumCount  
  17.     }  
  18. }  
  19.   
  20. public class CommonUIManager : MonoBehaviour {  
  21.       
  22.     public GameObject commonUIPrefab = null;  
  23.       
  24.     public GameObject root;  
  25.     public TweenPosition messageBoxTween;  
  26.     public UILabel messageBoxTitle;  
  27.     public UILabel messageBoxContent;  
  28.     public GameObject[] buttonGroups = new GameObject[(int)MessageBox.Style.eNumCount];  
  29.       
  30.     private MessageBox.OnReceiveMessageBoxResult messageBoxCallback = null;  
  31.       
  32.     // Use this for initialization  
  33.     void Start () {  
  34.       
  35.     }  
  36.       
  37.     // Update is called once per frame  
  38.     void Update () {  
  39.       
  40.     }  
  41.       
  42.     public void ShowMessageBox(string title, string content, MessageBox.Style style,   
  43.         MessageBox.OnReceiveMessageBoxResult callback) {  
  44.         if (root == null) {  
  45.             commonUIPrefab = Resources.Load("CommonUIRoot"as GameObject;  
  46.             root = GameObject.Instantiate(commonUIPrefab) as GameObject;  
  47.             root.transform.parent = this.transform;  
  48.               
  49.             CommonUIDetail uiDetail = root.GetComponent<CommonUIDetail>();  
  50.             messageBoxTween = uiDetail.messageBoxTween;  
  51.             messageBoxTitle = uiDetail.messageBoxTitle;  
  52.             messageBoxContent = uiDetail.messageBoxContent;  
  53.             buttonGroups[(int)MessageBox.Style.OnlyOK] = uiDetail.buttonGroups[(int)MessageBox.Style.OnlyOK];  
  54.             buttonGroups[(int)MessageBox.Style.OKAndCancel] = uiDetail.buttonGroups[(int)MessageBox.Style.OKAndCancel];  
  55.               
  56.             uiDetail.messageBoxConfirmCallback = OnConfirm;  
  57.             uiDetail.messageBoxCancelCallback = OnCancel;  
  58.         }  
  59.           
  60.         messageBoxTitle.text = title;  
  61.         messageBoxContent.text = content;  
  62.         messageBoxCallback = callback;  
  63.           
  64.         switch ((int)style) {  
  65.         case (int)MessageBox.Style.OnlyOK:  
  66.             buttonGroups[(int)MessageBox.Style.OnlyOK].SetActive(true);  
  67.             buttonGroups[(int)MessageBox.Style.OKAndCancel].SetActive(false);  
  68.             break;  
  69.         case (int)MessageBox.Style.OKAndCancel:  
  70.             buttonGroups[(int)MessageBox.Style.OnlyOK].SetActive(false);  
  71.             buttonGroups[(int)MessageBox.Style.OKAndCancel].SetActive(true);  
  72.             break;  
  73.         }  
  74.           
  75.         messageBoxTween.Play(true);  
  76.     }  
  77.       
  78.     void OnConfirm() {  
  79.         if (messageBoxCallback != null) {  
  80.             messageBoxCallback(MessageBox.Result.OK);  
  81.             messageBoxCallback = null;  
  82.         }  
  83.           
  84.         messageBoxTween.Play(false);  
  85.     }  
  86.       
  87.     void OnCancel() {  
  88.         if (messageBoxCallback != null) {  
  89.             messageBoxCallback(MessageBox.Result.Cancel);  
  90.             messageBoxCallback = null;  
  91.         }  
  92.           
  93.         messageBoxTween.Play(false);  
  94.     }  
  95. }  


我只能帮你到这里了,这代码不长,相信如果你肯花时间一定可以看懂。

把之前的KeyDetector.cs代码添加到场景中的MainCamera上,运行,点击键盘上的ESC按键,应该就会弹出你的消息框了。

至此,整个过程结束。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值