文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

鸿蒙万能卡片开发详解-记忆翻牌游戏

2024-11-30 10:04

关注

鸿蒙万能卡片开发详解-记忆翻牌游戏_元服务

2.知识点

为丰富HarmonyOS对云端开发的支持、实现HarmonyOS生态端云联动,DevEco Studio推出了云开发功能,开发者在创建工程时选择云开发模板,即可在DevEco Studio内同时完成HarmonyOS应用/服务的端侧与云侧开发,体验端云一体化协同开发。

相比于传统开发模式,云开发模式具备成本低、效率高、门槛低等优势,具体区别见下表。

2.1. 开发流程

HarmonyOS应用端云一体化开发流程如下图所示。

鸿蒙万能卡片开发详解-记忆翻牌游戏_游戏卡片_02

2.2. 创建端云一体化开发工程

2.2.1  新建原子化服务工程

2.2  工程初始化配置

2.3  端云一体化开发工程介绍

2.3. 开发云工程

2.3.1  开发云函数

2  开发云数据库

2.4. 部署云工程

1  部署云工程

2.5. 小结

了解这些端云一体化开发知识点后,下面围绕翻牌游戏万能卡片,在云数据库里设计卡片表结构和游戏记录表结构,然后再编写相关云函数,在元服务业务逻辑调用云函数。

3.云数据库开发讲解

3.1. objecttype创建

1.1 展开CloudProgram -> clouddb -> objecttype 右击objecttype目录,创建 -> Cloud DB Object Type 输入Object Type Name为t_form,点击确认,代码内容如下:

{
  "fields": [
    {
      "isNeedEncrypt": false,
      "fieldName": "formId",
      "notNull": true,
      "belongPrimaryKey": true,
      "fieldType": "String"
    },
    {
      "isNeedEncrypt": false,
      "fieldName": "formName",
      "notNull": true,
      "defaultValue": "",
      "belongPrimaryKey": false,
      "fieldType": "String"
    },
    {
      "isNeedEncrypt": false,
      "fieldName": "dimension",
      "notNull": true,
      "defaultValue": "0",
      "belongPrimaryKey": false,
      "fieldType": "Integer"
    }
  ],
  "indexes": [
    {
      "indexName": "formId",
      "indexList": [{ "fieldName": "formId", "sortType": "ASC" }]
    }
  ],
  "objectTypeName": "t_form",
  "permissions": [...]
}

1.2 展开CloudProgram -> clouddb -> objecttype 右击objecttype目录,创建 -> Cloud DB Object Type 输入Object Type Name为t_record,点击确认,代码内容如下:

{
  "fields": [
    {
      "isNeedEncrypt": false,
      "fieldName": "formId",
      "notNull": true,
      "belongPrimaryKey": true,
      "fieldType": "String"
    },
    {
      "isNeedEncrypt": false,
      "fieldName": "matrixNum",
      "notNull": true,
      "defaultValue": "",
      "belongPrimaryKey": false,
      "fieldType": "String"
    },
    {
      "isNeedEncrypt": false,
      "fieldName": "bestScore",
      "notNull": true,
      "defaultValue": "0",
      "belongPrimaryKey": false,
      "fieldType": "Double"
    }
  ],
  "indexes": [
    {
      "indexName": "formId",
      "indexList": [{ "fieldName": "formId", "sortType": "ASC" }]
    }
  ],
  "objectTypeName": "t_record",
  "permissions": [...]
}

3.2. dataentry创建

2.1 展开CloudProgram -> clouddb -> dataentry 右击dataentry目录,创建 -> Cloud DB Data Entry 这里先选择上面创建的Object Type为t_form,再输入Data Entry Name为form_data,点击确认,代码内容如下:

{
  "cloudDBZoneName": "widgetCard",
  "objectTypeName": "t_form",
  "objects": [
    {
      "formId": "x000001",
      "formName": "卡片1",
      "dimension": 2
    }
  ]
}

2.2 展开CloudProgram -> clouddb -> dataentry 右击dataentry目录,创建 -> Cloud DB Data Entry 这里先选择上面创建的Object Type为t_record,再输入Data Entry Name为record_data,点击确认,修改内容如下:

{
  "cloudDBZoneName": "widgetCard",
  "objectTypeName": "t_record",
  "objects": [
    {
      "formId": "x000001",
      "matrixNum": "4x4",
      "bestScore": 2.234
    }
  ]
}

3.3. 小结

其实dataentry文件可以不创建,这里对两个表都初始化了一条数据,是方便下面的调用使用,云数据库就是定义好表结构、权限配置就可以,数据的添加、修改、删除、查询都可以通过云函数来完成。

