2.10 游戏UI和战斗管理

2.10.1 创建显示得分的UI界面

游戏的UI界面会显示当前得分、最高分和生命值,首先我们来创建一个UI界面,所有的操作都在编辑器内完成,不需要编写代码。

步骤 01 在Hierarchy窗口中单击鼠标右键,选择【UI】→【Canvas】创建一个UI根节点,这个操作同时还会自动创建一个EventSystem,用于处理UI事件。

步骤 02 确定Canvas处于选择状态,单击鼠标右键并选择【UI】→【Text】,创建一个文本控件,并将其命名为Text_score,用来显示得分。按照同样的方式再创建一个Text控件,命名为Text_best,用来显示最高得分;创建Text_life显示主角生命值,如图2-39所示。

图2-39 UI界面

步骤 03 在Scene窗口中调整文本位置,在Inspector窗口中选择对齐方式,这里生命值文本在屏幕左边,选择左上对齐,分数选择顶端对齐。在Text组件中可以改变文本的大小、颜色等,如图2-40所示。

图2-40 设置文本

运行游戏,会在屏幕上看到设置的UI文本,但它们还都只是静态文本,没有具体功能,如图2-41所示。

图2-41 UI界面

2.10.2 创建显示游戏失败的UI界面

在游戏失败时,会出现一个游戏失败界面,并有一个按钮可以重新游戏,下面我们将创建这个UI界面。

步骤 01 新建一个UI Canvas,为了和之前创建的UI加以区分,这里命名为Canvas_gameover,

步骤 02 确定Canvas_gameover处于选择状态,创建一个文本Text_gameover,显示“游戏失败”几个字。本示例中“游戏失败”几个字的字号较大,需要调整Rect Transform中的Width和Height,否则可能会看不到文字。选择【UI】→【Button】创建一个按钮,命名为Button_restart,按钮控件下面默认还包括一个文本控件,最后效果如图2-42所示。

图2-42 游戏失败的UI界面

步骤 03 运行游戏,效果如图2-43所示。

图2-43 游戏失败UI界面

2.10.3 编写脚本

现在的UI界面没有任何功能,下面我们将使用脚本控制UI界面的显示。

步骤 01 创建GameManager.cs脚本:

    using UnityEngine;
    using UnityEngine.UI;
    using UnityEngine.SceneManagement;

    [AddComponentMenu("MyGame/GameManager")]
    public class GameManager : MonoBehaviour {
        public static GameManager Instance;  // 静态实例

        public Transform m_canvas_main;  // 显示分数的UI界面
        public Transform m_canvas_gameover;  // 游戏失败UI界面
        public Text m_text_score;  // 得分UI文字
        public Text m_text_best;  // 最高分UI文字
        public Text m_text_life;  // 生命UI文字

        protected int m_score=0;  //得分
        public static int m_hiscore=0;  //最高分
        protected Player m_player;  //主角

        public AudioClip m_musicClip;  // 背景音乐
        protected AudioSource m_Audio;  // 声音源

        void Start () {
          Instance = this;
          m_Audio=this.gameObject.AddComponent<AudioSource>();  // 使用代码添加音效组件
          m_Audio.clip=m_musicClip;  // 指定音效
          m_Audio.loop=true;  // 循环播放
          m_Audio.Play();  // 播放音乐
          // 获取主角
          m_player = GameObject.FindGameObjectWithTag("Player").GetComponent<Player>();
          // 获得UI控件
          m_text_score = m_canvas_main.transform.Find("Text_score").GetComponent<Text>();
          m_text_best = m_canvas_main.transform.Find("Text_best").GetComponent<Text>();
          m_text_life = m_canvas_main.transform.Find("Text_life").GetComponent<Text>();
          m_text_score.text=string.Format("分数  {0}", m_score);  // 初始化UI分数
          m_text_best.text=string.Format("最高分 {0}", m_hiscore);  // 初始化UI最高分
          m_text_life.text=string.Format("生命 {0}", m_player.m_life);  // 初始化UI生命值

          var restart_button = m_canvas_gameover.transform.Find("Button_restart").
          GetComponent<Button>();  // 获取重新开始游戏按钮
          restart_button.onClick.AddListener(delegate()  // 按钮事件回调
          {
              SceneManager.LoadScene(SceneManager.GetActiveScene().name);  // 重新开始关卡
          });
                m_canvas_gameover.gameObject.SetActive(false);  // 默认隐藏游戏失败UI
            }

            // 增加分数
            public void AddScore( int point )
            {
                m_score += point;
                // 更新高分纪录
                if (m_hiscore < m_score)
                    m_hiscore = m_score;
                m_text_score.text=string.Format("分数  {0}", m_score);
                m_text_best.text=string.Format("最高分 {0}", m_hiscore);
            }

            // 改变生命值UI显示
            public void ChangeLife(int life)
            {
                m_text_life.text=string.Format("生命 {0}", life);  // 更新UI
                if ( life<=0)
                {
                    m_canvas_gameover.gameObject.SetActive(true); // 如果生命为0,显示游戏失败UI
                }
            }
          }

① Instance是一个静态实例,在Start函数中指向自身,这样可以方便在其他类的对象中引用GameManager实例,这种做法通常用于只有一个实例的类。

② 在Update函数中,循环播放背景音乐。

③ SceneManager.LoadScene用来读取关卡,在读取下一个关卡的时候,当前关卡的游戏体都会被销毁,如果希望可以保存一些游戏变量的值,可以将这类变量设置为static。

步骤 02 创建空游戏体作为游戏管理器,指定GameManager.cs作为其脚本组件,将场景中的两个Canvas UI和GameManager的m_canvas_main、m_canvas_gameover相关联。

步骤 03 在资源文件中找到music.mp3,把它与游戏管理器的m_musicClip属性相关联。

步骤 04 打开Enemy.cs,为其添加一个分数属性,每消灭一个敌人获得一定分数。

        public int m_point = 10;

步骤 05 在Enemy.cs的OnTriggerEnter函数中添加GameManager.Instance.AddScore(m_point)语句,当敌人被消灭时,我们会获得一定分数:

                    if (m_life <= 0)
                    {
                        GameManager.Instance.AddScore(m_point);  // 添加代码,更新UI上的分数
                        Instantiate(m_explosionFX, m_transform.position, Quaternion.identity);
                      Destroy(this.gameObject);  // 自我销毁
                  }

步骤 06 在Player.cs的OnTriggerEnter函数中添加如下语句,当主角受到伤害时,更新UI界面上的生命值显示。

        if(other.tag.CompareTo("PlayerRocket")! =0)  // 如果与主角子弹以外的碰撞体相撞
        {
              m_life-=1;  // 减少生命
              GameManager.Instance.ChangeLife(m_life);  // 添加代码,更新UI

运行游戏,最后的效果如图2-44所示。

图2-44 游戏UI

如果UI上的中文显示为乱码,使用Visual Studio打开GameManager.cs脚本,在菜单栏中选择【Save】→【Advanced Save Options】,然后将其保存为UTF-8格式即可,如图2-45所示。

图2-45 将脚本存储为UTF-8格式