天天看點

unity應用執行個體——從頭撸一個全新的FPS遊戲(5)

這篇文章進行對遊戲ui邏輯的總結。

首先給每個機器人添加一個血條的效果,在機器人的遊戲物體下建立一個畫布,并添加一個slider,隻保留其中的Fill Area,把其他的删掉,如圖。

unity應用執行個體——從頭撸一個全新的FPS遊戲(5)

将Fill中的image修改為紅色,然後給slider添加一個腳本,主要功能是讓slider的value的值與血量占比相當

using UnityEngine;
using UnityEngine.UI;
public class follower : MonoBehaviour
{
    [SerializeField]
    private float m_offsety;
    public Transform m_robot;
    private float m_robotinithp;//機器人初始的hp

    private void Start()
    {
        m_robotinithp = m_robot.gameObject.GetComponent<RobotController>().M_hp;
    }
    private void Update()
    {
        //确定血條位置
        gameObject.transform.position = 
            new Vector3(m_robot.position.x, m_robot.position.y + m_offsety, m_robot.position.z);
        //根據實際情況扣血
        gameObject.GetComponent<Slider>().value=
            ((m_robot.gameObject.GetComponent<RobotController>().M_hp / m_robotinithp));
    }
}
           

然後對該畫布的Canvas元件中的Render Mode進行如圖設定:

unity應用執行個體——從頭撸一個全新的FPS遊戲(5)

建立一個新的相機,将它拖入Canvas元件中的Render Camera,在第三篇文章中的gamemanager類中擁有該相機遊戲對象的引用,名為m_secondcamera,并将其與主相機的transform同步。這樣子就相當與每個機器人都擁有一個與血量相當slider,并且它時刻面向玩家的視角,形成血條的效果。

血條設定好以後,建立多個scene來存儲關卡,把每個scene的地圖自己div一下,将多個機器人放置其中并設定好巡邏點。然後開始進行ui腳本的建立。

首先是第一個scene也就是主菜單,建立一個名為UI的空物體,在它下面建立三個畫布,再為每個畫布添加各種功能對象,如圖:

unity應用執行個體——從頭撸一個全新的FPS遊戲(5)

建立腳本進行管理,挂在ui上

using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class menuui : MonoBehaviour {

    public GameObject m_setcanvas;
    public GameObject m_Authorcanvas;
    public GameObject m_volumeslider;

    private void Start()
    {
        m_setcanvas.SetActive(false);
        m_Authorcanvas.SetActive(false);

        m_volumeslider.GetComponent<Slider>().value = datamanager.m_volume;
    }
    private void Update()
    {
        //音量調節
        datamanager.m_volume = m_volumeslider.GetComponent<Slider>().value;
    }

    //下面的方法全都挂在不同的Button上
    public void OnStart()
    {
        SceneManager.LoadScene(1);
    }
   public void OnExit()
    {
        Application.Quit();
    }

    public void OnSetOpen()
    {
        m_setcanvas.SetActive(true);
    }
    public void OnSetClose()
    {
        m_setcanvas.SetActive(false);
    }
    public void OnAuthorOpen()
    {
        m_Authorcanvas.SetActive(true);
    }
    public void OnAuthorClose()
    {
        m_Authorcanvas.SetActive(false);
    }
}
           

還建立一個空物體負責播放bgm,也挂一個腳本控制音量,在其他scene中也有這個物體

using UnityEngine;

public class bgm : MonoBehaviour {	

	void Update ()
    {
        gameObject.GetComponent<AudioSource>().volume = datamanager.m_volume;
    }
}
           

然後是開始遊戲後的ui,之前在建立武器系統時做了一部分,現在補充完整

unity應用執行個體——從頭撸一個全新的FPS遊戲(5)

建立腳本對其進行管理

using System.Collections;
using UnityEngine;
using UnityEngine.UI;

//遊戲界面狀态
enum PlayUiState
{
    BATTLE,
    END,
    SET
}