4.云函数开发讲解

4.1. 卡片云函数创建

1.1 展开CloudProgram -> cloudfunctions 右击cloudfunctions目录,创建 -> Cloud Function 输入Cloud Function Name为form,点击确认, 卡片云函数里包含了增删改查操作,所以在form下,创建不同的文件夹来区分,目录结构如下:

鸿蒙万能卡片开发详解-记忆翻牌游戏_Serverless_03

1.2 首先说一下与云数据库交互文件,t_form.js对应的是云数据库实体类,如各属性的get和set方法,之前FA模式下的DevEco Studio端云一体化开发,支持直接调用云数据库,现在Stage模式下的DevEco Studio端云一体化开发,还不支持直接调用云数据库,通过云函数来调用,所以这里的云数据库实体类,可以通过AGC导出,然后复制到t_form文件内,导出步骤图:

鸿蒙万能卡片开发详解-记忆翻牌游戏_游戏卡片_04

如卡片实例体类:

class t_form {
    getFieldTypeMap() {
        let fieldTypeMap = new Map();
        fieldTypeMap.set('formId', 'String');
        fieldTypeMap.set('formName', 'String');
        fieldTypeMap.set('dimension', 'Integer');
        return fieldTypeMap;
    }
    
    getClassName() {
        return 't_form';
    }

    getPrimaryKeyList() {
        let primaryKeyList = [];
        primaryKeyList.push('formId');
        return primaryKeyList;
    }

    getIndexList() {
        let indexList = [];
        return indexList;
    }

    getEncryptedFieldList() {
        let encryptedFieldList = [];
        return encryptedFieldList;
    }

	// set and get
    setFormId(formId) {this.formId = formId;}
    getFormId() {return this.formId;}
    setFormName(formName) {this.formName = formName;}
    getFormName() {return this.formName;}
    setDimension(dimension) {this.dimension = dimension;}
    getDimension() {return this.dimension;}
}

module.exports = {t_form}

1.3 CloudDBZoneWrapper操作云数据库,这里主要列举构造函数和增加方法内容:

import * as clouddb from '@agconnect/database-server';
import { t_form as FormBean } from './models/t_form';
import * as agconnect from '@agconnect/common-server';

const ZONE_NAME = "widgetCard";

export class CloudDBZoneWrapper {
  logger;
  cloudDbZone;

  constructor(credential, logger) {
    this.logger = logger;
    try {
      // 初始化AGCClient
      let agcClient;
      try {
        agcClient = agconnect.AGCClient.getInstance();
      } catch {
        agconnect.AGCClient.initialize(credential);
        agcClient = agconnect.AGCClient.getInstance();
      }
      // 初始化AGConnectCloudDB实例
      let cloudDbInstance;
      try {
        cloudDbInstance = clouddb.AGConnectCloudDB.getInstance(agcClient);
      } catch {
        clouddb.AGConnectCloudDB.initialize(agcClient);
        cloudDbInstance = clouddb.AGConnectCloudDB.getInstance(agcClient);
      }
      // 创建CloudDBZoneConfig配置对象,并设置云侧CloudDB zone名称,打开Cloud DB zone实例
      const cloudDBZoneConfig = new clouddb.CloudDBZoneConfig(ZONE_NAME);
      this.cloudDbZone = cloudDbInstance.openCloudDBZone(cloudDBZoneConfig);
    } catch (err) {
      logger.error("xx [form-func]CloudDBZoneWrapper init CloudDBZoneWrapper error: " + err);
    }
  }

  async insert(addForm) {
    if (!this.cloudDbZone) {
      this.logger.error("xx  [form-func]CloudDBZoneWrapper->insert CloudDBClient is null, try re-initialize it");
    }

    try {
      let res = await this.cloudDbZone.executeUpsert(addForm);
      this.logger.info("xx  [form-func]CloudDBZoneWrapper->insert Insert " + res + " records success");
    } catch (error) {
      this.logger.error("xx  [form-func]CloudDBZoneWrapper->insert executeInsert addressRecords failed " + error);
    }
  }
}

1.4 新增卡片函数form-insert,关键代码如下:

import { CloudDBZoneWrapper } from '../clouddb/CloudDBZoneWrapper.js';
import * as Utils from '../utils/Utils.js';

export const myHandler = async function (event, context, callback, logger) {
  const credential = Utils.getCredential(context, logger);
  try {
    const cloudDBZoneWrapper = new CloudDBZoneWrapper(credential, logger);
    let formObj = cloudDBZoneWrapper.getForm(event);
    await cloudDBZoneWrapper.insert(formObj);

    callback({
      ret: { code: 0, desc: "SUCCESS" },
    });
  } catch (err) {
    logger.error("xx [form-func]insert func error:" + err.message + " stack:" + err.stack);
    callback({
      ret: { code: -1, desc: "ERROR" },
    });
  }
};

