SwiftShot:为增强现实创建游戏
SwiftShot:为增强现实创建游戏
了解Apple如何为WWDC18构建精选演示,并获得使用ARKit,SceneKit和Swift制作自己的多人游戏的技巧。
概观
SwiftShot是一款针对2到6名玩家的AR游戏,在WWDC18主题演讲中有所体现。使用此示例代码项目在您自己的设备上体验它,查看它是如何工作的,并构建您自己的自定义版本的游戏。
点击“主持人”按钮为其他附近玩家开始游戏,或点击“加入”按钮参与在其他设备上启动的游戏。如果您正在托管,该应用程序会要求您找到一个平面(如桌子)来放置游戏板:拖动,旋转和捏合以定位和调整板的大小,然后在准备好玩时点击,并出现游戏板。
当游戏板出现时,你会在桌子上找到木块的景观,每端有三个弹弓。将您的设备移到弹弓附近并触摸屏幕以抓住它,然后向后拉并释放以瞄准并射击球。用球击打盖子击倒它们,并击倒其他球队的所有三个弹弓以获胜。
入门
需要Xcode 10.0,iOS 12.0和带有A9或更高版本处理器的iOS设备。iOS模拟器不支持ARKit。
为AR设计游戏玩法
SwiftShot将增强现实作为吸引游戏玩法的媒介。
鼓励玩家运动,使游戏更加身临其境。在SwiftShot中,你可能会发现你无法在敌人的弹弓上得到很好的射击,因为挡住了挡路。你可能会发现一个块的结构,从一个角度不容易被击倒。但是你可以转移到其他弹弓并与你的队友一起找到获胜比赛的最佳角度。
不要鼓励过多的运动。**你必须小心瞄准射击,所以你不太可能撞到你的队友并让你的设备飞过房间。
促进社会参与。多人游戏AR游戏将玩家聚集在同一个空间,为他们提供令人兴奋的新方式,让他们一起玩乐。使用AR观看作为旁观者的游戏提供了不同的视角和新的体验。
保持游戏简短,但通过变化增加乐趣。站起来和手臂挥动你的设备可以令人兴奋的游戏,但它也可能是累人。SwiftShot保持比赛简短,鼓励派对式游戏,玩家可以经常进出游戏。但是SwiftShot还提供了几种游戏板布局和特效,这样每个游戏都可以有所不同。
使用本地多路由器网络和共享世界地图
SwiftShot使用MultipeerConnectivity框架与其他本地玩家建立连接,并在设备之间发送游戏数据。当您开始自己的会话时,启动会话的玩家会创建一个ARWorldMap
包含ARKit对游戏板周围区域的空间理解。加入会话的其他玩家会收到地图的副本,并查看主持人查看该表的照片。移动他们的设备以便他们看到类似的视角有助于ARKit处理收到的地图并为多人游戏建立共享参考框架。
有关设置多人AR会话的更多详细信息,请参阅创建多用户AR体验。有关此应用程序如何实现Multipeer Connectivity的详细信息,请参阅 GameBrowser
和GameSession
类。
- 注意:使用Multipeer Connectivity有助于确保ARKit收集的本地空间映射数据的用户隐私。Multipeer Connectivity使用点对点无线网络在设备之间直接传输数据。使用
required
加密设置时,它还可以防止窃听。
同步游戏动作
要在玩家之间同步游戏事件 - 比如从弹弓中发射球 - SwiftShot使用动作队列模式:
- 所述
GameManager
类维护的列表GameCommand
结构,其中每一个对一个的GameAction
描述与负责该事件的游戏者的识别符的情况下枚举值。 - 每当本地玩家执行将触发游戏事件的动作(例如在弹弓附近触摸屏幕时),游戏创建相应的
GameAction
并将其添加到列表的末尾。 - 同时,游戏对其进行编码
GameAction
并通过多重同步会话将其发送给其他玩家。每个玩家GameSession
在收到动作时对其进行解码,并将其添加到本地GameManager
实例的命令队列中。 -
GameManager
类的更新的游戏状态为SceneKit渲染每个循环过程(以每秒60帧)。在每一个上update
,它按照添加顺序从队列中删除命令,并在游戏世界中为每个命令应用结果效果(如启动球)。
将游戏事件集定义为Swift枚举可带来多种好处。枚举可以包含特定于每个游戏动作的附加信息(如弹弓抓取的状态或球发射的速度)作为每个枚举案例的相关值,这意味着您不需要在别处编写代码来确定哪些信息是相关的为哪个行动。通过Codable
在这些枚举类型上实现Swift 协议,可以轻松地序列化和反序列化操作,以便通过本地网络进行传输。
解决多人物理问题
SceneKit
有一个内置的物理引擎,为SwiftShot提供逼真的物理行为。SceneKit仅在一个设备上模拟物理,因此SwiftShot需要确保会话中的所有玩家看到相同的物理结果,同时仍然提供逼真的平滑动画。SwiftShot支持所有支持ARKit的iOS设备和不可靠的网络方案,因此无法保证会话中的所有设备都能以每秒60帧的速度进行同步。
SwiftShot使用两种技术来解决这些问题:
会话中的每个对等体都运行自己的本地物理模拟,但同步物理结果。为了确保所有同伴的游戏相关物理结果一致,游戏将开始游戏的玩家指定为真相的来源。该“服务器”角色中的对等体不断地将物理状态信息发送给所有其他对等体,这些对等体相应地更新其本地物理模拟。物理服务器不编码和传输SceneKit物理模拟的整个状态,但是它仅为与游戏相关且自上次更新以来状态已更改的主体发送更新。有关实现的详细信息,请参阅PhysicsSyncSceneData
示例代码中的类。
特定于域的数据压缩可最大限度地降低物理同步的带宽成本。为了传输物理状态信息,服务器仅编码精确同步所需的最小信息:位置,方向,速度和角速度,以及指示身体是否应被视为运动或静止的布尔标志。为了在设备之间有效地发送该信息,PhysicsNodeData
和PhysicsPoolNodeData
类型将其编码为最小二进制表示。例如:
- Position是32位浮点值的三分量向量(总共96位),但游戏被限制在80个单位宽,高和深的空间。应用此约束提供仅48位(每个组件16位)的编码位置。
- 方向可以表示为始终为正的幅度的单位四元数,而后者又可以写为四分量向量。另外,单位四元数的一个分量总是取决于其他三个,并且这些组件的值总是在从范围
-1/sqrt(2)
到1/sqrt(2)
。应用这些约束提供了38位的编码方向(2位用于标识从属组件,12位用于其他三个组件)。
为了使用这种紧凑的位打包对结构进行编码和解码,SwiftShot定义了一种BitStreamCodable
协议,扩展了Swift Codable
协议的模式,并提供了一种将位流编码类型与Codable
同一数据流中的其他Swift 类型相结合的方法。
- 注意:SwiftShot的比特流编码是专为最小数据量而构建的,因此它省略了通用编码器的功能,例如模式更改的弹性。
的GameSession
类发送和除了游戏动作接收物理同步数据。物理数据同步发生在用于游戏操作的队列之外,因此每个对等体的物理世界都会更新,以便尽早匹配服务器。