与嵌入在 SwiftUI iOS APP中的 Unity 游戏建立通信

如果你按照我之前写的关于从 SwiftUI APP启动 Unity 游戏的帖子进行操作,那你就能成功地将Unity 游戏集成到SwiftUI 项目中,并通过操控按钮进行下载或卸载。

然而,我们的 Swifty 之旅并不能就此结束,因为如果不能在两个APP之间进行通信,那几乎就等于没用。你可能需要从 iOS 向 Unity 端发送一些游戏或玩家信息以正确初始化游戏,或者,你可能要在完成游戏后将玩家的分数发送回本机APP。

这都能通过 Unity 框架实现,我们只需稍加设置,就可以轻松创建双向通信。让我们往下看吧!

注意: 我们将接着上次的讲解,所以如果你还没有看本系列的第一部分,记得一定要补上,因为第一部分所包含的项目都已经设置完成了。

我们的目标?

为了实现 iOS APP和 Unity 游戏之间的通信,我们需要制作一些比单个按钮APP稍复杂的东西,但操作仍要简单,只有这样,才不会被游戏机制分心。

因此,对于 iOS Unity 通信 ,我们要采用以下这个简单的思路:我们的 Unity 游戏将包含一个球,这个球可以根据我们从本机端发送的消息而改变颜色。在本地 iOS 端,我们将实现三个用不同颜色名称标记的按钮: 红色绿色蓝色 。每个按钮都将启动同一个Unity 游戏。但是,每个按钮向游戏发送的消息内容将会不同,因此如果用户点击 红色 按钮,球的颜色将为红色,蓝色按钮使球变为蓝色,依此类推。

对于 Unity iOS 通信, 我们将反其道而行。我们将在 Unity 游戏中添加一个按钮,通过每次按下按钮时从 Unity 向 iOS 发送的消息来跟踪它被按下的次数。

这些例子很简单,虽不代表真正的游戏,但足以让我们清楚建立通信的原理。现在我们知道该怎么做了,那就开始吧!

iOS Unity 通信

先创建一个新的 Unity 项目。在该项目中,添加一个 Quit Game 按钮并使其只调用 Application.Unload() ,这与我们在上一篇文章中所做的完全相同。如有需要,你可以重新使用之前已经具备退出按钮功能的 Unity 项目。

接下来,添加一个球体游戏对象并将其命名为

我们这个闪亮的球目前并没有什么特别之处,但一旦我们赋予它一些功能,那性质就不一样了。因此,创建一个名为 BallBehavior.cs 的新脚本并将其附加到我们的 Ball 游戏对象中。这个脚本需要有以下代码:

image
不管你信不信,这段代码是 Unity 端建立 iOS Unity 通信所需的全部代码。本机APP只需使用 UnityFramework SDK来调用 SetBallColor 方法就行。

现在我们需从Unity 导出这个游戏,并将其导出到名为 UnityBallExport 的文件夹中。

注意,每次导出 Unity 游戏时,都必须重复集成步骤:

  • 将导出的项目的 Unity-iPhone.xcodeproj 文件 拖到 主要iOS APP的 XCode 工作区

  • (重新)在 XCode 中导入 UnityFramework.framework 库,

  • 选择 Data 文件夹并选中 UnityFramework 旁边的 Target Membership 框

有关如何执行此操作的更多信息,可参阅上一篇文章将 Unity 与 iOS 连接 的部分。

现在是时候修改我们的 SwiftyUnity 项目了。我们的主要目标是从 iOS APP中调用我们刚刚在 Unity 端执行的 SetBallColor 方法。回想一下,我们从 ContentView.swift 文件中加载 Unity 游戏,我们将在演示完Unity 游戏后立即设置球的颜色。

image

需要考虑到的关键一点是,当我们发送消息时,游戏可能尚未初始化,这将导致消息丢失,这就是为什么我们将实施一种缓存机制来存储任意待处理的消息,以便在游戏加载完全后发送。

打开 Unity.swift 文件,这是我们游戏的主要入口点。添加一个名为 UnityMessage 的新结构,它将包含我们向 Unity 发送消息所需的所有数据。

现在我们有一种方法向Unity发送消息,即使用 sendMessage 调用 Unity 框架 sendMessageToGO 方法(GO 代表游戏对象)。如你所见,该APP将检查 Unity 是否已经初始化,如果已完成初始化,则会立即发送消息,否则,消息将被缓存,以便稍后发送。

我们现在需要处理发送和清理缓存消息的机制。考虑到这一点,你的 Unity.swift 文件应如下所示:




image
我在此文件中添加了注释,以便你可以和上一个比较已添加哪些内容。如你所见, sendCachedMessages method 确保在游戏初始化后发送缓存的消息(如果有的话),因此不会丢失任何内容。

Now let’s get back to our ContentView.swift so we can make use of this feature by creating our red, blue and green buttons. I added the view modifiers just to make the buttons look a bit prettier, so don’t mind them.

现在让我们回到 ContentView.swift 以便我们可以通过创建好的红、蓝和绿色按钮来对这个功能加以使用。我添加了视图修饰符只是为了让按钮看起来更漂亮一些,没有其他意思。


image
这些按钮中的每一个都调用了 Unity.shared.sendMessage 方法。第一个参数是我们在 Unity 中的游戏对象的名称,在本例中是 Ball 。第二个参数是附加到游戏对象的脚本中方法的名称,即 SetBallColor 。 第三个参数是我们要发送的消息,也就是颜色名称。记住,消息 必须是字符串类型 ,因此如果你想发送不同的类型,你需要将其封装在一个字符串中并在 Unity 端展开。

