VR-Sample:4.游戲菜單

<p>
  本篇完成游戲菜單界面,場景中呈現(xiàn)所有的游戲選擇界面贷腕,激活相應的游戲界面進入游戲場景状共,這里面使用到了VRStandardAssets.Menu中的一些腳本。下面用到的時候會寫出注釋构灸,場景如下圖:


游戲菜單.png

</p>

一、實現(xiàn)功能

  • 游戲選擇界面的動畫播放
      當視線準心選擇界面的時候岸梨,界面會向玩家彈出一段距離喜颁,并播放該游戲的介紹動畫稠氮,視線移開時,停止播放半开,界面回到原來位置隔披。
  • 選擇條的跟隨,填充和場景的進入
      選擇條會動態(tài)的移動到當前準心的游戲界面上寂拆,并且在進入過程中會進行填充奢米,填充完畢后開始相應的游戲。

二纠永、步驟

1. UI的制作

游戲菜單的UI分為3塊:BackGround鬓长,Menu,Selector尝江。


游戲菜單.png

下面開始一步一步制作痢士,首先是BackGround,這里需要注意的是:3D UI的呈現(xiàn)是通過MeshFilter和MeshRenderer這兩個組件茂装,MeshFilter加載Mesh,MeshRenderer呈現(xiàn)Mesh善延;

1.1 BackGround

首先創(chuàng)建一個空對象少态,命名為BackGround,作為所有背景元素的父對象存在:


BackGround.png

MenuBg和上一篇中一樣(注意環(huán)境光的設置)易遣,這里就不在敘述直接進入MenuInfo步驟彼妻,創(chuàng)建一個空對象作為BackGround的子對象,同時加入MeshFilter和MeshRenderer這兩個組件豆茫,同時添加上如下圖所示的Mesh和Materials:


MenuInfo.png

完成之后呈現(xiàn)如下圖:


front.png

behind.png

MenuLogo在前面骤素,MenuElements在后面稚字,旋轉(zhuǎn)一下就可看到了。

1.2 Menu

同樣的,在Menu中也包含了兩個子元素:Fly和Shooter360唁桩,按照如下圖的層級關(guān)系建立空對象:


Menu.png

完成后,在ItemFly和FlyDescription上分別添加MeshFilter和MeshRenderer組件牵寺,如下圖:


ItemFly.png

FlyDescription.png

這里需要注意的是堂污,這個ItemFly是一個可交互項,所以添加一個Mesh Collider組件來響應射線的碰撞檢測:


Mesh Collider.png

Shooter360中的設置如下圖:

ItemShooter360.png

ShooterDescription.png

完成之后倦挂,呈現(xiàn)如下圖:


Menu.png
1.3 Selector

Selector的設置類似畸颅,如下圖:


Selector.png

完成設置后,游戲菜單的UI部分就完成方援,呈現(xiàn)如下圖:

Completed.png
2.界面功能實現(xiàn)

在VR-Sample中所有的菜單功能在VRStandardAssets.Menu這個命名空間下没炒。

2.1 界面的彈出功能

當準心移動到游戲界面時,界面會彈出一段距離犯戏,提醒玩家當前選擇的是該游戲送火,使用到的是MenuItemPopout 腳本拳话,代碼的注釋如下:

  public class MenuItemPopout : MonoBehaviour
    {
        //控制彈出的Transform組件,用來改變位置
        [SerializeField] private Transform m_Transform;         
        //彈出的交互項
        [SerializeField] private VRInteractiveItem m_Item;      
        //彈出的速度
        [SerializeField] private float m_PopSpeed = 8f;         
        //彈出的距離
        [SerializeField] private float m_PopDistance = 0.5f;    

        //交互項的原始位置
        private Vector3 m_StartPosition;                       
        //交互項需要彈出到的目標位置
        private Vector3 m_PoppedPosition;                       
        //當前需要移動到的位置(被選中時為目標位置m_PoppedPosition,未被選中時為原始位置m_StartPosition)
        private Vector3 m_TargetPosition;                       


        private void Start ()
        {
            // 開始運行時保存交互項的初始位置
            m_StartPosition = m_Transform.position;

            // 保存目標位置
            m_PoppedPosition = m_Transform.position - m_Transform.forward * m_PopDistance;
        }


        private void Update ()
        {
            // 確定當前需要移動到的位置漾脂,被選中為m_PoppedPosition假颇,沒有被選中為m_StartPosition
            m_TargetPosition = m_Item.IsOver ? m_PoppedPosition : m_StartPosition;

            // MoveTowards方法移動位置
            m_Transform.position = Vector3.MoveTowards(m_Transform.position, m_TargetPosition, m_PopSpeed * Time.deltaTime);
        }
    }

