<p>
本篇完成游戲菜單界面,場景中呈現(xiàn)所有的游戲選擇界面贷腕,激活相應的游戲界面進入游戲場景状共,這里面使用到了VRStandardAssets.Menu中的一些腳本。下面用到的時候會寫出注釋构灸,場景如下圖:
</p>
一、實現(xiàn)功能
- 游戲選擇界面的動畫播放
當視線準心選擇界面的時候岸梨,界面會向玩家彈出一段距離喜颁,并播放該游戲的介紹動畫稠氮,視線移開時,停止播放半开,界面回到原來位置隔披。 - 選擇條的跟隨,填充和場景的進入
選擇條會動態(tài)的移動到當前準心的游戲界面上寂拆,并且在進入過程中會進行填充奢米,填充完畢后開始相應的游戲。
二纠永、步驟
1. UI的制作
游戲菜單的UI分為3塊:BackGround鬓长,Menu,Selector尝江。
下面開始一步一步制作痢士,首先是BackGround,這里需要注意的是:3D UI的呈現(xiàn)是通過MeshFilter和MeshRenderer這兩個組件茂装,MeshFilter加載Mesh,MeshRenderer呈現(xiàn)Mesh善延;
1.1 BackGround
首先創(chuàng)建一個空對象少态,命名為BackGround,作為所有背景元素的父對象存在:
MenuBg和上一篇中一樣(注意環(huán)境光的設置)易遣,這里就不在敘述直接進入MenuInfo步驟彼妻,創(chuàng)建一個空對象作為BackGround的子對象,同時加入MeshFilter和MeshRenderer這兩個組件豆茫,同時添加上如下圖所示的Mesh和Materials:
完成之后呈現(xiàn)如下圖:
MenuLogo在前面骤素,MenuElements在后面稚字,旋轉(zhuǎn)一下就可看到了。
1.2 Menu
同樣的,在Menu中也包含了兩個子元素:Fly和Shooter360唁桩,按照如下圖的層級關(guān)系建立空對象:
完成后,在ItemFly和FlyDescription上分別添加MeshFilter和MeshRenderer組件牵寺,如下圖:
這里需要注意的是堂污,這個ItemFly是一個可交互項,所以添加一個Mesh Collider組件來響應射線的碰撞檢測:
Shooter360中的設置如下圖:
完成之后倦挂,呈現(xiàn)如下圖:
1.3 Selector
Selector的設置類似畸颅,如下圖:
完成設置后,游戲菜單的UI部分就完成方援,呈現(xiàn)如下圖:
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 這兩個腳本骨稿,設置如下:
同樣笨鸡,ItemShooter360設置和ItemFly一致,設置完成后坦冠,當準心移動到Fly界面時形耗,界面會彈出一段距離。
2.2 界面動畫播放
完成彈出功能后辙浑,繼續(xù)進行動畫播放的功能實現(xiàn)激涤,大致思路為:將一組連續(xù)的圖片紋理快速的替換到MeshRenderer的Material中,達到動畫播放的效果:
使用到的腳本為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上,設置如下:
在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上旅东,設置如下:
運行后灭抑,選擇條就可以跟隨當前的交互項而移動了。
2.4準心和選擇條的填充以及進入相應場景功能
-
進度條的填充
這個功能使用到是SelectionSlider腳本抵代,這個腳本用來控制Slider的填充腾节,設置如下:
這里需要注意的是,這個腳本可以做2D或者3D的填充,2D使用Slider字段案腺,3D使用Renderer字段:
- 準心填充以及進入下一個場景
這里使用到了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上,設置如下:
同樣的旱函,在Shoter360上配置一樣响巢,這里完成后,就可以進行運行測試啦棒妨。
三.注意事項
1.MenuButton腳本中OnButtonSelected事件使用:
這個是一個Action事件踪古,添加了一個MenuButton參數(shù),在使用的時候把當前腳本this作為參數(shù)傳遞:
這樣當其他地方訂閱這個事件的時候券腔,在Reticle填充完畢后伏穆,可以對這個MenuButtion進行一些操作,當然也可以做其他的操作不管這個參數(shù)纷纫。