1. はじめにワイルド カード フリップ ゲームでは、合計 8 つのまったく異なる画像を持つ 16 枚のカードがランダムに生成されます。ゲームの目的は、30 秒の制限時間内に 16 枚のカードで同じ画像のカードをペアにすることです。マッチングのルールは、2 枚のカードを連続してクリックすることです。カードの裏面の画像が同じであれば、マッチングは成功です。異なる場合は、ペアリングは失敗です。このゲームでは主にプレイヤーの記憶力がテストされます。ゲームでは、めくられるカードの数が最大 2 枚までと規定されており、そうでない場合は、最初にクリックしてめくったカードが再び覆われます (カードがうまく一致しなかった場合)。このプロジェクトは、DevEco Studio 3.1 Releaseの最新バージョンを使用して、ターミナルとクラウドの統合開発を作成します。このバージョンではクラウドデータベースへの直接呼び出しがサポートされていないため、クラウド関数を介してクラウドデータベースを呼び出すことができます。つまり、サービスカードのビジネスロジックでクラウド関数を呼び出して、ゲームデータをクラウドデータベースに保存します。開発ツールはローカル関数呼び出しテストをサポートしているため、開発が大幅に容易になります。この記事では、クラウド関数とクラウドデータベース開発に焦点を当て、サーバーレスの知識をさらに習得します。フリップゲームのユニバーサルカードの効果図は次のとおりです。 Hongmengユニバーサルカード開発詳細説明 - メモリフリップゲーム_メタサービス 2. 知識ポイントHarmonyOSのクラウド開発サポートを充実させ、HarmonyOSエコシステムのエンドクラウド連携を実現するために、DevEco Studioはクラウド開発機能を開始しました。開発者はプロジェクト作成時にクラウド開発テンプレートを選択し、DevEco StudioでHarmonyOSアプリケーション/サービスのエンドサイドとクラウドサイドの開発を同時に完了し、エンドクラウド統合型の共同開発を体験できます。 従来の開発モデルと比較すると、クラウド開発モデルは低コスト、高効率、低敷居などの利点があり、具体的な違いは以下の表に示されています。 2.1. 開発プロセス
HarmonyOS アプリケーションエンドクラウド統合開発プロセスを下の図に示します。 Hongmengユニバーサルカードの開発の詳細説明 - メモリフリップゲーム_ゲームカード_02 2.2. ターミナルクラウド統合開発プロジェクトの作成2.2.1 新しい原子力サービスプロジェクト 2.2.2 プロジェクト初期化構成 2.2.3 エンドクラウド統合開発プロジェクトの紹介 2.3. クラウドプロジェクトの開発2.3.1 クラウド機能の開発 2.3.2 クラウドデータベースの開発 2.4. クラウドプロジェクトの展開2.4.1 クラウドプロジェクトの展開 2.5. まとめ
これらのエンドクラウド統合開発の知識ポイントを理解した後、フリップゲームのユニバーサルカードを中心に、クラウドデータベース内のカードテーブル構造とゲーム記録テーブル構造を設計し、関連するクラウド関数を記述して、メタサービスビジネスロジックでクラウド関数を呼び出します。 3. クラウドデータベース開発の説明3.1. オブジェクト型の作成
3.1.1 CloudProgram -> clouddb -> objecttype を展開します。objecttype ディレクトリを右クリックし、Create -> Cloud DB Object Type を選択します。Object Type Name に t_form と入力し、OK をクリックします。コードの内容は次のとおりです。 { "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": [...] } 3.1.2 CloudProgram -> clouddb -> objecttype を展開します。objecttype ディレクトリを右クリックし、Create -> Cloud DB Object Type を選択します。Object Type Name に t_record と入力し、OK をクリックします。コードの内容は次のとおりです。 { "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. データエントリの作成3.2.1 CloudProgram -> clouddb -> dataentry を展開します。dataentry ディレクトリを右クリックし、create -> Cloud DB Data Entry を選択します。上記で作成したオブジェクト タイプとして t_form を選択し、データ エントリ名として form_data と入力して OK をクリックすると、コードの内容は次のようになります。 { "cloudDBZoneName": "widgetCard", "objectTypeName": "t_form", "objects": [ { "formId": "x000001", "formName": "卡片1", "dimension": 2 } ] } 3.2.2 CloudProgram -> clouddb -> dataentry を展開します。dataentry ディレクトリを右クリックし、作成 -> Cloud DB データ エントリをクリックします。上記で作成したオブジェクト タイプとして t_record を選択し、データ エントリ名として record_data と入力して [OK] をクリックし、内容を次のように変更します。 { "cloudDBZoneName": "widgetCard", "objectTypeName": "t_record", "objects": [ { "formId": "x000001", "matrixNum": "4x4", "bestScore": 2.234 } ] } まとめ
実際、データエントリ ファイルを作成する必要はありません。ここでは、後続の呼び出しを容易にするために、両方のテーブルに対して 1 つのデータが初期化されます。クラウド データベースでは、テーブル構造と権限構成を定義するだけで済みます。データの追加、変更、削除、クエリはすべて、クラウド機能を通じて完了できます。 4. クラウド機能開発の説明4.1. カードクラウド機能の作成4.1.1 CloudProgram -> cloudfunctions を展開します。cloudfunctions ディレクトリを右クリックし、作成 -> Cloud Function を選択します。フォームに Cloud Function Name を入力し、確認をクリックします。カード クラウド関数には、追加、削除、変更、クエリ操作が含まれるため、フォームの下に、それらを区別するために異なるフォルダーを作成します。ディレクトリ構造は次のとおりです。 Hongmengユニバーサルカード開発の詳細説明-Memory Flip Game_Serverless_03 4.1.2 まず、クラウド データベースとのインタラクション ファイルについて説明します。t_form.js は、各属性の get メソッドや set メソッドなど、クラウド データベース エンティティ クラスに対応しています。以前は、DevEco Studio の FA モードでのエンド クラウド統合開発では、クラウド データベースへの直接呼び出しがサポートされていました。現在、DevEco Studio の Stage モードでのエンド クラウド統合開発では、クラウド データベースへの直接呼び出しはサポートされておらず、クラウド関数を介した呼び出しがサポートされています。したがって、ここでのクラウド データベース エンティティ クラスは、AGC を介してエクスポートしてから、t_form ファイルにコピーできます。エクスポート手順は次のとおりです。 Hongmengユニバーサルカードの開発の詳細説明 - メモリフリップゲーム_ゲームカード_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} 4.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); } } } 4.1.4 新しいカード機能フォーム挿入を追加します。キーコードは次のとおりです。 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" }, }); } }; 4.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 と入力し、OK をクリックします。スコア クラウド関数には、追加、削除、変更、クエリ操作が含まれるため、レコードの下に、それらを区別するための異なるフォルダーを作成します。ディレクトリ構造は次のとおりです。 Hongmengユニバーサルカード開発の詳細説明-Memory Flip Game_Serverless_05 4.2.2 レコードテーブルのクラウドデータベース操作はカード操作と同じなので、ここでは繰り返しません。上記のカード操作方法を参照してください。 5. メタサービス開発5.1. 1×2カードの開発5.1.1 カードを作成する手順: 鴻蒙ユニバーサルカード開発の詳細説明-メモリフリップゲーム_終了-クラウド統合開発_06 鴻蒙ユニバーサルカード開発の詳細説明-メモリフリップゲーム_終了-クラウド統合開発_07 Hongmengユニバーサルカード開発の詳細説明-Memory Flip Game_Serverless_08 5.1.2 カードテンプレートを作成したら、それをフリップカードゲームUIに変更します。つまり、左側にメダルの画像が表示され、右側に最速記録時間が表示されます。画像効果は次のとおりです。 Hongmengユニバーサルカードの開発の詳細説明 - メモリフリップゲーム_ゲームカード_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カードの開発5.2.1 カードを作成する手順は上記と同じです。 5.2.2 カードテンプレートが作成された後、それはフリップゲームUIに変更されます。つまり、ゲームタイトル、現在の時刻、カウントダウン、ゲーム開始などのゲーム情報が上部に表示され、中央に16枚のカードが表示されます。画像効果は次のとおりです。 Hongmengユニバーサルカード開発の詳細説明-Memory Flip Game_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); } /** * 插入卡片数据。 * * @param{Form}Form表单实体。 * @param{DataRdb.RdbStore}RDB存储RDB数据库。 * @return返回操作信息。 */ 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. カード能力はパブリッククラスを呼び出す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<FormData> = [] 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. まとめカードめくりゲームメタサービスでサーバーレスクラウド関数とクラウドデータベースを使用することで、多くのことを学びました。最初は、クラウド関数を使用してクラウドデータベースを呼び出す方法がわかりませんでした。公式モールテンプレートを参照しながらテストし、このゲームで使用しました。まとめると、このプロジェクトでは次の知識ポイントが使用されました。 - 通知を公開するには、通知を使用します。
- エンドクラウド統合開発を活用し、クラウド機能を開発し、クラウドデータベースを開発します。
- FormExtensionAbility を使用して、メタサービス カードを作成、更新、削除します。
さらに詳しい情報については、Yuan Service の公式 Web サイトをご覧ください。 Yuan Service 公式ウェブサイトリンク: https://developer.huawei.com/consumer/cn/harmonyos/fa?ha_source=yuanfuwuGW&ha_sourceld=89000452
©著作権は著者に帰属します: 51CTO ブロガー Wolf Army によるオリジナル作品です。転載許可を得るには著者に連絡してください。そうでない場合は法的責任を追及されます。Hongmeng ユニバーサル カード開発の詳細な説明 - メモリ フリップ ゲーム https://blog..com/u_15008042/6972493 |