随着VR玩家团队的不断壮大,广大开发者越来越重视在VR中的互联和社交。今天我们就来讨论一下如何创建一个基于Unity的多人连线VR游戏的基础构架。本文中使用Unity版本为Pro 5.5.1, 硬件以Oculus Rift CV1举例,其他的PC端VR设备也可以以此类推。
关键点一:玩家互联
在Unity中创建一个多人在线的VR游戏,第一步首先要考虑的是如何将玩家互联。我们需要用到的是Photon UnityNetworking(简称PUN)。有联网游戏开发经验的Unity3D开发者应该对Photon并不陌生,Photon是一款实时多人游戏开发框架,相比Unity内置的网络工具开发包,PUN功能更加成熟、强大、灵活,在全球拥有数十万开发者。PUN可以直接在Unity Asset Store免费下载,免费版的PUN可支持20人同时在线。
下载PUN导入Unity后,创建一个新场景,并创建一个空白物体,取名为ConnectionObject。这个物体将承载我们关于将玩家联网、创建玩家Avatar、连接联网玩家与VR虚拟相机等一系列有关联网的功能。
首先,在Connection Object上加载PUN自带的Connect And Join Random脚本。简单介绍一下这个脚本:我们可以把Photon的联网架构想象成一个旅馆,玩家进入游戏时会首先进入大厅(Lobby),之后PUN会再把玩家分配给不同的房间(Room),而只有进入了同一个房间的玩家才可以互相交流。而Connect AndJoin Random脚本则实现了类似旅馆前台的职责,使玩家进入大厅、检查没有有空位房间、随机分配房间给玩家、若无空位房间则再开一个房间给玩家等一系列功能。
为了检查网络连接的状态,我们可以选择再加载PUN自带的Show Status When Connecting脚本,在游戏运行时更清晰的看到是否已连接。
最后,编写PlayerMovement脚本并添加给Connection Object,用于生成玩家Avatar、并定义跟随的虚拟摄像机。这段代码会在文章后面详细说明。

泰课在线承载玩家互联功能的ConnectionObject

关键点二:创建玩家Avatar
相比第一人称的VR游戏,多人联网VR需要玩家之间的互动,自然需要看到彼此的虚拟形象(Avatar)。这里,我使用的是一个连接跑动动画的全身虚拟形象。除了在这个玩家Avatar上加载Character Controller来实现游戏控制、加载Animator来实现Avatar运动动画等传统步骤外,我们还需要在玩家Avatar上加载PUN自带的PhotonView来给玩家编号,并在房间中的众多联网玩家中确定哪一个是当前本地玩家;同时,再加载PhotonTransform View,并把Photon Transform View拖入Photon View的Observed Componets中。
另外,编写脚本NetworkPlayerMove用于控制玩家的移动、速度、动画切换等。我们需要在这个脚本的Update函数中确定所操控的是当前玩家,关键代码如下:

 public class NetworkPlayerMove : MonoBehaviour {
...
    void Update()
    {
        if(m_PhotonView.isMine == true ) //确定只操控当前玩家
       {
           UpdateMovement();
           MoveCharacterController();
           ApplySynchronizedValues();
       }
        UpdateAnimation();
    }
...
}
其中,在UpdateMovement()功能函数中,我们可以定义操控玩家Avatar前后左右移动的方式,例如,可以使用Oculus Rift所配备的Oculus Remote的上下左右按键、Xbox Controller、Oculus Touch或者鼠标键盘等。但需要注意的是,这个功能应该只控制玩家的移动而不包括旋转,玩家的旋转会通过头戴HMD的旋转而控制。
最后,玩家Avatar需要以Prefab的形式在玩家进入游戏房间时自动生成,所以,我们需要把准备好的玩家Avatar转换为Prefab文件,并创建一个Resources文件夹来储存这个Prefab。这是因为接下来我们要用到的用于生成玩家Avatar的 PhotonNetwork.Instantiate 功能仅能从Resources文件夹中寻找Prefab文件的。最终生成的Prefab如下图:

泰课在线Prefab:玩家Avatar

关键点三:虚拟摄像机跟随
在多人在线VR游戏中,只有一个主摄像机(也就是HMD对应的虚拟摄像机),而当玩家进入游戏房间时,游戏的主摄像机应该始终跟随当前玩家,并处于当前玩家Avatar的眼睛部位。
首先,要确保在Player Settings中 Virtual Reality Supported是被选中的。第二,为了更方便控制摄像机,我们先创建一个空白物体Camera作为主摄像机的父元素,并调整摄像机父元素和主摄像机的位置,以确保当摄像机父元素的位置和玩家Avatar位置一致时,主摄像机在玩家Avatar的眼睛部位。

泰课在线

泰课在线

主摄像机设置
之后,在摄像机父元素Camera上添加MultiplayerCamera脚本,用于将主摄像机永远置于当前玩家Avatar的眼睛的位置,并利用HMD的旋转来定义玩家Avatar的旋转。完整脚本如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MultiplayerCamera : MonoBehaviour {
    public Transform Target; //当前玩家Avatar
    void LateUpdate()
    {
        if( Target== null )
       {
            return;
       }
       transform.position = Target.transform.position;//主摄像机位置与当前玩家Avatar位置一致
        float temp = transform.Find ("Main Camera").gameObject.transform.eulerAngles.y;
       Target.transform.eulerAngles= new Vector3 (0, temp, 0); //当前玩家Avatar随着HMD旋转而旋转
    }

}
综上所述,我们已经确保玩家之间的连线,当玩家通过PUN进入房间后,我们也准备好了需要复制给每一个玩家的Avatar,Avatar的移动、动画等可以且仅可以被自己控制,玩家Avatar的旋转被HMD控制,并且被HMD所控制的游戏虚拟主摄像机会一直处于玩家Avatar眼睛的位置。
万事俱备,只欠东风,我们只需要在玩家连线进入房间之时为玩家生成Avatar,并且告诉主摄像机当前的Avatar是所要跟随的对象。这就是我们一开始赋予确定玩家互联的Connection Object的PlayerMovement脚本,完整代码如下。到此,利用Oculus Rift在Unity中创建多人在线VR游戏的基本构架就完成了。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour {
    public MultiplayerCamera Camera;  //主相机的父元素
    public string Player; //已经定义并储存于Resources文件夹的Prefab,这里只要以string的形式写出Prefab的名字即可
    void OnJoinedRoom()
    {
        Vector3 position = new Vector3( 0, 0, 0 );
        GameObject newPlayerObject = PhotonNetwork.Instantiate( Player, position, Quaternion.identity, 0 ); //生成Prefab的玩家Avatar
       Camera.Target = newPlayerObject.transform; //确定主相机的跟随对象
    }
}