大多数浏览器和
Developer App 均支持流媒体播放。
-
利用虚拟和物理游戏手柄
是时候提高您的输入游戏了:敬请了解适用于 iPhone、iPad、Mac 和 Apple TV 的虚拟和物理游戏手柄的最新改进。认识将触摸输入转换为游戏手柄输入的屏幕虚拟手柄,并了解如何向您的 app 添加手柄共享功能。此外,我们还将展示如何支持 DualSense 手柄中的自适应触发技术,介绍手柄支持的最佳实践并指导您在提交到 App Store 之前针对可访问和可自定义输入完成一些常见的实施前检查。关于从游戏手柄保存精彩片段的更多信息,请查看 WWDC21 的“探索 ReplayKit 中的滚动剪辑”。
资源
相关视频
WWDC23
WWDC22
WWDC21
WWDC20
-
下载
♪ ♪ 嗨 我叫纳特 我在Apple的游戏科技部门工作 谢谢你们今年回来 一起了解有关游戏输入 在iOS、tvOS和macOS上的进展 首先我要为刚接触 Apple平台游戏输入的人 针对“如何”和“为什么” 做个快速回顾 然后我会展示一种全新的 虚拟GameController 然后再来一起写点小代码 最后 我想要谈更多有关实体手柄 并探讨更多新功能 所以 让我们开始复习吧 GameController架构的目标 就是能轻松 在Apple全平台加入不同种类 高效低延迟输入的支持 通过一般API 将输入硬件抽象化 GameController的架构让你 可以一口气写出你的输入代码 而不用担心输入会被重新映射 无论是在不同的手柄上 键盘或点击装置上 在iOS、iPadOS、和tvOS上 玩家可以创建全系统的 以及适用各个应用的 GameController输入映射 能让你的游戏更加自定义化 且更加无障碍 而在全平台上 你可以让UI对应 玩家手柄的特定功能或符号上 所以无论玩家 偏好圈圈、方块、三角、叉叉 或是A、B、X、Y 你的游戏UI在他们眼中都是正确的 GameController的基本框架 就是对不同的 游戏控制装置(GCDevice) 对象连线及断线的通知做反应 并轮询装置作用中的输入状态 或设置值变化处理程序 来接收输入状态变化的通知 在手柄与系统连接或断线时 GCController对象 也会被创建或移除 而你会发送 GCControllerDidConnect 以及GCControllerDidDisconnect 的通知 在GCKeyboard对象上 也是一样的模式 在键盘连线或断线 以及GCMouse对象 在指向装置连线或断线的时候都是 你要做的就是加入观察者 找出 GCController对象 何时连线或断线 你可以决定要不要 设置这些变更处理程序 来通知你输入状态的变化 或是轮询手柄位置的状况 你应该要运用这个模式 不管是在手柄、键盘 或是指向装置上 我们看过了不少很棒的新游戏 支持GameController 而大量顾客也对 支持手柄的游戏感兴趣 这就是为什么我们十分希望 帮助大家找到 支持手柄的游戏 当我们知道一款游戏支持手柄时 我们会在App Store里 加上手柄支持的标章 看起来没什么 对吧? 但这是喜爱手柄的玩家所需要的 我也知道我需要这个标章 我们总是热衷于展示及推广 支持GameController的应用 在游戏专区里我们会精选一些 充分利用手柄的应用 我不保证你的应用会被选上推广 但若你对手柄做了很好的适配 玩家们一定会察觉 所以在标记应用支持时 这就是你得做的 在Xcode里 只要加上 GameController的能力 这会为应用的Info.plist 添加GameController能力的标记 在上架App Store之前 你只要做这些就行了 当你的游戏有了这个能力后 别忘了将其放入 GameController偏好设定的 个别应用自定义区块中 玩家都喜欢按照喜好调整控制设定 而这也是增加游戏可玩性的好方法 你不需要做什么来涉及输入重新映射 但只要你标记了你的游戏 玩家们就能自己定义 当你采用GameController架构后 另一个很棒的免费特色 就是截屏及视频 玩家们可以截屏或开始视频录制 只要按一下手柄上的分享键 这里我用Fox2示范
我按了两下分享键就截屏了
该截屏会出现在我的相机胶卷里 在我的macOS台式机上 或是从AppleTV通过AirDrops 到我的手机上 现在如果我要开始或暂停录制视频 只要长按分享键 没两下子 我的通知就显示了 通过今年刚加入的功能 所录制的游戏视频
我最后对游戏在手柄支持上的建议 就是善用UI的字样 思考一下按键提示 显示在你的清单上 在MFi认证或Xbox手柄上 我们会显示Y按钮 在PlayStation手柄上 我们会显示三角形 看起来似乎是小事 但我们真的收到反映 有关UI上的按钮显示错误 你也可以考虑另一种方法 就是选择性显示按键的位置 如果这样更适合你的游戏的话 有些玩家 特别是年轻玩家 能更快地辨识出显示出来的位置 而且不用往下瞄按键名称
我们让显示正确字样变得更简单了 哪怕玩家在系统UI中 重新映射了按键 举例来说 如果你映射了 按X键会做出A键的动作 就像在映射选项显示的这样 而我们要让用户知道 按下A动作来继续 事实上我们想要显示的是X字样 如果开发者将A键动作 与该字样连结的话 为了做到这点 只要询问 A按键的sfSymbolsName 再用UIImage system-该图像名称 来显示该图像 现在就得到了重新映射后的 正确字样了 以上为我的快速回顾 如果你想知道更多细节 可以查阅其他 有关GameController的WWDC研讨会 在过去几年间 我们谈过了 有很多的开发者 将游戏带到iOS及iPadOS上 其中不少游戏是原本就为 GameController而开发的 所以预期中会有两根摇杆 或十字键、或是触控板 还有数字按键输入 我们听说了你们有些人费尽了心思 打造稳定的、舒适的 以及好看的游戏触控输入体验 我们也知道你们的 触控输入处理代码 和键盘、鼠标 GameController输入代码路径不同 为了说明这一点 我想谈谈 新的虚拟屏幕触控手柄 可以适配你们目前的 GameController输入代码 这些iPhone和iPad上的 屏幕触控操作好看极了 而且也为了手掌尺寸抓握范围 仔细调整过 反馈与感受都非常好 你可以很容易地把这些加入到应用中 而且用起来就像GameController一样 而不用再特地写一个 屏幕覆盖的UI 然后把触控输入转译到 游戏输入系统里 这些屏幕触控在代码里看起来 就像GameController架构的 GCController对象 所以你可以保有更一致的输入逻辑 它们都是能用你的图标自定义的 也能与你的颜色及式样整合 同时仍然享有iOS与iPadOS上 同样的设计语言元素 它们可以适应你想要的按键布局 例如一个或三个按键 或是十字键和多个按键 屏幕上手柄的核心原则 就是左右范围是分别配置的 而布局是根据配置来决定的 手动分配元素是不支持的 每一边的配置可以是零到四个按键 或是其中一个摇杆 一个十字键或触控板 按键和摇杆也有震动 而最后 配置在创建之后便固定了 你可以显示或隐藏元素 但你不能加入或移除它们 除非创建另一个新虚拟手柄 所以来看看要怎么选择布局 以及显示屏幕虚拟GameController 首先 创建一个GCController配置 辨认所有可能的 你想使用的按键或摇杆 再来 根据那个配置创建虚拟手柄 然后 你可以选择性地 对那些元素做配置 例如设置自定义的形状 或是将一些元素隐藏 接下来 告知系统连接手柄 然后这会触发 GCGameControllerDidConnect 通知 这你们都熟悉了 然后它会给你GCController对象 所以来看看我们要写什么代码 才能产出以下的布局吧 左右边各有个拇指摇杆 右边也有个A和B键 超级简单 首先创建一个新的 GCVirtualControllerConfiguration 对象 再来建立我们想要的元素 我们想要两根拇指摇杆和两颗按键 出现在右边 就像上述的图片一样 接下来创建 GCVirtualController对象 作为配置之用 最后再来呼叫连结 我们的标准 GCControllerDidConnectNotification 就会出现了
所以真的很简单 但我们是怎么像上述图片那样 建立这些按键的视觉的? 可以简单做到这点 通过 调整GCVirtualController 元素的配置 在这个布局里我改变了 A按键来表示回旋攻击 而B按键表示跳跃 我调整了A键的配置 来增加BezierPath 接着我设置了B键 来建立它的BezierPath 可以通过config.hidden属性 轻易地显示或隐藏按键元素 如你所见 不需要花太多时间 能随意自定义按键 好的 让我们回来 讨论真实世界的实体手柄 市面上有很多优秀的手柄 可供玩家选择 有些是为iPhone打造的 MFi认证手柄 并且我们经常看到它们推陈出新 独立的SteelSeries Nimbus+ 现在有了L3/R3拇指板机 以及更多系统按键 太棒了 我也很喜爱大小适中的 Razer Kishi和Backbone One 这些大小适中的手柄 是我会放进背包里的最爱 当然 除了MFi手柄 我们也支持Sony DualShock 4 和Xbox One手柄 在全Apple平台上使用 玩家对去年加入Xbox Elite V2 与Xbox自适应手柄的支持 也非常喜爱 我们在iOS 14.5 和macOS 11.3上加入了最新一代 主机手柄的支持 Sony DualSense手柄 和Xbox Series X手柄 都是手感非常棒的手柄 在你运用游戏手柄架构 作业时非常顺手 Xbox Series X手柄 有专门的分享键 而DualSense有很酷的 自适应板机技术 让我们深入探讨一下自适应板机 还有如何实际运用它们 DualSense自适应板机 能通过力道的回馈 真正提升游戏的沉浸感 根据玩家的操作 加入各种板机的阻力 就能模拟拉弓的感觉 或是弹弓的张力 以及其他更多感觉 我希望你们都能亲身体会 这些板机有多棒 在游戏手柄架构中 支持自适应板机的方法 非常直白明了 首先得验证玩家手柄上的 实体输入描述文件是DualSense 接下来 通过方法呼叫 (method call) 设置想要的板机效果 如果你要创造更生动的效果 你可以不断读取游戏和板机的状态 并分别调整你的效果 例如 你能加入更多的阻力 无论是用力按下板机 或是玩家将绳子拉得更紧 最后 就像我孩子离开房间 会记得关灯一样 你得确保 在结束之后关掉自适应板机效果 来看看这个代码范例 在实例中是如何达成的 例如说这款游戏中 玩家可以发射弹弓 击倒一些目标 玩家可以用左板机瞄准 和使用右板机来拉弹弓 我们希望在玩家拉弹弓时 加入自适应板机的效果 首先 我们要确认玩家的 手柄是DualSense 既然我们的游戏都是单人游戏 我们需要检查 GCController.current 来找到运作中的手柄 在这之后 我们可以抓取 DualSense的右自适应板机 在这个例子中 我们希望只有在 玩家拉弓瞄准时加入阻力 我们会根据板机扣下的力道 来动态计算阻力的大小 如果板机没有被扣到底 我们就会为板机加入反馈效果 回馈效果会在你扣下板机时 为手指带来持续性的阻力 但现在如果板机被扣到底时 我们会加入低频的震动效果 这个效果会让板机震动 模拟保持瞄弓的挣扎感 往后拉弓的张力 最后 一旦玩家发射了弹弓 我们想将自适应板机关闭 今天我们最后的一个话题是 关于通过手柄分享键的媒体撷取 去年 我们介绍过一些手柄分享键上 专用的媒体截取手势 分享键通常是映射在 手柄最左上角的系统按钮 但一些手柄 如Xbox Series X 则另外标明了分享键的位置 如同我先前展示的 系统的媒体撷取手势 是通过双击按钮截屏 并存入相机胶卷中 以及长按来启动或暂停 ReplayKit录制视频 在今年 我们加入了超级酷的 媒体撷取方式 15秒高光时刻 所以比起得记住什么时候 开始和停止录像 玩家可以开启自动背景缓冲 让他们可以储存 最近15秒的游玩画面 只要长按就行 ReplayKit视频是个很好的方法 让玩家们捕捉伟大的头目战 美妙的连续技 或是壮烈的失误 如果要在自动录制一段长视频 或是在背景录制长达15秒的高光 这两者之间做选择 只要在游戏手柄的偏好设定面板 切换到全球或个别应用设定 如果想在游戏中某个重要时刻 触发自己的高光 这有个专门的API 这也会触发15秒的快照 咻 好的 以上就是今年游戏输入的新消息 在结束之前 请记得将你的应用 标记为支持游戏手柄 来取得个别应用自定义 如此App Store才会 帮你的应用找到合适的分类 我们很期待看到你们在游戏中 运用游戏手柄、键盘和鼠标 如果你们想要看更多 有关游戏开发者和玩家的特别节目 请看 《探索ReplayKit中的卷动片段》 以及《Game Center新鲜事》 感谢你们的收看 希望很快能亲自与你们见面 至于现在 我们很期待与你们 在线上见面 及解答你们的问题 [轻快音乐]
-
-
2:06 - GameController Basics
func setupGameController() { // Add handler for when controller connects. NotificationCenter.default.addObserver( forName: NSNotification.Name.GCControllerDidConnect, object: nil, queue: nil) { (note) in guard let _controller = note.object? as GCController else { return } // Add controller input change handlers. _controller.physicalInputProfile[GCInputButtonA]?.valueChangedHandler = { ... } _controller.physicalInputProfile[GCInputButtonB]?.valueChangedHandler = { ... } } // Add handler for when controller disconnects. NotificationCenter.default.addObserver( forName: NSNotification.Name.GCControllerDidDisconnect, object: nil, queue: nil) { (note) in ... } } // Polling for controller input. func checkInput() { if controller.physicalInputProfile[GCInputButtonA]?.pressed { ... } if controller.physicalInputProfile[GCInputButtonB]?.pressed { ... } }
-
8:42 - Virtual Controller Initial
// Creating an on-screen controller let virtualConfiguration = GCVirtualControllerConfiguration() virtualConfiguration.elements = [GCInputLeftThumbstick, GCInputRightThumbstick, GCInputButtonA, GCInputButtonB] let virtualController = GCVirtualController(configuration: virtualConfiguration) virtualController.connect()
-
9:17 - Customizing Buttons
// Creating customized buttons vc.changeElement(GCInputButtonA) { config in let spinningPath = UIBezierPath() // load or draw the spinning attack path config.path = spinningPath return config } vc.changeElement(GCInputButtonB) { config in let jumpPath = UIBezierPath() // load or draw the jump path config.path = jumpPath return config }
-
12:06 - DualSense Adaptive Triggers
func updateControllerAdaptiveTriggers() { guard let dualSense = GCController.current?.physicalInputProfile as? GCDualSenseGamepad else { return } let adaptiveTrigger = dualSense.rightTrigger if playerIsPullingSlingshot { let resistiveStrength = min(1, 0.4 + adaptiveTrigger.value) if adaptiveTrigger.value < 0.9 { adaptiveTrigger.setModeFeedbackWithStartPosition( 0, resistiveStrength: resistiveStrength) } else { adaptiveTrigger.setModeVibrationWithStartPosition( 0, amplitude: resistiveStrength, frequency: 0.03) } } else if adaptiveTrigger.mode != .off { adaptiveTrigger.setModeOff() } }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。