1.5 卡片云函数主入口,关键代码如下:

let myHandler = async function (event, context, callback, logger) {
  let operation;
  let params;

  logger.info("xx enter form func with operation " + event.operation);
  operation = event.body ? JSON.parse(event.body).operation : event.operation;
  params = event.body ? JSON.parse(event.body).params : event.params;

  switch (operation) {
    case "query":
      query.myHandler(params, context, callback, logger);
      break;
    case "queryById":
      queryById.myHandler(params, context, callback, logger);
      break;
    case "insert":
      insert.myHandler(params, context, callback, logger);
      break;
    case "update":
      update.myHandler(params, context, callback, logger);
      break;
    case "delete":
      deleteByObj.myHandler(params, context, callback, logger);
      break;
    default:
      callback({
        ret: { code: -1, desc: "no such function" },
      });
  }

};
module.exports.myHandler = myHandler;

4.2. 记录云函数创建

4.2.1 展开CloudProgram -> cloudfunctions 右击cloudfunctions目录,创建 -> Cloud Function 输入Cloud Function Name为record,点击确认, 成绩云函数里包含了增删改查操作,所以在record下,创建不同的文件夹来区分,目录结构如下:

鸿蒙万能卡片开发详解-记忆翻牌游戏_Serverless_05

2.2 记录表云数据库操作与卡片操作一样,这里就不在重复了,可以参考一下上面卡片操作方法就可以。

5.元服务开发

5.1. 1*2卡片开发

1.1 创建卡片步骤:

鸿蒙万能卡片开发详解-记忆翻牌游戏_端云一体化开发_06

鸿蒙万能卡片开发详解-记忆翻牌游戏_端云一体化开发_07

鸿蒙万能卡片开发详解-记忆翻牌游戏_Serverless_08

1.2 卡片模板创建好后,修改为翻牌游戏UI, 就是左边显示一张奖牌图片,右边显示最快记录时间,图片效果为:

鸿蒙万能卡片开发详解-记忆翻牌游戏_游戏卡片_09

UI代码如下:

build() {
    Row() {
      Image($r('app.media.cup'))
        .width(32).height(32).objectFit(ImageFit.Cover)
      Text(`最快成绩:${this.totalBestScore}'s`)
        .fontSize($r('app.float.font_size'))
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.SpaceEvenly)
    .onClick(() => {
      postCardAction(this, {
        "action": 'router',
        "abilityName": 'EntryAbility',
        "params": {
          "message": 'view history'
        }
      });
    })
  }

5.2. 4*4卡片开发

2.1 创建卡片步骤如上面步骤。

2.2 卡片模板创建好后,修改为翻牌游戏UI, 就是顶部显示游戏信息,如:游戏,当前用时,倒计时,开始游戏,中部显示16张卡片,图片效果为:

鸿蒙万能卡片开发详解-记忆翻牌游戏_Serverless_10

UI部分代码如下:

build() {
    Column() {
      Row() {
        Text('记忆翻牌游戏')
        // Text(`最快:${this.totalBestScore}'s`)
        //   .fontSize(10)
        Text(`当前:${this.tookTime}'s`)
          .fontSize(10)
        Text(`倒计时:${this.timeCount}'s`)
          .fontSize(10)
        Text('开始')
          .visibility(this.isStart ? Visibility.Visible : Visibility.Hidden)
          .onClick(() => {
            this.startGame()
          })
      }
      .width(FULL_WIDTH_PERCENT)
      .justifyContent(FlexAlign.SpaceBetween)
      .height(30)

      Stack(){
        Flex({wrap: FlexWrap.Wrap, direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceEvenly}) {
          ForEach(this.arr, (idx) => {
            GameCard({card: this.cards[idx], cardArray: $cards, startTime: this.startTime})
          }, (idx) => idx.toString())
        }

        Text(this.resultMessage)
          .width(FULL_WIDTH_PERCENT)
          .height(FULL_HEIGHT_PERCENT)
          .textAlign(TextAlign.Center)
          .fontColor(Color.White)
          .backgroundColor('rgba(0,0,0,0.5)')
          .visibility(this.isStart ? Visibility.Visible : Visibility.None)
      }
      .width(FULL_WIDTH_PERCENT)
      .layoutWeight(1)
    }
    .width(FULL_WIDTH_PERCENT)
    .height(FULL_HEIGHT_PERCENT)
    .padding(10)
  }