public class playui : MonoBehaviour
{

    private PlayUiState m_state;//目前界面狀态

    private gun m_gun;
    private playerhp m_playerhp;
    private player m_player;
    private gamemanager m_manager;

    public GameObject m_hptext;//擷取畫布中的一個text
    public GameObject m_bulletText;//子彈數文本
    public GameObject m_snipertexture;//瞄準時加載的圖檔
    public GameObject m_aimtexture;
    public GameObject m_time;
    public GameObject m_endcanvas;
    public GameObject m_endtext;
    public GameObject m_playerstatetext;
    public GameObject m_hurtimage;
    public GameObject m_warningtext;
    public GameObject m_scoretext;
    public GameObject m_setcanvas;
    public GameObject m_bgm;
    public GameObject m_volumeslider;
    public GameObject m_mouseslider;

    private Color m_flashcolor; //記錄受傷圖檔的色彩值
    public float m_flashspeed = 2;

    private float m_musictime = 0;//記錄音樂播放位置
    private bool m_dead = false;
    private float m_finaltime = 0;

    void Start()
    {
        m_state = PlayUiState.BATTLE;

        m_player = FindObjectOfType<player>();
        m_playerhp = FindObjectOfType<playerhp>();
        m_manager = FindObjectOfType<gamemanager>();


        m_playerhp.diedelegate += OnDie;//添加委托事件

        
        m_volumeslider.GetComponent<Slider>().value = datamanager.m_volume;
        m_mouseslider.GetComponent<Slider>().value = datamanager.m_mosen;

        //記錄目前設定好的受傷圖檔的顔色值
        m_flashcolor = m_hurtimage.GetComponent<Image>().color;
        //将受傷圖檔先設定為透明
        m_hurtimage.GetComponent<Image>().color = Color.clear;

        m_setcanvas.SetActive(false);
        m_endcanvas.SetActive(false);
        m_hurtimage.SetActive(true);
        m_playerstatetext.SetActive(false);
        m_warningtext.SetActive(false);

        //若是第一關 為玩家顯示提示
        if (datamanager.M_gamelevel == 1)
        {
            StartCoroutine(FirstWarning());
        }

        Cursor.visible = false;//隐藏滑鼠
    }

    void Update()
    {
        #region 戰鬥界面
        if (m_state == PlayUiState.BATTLE)
        {
            m_gun = FindObjectOfType<gun>();

            FreshHpText();
            FreshBulletText();
            ShowAimImage();
            ShowTheTime();

            //當玩家處于休息狀态 顯示提示
            if (playerstatemanager.m_state == PlayerState.RELAXE)
            {
                m_playerstatetext.GetComponent<Text>().text = "Relaxing...";
                m_playerstatetext.SetActive(true);
            }
            else m_playerstatetext.SetActive(false);

            //将受傷圖檔的顔色漸變為透明
            m_hurtimage.GetComponent<Image>().color =
                Color.Lerp
                (
                 m_hurtimage.GetComponent<Image>().color,
                 Color.clear,
                 m_flashspeed * Time.deltaTime
                );
            //設定滑鼠靈敏度
            datamanager.m_mosen = m_mouseslider.GetComponent<Slider>().value;
            m_player.m_mouserate = datamanager.m_mosen * 5;
            //狀态轉換
            if (datamanager.M_gamelevel == datamanager.m_maxlevel || m_dead) m_state = PlayUiState.END;
            if (Input.GetKeyUp(KeyCode.Y)) m_state = PlayUiState.SET;

        }
        #endregion

        #region 結束界面
        if (m_state == PlayUiState.END)
        {
            Cursor.visible = true;//顯示滑鼠

            m_gun.enabled = false;

            m_player.enabled = false;

            m_endcanvas.SetActive(true);

            string score = "";

            if (datamanager.M_gamelevel == datamanager.m_maxlevel)//勝利
            {
                m_endtext.GetComponent<Text>().text = "Victory!";

                //記錄遊戲時間
                if (m_finaltime == 0)
                    m_finaltime = (int)datamanager.M_playtime;

                score =
                  "殺敵數:" + datamanager.M_gamescore +
                  "\n目前關卡:" + "final" +
                  "\n用時:" + m_finaltime + "s";
            }
            else if (m_dead)//死亡
            {
                m_endtext.GetComponent<Text>().text = "Game Over";

                m_playerhp.diedelegate -= OnDie;//釋放委托事件
               
                //記錄遊戲時間
                if (m_finaltime == 0)
                    m_finaltime = (int)datamanager.M_playtime;

                score =
                    "殺敵數:" + datamanager.M_gamescore +
                    "\n目前關卡:" + datamanager.M_gamelevel +
                    "\n用時:" + m_finaltime + "s";
            }

            m_scoretext.GetComponent<Text>().text = score.ToString();
        }
        #endregion

        #region 設定界面
        if (m_state == PlayUiState.SET)
        {
            m_gun.enabled = false;
            //音樂暫停
            m_musictime = m_bgm.GetComponent<AudioSource>().time;
            m_bgm.GetComponent<AudioSource>().Pause();

            Cursor.visible = true;//顯示滑鼠

            Time.timeScale = 0;//時間暫停

            m_setcanvas.SetActive(true);
            //聲音設定
            datamanager.m_volume = m_volumeslider.GetComponent<Slider>().value;
        }
        #endregion

    }


