大多数浏览器和
Developer App 均支持流媒体播放。
-
利用 RealityKit 构建 App
通过利用容易掌握的 RealityKit API 开发游戏,从实践角度了解 RealityKit 的各项功能。了解载入素材资源、构建场景、应用动画和处理游戏输入的推荐方法。看看实体和组件如何表达 RealityKit 的强大元素,同时提供灵活的自定功能。学习如何利用内建联网功能,并详细了解如何将游戏扩展为沉浸式多玩家体验。
资源
相关视频
WWDC19
-
下载
大家好 我叫 Ross 是 Apple RealityKit 团队的工程师 欢迎来到通过 RealityKit 构建 App
本场会议是一个后续会议 你可能需要先查看一下先前的会议 RealityKit 和 Reality Composer 的介绍 今天我们要讲的是 RealityKit 的应用方法 我们将指导你 创建增强现实 App 告诉你如何使用 很多框架的关键功能 在深入了解之前 先简单回顾一下 RealityKit 是什么 RealityKit 是 Apple 的新框架 用于构建 AR App 致力于为所有开发人员 提供简单直观的体验 可以让你从零开始使用 AR 可以将渲染过的内容 和真实世界的场景无缝融合 它的 Swift API 操作简单 功能强大 只需几行代码 就可以帮你完成很多工作 好了 让我们构建一个 App
我们今天要构建的 App 名字叫做 Memory Cards 顾名思义 就是一款卡片匹配游戏
点按这张卡片选择它 就可以看到它的图像 选择另一张卡片 显示图像 如果这对卡片是匹配的 它们就被移除 如果这两张卡片不匹配 卡片就会翻过去 你可以选择下一对 这个游戏很简单 但可以让我们关注和讨论 很多 RealityKit 有用的功能 我们将分四个阶段 构建 Memory Cards 首先 我们要合成一个原型 能将我们的内容 放在 AR 里 还能做一些简单交互
接下来我们要进行润色 加一些精致的艺术元素 提高性能和 AR 渲染
然后利用实体组件系统来追踪 用户状态信息
最后我们向你展示 如何使用 RealityKit 的内置网络支持 在游戏中添加多人游戏
好了 开始制作我们的原型 在之前的介绍会议中提过 有四个对象 在每个 RealityKit App 中都会用到 ARView 场景 锚点 和 实体 ARView 是你进入 AR 世界的窗口 也是使用 RealityKit 的起点 它是一个视图 属于 App 的视图层次结构 场景包含虚拟内容 用于构建你的 App 它属于 ARView
在 RealityKit 中 锚点描述 对象与真实世界的关联 需要有它们 才能放置你的虚拟内容 放置锚点的方法 是将其添加在场景中 如果合适的目标出现 锚点将自动被放置在世界中 对 Memory Cards 这个游戏 我们用一个锚点 将游戏面板放在水平面上 实体用于表示 你的虚拟内容 也是构建场景的基本单位 在 Memory Cards 中 每张卡片都由一个实体表示 你的游戏有 16 张卡片 我们就需要 16 个实体
我们现在已经知道了 App 中所需要的重要元素 现在谈谈如何创建锚点 来将虚拟游戏面板 放到现实世界中
RealityKit 的锚定 基于 ARKit 并与之整合而成 所以你可以使用它的完整功能集
要定义锚点的内容 你要创建一个锚点实体 明确你要用的锚点类型 然后把锚点实体加到场景中 一旦 ARKit 发现合适目标 锚点实体就会自动跟踪 让你的虚拟内容 如同在现实世界一样 随着你设备的移动而移动
像介绍会议中所说的 RealityKit 支持 ARKit 中所有类型的锚点 能让我们能够锚定 平面 人脸 图像 物体 新的 ARKit 3 还有身体锚点
在 Memory Cards 中 我们只需要 一个锚点放置游戏面板
我们需要把它放在一个 有足够空间的水平面上 能放下所有卡片 大约为 20 平方厘米
这个锚点就代表 在世界中的游戏面板 我们把内容放在上面 为此 我们需要写一些代码
这是 Memory Cards 原型的视图控制器 我们在视图层次结构中 放置一个 ARView 我们已经准备好找锚点 创建我们的虚拟内容 我们将在 viewDidLoad 方法中创建
为了定义我们的锚 我们创建一个锚实体 利用这个便捷的初始程序 我们可以指定锚定的平面类型 这个例子里是水平平面
我们可以输入需要的最小面积 20 平方厘米 RealityKit 的单位是米 所以 20 厘米乘以 20 厘米 就应该是 0.2 乘以 0.2 然后我们把锚点放在场景中 只要 RealityKit 发现一个 大于 20 平方厘米的水平平面 我们放在这个锚点上的 虚拟内容就会 出现在 AR 里 现在已经建好了锚点 让我们加一些虚拟内容 首先我们需要加载模型 RealityKit 原生支持 USDZ 格式的素材 以及新的 Reality File 格式
加载可以同步完成 也可以异步完成 现在我们从同步加载开始 稍后 我们会仔细讲解 当你加载 USDZ 或者 Reality File 素材时 RealityKit 会自动导入 实体层次结构 使用的网格 它的材料 以及可能使用的动画
让我们加载基本的卡片素材 要加载模型 你只需要调用 Entity.loadModel 方法 并提供素材名称 如果素材在你的 App 包里 就不需要指定文件扩展名
如果 RealityKit 可以加载素材 它就会自动创建一个 随时可用的实体供你使用 我们在这里加载了 八个基本的卡片模型 存储在数组中 Memory Cards 共有 16 张卡片 有八种不同的卡片 每种的图像不同 每种类型需要有两个实例 才能帮助我们创建八对卡片 现在只加载了八个类型的模型 另外八个模型应该怎么做呢
我们可以再调用一次 Entity.loadModel 方法 之前我们在所有卡片上进行的设置 也要在这些卡片上 都进行一遍
RealityKit 提供了更方便的解决方法 实体克隆 创建一个克隆体 需要调用 Entity.clone 方法
可以创建一个 和原来一模一样的实体
它引用的所有素材 都和原实体一样 克隆也可以递归完成 这样可以克隆实体的所有子实体 这在处理 具有多层次机构的 复杂场景时非常有用 需要注意的是 克隆实体是原实体的副本 而不是实例 如果你对原实体 做了一些改变 比方说 移除了一个子实体 这个改变不会出现在 已经存在的克隆体中
让我们开始克隆 制作卡片对 我们在这里克隆了 每种卡片类型的两个实例 把它们储存在 两个数组中 用于构建我们的游戏面板
我们可以使用原始的卡片模版 只克隆一个新的实例 但是这样将卡片模版单独保留 稍后 我们可以 轻松地再次引用 重新创建游戏面板 而不需要从头开始加载模版
你现在有 16 张卡片 我们需要把它们 放在游戏面板中 锚点居于游戏区域的中心位置 我们把卡片摆成 四乘四的网格状 下面我们需要 把每张卡片与锚点联系起来 它们就会出现在 AR 里 为此 我们需要计算 每张卡片的位置 根据其下标和数组 确定它的位置属性 当我们在锚点上 添加卡片时 锚点就相当于父项目 这就是我们需要做的 在 AR 中排列我们的卡片 并进行渲染 现在我们把卡片放在 AR 中的一个平面上 但它们什么都做不了 让我们添加交互 我们希望点按它们的时候 卡片翻转 为了达到这个效果 我们需要把 设备屏幕上的点按 转换为 AR 世界里的点按 这样 我们就知道 点按的是什么 RealityKit提供了一个点触检测 来解决这个问题
点触检测的工作原理 是将设备屏幕上 点按的 2D 点转换为 虚拟场景中的光线 然后将光线投射到场景中 RealityKit 找到 光线指向的所有对象 并返回 光线指向的 所有实体 让你知道点按的对象是什么
ARView 提供了 点触检测的方法 entity(at point:)返回 所给点距摄像头最近的实体 entities(at point:) 返回所给点处 光线指向的 所有实体 我们可以轻松地将其 集成到我们的 Memory Cards App 中 我们有一个方法响应 点按手势识别器 我们在 ARView 中 确定点按的位置 然后传递 entity(at:) 因为我们只想获得 最靠近设备的实体 如果点按位置下有一个实体 这个方法就会返回实体 我们就可以 和它进行交互 但仍需要再做一件事 才能使点按检测 正常工作
对点按检测的实体来说 它们需要一个可碰撞的形状
碰撞形状是一个简化的几何形状 通常是个盒子 它们很容易检测 也可以进行有效的交叉 和碰撞计算 更重要的是 没有碰撞形状 实体则无法进行点按检测 所以让我们给卡片增加形状 这个代码和之前制作模型 创建卡片模版的代码相同 我们在这里做一个小改动 加上实体生成 碰撞形状的方法 这将自动为实体生成 简单的盒子碰撞形状 利用实体的视觉边界 可以看到 与克隆相似 这个方法可以递归地 为实体所有的子实体 创建碰撞形状
说到克隆 碰撞形状包含在 实体克隆时 复制的数据中 由于我们已经准备好 克隆卡片模版 来构建游戏面板 因此它们也就自动包含了 这些碰撞形状 现在我们可以弄清楚 我们互动的实体是什么 让我们加上一个动画 点按卡片的时候就会播放 RealityKit 支持两种动画 第一个是变换动画 可以让你在代码中 为实体的位置 旋转 和缩放 设计动画 第二个是素材动画 它播放的动画 是嵌入到 从 USDZ 或者 Reality File 中 加载的素材里的 RealityKit 还提供了 完成处理器 可应用于这两种动画 让你知道 动画何时结束
一旦我们的卡片素材 没有嵌入的动画 那么为了翻转卡片 我们将在卡片实体上使用变换动画
变换动画可以使用 多种多样的计时功能 来控制动画的播放速度 这是线性 以恒定速率 播放动画 加速和减速 都是瞬时完成的 这是渐入 在持续的时间内 逐渐提高动画速度 渐出与渐入相反 会使动画减速 直至完成 渐入渐出还可以 结合使用 将动画加速到时间轴的中点 然后减速 直至完成 还有一个贝塞尔曲线 可以定制你的 计时功能 让我们为翻转卡片 创建一个动画 我们首先要复制一下 卡片当前的形状 这可以确保 保留当前实体的 比例和变化 这是我们不想改变的
接下来我们将使用四元参数 将变换设置为 围绕 X 轴的 180 度旋转 这样就可以翻转卡片 使图像朝上 现在开始制作动画 变换动画 使用实体的 move(to:) 方法
RealityKit 可以让 加了动画的实体 在当前状态和方法中的变换 流畅过渡 使用请求的计时功能 在这个例子中 是在给定的时间长度内执行 easeInOut
这给了我们 卡片翻转至正面向上所需的动画 实体的 move 方法 提供了播放控制器 可以让你暂停 恢复 或停止动画或接收 动画完成的通知 就像我们现在做的一样 然后翻转卡片 使其正面向下 我们只需要做个小调整 让变换的旋转设置归零 当我们调用这个 move 方法 卡片就可以 翻转朝下
现在我们的 App 能够互动了 使用点按检测 检查用户选择的对象 用变换动画隐藏卡片
现在我们完成了基本的工作 让我们增加一些细节 来改进一下 我们已经加载了简单的卡片模型 并把它们放在了 AR 里 但卡片上的 2D 图像有些无趣 感谢我们的美术团队 创作了一系列高质量的模型 我们把它们添加到组合中 让我们的 App 更加立体 我们可以用之前 同步加载的 Entity.load 方法 加载这些新的素材 但是这些模型 比之前简单的卡片素材 复杂的多 加载这些更大的素材 需要更长时间 加载可能会很快 但加载的同时 App 也可能会阻塞 如果你正在加载大量素材 而这些会累积起来 造成明显延迟影响体验 我们能做些什么改善情况呢
还好我们之前提过 RealityKit 支持 同步加载和异步加载 我们可以通过调用 Entity.loadModelAsync 方法 异步加载模型 使用异步加载 素材可以在后台加载 这样就可以解放 App 使它继续运行而不被干扰 让你的 App 响应流畅 也让 ARKit 继续观察世界的情况 当异步加载完成 你会收到一个回调 然后就可以使用你的素材 就像在同步加载时所做的一样 此外 你还可以把 加载请求结合起来 同时执行它们 在所有素材加载完成以后 接收通知 所以你不需要一点一点地 下载素材 让我们编写一些代码 异步加载我们的新模型
我们首先异步加载 单个模型 Entity.loadModelAsync 方法 需要素材的名称 就像同步加载一样 它会返回一个加载请求 用于当模型加载完成并 可以投入使用时接收通知 我们采用闭包 调用 sink 方法 在素材准备完成时执行 加载请求使用的 API 是从新的 Swift 框架 Combine 中引入的 因此我推荐大家 查看一下 Introducing Combine 和 Advances in Foundation 两场会议 这就是实现 异步加载内容的操作 现在你可以像这样 分开下载所有的素材 你也可以将多个加载请求 合并为一个
我们可以通过简单地 将另一个加载请求 附加在第一个上 然后调用 collect 将两个加载请求组合起来 之后我们调用 sink 当两个模型加载完成 闭包就开始执行 打包到数组 参数模型中以便处理
我们可以根据自己的需要进行扩展 我们集合了 八个复杂的卡片模型 做成一个加载请求
我们的 sink 闭包 会在八个卡片模型加载结束后 开始执行 组合和加载请求的闭包 让内容管理更加简单
我们展示一下 同步加载和异步加载的对比 左边的 App 使用的是同步加载 右边是异步加载 一旦同步的 App 开始加载 其他的工作都停了 因为 App 被阻塞 直到加载完成 作为对比 异步的 App 还能继续响应 用户的输入 更新摄像头 你还可以继续 观察摄像头前的世界 这两个 App 加载的时间 都是相同的 但使用异步加载的设备 可以首先显示内容 因为它可以让你 在加载的同时 继续观察世界的情况 但使用同步加载的设备 则无法做到 所以异步加载更适合 与 AR 一起使用
所以 我们需要 加载复杂模型 而不用暂停 App 但是精明的观察者 可能已经注意到了 卡片朝下时 还是能看到模型 00:16:43.356 --> 00:16:44.366 A:middle 当卡片朝下时
我们可以简单地隐藏模型 但我们无法阻止 用户弯腰查看 卡片下面的内容 查找配对的卡片 而不是翻转卡片 所以 RealityKit 有一个 特别有用的方法来解决遮挡材料 遮挡材料是不可见的 当应用在场景中的 几何体上时 就会隐藏后面的虚拟内容 显示穿过虚拟内容的影像 这里你们可以看到 我们在场景中 加了遮挡几何体 还有一些标记 将不可见物体的 形状显示出来 在遮挡动画上下移动时 它与机器人相交的部分被隐藏 而背后的真实世界 显示出来
遮挡材料非常适合 模仿真实世界的物体 这些物体会阻挡 虚拟物体 就像桌子和墙 在我们的 App 中使用一下
首先在我们的游戏面板上 加一个遮挡面 我们要创建一个 半米宽半米深的平面网格
然后创建遮挡材料 再接着创建一个模型实体 把它用在平面网格上 把它放在游戏面板 下面一点 就不会与我们模型底部交叉 之后 把它添加在锚点上 以便把遮挡材料 放在场景中
这里我们能看到遮挡平面在工作 粗略一看 好像很好的解决了问题 但当我们 向下移动设备时 可以看到遮挡平面的边缘 看到桌子里 虚拟内容的渲染 所以 游戏面板之上 这个平面做的很好 但这种情况下 我们需要在任意角度都要遮挡 解决方案是使用 遮挡盒子而非遮挡平面 我们要生成一个遮挡盒子 使用相同的遮挡材料 然后创造一个模型实体 使用遮挡盒子 取代遮挡平面
生成的几何对象 默认位于锚点中心 所以我们要将它下移半个盒子的距离 再下移一点点 这样盒子的顶部 就刚好位于 游戏板底部的下方
我们再次把它 加到锚点上 将遮挡盒子放在场景中 表面看来 和遮挡平面作用相同 但当我们开始向下移动设备 我们会看到 已经看不到我们的虚拟内容了 我们的遮挡盒子可以阻止 内容在桌子内渲染 在虚拟场景中 模拟出了真实世界的对象
现在我们的 App 可以将虚拟卡片放在 现实世界里 进行互动 我们采用异步加载资源 利用遮挡几何模拟 虚拟内容 被真实世界对象遮住 现在我想邀请 我的同事 Courtland 讲讲追踪游戏状态 Courtland
谢谢 Ross 大家好 我是 Courtland Apple RealityKit 团队的工程师 我们刚刚了解了 如何为一个 AR 游戏制作原型 添加互动 增加艺术素材 现在我想向大家展示 如何利用自定义组件和实体 追踪你的状态 以及最后的如何添加多人游戏 我们先说追踪状态
正如在介绍会议中所讲 RealityKit 使用 实体—组件设计模式 在虚拟世界中构建对象 实体本身由称为 组件的部分组成 这些组件可以定义 添加到各个实体的 特定行为和数据 使用实体和组件 可以重复使用代码 而且使用灵活 我们来看一下 怎么运用组件 我们用 RealityKit 的模型实体 来代表我们的卡片 它给我们提供了 一组组件 可表示常见的虚拟对象 我们将模型组件 应用于视觉外观 将碰撞组件应用于点按检测
模型实体还包含 一个物理组件 能让实体 以物理逼真的方式 移动以及与其他对象互动 虽然这里没有使用
RealityKit 可以让你 自定义实体 通过使用实体组件设计 你可以留下想要的行为 排除那些 你不需要的 增加你自己的新行为
让我们为卡片定制 这个实体 模型实体有我们需要的大部分内容 我们需要移除物理 因为我们没有使用
我们想储存卡片属性 表明它是显示还是隐藏状态 还有卡片种类 用来确定两张卡片是否配对
为此我们需要创建 一个具有这些属性的 新卡片组件 把它加到实体中
究竟什么是组件 一个 RealityKit 组件是一个 包含属性的 Swift 结构体
它符合组件协议 可以被添加到实体上
遵循 Codable 也是一个好主意 00:21:30.376 --> 00:21:32.556 A:middle 我们在多人游戏部分将会看到
我们开始动手做
首先声明我们的结构体 命名为 CardComponent
我们采用了 Codable 协议中的 Component
接下来 加上两个属性 一个名为 revealed 的布尔值 表示卡片的内容 是隐藏还是显示 还有一个字符串 kind 可以用来匹配两张卡片 这就是所有类型 我们先从之前 Ross 加载的一个卡片模型开始 为了演示目的 我将展示如何删除 physicBody 组件 模型实体提供了 一个 physicBody 属性 这就简单多了 我们赋值为 nil 就完成了 现在我们加载卡片组件 通过赋值给组件类型索引的 组件数组来完成
这一操作将增加组件 如果实体上 原来没有这一组件的话 更改 kind 属性也是一样的 索引到实体组件数组 赋值给 kind 属性 不是每个实体 都有一个卡片组件 访问器将返回一个备选值
对于你游戏中 使用的组件通用配置 我们可以更进一步 创建我们自己的 自定义实体 RealityKit 附带有很多 实体配置 如平行光和模型实体 你可以轻松制作自己的配置 我们在游戏中随处可见卡片 所以把它转化为实体 是一个理想的候选
我们将获得这些对象的 编译时输入检查 和代码补全 也可以添加方法 封装功能
这特别有用 当你需要同时更改多个组件时 比如在掀开卡片的同时 将卡片状态改为 revealed 创造新实体只需几步
首先需要一个新的类 代表我们的实体 然后添加我们需要的 RealityKit 组件
然后添加任意的自定义组件 我们之前看到了 模型实体上的 physicBody 属性 这是访问 physicBody 属性 简便的语法 我们将对卡片进行相同操作
我们之前扩展了
reveal 和 hide 方法
因此我们创建了派生于实体的 卡片实体类
接下来要添加 RealityKit 组件 我们加上 HasModel 还有 HasCollision 协议 这些协议让我们通过属性 或它们提供的其他方法 比如生成碰撞形状 来访问模型和碰撞组件 最后我们添加一个卡片属性 可以返回 CardComponent 因为所有卡片都需要卡片组件 所以将其设置为非可选 get 可以从数组中 获取我们的 CardComponent 如果我们没有准备好卡片 就使用空合运算符 返回默认值
set 将复制新值 到组件数组中 现在我们有了类 并用方法进行了扩展 我用 reveal 方法 来展示轻松地 协调多个更新
我们首先更新卡片的状态 表示它是显示的 我们立即执行此操作 而不是等到动画结束之后 是为了防止你在动画播放时再次点按
接下来 我们使用 Ross 之前使用的代码 来翻转卡片 就是这样 hide 方法是相反的 设置 revealed 为假 翻转卡片向下
我们看看现在使用是什么样
我们回到 onTap 处理器
调用相同的 arView.entity(at:)方法 但是这次需要 将结果投射到卡片实体 虽然我们的游戏中只有卡片 但你的 App 中可能有多种实体
转换为卡片实体 可以执行对卡片的特定操作
有新的卡片实体和组件 我们可以询问 卡片是否显示 如果它当前是显示的 我们就隐藏 反之 就显示隐藏和显示被封装 为实体的方法 我们不需要关注 隐藏和显示 卡片的具体操作 我们让代码清晰明了 通过在实体中 添加自定义组件 并在此做了一项重要功能性改进
我们现在知道 一张显示的卡片 点按之后就可隐藏起来 如果它不是 你记住的卡片 我们已经为状态构建 组件和实体 现在该进入游戏的下一阶段 还能添什么简单的东西呢
只需添加多人游戏了
AR 游戏很有意思 能和朋友一起玩更有意思
多人游戏能将简单的 卡片配对游戏变成 一场比赛 但是制作多人 AR 游戏 有很多其他的挑战 在非 AR 游戏中不会遇到
当他们把虚拟对象 放到真实世界里 我们希望所有玩家 看到对象都在同一个位置 因为所有人都在一个地方 我们希望设备之间的 更新速度可以很快 以保持现实的共享
为了实现这一点 我们从头开发了 RealityKit 去支持多人 AR 游戏 结合 ARKit 的 Collaborative Session 今年的会议也有介绍 它提供了一个工具 可以给你的 AR 体验 增加多用户的支持
我们先看一下多人游戏 对我们的游戏意味着什么 玩家会同时在游戏中 可能在任何时间 翻转卡片
每个人都会看到显示的卡片 因此 如果你关注 其他玩家的情况 就会获得一定优势 我们加上一个白色的小圈 用来提示玩家 他们正在翻转的卡片
我们看一下 RealityKit 中的 多人游戏功能 RealityKit 提供 场景自动同步 更改会在所有设备上 自动更新
提升了 MultipeerConnectivity 的设备发现和连接
这样就能轻松查找 并连接附近设备 而无需维护服务器 甚至无需连接到 相同的 Wi-Fi 网络 它提供了一个易于使用的 所有权模型 能让你控制 允许哪个玩家更改哪个实体 即使是网络繁忙的 Wi-Fi 也能降低延迟 这对加强 AR 体验十分重要
下面进行下一步 为我们游戏增加多人游戏
首先需要指定一个发起人 我们来放置游戏面板
在游戏的主菜单上 请用户选择 然后把会话连起来 它们之间就可以相互交流
我们还使用 ARKit 的 Collaborative Session 可以让我们的玩家 创建一个共享的环境地图
我们创建一个同步锚点 它可以将我们的游戏面板 连接到世界的特定位置 并在玩家之间进行协调 最后 我们利用所有权 对游戏面板进行更改 例如翻转卡片 移除卡片 我们请用户在主菜单中 选择发起 或加入 现在我们需要建立一个连接
我们使用 MultipeerConnectivity 框架 进行连接 我们不会过多介绍 MultipeerConnectivity 的细节 如果你想了解 请查看 2014 年的会议 Cross Platform Nearby Networking
首先创建一个 MCPeerID 和 MCSession
一定要启用加密 因为要和 RealityKit 一起使用
在继续推进之前 我们先检查用户角色 如果他们选择发起 我们将使用 MCNearbyServiceAdvertiser 传播会话 这说明我们有一个 可用的会话 客户端创建了一个 MCNearbyServiceBrowser 开始查找会话 现在我们有了一个 MCSession 我们需要让 RealityKit 使用进行同步 我们创建一个 MultipeerConnectivityService 来实现这一点 该服务是一个 RealityKit 类 它包含着 MCSession 使其可应用于场景同步 我们创建一个该服务 并把它赋值给场景中的 synchronizationService 属性 现在我们连接了两个设备 同步了他们的场景 但是他们还不知道 他们在物理世界中 相对于彼此的位置
让我们使用 ARKit 3 的 Collaborative Session RealityKit 提供了对其原生的支持
Collaborative Session 可以让我们 更快地建立世界 让多用户可以共享 相同的世界体验 因为我们想要协作映射 就需要打开它 我们在 viewDidLoad 的最后来做 我们要创建一个新的 WorldTrackingConfiguration
设置 isCollaborationEnabled 为真
指示 AR 会话去运行我们的配置
现在我们有 Collaborative Session 可以让我们创建一个 同步锚点 之前我们创建了一个 锚实体 要求有一个 不小于 20 平方厘米的水平面 因为现在是多玩家 我们希望 游戏面板放在一个好位置上 能让两个玩家使用 为达到这个效果 我们让 游戏发起人放置游戏面板 因为希望所有玩家看到 相同的世界位置 我们让 ARKit 同步锚点
那应该怎么做呢
发起人这端 我们使用 之前用过的 onTap 控制器
我们想挑选一个点适合所有人 我们将光线投射到现实世界
这和 Ross 之前展示过的 点按检测相似 但这个是针对 现实世界判断 而不是虚拟对象来运行的 我们的游戏面板需要 一个平坦的表面 所以我们要找一个水平面 如果它找到一个水平面 我们就采用 worldTransform 创建一个 AR 锚点 这是一个 ARKit 锚点 我们将其添加到视图提供的 AR 会话 这会创建一个同步锚点 它在真实世界的位置 会由 ARKit 协调
使用那个 AR 锚点 我们创建了一个 RealityKit 锚点实体 这是 ARKit 和 RealityKit 之间的桥梁 允许我们添加卡片 我们已经有 Ross 之前展示过的 游戏面板了
只有发起人需要建立随机游戏面板 其他人通过 网络同步自动接收
我们加载的模型 不会作为场景的一部分 进行同步 因为数据量太大 还记得 Ross 向我们展示 如何加载卡片模板吗 保证我们在所有的外观上都这样做 这就足够让我们的游戏 开始运行
在左边 我们能看到 发起人放置了游戏面板 参与者也看到了 在真实世界里的位置 是相同的 看发起人翻动卡片 然后是另一张 好吧 不是一对 可以看到它在参与者这边 是自动反应的 动画也非常流畅 不需要网络程序 现在来看参与者翻转卡片 参与者的屏幕上翻转了 但发起人的屏幕上没有 为了解释这一现象 需要先解释一下所有权 所有权是什么? 它是修改实体的权利
在一个共享会话中 一个实体一次只有一个所有者 默认为是创造这个实体的人 在我们的例子中就是发起人
所有权是可以转移的 这也是允许其他玩家 作出更改的方法 所有权的转移是可配置的 所以你可以决定 哪些实体可以转移 什么时间转移
为了阐明所有权 我们看看在游戏中发生了什么
发起人创建了卡片 说明他拥有这些卡片 这些卡片会自动出现在 参与者屏幕上 当实体的所有者 进行更改 比如 翻转卡片 这个改变 会发送给参与者 反映在他们的场景中
由于 RealityKit 从头开始 构建多人游戏 我们只能将指令同步到动画 而不能转换每一帧 所以在参与者界面上 看起来十分流畅 现在参与者翻转卡片
由于参与者不是 实体的拥有者 因此不会同步更改
虽然还是可以在 本地做出更改 但下次所有者发送更新时 它们可能会被覆盖
这会陷入两难境地 因为我们确实希望对卡片做些改变 让我们退一步 退到参与者翻转机器人卡片之前
我之前提过 所有权可以转移 任何参与者都可以请求实体的所有权 在更改之前 我们让参与者请求 黄色机器人卡片的所有权
它向发起人发送了请求 要求所有权
实体的所有者决定 是否转移所有权 他可能会拒绝 如果存在另一名参与者请求所有权 或者对象的转移模式发生改变
在默认状态 发起人接受请求 将所有权转移给参与者
参与者现在可以 随意更改卡片 我们可以显示卡片 发起人那里也会显示更改
我们让这一过程易于实现 参与者开始请求 实体的所有权 如果我们已经拥有这个对象就没问题 该请求将被通过 不需进行额外工作 请求所有权的信息返回时 我们就会知道 请求有没有被批准 如果被批准了 对卡片调用 reveal 翻转卡片
但是 如果请求被拒绝了 比如说 其他人 翻转了卡片 我们会给用户选择其他不同卡片的机会
这就是我们要做的 翻转卡片并在让所有游戏玩家看到 但是我们还想再进一步
当卡片处于显示状态时 我们希望它的所有权不会改变 当卡片处于显示状态时 我们想拒绝 对这张卡片所有权的全部请求 我们回到 reveal 方法
我们之前将 revealed 属性设为真
因为我们在卡片组件上 采用了 Codable 协议 它将自动在参与者界面上更新 不需要额外做什么 我们把卡片的 revealed 属性 设置为真 所有权转移模式设置为 manual 这会自动拒绝 任何实体所有权转移的请求 当我们翻转卡片 将状态改为隐藏 我们想开始 接受所有权转移的请求
hide 方法看起来就是这个样子
把 revealed 属性设置为假 我们把所有权转移模式 设置为 autoAccept 这将指示 RealityKit 自动接受 实体所有权转移的请求
我需要指出一件事 对所有权来说 发起人并不是特殊的 他放置了游戏面板 初始时拥有所有的卡片 但其他方面和参与者 没有差别 一旦实体的所有权转移 如果发起人想要翻转 他也需要请求
可以使用所有权转移模式 改变这个行为 以适应你的 App
我们的 App 还有 最后一个细节 当你和两个或更多玩家 一起玩游戏 你会发现 游戏板会让人困惑 你很难知道 你选择了哪张卡 别人选择了哪张 我们想添加一个透明圆圈 显示我们的选择 正如我们所见 一切都是共享的 这会显示给所有人 与它的意图不符
幸运的是 RealityKit 支持仅本地可见的实体 这非常适合展示 选择的标志或隐藏的信息 就像玩扑克的手 为此 我们移除了同步组件 在其他功能上 和别的实体一样 如果实体有子实体 它们也不会被共享 这对于将一整个实体树 设为本地可见十分有用
这里我就不展示了 我创建了一个 SelectionEntity 类 可以代表我们的选择 它的初始化增加了 一个略透明的白色圆圈
我们将它添加到 之前的 reveal 方法中 我们创建了实体和位置 稍微高于这个卡片
然后我们把同步组件 设置为 nil 这将指示 RealityKit 我们不想分享这个实体 我们把子实体正常 加入层次结构中
现在已经添加到了 reveal 中 我们也需要在隐藏卡片时移除它
更改其他属性后 我们将使用 for 循环 迭代子实体 我们可以使用 where 子句 查找类型为 selection 的实体
一旦找到 就会从父实体中移除 因为我们知道 只会有一个 selection 实体 我们将跳出循环 就是这样 我们正确处理了所有权 为选择而添加或移除了 本地实体 现在我们的游戏 在两个设备上正常运行 我们的演示为求简单 只使用两个设备进行游戏 事实上我们还能支持更多设备 而不需增加代码
让我们回顾一下 我们学了什么 我们今天展示了 RealityKit 如何简单快速的 构建 AR App
我们介绍了 如何用锚放置内容 同步和异步 加载素材 在点按检测中集成交互
实体中创建自定义组件 以及如何在 AR 体验中增加多玩家
我希望能让你们更了解 RealityKit 是什么 能做什么 我们迫不及待地想看看 你们能用它做什么 获取更多信息 以及会议视频 请查看会议的网站 并查看 Introducing RealityKit and Reality Composer 获取更多 RealityKit 的相关信息 不要错过 Introducing ARKit 3 可以了解 Collaborative Session 和其他新功能的更多信息
请一定要来我们的实验室 时间是今天下午以及 明天下午 3 点
谢谢大家 请好好享受接下来的会议 [掌声]
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。