6.代码讲解

6.1. 云函数调用公共类

export class DatabaseUtils {

  async callWithParams(context, trigger, operation, params) {
    await getAGConnect(context);
    let body = {
      "operation": operation,
      "params": params
    }

    try {
      let functionCallable = agconnect.function().wrap(trigger);
      let functionResult = await functionCallable.call(body);
      return functionResult.getValue();
    }
    catch (err) {
      return {
        "ret": {"code": -1, "desc": "ERROR"}
      }
    }
  }
    
  async invoke(context: any, trigger?: string, operation?: string, params?: object) {
    console.info(CommonConstants.DATABASE_TAG, 'xx invoke params: '+JSON.stringify(params))
    return await this.callWithParams(context, trigger, operation, params);
  }

  
  async insertForm(context: any, form: Form) {
    let res = await this.invoke(context, Triggers.FormFunc, RequestType.Insert, form);
    console.info(CommonConstants.DATABASE_TAG, 'xx insertForm result: ' + JSON.stringify(res));
  }
  ......
}

6.2. 卡片Ability调用公共类

EntryFormAbility.ets卡片生命周期代码如下:

onAddForm(want) {
    // 获取卡片ID:ohos.extra.param.key.form_identity
    let formId: string = want.parameters[CommonConstants.FORM_PARAM_IDENTITY_KEY] as string;
    // 获取卡片名称:ohos.extra.param.key.form_name
    let formName: string = want.parameters[CommonConstants.FORM_PARAM_NAME_KEY] as string;
    // 获取卡片规格:ohos.extra.param.key.form_dimension
    let dimensionFlag: number = want.parameters[CommonConstants.FORM_PARAM_DIMENSION_KEY] as number;

    // 卡片信息
    let form: Form = new Form();
    form.formId = formId;
    form.formName = formName;
    form.dimension = dimensionFlag;

    // 保存卡片信息到数据库
    DatabaseUtils.insertForm(this.context, form);
    // 获取最优成绩
    getScoreById(this.context, dimensionFlag, formId);

    // 每五分钟刷新一次
    formProvider.setFormNextRefreshTime(formId, CommonConstants.FORM_NEXT_REFRESH_TIME, (error, data) => {
      if (error) {
        console.error(CommonConstants.ENTRY_FORM_ABILITY_TAG, 'xx onAddForm 更新卡片失败:' + JSON.stringify(error))
      } else {
        console.info(CommonConstants.ENTRY_FORM_ABILITY_TAG, 'xx onAddForm 更新卡片成功')
      }
    });

    // 返回初始化卡片数据
    let formData: FormData = new FormData();
    formData.formId = formId;
    formData.bestScore = 0;
    formData.matrixNum = '1x1';
    formData.totalBestScore = 0;
    return formBindingData.createFormBindingData(formData);
  }

6.3. 主界面调用公共类

@Entry
@Component
struct Index {
  @State scoreDataList: Array = []

  aboutToAppear() {
    // 请求通知栏权限
    this.requestNotification();
    // 更新卡片信息
    DatabaseUtils.updateForms(getContext(this));
    // 获取成绩历史记录
    this.getScoreListData()
  }
  onPageShow() {
    // 更新卡片信息
    DatabaseUtils.updateForms(getContext(this));
    // 获取成绩历史记录
    this.getScoreListData()
  }
    // 获取成绩历史数据
  getScoreListData() {
    DatabaseUtils.getScoreListData(getContext(this))
      .then((res) => {
        this.scoreDataList = res;
        // 发送通知
        NotificationUtils.sendNotifications(this.scoreDataList[0].totalBestScore);
      }).catch((error) => {
      console.error(CommonConstants.MAIN_PAGE_TAG, 'xx aboutToAppear or onPageShow getScoreListData error ' + JSON.stringify(error));
    });
  }

  build() {...}
}

7.总结

通过翻牌小游戏元服务使用Serverless云函数、云数据库,学习到不少知识,开始时不懂得怎么使用云函数调用云数据库,一边参考官方商城模板,一边测试,到使用到这个小游戏上, 总结这个项目用到以下知识点:

各位也可以点击元服务官网,了解更多相关信息。

元服务官网链接: https://developer.huawei.com/consumer/cn/harmonyos/fa?ha_source=yuanfuwuGW&ha_sourceld=89000452


©著作权归作者所有:来自51CTO博客作者狼哥Army的原创作品,请联系作者获取转载授权,否则将追究法律责任 鸿蒙万能卡片开发详解-记忆翻牌游戏 https://blog.51cto.com/u_15008042/6972493

来源:51CTO博客内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