让我们通过点击按钮来测试一下:

没毛病!球收到信息并改变颜色,它们分别根据你按下的按钮,变为红色、蓝色或绿色。我们的 iOS Unity 通信到此结束。

Unity iOS 通信

以相反的方式发送消息有点棘手,但这影响不大!让我们重新审视我们的目标:我们需要通过在每次按下按钮时向 iOS 发送一条消息来跟踪 Unity 游戏中按钮被按下的次数。

那我们就先创建一个新的 Unity 项目并向场景中添加一个按钮。此外,在 Assets 文件夹内创建一个新文件夹并将其命名为 Plugins .

我们暂时离开 Unity,因为我们需要在 iOS 端做一些配置。在 SwiftyUnity 项目中,添加一个名为 NativeCallProxy 的新 Objective-C 文件。



当 XCode创建一个 Objective-C 桥接标头时,点击 Create Bridging Header 按钮并让 XCode 配置所有内容,以便也可以从项目中访问 Objective-C 代码。

重要提示: XCode 自动创建了一个名为 NativeCallProxy.m 的文件,但我们希望再扩展为 .mm 。因此,将文件重命名为 NativeCallProxy.mm

到目前为止,我们在 iOS 项目中有 2 个重要的新文件: NativeCallProxy.mmSwiftyUnity-Bridging-Header.h

再添加一个文件并将其命名为 NativeCallProxy.h 。编辑这些文件,使其具有以下内容:

image
image
image
我们将用 sendMessageToMobileApp 方法建立Unity iOS 通信。我们将通过按下我们在 Unity 场景中创建的按钮进行调用,并在本机端为该事件放置一个侦 听器。

现在是有趣的部分:我们需要将 NativeCallProxy.hNativeCallProxy.mm 移动到 Unity 项目中,因为我们将从 UnityFramework 调用它们!不过,我们也将在 XCode 中保留 SwiftyUnity-Bridging-Header.h

因此,让我们将 NativeCallProxy.hNativeCallProxy.mm 移到我们预先在 Unity 项目中创建的 Plugins 文件夹中。我们在 iOS 项目中不需要这些,因为无论如何它们都会被打包到导出的 Unity 项目中,所以可以随意从 SwiftyUnity 项目中删除它们。

是时候开始连接了。让我们创建一个名为 ButtonBehavior.cs 的 C# 脚本并用以下代码对其进行填充:

“魔法”就发生在 ButtonPressed() 方法内部。它用将在本机 iOS 端接收到的消息调用 NativeAPI.sendMessageToMobileApp() 方法。

现在 Unity 端要做的就是将此脚本与按钮本身连接起来,所以我们要将 ButtonBehavior.cs 脚本添加到按钮并连接 ButtonPressed 侦听器。

就是这样!下面让我们建立这个游戏。我们将其命名为 UnityButtonExport 并将其集成到我们的 XCode 工作区中,就像我们之前所做的一样。注意,每次将 Unity 游戏导出为 iOS 项目时,你必须:

  • 将导出项目的 Unity-iPhone.xcodeproj 文件 拖到 主 iOS APP的 XCode 工作区,
  • (重新)在 XCode 中导入 UnityFramework.framework 库,
  • 选择 Data 文件夹并选中 UnityFramework 旁边的 Target Membership 框

重要提示: 这次除了常用的配置外,我们还需要一点其他配置。还记得Unity 游戏 Plugins 文件夹中的 NativeCallProxy 文件吗?现在你将会在导出的 Unity-iPhone 项目中看到它们。

你需要选择 Unity-iPhone项目 Libraries/Plugins 文件夹里面的 NativeCallProxy.h 改变UnityFramework从 ProjectPublic 的目标成员。不要忘记这一步!

最后一步是将APP中的侦听器连接到 sendMessageToMobileApp 方法。让我们创建一个示例视图模型类,它将为我们的 Unity 消息注册一个侦听器。创建一个新的 Swift 文件,将其命名为 ViewModel.swift ,并使用以下代码对其进行填充:

image

我们还将简化我们的 ContentView.swift ,因此它只启动游戏:

image

做了这么多工作,终于到了测试通信的时候了。运行 iOS 项目并点击“按我!” 按钮。来自 Unity 的消息应该打印到你的 XCode 日志中。

注意,你必须使用 物理 iPhone 设备 (我在下面的示例 gif 中也使用了一个,我只是将其流式传输到屏幕上)。

https://miro.medium.com/max/1006/1*8TGNzqHAqpMT5dYBOZzhzQ.gif
演示网址

呼!这项工程真是不小。但你却可以将此设置应用于任何你所需要类型的通信! 这些例子虽然非常简单,但是有了这个基础,你可以进行更复杂的逻辑,例如在每一帧上发送或接收消息,甚至为游戏使用自定义蓝牙控制器,这些将在 iOS 端处理并传递给Unity。

希望你会喜欢我们的内容。愿你在 Unity 冒险中玩得开心!:nerd_face:

原文作者 Dino Trnka
原文链接 https://medium.com/mop-developers/communicate-with-a-unity-game-embedded-in-a-swiftui-ios-app-1cefb38ff439

推荐阅读
作者信息
AgoraTechnicalTeam
TA 暂未填写个人简介
文章
148
相关专栏
本专栏仅用于分享音视频相关的技术文章,与其他开发者和 Agora 研发团队交流、分享行业前沿技术、资讯。发帖前,请参考「社区发帖指南」,方便您更好的展示所发表的文章和内容。