完成后,在ItemFly上掛載VRInteractiveItem和MenuItemPopout 這兩個腳本骨稿,設置如下:


ItemFly.png

同樣笨鸡,ItemShooter360設置和ItemFly一致,設置完成后坦冠,當準心移動到Fly界面時形耗,界面會彈出一段距離。

2.2 界面動畫播放

完成彈出功能后辙浑,繼續(xù)進行動畫播放的功能實現(xiàn)激涤,大致思路為:將一組連續(xù)的圖片紋理快速的替換到MeshRenderer的Material中,達到動畫播放的效果:


Material.png

material.mainTexture.png

使用到的腳本為MenuAnimator 判呕,注釋如下:

    public class MenuAnimator : MonoBehaviour
    {
        //每秒圖片紋理改變的速度
        [SerializeField] private int m_FrameRate = 30;                 
        //需要做呈現(xiàn)的MeshRenderer
        [SerializeField] private MeshRenderer m_ScreenMesh;             
        //當前的交互項
        [SerializeField] private VRInteractiveItem m_VRInteractiveItem; 
        //保存圖片的數(shù)組
        [SerializeField] private Texture[] m_AnimTextures;              

        //協(xié)程方法的等待間隔
        private WaitForSeconds m_FrameRateWait;                        
        //當前圖片紋理的序號
        private int m_CurrentTextureIndex;                              
        //是否播放的標志
        private bool m_Playing;                                         


        private void Awake ()
        {
            // 新建一個WaitForSeconds對象
            m_FrameRateWait = new WaitForSeconds (1f / m_FrameRate);
        }


        private void OnEnable ()
        {
            //訂閱交互項的OnOver和OnOut事件
            m_VRInteractiveItem.OnOver += HandleOver;
            m_VRInteractiveItem.OnOut += HandleOut;
        }

        //取消訂閱交互項的OnOver和OnOut事件
        private void OnDisable ()
        {
            m_VRInteractiveItem.OnOver -= HandleOver;
            m_VRInteractiveItem.OnOut -= HandleOut;
        }
        private void HandleOver ()
        {
            m_Playing = true;
            StartCoroutine (PlayTextures ());
        }
        private void HandleOut ()
        {
            m_Playing = false;
        }
        private IEnumerator PlayTextures ()
        {
            // 當被準心選中時倦踢,這是一個死循環(huán),動畫會一直播放
            while (m_Playing)
            {
                // 修改m_ScreenMesh材質(zhì)中的圖片紋理為第m_CurrentTextureIndex個
                m_ScreenMesh.material.mainTexture = m_AnimTextures[m_CurrentTextureIndex];

                // m_CurrentTextureIndex自增侠草,當?shù)竭_最后一個時又從0開始
                m_CurrentTextureIndex = (m_CurrentTextureIndex + 1) % m_AnimTextures.Length;

                // 等待一個m_FrameRateWait在執(zhí)行
                yield return m_FrameRateWait;
            }
        }
    }

完成后辱挥,將腳本掛載到ItemFly上,設置如下:

ItemFly.png

在ItemShooter360上也做同樣的設置边涕,完成后晤碘,當準心移動到Fly界面上時,播放相應的動畫功蜓。

2.3選擇條跟隨移動和彈出

