[[427573]] 詳細については、以下をご覧ください。 51CTOとHuaweiが共同で構築したHongmengテクノロジーコミュニティ https://harmonyos..com 序文また来ましたよ。最近かなり忙しかったので、長い間この記事を書いていませんでした。国慶節の休暇中にしか時間を取って書くことができません。前回の2つの記事の準備に続き、この記事では分散型デジタル華龍島の2人用モードを実装します。以前のものについては、学習ノート「分散型デジタル華容路(中)」を参照してください。 今日から勉強を始めましょう。 [[427574]]
文章したがって、2人プレイモードでは、どのように同期するかが最も重要な問題になります。私たちのゲームでは、分散データベースを使用して 2 つのデバイス間でデータを同期します。 分散データベースを実装する場合は、まずいくつかの変数を定義する必要があります。 - プライベート静的最終 HiLogLabel TAG = new HiLogLabel(HiLog.LOG_APP,0x12345, "signal" );
- プライベートスタティック int難易度 = 3;
- プライベート DirectionalLayout レイアウト;
- プライベートスタティック 整数長さ;
- プライベート静的最終int間隔 = 5;
- プライベート静的最終int 左= 32;
- プライベート静的最終int トップ= 300;
- プライベート静的最終intマージン = 15;
- プライベートスタティック 整数長さ1;
- プライベート静的最終int left1 = 32;
- プライベート静的最終int top1 = 1350;
- プライベート静的最終int margin1 = 10;
- プライベートスタティック 整数row_a0;
- プライベートスタティック 列a0の整数値。
- プライベートスタティック 整数row_b0;
- プライベートスタティック 列b0の整数値。
- プライベートフロートstartX;
- プライベートフロートstartY;
- プライベート静的タイマータイマー;
- プライベート静的タイマー updatetimer;
- プライベート静的タイマー restarttimer;
- プライベート静的タイマーバックタイマー;
- プライベート静的テキストtimetext;
- プライベート静的テキストmaxtext;
- プライベート静的テキスト wintext;
- プライベートスタティック 整数 時間;
- プライベートスタティック 整数 分;
- プライベートスタティック 整数秒;
- プライベートスタティック 整数ミリ秒;
- プライベートスタティック 再起動 = 0;
- プライベートスタティック int戻る = 0;
- プライベートスタティック 最大時間 = 23;
- プライベートスタティック 整数最大値 = 59;
- プライベートスタティック 整数最大秒 = 59;
- プライベートスタティック 整数最大ミリ秒 = 99;
- プライベートスタティック int [][] グリッドa;
- プライベートスタティック int [][] グリッドb;
- プライベート静的最終文字列STROE_ID = "data" ;
- プライベート静的文字列 randomstr = "" ;
- プライベート静的文字列の勝者 = "" ;
- プライベート静的KvManager kvManager;
- プライベート静的文字列 strhour = "" ;
- プライベート静的文字列 strmin = "" ;
- プライベート静的文字列 strsec = "" ;
- プライベート静的文字列 strmsec = "" ;
- プライベート静的文字列テキスト = "一時停止" ;
- プライベート SingleKvStore シングルKvストア;
- プライベート静的ボタン button_moveback;
- プライベート静的ブール値 isLocal;
次のステップは分散データベースを書くことです - private KvManager createManger(){//補助クラス
- KvManager マネージャー = null ;
- 試す{
- KvManagerConfig config = 新しい KvManagerConfig(this);
- マネージャー = KvManagerFactory.getInstance().createKvManager(config);
- } キャッチ (KvStoreException 例外) {
- HiLog.info(タグ、 「エラー」 );
- }
- リターンマネージャー;
- }
-
- プライベート SingleKvStore createDb(KvManager kvManager) // データベース
- SingleKvStore kvStore = null ;
- 試す{
- オプション options = new Options();
- options.setCreateIfMissing( true ).setEncrypt( false ).setKvStoreType(KvStoreType.SINGLE_VERSION);
- kvStore = kvManager.getKvStore(オプション、STROE_ID);
- } キャッチ (KvStoreException 例外) {
- HiLog.info(タグ、 「エラー」 );
- }
- kvStoreを返します。
- }
- private void subscribeDb(SingleKvStore singleKvStore) サブスクライブ
- クラス KvStoreObserveClient は KvStoreObserver を実装します {
- @オーバーライド
- パブリックvoid onChange(ChangeNotification通知) {
-
- }
- }
- KvStoreObserver kvStoreObserverClient = 新しい KvStoreObserveClient();
- 単一のKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL、kvStoreObserverClient);
- }
-
- プライベートvoid initDbManager() {
- kvManager = createManger();
- 単一のKvStore = createDb(kvManager);
- subscribeDb(シングルKvStore);
- }
データベースに書き込むための関数を 2 つと、データベースから読み取るための関数を 1 つ追加で記述します。 - プライベートint queryContact_int(文字列キー) {
- 試す {
- singleKvStore.getInt(キー)を返します。
- } キャッチ (KvStoreException 例外) {
- HiLog.info(TAG, "int error" + exception.getMessage());
- -1 を返します。
- }
- }
- プライベート文字列queryContact_String(文字列キー) {
- 試す {
- singleKvStore.getString(キー)を返します。
- } キャッチ (KvStoreException 例外) {
- HiLog.info(TAG, "文字列エラー" + exception.getMessage());
- 戻る ヌル;
- }
- }
-
- プライベートvoid writeData_String(文字列キー、文字列値) {
- if (キー== null ||キー.isEmpty() || 値 == null || 値.isEmpty())
- 戻る;
- singleKvStore.putString(キー、値 );
- }
- プライベートvoid writeData_int(文字列キー、 int値) {
- if (キー== null ||キー.isEmpty()) {
- 戻る;
- }
- singleKvStore.putInt(キー, 値);
- }
次に、データベースからレコードを読み取る関数を記述します。ゲームが開始すると、その順序で最も速い記録が読み取られます。 - パブリックボイドgetrecord() {
- if (queryContact_int( "時間" + 難易度) != -1)
- maxhour = queryContact_int( "時間" + 難易度);
- それ以外
- 最大時間 = 23;
- if (queryContact_int( "min" + 難易度) != -1)
- maxmin = queryContact_int( "min" + 難易度);
- それ以外
- 最大最小 = 59;
- if (queryContact_int( "sec" + 難易度) != -1)
- maxsec = queryContact_int( "秒" + 難易度);
- それ以外
- 最大秒数 = 59;
- if (queryContact_int( "msec" + 難易度) != -1)
- maxmsec = queryContact_int( "msec" + 難易度);
- それ以外
- 最大ミリ秒 = 99;
- }
次に、配列の初期化を開始し、あるデバイスの初期化された配列をデータベースに書き込み、別のデバイスにデータベース内のデータを読み取らせ、それを使用してデバイスの配列を初期化します。 - パブリックボイドcreateGrids() {
- ランダム文字列 = "" ;
- if (isLocal) {
- 整数ランダム;
- 整数i = 0;
- while(i < 難易度 * 難易度 * 5) {
- ランダム = ( int )Math.floor(Math.random() *4);
- ランダムstr += ランダム;
-
- temp_row を row_a0 にセットします。
- 列a0にterm_columnを追加します。
-
- if(ランダム == 0){
- グリッドを変更します(行_a0 - 1、列_a0);
- }そうでない場合(ランダム == 1){
- グリッドを変更します(行_a0 + 1、列_a0);
- }そうでない場合(ランダム == 2){
- グリッドを変更します(行_a0、列_a0 - 1);
- }そうでない場合(ランダム == 3){
- グリッドを変更します(行_a0、列_a0 + 1);
- }
- if(temp_row != row_a0 || tem_column != column_a0){
- 私は++;
- }
- }
- HiLog.info(タグ、ランダム文字列);
- writeData_String( "ランダム文字列" ,ランダム文字列);
- }それ以外{
- (真)の間{
- if (queryContact_String( "randomstr" ) != null && !queryContact_String( "randomstr" ).isEmpty()) {
- 壊す;
- }
- }
- ランダム文字列 = queryContact_String( "ランダム文字列" );
- HiLog.info(タグ、 "ランダム文字列: " +ランダム文字列);
- 整数ランダム;
- 整数i = 0;
- while(i < randomstr.length()) {
- ランダム = ランダムstr.charAt(i) - '0' ;
- if(ランダム == 0){
- グリッドを変更します(行_a0 - 1、列_a0);
- }そうでない場合(ランダム == 1){
- グリッドを変更します(行_a0 + 1、列_a0);
- }そうでない場合(ランダム == 2){
- グリッドを変更します(行_a0、列_a0 - 1);
- }そうでない場合(ランダム == 3){
- グリッドを変更します(行_a0、列_a0 + 1);
- }
- 私は++;
- }
- singleKvStore.putString( "randomstr" , "" );
- }
- for ( int row = 0; row < 難易度; row++) {
- ( int 列= 0;列<難易度;列++) {
- grids_b[行][列] = grids_a[行][列];
- }
- }
- 行b0 = 行a0;
- 列b0 = 列a0;
- HiLog.info(タグ、 "row_a0: " + row_a0 + " column_a0: " + column_a0);
- }
次のステップは、配列内の数字を描画することです。 - パブリックvoid drawGrids() {
- ComponentContainer の LayoutConfig を新しい LayoutConfig に追加します。
-
- Component.DrawTask タスク = 新しい Component.DrawTask() {
- @オーバーライド
- public void onDraw(Component コンポーネント、Canvas キャンバス) {
- ペイント paint = new Paint();
-
- カラーバックカラー = new Color(Color.rgb(151,75,49));
- 背景色を設定します。
- RectFloat rect = new RectFloat(左- 余白、上- 余白、長さ * 難易度 + 間隔 * (難易度 - 1) +左+ 余白、長さ * 難易度 + 間隔 * (難易度 - 1) +上+ 余白);
- キャンバスに矩形を描画します。
-
- for ( int row = 0; row < 難易度; row++) {
- ( int 列= 0;列< 難易度;列++) {
- 色の背景色 = new Color(Color.rgb(229,188,132));
- 背景色を設定します。
- RectFloat rectFloat = new RectFloat(左+列* (長さ + 間隔)、上+ 行 * (長さ + 間隔)、左+ 長さ +列* (長さ + 間隔)、上+ 長さ + 行 * (長さ + 間隔));
- キャンバスに矩形を描画します。
-
- 色番号color = new Color(Color.rgb(140,85,47));
- paint.setColor(数値色);
- paint.setTextSize(長さ / 2);
- if(grids_a[行][列] != 0){
- if(grids_a[行][列] < 10){
- canvas.drawText(paint, Integer .toString(grids_a[row][ column ]), left + column * (length + interval) + length / 12 * 5, top + row * (length + interval) + length / 3 * 2);
- }それ以外{
- canvas.drawText(paint, Integer .toString(grids_a[row][ column ]), left + column * (length + interval) + length / 12 * 3, top + row * (length + interval) + length / 3 * 2);
- }
- }
- }
- }
-
- 背景色を設定します。
- 長さ1 = 600 / 難易度 - 間隔;
- RectFloat rect1= new RectFloat(left1 - margin1, top1 - margin1, length1 * 難易度 + 間隔 * (難易度 - 1) + left1 + margin1, length1 * 難易度 + 間隔 * (難易度 - 1) + top1 + margin1);
- キャンバスに矩形を描画します。
- for ( int row = 0; row < 難易度; row++) {
- ( int 列= 0;列< 難易度;列++) {
- 色 backgroundcolor1 = new Color(Color.rgb(229,188,132));
- 背景色1を設定します。
- RectFloat rectFloat = new RectFloat(left1 + column * (length1 + interval), top1 + row * (length1 + interval), left1 + length1 + column * (length1 + interval), top1 + length1 + row * (length1 + interval));
- キャンバスに矩形を描画します。
-
- 色番号color1 = new Color(Color.rgb(140,85,47));
- paint.setColor(数値色1);
- ペイント.setTextSize(長さ1 / 2);
- if(grids_b[行][列] != 0){
- if(grids_b[行][列] < 10){
- canvas.drawText(paint, Integer .toString(grids_b[row][ column ]),left1 + column * (length1 + interval) + length1 / 12 * 5,top1 + row * (length1 + interval) + length1 / 3 * 2);
- }それ以外{
- canvas.drawText(paint, Integer .toString(grids_b[row][ column ]),left1 + column * (length1 + interval) + length1 / 12 * 3,top1 + row * (length1 + interval) + length1 / 3 * 2);
- }
- }
- }
- }
- }
- };
-
- レイアウトにタスクを追加します。
- UIContent を設定します。
- }
次のステップは、時間とボタンを描画することです。 - パブリックボイド描画() {
- maxtext = 新しいテキスト(これ);
- テキストの最大サイズを設定します。
- テキストサイズを80に設定します。
- maxtext.setMarginTop(40);
- maxtext.setMarginLeft(140);
- レイアウトにコンポーネントを追加します(最大テキスト)。
-
- timetext = 新しいテキスト(これ);
- timetext.setText( "時間: 00:00:00:00" );
- タイムテキスト.setTextSize(80);
- 時間テキスト.setMarginTop(10);
- 時間テキスト.setMarginLeft(230);
- レイアウトにコンポーネントを追加します。
-
- ShapeElement の背景 = 新しい ShapeElement();
- 背景.setRgbColor(新しいRgbColor(138,70,50));
- 背景.setCornerRadius(100);
-
- ボタン button_again = new Button(this);
- button_again.setText( "再起動" );
- button_again.setTextAlignment(TextAlignment.CENTER);
- button_again.setTextColor(Color.WHITE);
- ボタンをもう一度押します。テキストサイズを100に設定します。
- ボタンをもう一度クリックします。
- ボタンをもう一度設定します。左余白を設定します(730);
- ボタンをもう一度設定します。パディングを 30, 0, 30, 0 に設定します。
- button_again.setBackground(背景);
- button_again.setClickedListener(新しいComponent.ClickedListener() {
- @オーバーライド
- パブリックvoid onClick(コンポーネント コンポーネント) {
- レコードを取得します。
- writeData_int( "再起動" ,1);
- }
- });
- レイアウトにコンポーネントを追加します(ボタンをもう一度)。
-
- ボタン button_back = new Button(this);
- button_back.setText( "戻る" );
- button_back.setTextAlignment(TextAlignment.CENTER);
- ボタンを戻すには、テキストの色を白に設定します。
- ボタンを戻す。テキストサイズを100に設定する。
- ボタンの左余白を設定します(730);
- ボタンを戻す。上マージンを90に設定する。
- ボタンの後ろのパディングを設定します(30, 0, 30, 0);
- button_back.setBackground(背景);
- button_back.setClickedListener(新しいComponent.ClickedListener() {
- @オーバーライド
- パブリックvoid onClick(コンポーネント コンポーネント) {
-
- }
- });
- レイアウトにコンポーネントを追加します(ボタンバック);
-
- UIContent を設定します。
- }
これが私たちのレンダリングです。実行して、まったく同じかどうかを確認することもできます。すべてが同じであることを確認した後でのみ、手順を追って続行してください。 比較的重要な問題である初期同期の問題はすでに解決しています。次に、ゲーム機能を完成させていきます。ゲーム機能を完成させる前に、ゲームが成功したかどうかを判断する関数を記述する必要があります。 - パブリックブール型ゲーム成功() {
- int [][] Grids = new int [難易度][難易度];
- for ( int row = 0; row < 難易度; row++){
- ( int 列= 0;列< 難易度;列++){
- グリッド[行][列] = 難易度 * 行 +列+ 1;
- }
- }
- グリッド[難易度 - 1][難易度 - 1] = 0;
-
- for ( int row = 0; row < 難易度; row++){
- ( int 列= 0;列< 難易度;列++){
- if(grids_a[行][列] != Grids[行][列]){
- 戻る 間違い;
- }
- }
- }
-
- 戻る 真実;
- }
次に、現在の時刻が最短時刻よりも早いかどうかを判断する関数と、現在の時刻をデータベースに書き込む関数を記述します。 - パブリックブール比較() {
- int nowtime =時間* 36000 +分* 6000 + 秒 * 100 + ミリ秒;
- int maxtime = maxhour * 36000 + maxmin * 6000 + maxsec * 100 + maxmsec;
-
- nowtime > maxtimeを返します。
- }
-
- パブリックvoid書き込み() {
- 比較() の場合
- writeData_int( "時間" + 難易度,時間);
- writeData_int( "min" + 難易度, min );
- writeData_int( "秒" + 難易度,秒);
- writeData_int( "msec" + 難易度, msec);
- }
- }
これでゲーム機能が完成し、このデバイスでゲームをプレイし、データベースにデータを書き込み、別のデバイスにデータを読み取らせ、データの同期を実現する必要があります。 - パブリックvoid swipeGrids(){
- layout.setTouchEventListener(新しいComponent.TouchEventListener() {
- @オーバーライド
- パブリックブールonTouchEvent(コンポーネントコンポーネント、TouchEvent touchEvent) {
- MmiPoint ポイント = touchEvent.getPointerScreenPosition(0);
-
- スイッチ(タッチイベント.getAction()){
- TouchEvent.PRIMARY_POINT_DOWNの場合:
- startX = point.getX();
- ポイントYを取得する
-
- 文字列 str_row = String.valueOf(Math.floor((startY - top - 80) / (length + interval)));
- 文字列 str2_column = String.valueOf(Math.floor((startX - left ) / (length + interval)));
- ゲームが成功した場合
- writeData_int( "行" + isLocal 、str_row.charAt(0)- '0' );
- writeData_int( "列" + isLocal ,str2_column.charAt(0)- '0' );
- グリッドを変更します(str_row.charAt(0)- '0' 、 str2_column.charAt(0)- '0' );
- グリッドを描画します。
- ゲームが成功した場合(){
- レコードを取得します。
- 最大テキストを設定します。
- HiLog.info(タグ、整数.toString(maxmsec));
- タイマーをキャンセルします。
- 更新タイマーをキャンセルします。
- 比較() の場合
- maxhour =時間;
- 最大値最小値 =最小値;
- 最大秒数 = 秒;
- 最大ミリ秒 = ミリ秒;
- 書く();
- テキストの最大サイズを設定します。
- UIContent を設定します。
- }
- }
- }
- 壊す;
- }
- 戻る 真実;
- }
- });
- }
データが同期された後、まだデータの書き込みと提示は行われていません。ここで、配列 b の内容を描画する必要があるため、この関数を実装するために別のタイム スレッドを作成します。 - パブリックボイドアップデート(){
- updatetimer = 新しいタイマー();
- タイマーのスケジュールを更新します(新しいタイマータスク() {
- @オーバーライド
- パブリックボイド実行(){
- getUITaskDispatcher().asyncDispatch(() -> {
- グリッドを描画します。
- });
- }
- },0,500);
- }
次に、サブスクリプション機能にデータ同期操作も追加する必要があります。 - (queryContact_int( "行" + !isLocal)!=-1 && queryContact_int( "列" + !isLocal)!=-1)の場合
- changeGrids_b(queryContact_int( "行" + !isLocal),queryContact_int( "列" + !isLocal));
次に、時間を動かす関数を書いてみましょう。 - パブリックvoid 実行(){
- タイマー = 新しいタイマー();
- timer.schedule(new TimerTask() {
- @オーバーライド
- パブリックボイド実行(){
- getUITaskDispatcher().asyncDispatch(()->{
- ミリ秒++;
- (ミリ秒 >= 100)の場合{
- 秒++;
- ミリ秒 = ミリ秒 % 100;
- (秒> = 60)の場合{
- 最小++;
- 秒 = 秒 % 60;
- (最小値>=60)の場合
- 時間++;
- 最小=最小% 60;
- }
- }
- }
- 文字列 strhour = "" ;
- 文字列 strmin = "" ;
- 文字列 strsec = "" ;
- 文字列 strmsec = "" ;
- (ミリ秒<10)の場合{
- strmsec = "0" +整数.toString(msec);
- }それ以外の場合 (ミリ秒 >= 10) {
- strmsec =整数.toString(msec);
- }
- (秒<10)の場合{
- strsec = "0" +整数.toString(sec);
- }それ以外の場合 (秒 >= 10) {
- strsec =整数.toString(sec);
- }
- (最小値<10)の場合{
- strmin = "0" +整数.toString( min );
- }そうでなければ (最小値>= 10) {
- strmin =整数.toString( min );
- }
- (時間< 10 ) の場合 {
- strhour = "0" +整数.toString(時間);
- }そうでない場合 (時間>= 10) {
- strhour = Integer .toString(時間);
- }
- timetext.setText( "time: " + strhour + ":" +strmin+ ":" +strsec+ ":" +strmsec);
- });
- }
- },0,10);
- }
同様に、サブスクリプション機能ではデータ同期を実装する必要がある。 - if (queryContact_int( "時間" + 難易度) != -1)
- maxhour = queryContact_int( "時間" + 難易度);
- if(queryContact_int( "min" + 難易度)!=-1)
- maxmin = queryContact_int( "min" +難易度);
- if(queryContact_int( "秒" +難易度)!=-1)
- maxsec = queryContact_int( "秒" + 難易度);
- if (queryContact_int( "msec" + 難易度)!=-1)
- maxmsec = queryContact_int( "msec" + 難易度);
これでゲーム機能が完成しました。次に、戻るボタンのクリックイベントを実装しましょう。 - タイマーをキャンセルします。
- 更新タイマーをキャンセルします。
- 終了();
次に、再起動クリックイベントを記述します。両方のデバイスを同時に再起動できるようにするには、再起動ボタンがクリックされたときにデータベースに信号を書き込み、タイムスレッドを使用してこの信号を検出します。検出されると、ゲームが再起動されます。 - パブリックvoid再起動() {
- タイマーを再起動します。
- タイマーを再起動する。スケジュール(新しいタイマータスク() {
- @オーバーライド
- パブリックボイド実行(){
- getUITaskDispatcher().asyncDispatch(() ->{
- (再起動 == 1)の場合{
- タイマーをキャンセルします。
- 更新タイマーをキャンセルします。
- 再起動 = 0;
- 初期化します。
- 実行中();
- アップデート();
- }
- });
- }
- },0,25);
- }
これでゲームは完成しました。これらの分散機能を使用して、さらに多くの 2 人用ゲームを作成することもできます。 記事に関連する添付ファイルをダウンロードするには、以下のリンクをクリックしてください。 https://harmonyos..com/resource/1294 詳細については、以下をご覧ください。 51CTOとHuaweiが共同で構築したHongmengテクノロジーコミュニティ https://harmonyos..com |