    void FreshHpText()
    {
        m_hptext.GetComponent<Text>().text = "HP:" + m_playerhp.M_hp.ToString();
    }

    void FreshBulletText()
    {

        m_bulletText.GetComponent<Text>().text = m_gun.Curbulletnum.ToString() + "/"
            + m_gun.Storebulletnum.ToString();
    }

    void ShowAimImage()
    {
        if (sniperscope.m_isaiming)
        {
            m_snipertexture.SetActive(true);
            m_aimtexture.SetActive(false);
        }
        else
        {
            m_snipertexture.SetActive(false);
            m_aimtexture.SetActive(true);
        }
    }

    void OnDie()
    {
        m_dead = true;
    }

    void ShowTheTime()
    {
        int time = (int)m_manager.M_WaitTime;
        if (time == 0)
            m_time.GetComponent<Text>().text = "The door is open!";
        else
            m_time.GetComponent<Text>().text = time.ToString();
    }

    public void HurtEffect()
    {
        m_hurtimage.GetComponent<Image>().color = m_flashcolor;
    }

    //下面兩個方法是綁定在Button上的
    public void OnSetClose()
    {
        Cursor.visible = false;

        // 繼續播放音樂
        m_bgm.GetComponent<AudioSource>().Play();
        m_bgm.GetComponent<AudioSource>().time = m_musictime;

        Time.timeScale = 1;//時間恢複正常

        m_setcanvas.SetActive(false);
        m_gun.enabled = true;
        
        m_state = PlayUiState.BATTLE;//轉換狀态

    }
    public void OnExit()
    {
        Application.Quit();
    }
    
    //顯示警告,延遲消失
    IEnumerator FirstWarning()
    {
        m_warningtext.GetComponent<Text>().text = "Live and get out";
        m_warningtext.SetActive(true);

        yield return new WaitForSeconds(5f);

        m_warningtext.GetComponent<Text>().text = " ";
        m_warningtext.SetActive(false);
    }
}
           

因為每個關卡的ui都相同,可以設定為全局ui,在gamemanager中将名為ui的物體DontDestroyOnLoad了就行。

效果如下(結束界面):

unity應用執行個體——從頭撸一個全新的FPS遊戲(5)

ui寫完後,這個小遊戲就基本完成的差不多了,後面可能還會有些改進和補充,現在已經可以愉快的玩耍了,謝謝觀看:)