首先簡(jiǎn)單介紹下Gear? VR頭盔上的功能按鍵:
Gear VR 第一代 的功能按鍵全部位于頭盔右側(cè)漱贱,分別如下:
兩個(gè)音量增減鍵掂僵,用來(lái)調(diào)節(jié)手機(jī)的音量反惕,功能和手機(jī)本身的音量鍵完全一樣
一個(gè)返回鍵昌渤,類似android手機(jī)上的返回鍵齐邦,在VR游戲中可以用來(lái)實(shí)現(xiàn)椎侠,返回主菜單,或者退出游戲之類的操作
觸控區(qū)域措拇,可以通過(guò)該區(qū)域識(shí)別玩家的點(diǎn)擊我纪,按下,松開(kāi)丐吓,雙擊浅悉,長(zhǎng)按,以及滑動(dòng)操作券犁,這將是玩家在游戲內(nèi)的主要操作方式(還有一個(gè)就是頭部的轉(zhuǎn)動(dòng))术健。當(dāng)然從個(gè)人體驗(yàn)來(lái)講,因?yàn)樵搮^(qū)域位于頭部側(cè)方粘衬,不同于手機(jī)屏幕荞估,不適合讓玩家通過(guò)滑動(dòng)來(lái)完成太復(fù)雜的操作,超過(guò)上下左右四方向以外的滑動(dòng)識(shí)別稚新,體驗(yàn)都不是很好勘伺。
通過(guò)圖片和按鍵講解可以看到,gearVR 與暴風(fēng)魔鏡之流的設(shè)備的區(qū)別就是褂删,它通過(guò)USB口連接手機(jī)飞醉,然后玩家可以通過(guò)頭戴設(shè)備的輸入完成一些相對(duì)完善的操作。
Unity是如何映射這些功能按鍵的:
用Unity創(chuàng)建一個(gè)空項(xiàng)目屯阀,GearVRTest_1_2,然后打開(kāi)InputManager:通過(guò)Edit-> Project Settings ->Input
點(diǎn)開(kāi)第一個(gè)Fire1:可以看到這個(gè)名稱對(duì)應(yīng)的按鍵是Left Ctrl(鍵盤(pán)上的左Ctrl鍵)缅帘,以及mouse 0(鼠標(biāo)左鍵,同時(shí)也是觸屏手機(jī)的單點(diǎn)觸屏操作难衰,也是GearVR touchpad的點(diǎn)擊操作)
點(diǎn)開(kāi)第二個(gè)Fire1:可以看到對(duì)應(yīng)的是joystick button 0 (也就是手柄上第二排第一個(gè)按鍵)
點(diǎn)開(kāi)唯一的一個(gè)Cancel:可以看到對(duì)應(yīng)的是escape(鍵盤(pán)左上角的esc鍵和安卓手機(jī)和GearVR的返回鍵)股毫,以及joystick button 1(手柄上的第二個(gè)按鍵)
通過(guò)這些按鍵映射可以看到,我們可以通過(guò)合理的按鍵映射召衔,可以使我們的VR游戲做到手機(jī),頭顯和藍(lán)牙手柄公用一套按鍵邏輯(VR頭顯bing)
通過(guò)代碼獲取玩家操作:
我們要實(shí)現(xiàn)的是一個(gè)獲取玩家輸入的腳本祭陷,而不處理具體邏輯苍凛,行為邏輯代碼通過(guò)委托的方式從該腳本獲取玩家的操作
[csharp]view plaincopy
usingUnityEngine;
usingSystem.Collections;
usingSystem;
namespacecom.bt.gearVR
{
publicclassVRInput?:?MonoBehaviour
{
publicenumSwipeDirection
{
NONE,
UP,
DOWN,
LEFT,
RIGHT,
};
publiceventAction?OnSwipe;//在touchPad上滑動(dòng)
publiceventAction?OnClick;//點(diǎn)擊touchPad
publiceventAction?OnDown;//按下
publiceventAction?OnUp;//抬起
publiceventAction?OnDoubleClick;//雙擊
publiceventAction?OnCancel;//點(diǎn)擊touchPad的返回鍵
[SerializeField]privatefloatm_DoubleClickTime=0.3f;//有效雙擊的最大時(shí)間間隔
[SerializeField]privatefloatm_SwipeWidth=0.3f;//有效滑動(dòng)的最小位移
privateVector2?m_MouseDownPosition;//記錄手指按下的位置
privateVector2?m_MouseUpPosition;//記錄手指抬起的位置
privatefloatm_LastMouseUpTime;//上一次手指抬起的時(shí)間趣席,用來(lái)檢測(cè)雙擊
privatefloatm_LastHorizontalValue;
privatefloatm_LastVerticalValue;
publicfloatDoubleClickTime?{get{returnm_DoubleClickTime;?}?}
//?Use?this?for?initialization
voidStart()
{
}
//?Update?is?called?once?per?frame
privatevoidUpdate()
{
CheckInput();
}
privatevoidCheckInput()
{
SwipeDirection?swipe?=?SwipeDirection.NONE;
if(Input.GetButtonDown("Fire1"))//手指觸碰到touchPad
{
m_MouseDownPosition?=newVector2(Input.mousePosition.x,?Input.mousePosition.y);
if(OnDown!=null)
{
OnDown();
}
}
if(Input.GetButtonUp("Fire1"))//手指離開(kāi)touchPad
{
m_MouseUpPosition?=newVector2(Input.mousePosition.x,?Input.mousePosition.y);
swipe?=?DetectSwipe();//
}
if(swipe==SwipeDirection.NONE)
{
swipe?=?DetectKeyboardEmulatedSwipe();
}
if(OnSwipe!=null)
{
OnSwipe(swipe);
}
if(Input.GetButtonUp("Fire1"))
{
if(OnUp!=null)
{
OnUp();
}
if(Time.time-m_LastMouseUpTime
{
if(OnDoubleClick!=null)
{
OnDoubleClick();
}
}
else
{
if(OnClick!=null)
{
OnClick();
}
}
m_LastMouseUpTime?=?Time.time;
}
if(Input.GetButtonDown("Cancel"))//點(diǎn)擊頭顯上的返回鍵
{
if(OnCancel!=null)
{
OnCancel();
}
}
}
///?
///?檢測(cè)滑動(dòng)方向
///?
///??滑動(dòng)方向,上下左右
privateSwipeDirection?DetectSwipe()
{
Vector2?swipeData?=?(m_MouseUpPosition?-?m_MouseDownPosition).normalized;
boolswipeIsVertical?=?Mathf.Abs(swipeData.x)?<?m_SwipeWidth;
boolswipeIsHorizontal?=?Mathf.Abs(swipeData.y)?<?m_SwipeWidth;
if(swipeData.y>0f?&&?swipeIsVertical)
{
returnSwipeDirection.UP;
}
if(swipeData.y<0?&&?swipeIsVertical)
{
returnSwipeDirection.DOWN;
}
if(swipeData.x>0?&&?swipeIsHorizontal)
{
returnSwipeDirection.RIGHT;
}
if(swipeData.x<0&&?swipeIsHorizontal)
{
returnSwipeDirection.LEFT;
}
returnSwipeDirection.NONE;
}
//檢測(cè)鍵盤(pán)或者手柄模擬的晃動(dòng)方向
privateSwipeDirection?DetectKeyboardEmulatedSwipe()
{
floathorizontal?=?Input.GetAxis("Horizontal");
floatvertical?=?Input.GetAxis("Vertical");
boolnoHorizontalInputPreviously?=?Mathf.Abs(m_LastHorizontalValue)?
boolnoVerticalInputPreviously?=?Mathf.Abs(m_LastVerticalValue)?
m_LastHorizontalValue?=?horizontal;
m_LastVerticalValue?=?vertical;
if(vertical?>?0f?&&?noVerticalInputPreviously)
returnSwipeDirection.UP;
if(vertical?<?0f?&&?noVerticalInputPreviously)
returnSwipeDirection.DOWN;
if(horizontal?>?0f?&&?noHorizontalInputPreviously)
returnSwipeDirection.RIGHT;
if(horizontal?<?0f?&&?noHorizontalInputPreviously)
returnSwipeDirection.LEFT;
returnSwipeDirection.NONE;
}
privatevoidOnDestroy()
{
OnSwipe?=null;
OnClick?=null;
OnDoubleClick?=null;
OnDown?=null;
OnUp?=null;
}
}
}
然后是測(cè)試代碼醇蝴,后面會(huì)上傳項(xiàng)目路徑宣肚,會(huì)有一個(gè)控制玩家移動(dòng)的腳本,這里不再貼出
[csharp]view plaincopy
usingUnityEngine;
usingSystem.Collections;
namespacecom.bt.gearVR
{
publicclassVRInputTest?:?MonoBehaviour
{
[SerializeField]privateVRInput?m_VRInput;
//該腳本激活時(shí)悠栓,注冊(cè)對(duì)玩家操作的監(jiān)聽(tīng)
voidOnEnable()
{
m_VRInput.OnCancel?+=?OnCalcel;
m_VRInput.OnClick?+=?OnClick;
m_VRInput.OnDown?+=?OnDown;
m_VRInput.OnUp?+=?OnUp;
m_VRInput.OnDoubleClick?+=?OnDoubleClick;
m_VRInput.OnSwipe?+=?OnSwip;
}
voidOnSwip(VRInput.SwipeDirection?swipeDirection)
{
if(swipeDirection!=VRInput.SwipeDirection.NONE)
{
Debug.Log("Unity+OnSwipe"+?swipeDirection);
}
}
//取消對(duì)玩家輸入的監(jiān)聽(tīng)
voidOnDisable()
{
m_VRInput.OnCancel?-=?OnCalcel;
m_VRInput.OnClick?-=?OnClick;
m_VRInput.OnDown?-=?OnDown;
m_VRInput.OnUp?-=?OnUp;
m_VRInput.OnDoubleClick?-=?OnDoubleClick;
m_VRInput.OnSwipe?-=?OnSwip;
}
voidOnCalcel()
{
Debug.Log("Unity+OnCancel");
}
voidOnClick()
{
Debug.Log("Unity+OnClick");
}
voidOnDown()
{
Debug.Log("Unity+OnDown");
}
voidOnUp()
{
Debug.Log("Unity+OnUp");
}
voidOnDoubleClick()
{
Debug.Log("Unity+OnDoubleClick");
}
//?Use?this?for?initialization
voidStart()
{
}
}
}
注1:GearVR第二代又新加了一個(gè)Home鍵霉涨,功能類似于手機(jī)上的Home鍵,游戲內(nèi)用不到這里不再列出
注2:玩家在游戲內(nèi)移動(dòng)時(shí)惭适,不可以直接移動(dòng)攝像機(jī)本身笙瑟,因?yàn)镚earVR限制了攝像機(jī)的移動(dòng),但是可以把攝像機(jī)掛到一個(gè)父節(jié)點(diǎn)下癞志,通過(guò)移動(dòng)父節(jié)點(diǎn)來(lái)移動(dòng)攝像機(jī)
注3:本教程中的部分代碼和圖片來(lái)源于Unity官方的教程往枷,VRSamples,感興趣的讀者可以去AssetsStore下載
Demo下載地址:https://git.coding.net/bt_coder/GearVRTurorial_1_2.git