當準心移動到某個游戲界面時园爷,界面下方的選擇條會跟隨移動,彈出提示當前的選擇界面式撼,這個功能使用到的是MenuSelectorMover腳本童社,值得一提的是,這里是通過父對象來控制旋轉(zhuǎn)端衰,子對象(即當前的交互項來控制移動)叠洗,注釋如下:

    public class MenuSelectorMover : MonoBehaviour
    {
        //彈出的速度
        [SerializeField] private float m_PopSpeed = 8f;         
        //彈出的距離
        [SerializeField] private float m_PopDistance = 0.5f;    
        //跟隨移動的速度
        [SerializeField] private float m_MoveSpeed = 7f;        
        //父對象的Transform,用來控制Rotation移動
        [SerializeField] private Transform m_ParentTransform;   
        //子對象的Transform,用來控制自身的彈出
        [SerializeField] private Transform m_ChildTransform;    
        //場景中的所有界面交互項數(shù)組
        [SerializeField] private VRInteractiveItem[] m_Items;   

        //旋轉(zhuǎn)到的目標位置
        private Quaternion m_TargetRotation;                    
        //彈出的初始位置
        private Vector3 m_StartPosition;                        
        //彈出的目標位置
        private Vector3 m_PoppedPosition;                       
        //當前需要到達的位置
        private Vector3 m_TargetPosition;                       


        void Awake ()
        {
            // 保存初始位置
            m_StartPosition = m_ChildTransform.localPosition;

            // 保存需要彈出到的位置
            m_PoppedPosition = m_ChildTransform.localPosition - Vector3.forward * m_PopDistance;
        }

        
        void Update ()
        {
            // 選擇條默認位置為初始位置
            m_TargetPosition = m_StartPosition;

            // 遍歷交互項數(shù)組,如果有交互項被選中,則將m_TargetPosition位置修改,沒有則不變
            for (int i = 0; i < m_Items.Length; i++)
            {
                //判斷是否有交互項被選中
                if (!m_Items[i].IsOver)
                    continue;

                //設置目標位置的Rotation
                m_TargetRotation = m_Items[i].transform.rotation;
                //設置目標位置的Postion為m_PoppedPosition
                m_TargetPosition = m_PoppedPosition;
                break;
            }

            // 使用Vector3.MoveTowards方法控制跟隨移動
            m_ChildTransform.localPosition = Vector3.MoveTowards (m_ChildTransform.localPosition, m_TargetPosition,
                m_PopSpeed * Time.deltaTime);

            //使用Quaternion.Slerp方法控制旋轉(zhuǎn)
            m_ParentTransform.rotation = Quaternion.Slerp(m_ParentTransform.rotation, m_TargetRotation, m_MoveSpeed * Time.deltaTime);
        }

完成后,掛載到Selector上旅东,設置如下:


Selector.png

運行后灭抑,選擇條就可以跟隨當前的交互項而移動了。


SelectorMove.png
2.4準心和選擇條的填充以及進入相應場景功能
  • 進度條的填充
      這個功能使用到是SelectionSlider腳本抵代,這個腳本用來控制Slider的填充腾节,設置如下:


    SelectionSlider.png

這里需要注意的是,這個腳本可以做2D或者3D的填充,2D使用Slider字段案腺,3D使用Renderer字段:


填充方式.png
  • 準心填充以及進入下一個場景
      這里使用到了MenuButton腳本庆冕,里面控制了準心背景的顯示,以及進入下一個場景兩個功能劈榨,腳本注釋如下:
public class MenuButton : MonoBehaviour
    {
        //這個事件在當選中的 MenuButton進度條完成后執(zhí)行
        public event Action<MenuButton> OnButtonSelected;                   

        //下一個場景的名字
        [SerializeField] private string m_SceneToLoad;                      
        //攝像機的淡出腳本访递,進入下一個場景時需要進行攝像機的淡出動作
        [SerializeField] private VRCameraFade m_CameraFade;                
        //準心的背景控制腳本,需要控制背景的顯示和隱藏以及填充完畢時訂閱相應的事件
        [SerializeField] private SelectionRadial m_SelectionRadial;         
        //當前的交互項
        [SerializeField] private VRInteractiveItem m_InteractiveItem;       

        //準心是否移入
        private bool m_GazeOver;                                            

        //事件的訂閱
        private void OnEnable ()
        {
            m_InteractiveItem.OnOver += HandleOver;
            m_InteractiveItem.OnOut += HandleOut;
            m_SelectionRadial.OnSelectionComplete += HandleSelectionComplete;
        }

        //取消事件訂閱
        private void OnDisable ()
        {
            m_InteractiveItem.OnOver -= HandleOver;
            m_InteractiveItem.OnOut -= HandleOut;
            m_SelectionRadial.OnSelectionComplete -= HandleSelectionComplete;
        }
        
        //準心移入時執(zhí)行的方法
        private void HandleOver()
        {
            //準心背景顯示
            m_SelectionRadial.Show();

            m_GazeOver = true;
        }

        //準心移出時執(zhí)行的方法
        private void HandleOut()
        {
            // 準心背景隱藏
            m_SelectionRadial.Hide();

            m_GazeOver = false;
        }

        //當準心背景填充完畢時執(zhí)行的方法
        private void HandleSelectionComplete()
        {
            //準心在當前交互項時
            if(m_GazeOver)
                StartCoroutine (ActivateButton());
        }

        private IEnumerator ActivateButton()
        {
            // 當攝像機正在漸入時同辣,不執(zhí)行
            if (m_CameraFade.IsFading)
                yield break;

            //當事件被訂閱時執(zhí)行
            if (OnButtonSelected != null)
                OnButtonSelected(this);

            // 開始攝像機漸出的動作.
            yield return StartCoroutine(m_CameraFade.BeginFadeOut(true));

            // 載入下一個場景
            SceneManager.LoadScene(m_SceneToLoad, LoadSceneMode.Single);
        }
    }

完成后拷姿,掛載在ItemFly上,設置如下:


MenuButton.png

同樣的旱函,在Shoter360上配置一樣响巢,這里完成后,就可以進行運行測試啦棒妨。

三.注意事項

1.MenuButton腳本中OnButtonSelected事件使用:
OnButtonSelected.png

這個是一個Action事件踪古,添加了一個MenuButton參數(shù),在使用的時候把當前腳本this作為參數(shù)傳遞:


OnButtonSelected_Use.png

這樣當其他地方訂閱這個事件的時候券腔,在Reticle填充完畢后伏穆,可以對這個MenuButtion進行一些操作,當然也可以做其他的操作不管這個參數(shù)纷纫。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蜈出,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子涛酗,更是在濱河造成了極大的恐慌,老刑警劉巖偷厦,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件商叹,死亡現(xiàn)場離奇詭異,居然都是意外死亡只泼,警方通過查閱死者的電腦和手機剖笙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來请唱,“玉大人弥咪,你說我怎么就攤上這事∈螅” “怎么了聚至?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長本橙。 經(jīng)常有香客問我扳躬,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任贷币,我火速辦了婚禮击胜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘役纹。我一直安慰自己偶摔,他們只是感情好,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布促脉。 她就那樣靜靜地躺著辰斋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪嘲叔。 梳的紋絲不亂的頭發(fā)上亡呵,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天,我揣著相機與錄音硫戈,去河邊找鬼锰什。 笑死,一個胖子當著我的面吹牛丁逝,可吹牛的內(nèi)容都是我干的汁胆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼霜幼,長吁一口氣:“原來是場噩夢啊……” “哼嫩码!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起罪既,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤铸题,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后琢感,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體丢间,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年驹针,在試婚紗的時候發(fā)現(xiàn)自己被綠了烘挫。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡柬甥,死狀恐怖饮六,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情苛蒲,我是刑警寧澤卤橄,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站臂外,受9級特大地震影響虽风,放射性物質(zhì)發(fā)生泄漏棒口。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一辜膝、第九天 我趴在偏房一處隱蔽的房頂上張望无牵。 院中可真熱鬧,春花似錦厂抖、人聲如沸茎毁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽七蜘。三九已至,卻和暖如春墙懂,著一層夾襖步出監(jiān)牢的瞬間橡卤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工损搬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留碧库,地道東北人。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓巧勤,卻偏偏與公主長得像嵌灰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子颅悉,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,781評論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理沽瞭,服務發(fā)現(xiàn),斷路器剩瓶,智...
    卡卡羅2017閱讀 134,633評論 18 139
  • 大學時代驹溃,在圖書館曾看過國斯賓塞.約翰遜所著《誰動了我的奶酪》,年輕氣盛的我當時對這本書并沒有什么感覺延曙,現(xiàn)在記憶中...
    寧博Villa閱讀 766評論 2 5
  • 每個人心底總會有個人 當你與他目光交錯 就像是觸到花火 他的眼睛里滿是深邃 旋轉(zhuǎn)著溫暖的銀河 我總是不禁地沉溺 深...
    STARLIGHTSMoon閱讀 82評論 0 0
  • “當局者迷 旁觀者清”搂鲫,亙古不變的真理! 傾聽小伙伴講述她的戀愛故事磺平,正處在熱戀中的她變得越來越漂亮魂仍,也變得越來越...
    福貴牌Romeo閱讀 480評論 0 0