8

HarmonyOS实战:基于鸿蒙服务卡片的分布式游戏

 3 years ago
source link: https://blog.csdn.net/nokiaguy/article/details/119516196
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

       2021年7月31日,我在杭州HarmonyOS开发者日做了一个分享,主题是关于鸿蒙服务卡片的奇妙用法。通过让多张服务卡片之间相互交互来实现一个类似“连连看”的游戏(项目名称是“找我”),而且还支持分布式,可以让多部鸿蒙设备参与进来。在过去的一段时间,经常有小伙伴私信我,问能否讲解一下这款游戏的实现原理。现在我就借这篇文章的机会,来谈一谈这款基于鸿蒙服务卡片的分布式游戏的实现原理。

1. 项目概述

游戏演示请看下面的视频

杭州鸿蒙开发者日“找我”游戏演示视频

        “找我”游戏包含两个服务卡片,尺寸分别是2×4和1×2。其中2 ×4的服务卡片用于控制游戏(相当于游戏面板)、1×2的服务卡片用于玩游戏。游戏面板卡片只能在桌面上放一个(就算放置多个,也只有第一个起作用),1×2的服务卡片用于玩游戏,可以在桌面上放置1个或多个。每一个1×2的服务卡片被分成左右两部分,分别用来显示两个随机字符,而且随机字符的颜色和背景色也是随机的,如下图所示。

         在游戏控制面板的左侧也显示一个随机字符。用户可以单击1×2的服务卡片左侧或右侧。如果被单击的随机字符与游戏控制面板上的随机字符是否相同,在游戏控制卡片上的得分就会加5分(可以设置积分增量)。当游戏控制面板右侧的倒计时为零时游戏结束,并将游戏最终的积分和相关的数据保存到数据库中,可以查看不同用户的游戏积分,如下图所示。

         如果点击游戏控制面板右侧的扩展按钮,会弹出设备列表,点击某一个设备,将该窗口流转到另外一部鸿蒙的设备,同时,两部鸿蒙设备已经连接,如下图所示。

 这时两部鸿蒙设备可以同时玩游戏,如下图所示。

         加入的鸿蒙设备越多,难度越大。而且需要脑袋来回转动寻找相同的字符,所以这款游戏对颈椎相当有好处。

2. 服务卡片的布局

        在游戏中有两个服务卡片,他们的布局都需要使用CSS和HML来实现,例如,游戏控制卡片的布局代码如下:

        这段布局代码与html非常类似。整段代码分成两部分,上半部分是游戏信息显示界面,下半部分是3个按钮。而且在这段布局代码中包含了大量的变量,如 {{ score }}、{{ randomChar}}等。这些变量都需要用Java代码进行设置。

3. 如何高频刷新服务卡片

        在默认的情况下,服务卡片的定时刷新时间最短是30分钟(需要是30分钟的整数倍)。但这个游戏要求以秒为单位刷新,所以我们需要使用其他的方式定时刷新服务卡片。可以使用线程或者是定时器进行刷新,这款游戏使用了线程来刷新服务卡片。

        例如下面的代码创建了一个线程对象gameThread。在线程对象的run方法中通过休眠的方式定时刷新服务卡片。在本例中,每2秒刷新一次(使用updateForm方法刷新服务卡片)。

4. 多张服务卡片如何交互

        在本例中需要多张服务卡片进行交互。也就是通过控制游戏的服务卡片来更新用于玩游戏的服务卡片。一个服务卡片要想控制其他的服务卡片,首先需要获得这些服务卡片的FormId。每一个服务卡片都拥有唯一的FormID。

        以首先需要在onCreateForm方法中保存这些服务卡片的FormID,代码如下:

        在这段代码中,使用了gameWidgetFormIds来保存所有1×2服务卡片的FormId,其中GameWidgetFormIds类用于保持与1*2服务卡片相关的数据,如字符颜色、背景色等。通过服务卡片的FormId,可以获取与该服务卡片相关的信息。

        不过光在onCreateForm里保存FormID还不行。因为,onCreateForm方法并不是将服务卡片放到桌面上时调用的,而是在显示服务卡片列表时调用的,看下面的图。在这张图中展示了日历应用中所有的服务卡片。其实在这时onCreateForm方法已经被调用了,而且是被调用了多次。

        实际上,日历应用里有4个服务卡片,分别是4个尺寸(1×2、2×2、2×4和4×4)。所以onCreateForm方法被调用了4次。也就是说,App中有n张服务卡片,那么onCreateForm方法就会被调用n次。

         不过不管App中有多少张服务卡片,一次只能将1张服务卡片放到桌面上,所以要获得放在桌面上的服务卡片的FormId,还需要刨除其他n-1张服务卡片的ID。因此,需要在onDeleteForm方法中删除其他n-1张服务卡片的FormID,代码如下:

也就是说,如果App中有n张服务卡片,将某一张服务卡片放到桌面上,那么会调用2n - 1次事件方法。其中n次是onCreateForm,另外n - 1次是onDeleteForm。

这里还要提一下onDeleteForm方法。该方法有如下两种情况会被调用:

(1)将服务卡片放到桌面之前(前面介绍的场景)

(2)从桌面上删除服务卡片

5. 实现分布式服务卡片

实现分布式服务卡片需要如下3步:

(1)发现其他鸿蒙设备

(2)连接鸿蒙设备

(3)鸿蒙设备之间交互数据

(1)发现其他鸿蒙设备

        发现鸿蒙设备有多种方式,本例使用了鸿蒙特有的分布式技术,就是发现其他设备的DeviceID,每一个鸿蒙设备都有唯一的DeviceID。获取其他设备的DeviceID以及相关信息,使用下面一行代码即可。getDeviceList方法会返回List类型的值,保存发现的所有鸿蒙设备的信息。

DeviceManager.getDeviceList(DeviceInfo.FLAG_GET_ALL_DEVICE);

(2)连接鸿蒙设备

        这里的连接是指望网络连接,本例使用socket连接两部鸿蒙设备。因为Socket处理高频数据传输比较有优势。在第一步发现鸿蒙设备后,通过FA流转,将发起流转的鸿蒙设备的IP通过onSaveData方法传给另外一部鸿蒙设备,代码如下:

getLocalIP方法用于获取本地IP,代码如下:

        假设发起FA流转的鸿蒙设备为A,FA流转的目标鸿蒙设备为B。这时B已经获取了A的IP。A端需要启动Socket服务,等待B端的连接,代码如下:

        B端在接收到A的IP后,会在onRestoreData方法中获取A的IP,并通过Socket连接到A,代码如下:

(3)鸿蒙设备之间交互数据

        经过前两步后,A和B已经建立了Socket数据线路,剩下的事情就简单得多了。首先A会同时为A和B产生随字符,然后从A端将随机字符传送到B端,这时B会将传输过来的随机字符显示在1×2的服务卡片上,就会看到本文一开始的效果。然后B端点击某一个卡片,会自己判断点击结果,如果点击正确,会通知A端加分。

6. 保存游戏记录

        如果想要游戏有更好的可玩性,可以将游戏中所产生的数据保存起来。本例将游戏所产生的积分保存在SQLite数据库中,以便可以查询游戏积分。保存积分数据的核心代码如下:

        上面的代码将建立一个名为game.sqlite的SQLite数据库文件,并创建一个t_records表,每次游戏结束(倒计时为0),会将游戏积分和用户名保存在t_records表中。并通过getGameRecords方法获取所有用户的游戏积分数据,并可以通过这些数据显示本文一开始展示的游戏积分列表。

        到现在为止,已经深度剖析了“找我”的核心实现原理,其中涉及到了大量鸿蒙的技术,如服务卡片、FA流转、数据库等。在开发类似应用之前,需要先掌握这些技术。如果对这些技术还不熟悉,或想完整掌握本例的实现过程,可以参考如下的视频课程:

《鸿蒙(HarmonyOS)编程思想(Java版)》

《【鸿蒙项目实战】基于鸿蒙服务卡片的分布式游戏:找我》

也可以参考我新出的《鸿蒙征途:App开发实战》一书。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK